1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2018, Joyent, Inc.
25 * Copyright 2017 Gary Mills
26 * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
27 * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
28 * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
29 */
30
31 #include <arpa/inet.h>
32 #include <errno.h>
33 #include <getopt.h>
34 #include <inet/ip.h>
35 #include <inet/iptun.h>
36 #include <inet/tunables.h>
37 #include <libdladm.h>
38 #include <libdliptun.h>
39 #include <libdllink.h>
40 #include <libinetutil.h>
41 #include <libipadm.h>
42 #include <ipmp.h>
43 #include <ipmp_admin.h>
44 #include <locale.h>
45 #include <netdb.h>
46 #include <netinet/in.h>
47 #include <ofmt.h>
48 #include <stdarg.h>
49 #include <stddef.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <strings.h>
54 #include <sys/stat.h>
55 #include <sys/types.h>
56 #include <zone.h>
57 #include <sys/list.h>
58 #include <stddef.h>
59
60 #define STR_UNKNOWN_VAL "?"
61 #define LIFC_DEFAULT (LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES |\
62 LIFC_UNDER_IPMP)
63
64 static void do_create_ip_common(int, char **, const char *, uint32_t);
65
66 typedef void cmdfunc_t(int, char **, const char *);
67 static cmdfunc_t do_help;
68 static cmdfunc_t do_create_ip, do_delete_ip;
69 static cmdfunc_t do_create_ipmp, do_add_ipmp, do_remove_ipmp;
70 static cmdfunc_t do_disable_if, do_enable_if, do_show_if;
71 static cmdfunc_t do_set_ifprop, do_reset_ifprop, do_show_ifprop;
72 static cmdfunc_t do_create_addr, do_delete_addr, do_show_addr, do_refresh_addr;
73 static cmdfunc_t do_disable_addr, do_enable_addr, do_down_addr, do_up_addr;
74 static cmdfunc_t do_set_addrprop, do_reset_addrprop, do_show_addrprop;
75 static cmdfunc_t do_set_prop, do_reset_prop, do_show_prop;
76
77 typedef struct cmd {
78 char *c_name;
79 cmdfunc_t *c_fn;
80 const char *c_usage;
81 } cmd_t;
82
83 static cmd_t cmds[] = {
84 { "help", do_help, NULL },
85 /* interface management related sub-commands */
86 { "create-if", do_create_ip, "\tcreate-if\t[-t] <interface>" },
87 { "create-ip", do_create_ip, "\tcreate-ip\t[-t] <interface>" },
88 { "delete-if", do_delete_ip, "\tdelete-if\t<interface>\n" },
89 { "delete-ip", do_delete_ip, "\tdelete-ip\t<interface>\n" },
90
91 { "create-ipmp", do_create_ipmp,
92 "\tcreate-ipmp\t[-t] [-i <interface>[,<interface>]...] "
93 "<ipmp-interface>" },
94 { "delete-ipmp", do_delete_ip,
95 "\tdelete-ipmp\t<ipmp-interface>" },
96 { "add-ipmp", do_add_ipmp,
97 "\tadd-ipmp\t[-t] -i <interface>[,<interface>]... "
98 "<ipmp-interface>" },
99 { "remove-ipmp", do_remove_ipmp,
100 "\tremove-ipmp\t[-t] -i <interface>[,<interface>]... "
101 "<ipmp-interface>\n" },
102
103 { "disable-if", do_disable_if, "\tdisable-if\t-t <interface>" },
104 { "enable-if", do_enable_if, "\tenable-if\t-t <interface>" },
105 { "show-if", do_show_if,
106 "\tshow-if\t\t[[-p] -o <field>,...] [<interface>]\n" },
107
108 { "set-ifprop", do_set_ifprop,
109 "\tset-ifprop\t[-t] -p <prop>=<value[,...]> -m <protocol> "
110 "<interface>" },
111 { "reset-ifprop", do_reset_ifprop,
112 "\treset-ifprop\t[-t] -p <prop> -m <protocol> <interface>" },
113 { "show-ifprop", do_show_ifprop,
114 "\tshow-ifprop\t[[-c] -o <field>,...] [-p <prop>,...]\n"
115 "\t\t\t[-m <protocol>] [interface]\n" },
116
117 /* address management related sub-commands */
118 { "create-addr", do_create_addr,
119 "\tcreate-addr\t[-t] -T static [-d] "
120 "-a{local|remote}=addr[/prefixlen]\n\t\t\t<addrobj>\n"
121 "\tcreate-addr\t[-t] -T dhcp [-w <seconds> | forever]\n"
122 "\t\t\t[-1] [-h <hostname>] <addrobj>\n"
123 "\tcreate-addr\t[-t] -T addrconf [-i interface-id]\n"
124 "\t\t\t[-p {stateful|stateless}={yes|no}] <addrobj>" },
125 { "delete-addr", do_delete_addr, "\tdelete-addr\t[-r] <addrobj>" },
126 { "show-addr", do_show_addr,
127 "\tshow-addr\t[[-p] -o <field>,...] [<addrobj>]" },
128 { "refresh-addr", do_refresh_addr, "\trefresh-addr\t[-i] <addrobj>" },
129 { "down-addr", do_down_addr, "\tdown-addr\t[-t] <addrobj>" },
130 { "up-addr", do_up_addr, "\tup-addr\t\t[-t] <addrobj>" },
131 { "disable-addr", do_disable_addr, "\tdisable-addr\t-t <addrobj>" },
132 { "enable-addr", do_enable_addr, "\tenable-addr\t-t <addrobj>\n" },
133
134 { "set-addrprop", do_set_addrprop,
135 "\tset-addrprop\t[-t] -p <prop>=<value[,...]> <addrobj>" },
136 { "reset-addrprop", do_reset_addrprop,
137 "\treset-addrprop\t[-t] -p <prop> <addrobj>" },
138 { "show-addrprop", do_show_addrprop,
139 "\tshow-addrprop\t[[-c] -o <field>,...] [-p <prop>,...] "
140 "<addrobj>\n" },
141
142 /* protocol properties related sub-commands */
143 { "set-prop", do_set_prop,
144 "\tset-prop\t[-t] -p <prop>[+|-]=<value[,...]> <protocol>" },
145 { "reset-prop", do_reset_prop,
146 "\treset-prop\t[-t] -p <prop> <protocol>" },
147 { "show-prop", do_show_prop,
148 "\tshow-prop\t[[-c] -o <field>,...] [-p <prop>,...]"
149 " [protocol]" }
150 };
151
152 static const struct option if_longopts[] = {
153 {"temporary", no_argument, 0, 't' },
154 { 0, 0, 0, 0 }
155 };
156
157 static const struct option show_prop_longopts[] = {
158 {"parsable", no_argument, 0, 'c' },
159 {"prop", required_argument, 0, 'p' },
160 {"output", required_argument, 0, 'o' },
161 { 0, 0, 0, 0 }
162 };
163
164 static const struct option show_ifprop_longopts[] = {
165 {"module", required_argument, 0, 'm' },
166 {"parsable", no_argument, 0, 'c' },
167 {"prop", required_argument, 0, 'p' },
168 {"output", required_argument, 0, 'o' },
169 { 0, 0, 0, 0 }
170 };
171
172 static const struct option set_prop_longopts[] = {
173 {"prop", required_argument, 0, 'p' },
174 {"temporary", no_argument, 0, 't' },
175 { 0, 0, 0, 0 }
176 };
177
178 static const struct option set_ifprop_longopts[] = {
179 {"module", required_argument, 0, 'm' },
180 {"prop", required_argument, 0, 'p' },
181 {"temporary", no_argument, 0, 't' },
182 { 0, 0, 0, 0 }
183 };
184
185 static const struct option addr_misc_longopts[] = {
186 {"inform", no_argument, 0, 'i' },
187 {"release", no_argument, 0, 'r' },
188 {"temporary", no_argument, 0, 't' },
189 { 0, 0, 0, 0 }
190 };
191
192 static const struct option addr_longopts[] = {
193 {"address", required_argument, 0, 'a' },
194 {"down", no_argument, 0, 'd' },
195 {"interface-id", required_argument, 0, 'i' },
196 {"primary", no_argument, 0, '1' },
197 {"prop", required_argument, 0, 'p' },
198 {"reqhost", required_argument, 0, 'h' },
199 {"temporary", no_argument, 0, 't' },
200 {"type", required_argument, 0, 'T' },
201 {"wait", required_argument, 0, 'w' },
202 { 0, 0, 0, 0 }
203 };
204
205 static const struct option show_addr_longopts[] = {
206 {"parsable", no_argument, 0, 'p' },
207 {"output", required_argument, 0, 'o' },
208 { 0, 0, 0, 0 }
209 };
210
211 static const struct option show_if_longopts[] = {
212 {"parsable", no_argument, 0, 'p' },
213 {"output", required_argument, 0, 'o' },
214 { 0, 0, 0, 0 }
215 };
216
217 /* callback functions to print show-* subcommands output */
218 static ofmt_cb_t print_prop_cb;
219 static ofmt_cb_t print_sa_cb;
220 static ofmt_cb_t print_si_cb;
221
222 /* structures for 'ipadm show-*' subcommands */
223 typedef enum {
224 IPADM_PROPFIELD_IFNAME,
225 IPADM_PROPFIELD_PROTO,
226 IPADM_PROPFIELD_ADDROBJ,
227 IPADM_PROPFIELD_PROPERTY,
228 IPADM_PROPFIELD_PERM,
229 IPADM_PROPFIELD_CURRENT,
230 IPADM_PROPFIELD_PERSISTENT,
231 IPADM_PROPFIELD_DEFAULT,
232 IPADM_PROPFIELD_POSSIBLE
233 } ipadm_propfield_index_t;
234
235 static ofmt_field_t intfprop_fields[] = {
236 /* name, field width, index, callback */
237 { "IFNAME", 12, IPADM_PROPFIELD_IFNAME, print_prop_cb},
238 { "PROPERTY", 16, IPADM_PROPFIELD_PROPERTY, print_prop_cb},
239 { "PROTO", 6, IPADM_PROPFIELD_PROTO, print_prop_cb},
240 { "PERM", 5, IPADM_PROPFIELD_PERM, print_prop_cb},
241 { "CURRENT", 11, IPADM_PROPFIELD_CURRENT, print_prop_cb},
242 { "PERSISTENT", 11, IPADM_PROPFIELD_PERSISTENT, print_prop_cb},
243 { "DEFAULT", 11, IPADM_PROPFIELD_DEFAULT, print_prop_cb},
244 { "POSSIBLE", 16, IPADM_PROPFIELD_POSSIBLE, print_prop_cb},
245 { NULL, 0, 0, NULL}
246 };
247
248
249 static ofmt_field_t modprop_fields[] = {
250 /* name, field width, index, callback */
251 { "PROTO", 6, IPADM_PROPFIELD_PROTO, print_prop_cb},
252 { "PROPERTY", 22, IPADM_PROPFIELD_PROPERTY, print_prop_cb},
253 { "PERM", 5, IPADM_PROPFIELD_PERM, print_prop_cb},
254 { "CURRENT", 13, IPADM_PROPFIELD_CURRENT, print_prop_cb},
255 { "PERSISTENT", 13, IPADM_PROPFIELD_PERSISTENT, print_prop_cb},
256 { "DEFAULT", 13, IPADM_PROPFIELD_DEFAULT, print_prop_cb},
257 { "POSSIBLE", 15, IPADM_PROPFIELD_POSSIBLE, print_prop_cb},
258 { NULL, 0, 0, NULL}
259 };
260
261 static ofmt_field_t addrprop_fields[] = {
262 /* name, field width, index, callback */
263 { "ADDROBJ", 18, IPADM_PROPFIELD_ADDROBJ, print_prop_cb},
264 { "PROPERTY", 11, IPADM_PROPFIELD_PROPERTY, print_prop_cb},
265 { "PERM", 5, IPADM_PROPFIELD_PERM, print_prop_cb},
266 { "CURRENT", 16, IPADM_PROPFIELD_CURRENT, print_prop_cb},
267 { "PERSISTENT", 16, IPADM_PROPFIELD_PERSISTENT, print_prop_cb},
268 { "DEFAULT", 16, IPADM_PROPFIELD_DEFAULT, print_prop_cb},
269 { "POSSIBLE", 15, IPADM_PROPFIELD_POSSIBLE, print_prop_cb},
270 { NULL, 0, 0, NULL}
271 };
272
273 typedef struct show_prop_state {
274 char sps_ifname[LIFNAMSIZ];
275 char sps_aobjname[IPADM_AOBJSIZ];
276 const char *sps_pname;
277 uint_t sps_proto;
278 char *sps_propval;
279 nvlist_t *sps_proplist;
280 boolean_t sps_parsable;
281 boolean_t sps_addrprop;
282 boolean_t sps_ifprop;
283 boolean_t sps_modprop;
284 ipadm_status_t sps_status;
285 ipadm_status_t sps_retstatus;
286 ofmt_handle_t sps_ofmt;
287 } show_prop_state_t;
288
289 typedef struct show_addr_state {
290 boolean_t sa_parsable;
291 boolean_t sa_persist;
292 ofmt_handle_t sa_ofmt;
293 } show_addr_state_t;
294
295 typedef struct show_if_state {
296 boolean_t si_parsable;
297 ofmt_handle_t si_ofmt;
298 } show_if_state_t;
299
300 typedef struct show_addr_args_s {
301 show_addr_state_t *sa_state;
302 ipadm_addr_info_t *sa_info;
303 } show_addr_args_t;
304
305 typedef struct show_if_args_s {
306 show_if_state_t *si_state;
307 ipadm_if_info_t *si_info;
308 } show_if_args_t;
309
310 typedef enum {
311 SA_ADDROBJ,
312 SA_TYPE,
313 SA_STATE,
314 SA_CURRENT,
315 SA_PERSISTENT,
316 SA_ADDR
317 } sa_field_index_t;
318
319 typedef enum {
320 SI_IFNAME,
321 SI_IFCLASS,
322 SI_STATE,
323 SI_CURRENT,
324 SI_PERSISTENT
325 } si_field_index_t;
326
327 static ofmt_field_t show_addr_fields[] = {
328 /* name, field width, id, callback */
329 { "ADDROBJ", 18, SA_ADDROBJ, print_sa_cb},
330 { "TYPE", 9, SA_TYPE, print_sa_cb},
331 { "STATE", 13, SA_STATE, print_sa_cb},
332 { "CURRENT", 8, SA_CURRENT, print_sa_cb},
333 { "PERSISTENT", 11, SA_PERSISTENT, print_sa_cb},
334 { "ADDR", 46, SA_ADDR, print_sa_cb},
335 { NULL, 0, 0, NULL}
336 };
337
338 static ofmt_field_t show_if_fields[] = {
339 /* name, field width, id, callback */
340 { "IFNAME", 11, SI_IFNAME, print_si_cb},
341 { "CLASS", 10, SI_IFCLASS, print_si_cb},
342 { "STATE", 9, SI_STATE, print_si_cb},
343 { "CURRENT", 13, SI_CURRENT, print_si_cb},
344 { "PERSISTENT", 11, SI_PERSISTENT, print_si_cb},
345 { NULL, 0, 0, NULL}
346 };
347
348 #define IPADM_ALL_BITS ((uint_t)-1)
349 typedef struct intf_mask {
350 char *name;
351 uint64_t bits;
352 uint64_t mask;
353 } fmask_t;
354
355 typedef enum {
356 IPMP_ADD_MEMBER,
357 IPMP_REMOVE_MEMBER
358 } ipmp_action_t;
359
360 /*
361 * Handle to libipadm. Opened in main() before the sub-command specific
362 * function is called and is closed before the program exits.
363 */
364 ipadm_handle_t iph = NULL;
365
366 /*
367 * Opaque ipadm address object. Used by all the address management subcommands.
368 */
369 ipadm_addrobj_t ipaddr = NULL;
370
371 static char *progname;
372
373
374 static void warn(const char *, ...);
375 static void die(const char *, ...) __NORETURN;
376 static void die_opterr(int, int, const char *) __NORETURN;
377 static void warn_ipadmerr(ipadm_status_t, const char *, ...);
378 static void ipadm_check_propstr(const char *, boolean_t, const char *);
379 static void process_misc_addrargs(int, char **, const char *, int *,
380 uint32_t *);
381 static void do_action_ipmp(char *, ipadm_ipmp_members_t *, ipmp_action_t,
382 uint32_t);
383
384
385 static void
usage(int ret)386 usage(int ret)
387 {
388 int i;
389 cmd_t *cmdp;
390
391 (void) fprintf(stderr,
392 gettext("usage: ipadm <subcommand> <args> ...\n"));
393 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
394 cmdp = &cmds[i];
395 if (cmdp->c_usage != NULL)
396 (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
397 }
398
399 ipadm_destroy_addrobj(ipaddr);
400 ipadm_close(iph);
401 exit(ret);
402 }
403
404 static void
do_help(int argc __unused,char ** argv __unused,const char * use __unused)405 do_help(int argc __unused, char **argv __unused, const char *use __unused)
406 {
407 usage(0);
408 }
409
410 int
main(int argc,char * argv[])411 main(int argc, char *argv[])
412 {
413 int i;
414 cmd_t *cmdp;
415 ipadm_status_t status;
416
417 (void) setlocale(LC_ALL, "");
418 (void) textdomain(TEXT_DOMAIN);
419
420 if ((progname = strrchr(argv[0], '/')) == NULL)
421 progname = argv[0];
422 else
423 progname++;
424
425 if (argc < 2) {
426 argv[1] = "show-addr";
427 argc = 2;
428 }
429
430 status = ipadm_open(&iph, 0);
431 if (status != IPADM_SUCCESS) {
432 die("Could not open handle to library - %s",
433 ipadm_status2str(status));
434 }
435
436 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
437 cmdp = &cmds[i];
438 if (strcmp(argv[1], cmdp->c_name) == 0) {
439 cmdp->c_fn(argc - 1, &argv[1], gettext(cmdp->c_usage));
440 ipadm_destroy_addrobj(ipaddr);
441 ipadm_close(iph);
442 exit(0);
443 }
444 }
445
446 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
447 progname, argv[1]);
448 usage(1);
449
450 return (0);
451 }
452
453 /*
454 * Create regular IP interface or IPMP group interface
455 */
456 static void
do_create_ip_common(int argc,char * argv[],const char * use,uint32_t flags)457 do_create_ip_common(int argc, char *argv[], const char *use, uint32_t flags)
458 {
459 ipadm_status_t status;
460 int option;
461
462 opterr = 0;
463 while ((option = getopt_long(argc, argv,
464 ":t", if_longopts, NULL)) != -1) {
465 switch (option) {
466 case 't':
467 /*
468 * "ifconfig" mode - plumb interface, but do not
469 * restore settings that may exist in db.
470 */
471 flags &= ~IPADM_OPT_PERSIST;
472 break;
473 default:
474 die_opterr(optopt, option, use);
475 }
476 }
477 if (optind != (argc - 1)) {
478 if (use != NULL)
479 die("usage: %s", use);
480 else
481 die(NULL);
482 }
483 status = ipadm_create_if(iph, argv[optind], AF_UNSPEC, flags);
484 if (status != IPADM_SUCCESS) {
485 die("Could not create %s : %s",
486 argv[optind], ipadm_status2str(status));
487 }
488 }
489
490 /*
491 * Helpers to parse options into ipadm_ipmp_members_t list, and to free it.
492 */
493 static ipadm_ipmp_members_t *
get_ipmp_members(int argc,char * argv[],const char * use,uint32_t * flags)494 get_ipmp_members(int argc, char *argv[], const char *use, uint32_t *flags)
495 {
496 ipadm_ipmp_members_t *members = NULL;
497 ipadm_ipmp_member_t *member;
498 char *ifname;
499 int option;
500
501
502 opterr = 0;
503 while ((option = getopt_long(argc, argv, ":i:", if_longopts, NULL)) !=
504 -1) {
505 switch (option) {
506 case 't':
507 *flags &= ~IPADM_OPT_PERSIST;
508 break;
509 case 'i':
510 if (members == NULL) {
511 members = calloc(1,
512 sizeof (ipadm_ipmp_members_t));
513 if (members == NULL)
514 die("insufficient memory");
515 list_create(members,
516 sizeof (ipadm_ipmp_member_t),
517 offsetof(ipadm_ipmp_member_t, node));
518 }
519
520 for (ifname = strtok(optarg, ",");
521 ifname != NULL;
522 ifname = strtok(NULL, ",")) {
523 if ((member = calloc(1,
524 sizeof (ipadm_ipmp_member_t))) == NULL)
525 die("insufficient memory");
526
527 if (strlcpy(member->if_name, ifname,
528 sizeof (member->if_name)) >= LIFNAMSIZ)
529 die("Incorrect length of interface "
530 "name: %s", ifname);
531
532 list_insert_tail(members, member);
533 }
534 break;
535 default:
536 die_opterr(optopt, option, use);
537 }
538 }
539
540 if (optind != (argc - 1))
541 die("Usage: %s", use);
542
543 if (members != NULL && list_is_empty(members)) {
544 free(members);
545 members = NULL;
546 }
547
548 return (members);
549 }
550
551 static void
free_ipmp_members(ipadm_ipmp_members_t * members)552 free_ipmp_members(ipadm_ipmp_members_t *members)
553 {
554 ipadm_ipmp_member_t *member;
555
556 while ((member = list_remove_head(members)) != NULL)
557 free(member);
558
559 list_destroy(members);
560
561 free(members);
562 }
563
564 /*
565 * Create an IPMP group interface for which no saved configuration
566 * exists in the persistent store.
567 */
568 static void
do_create_ipmp(int argc,char * argv[],const char * use)569 do_create_ipmp(int argc, char *argv[], const char *use)
570 {
571 uint32_t flags = IPADM_OPT_PERSIST | IPADM_OPT_ACTIVE | IPADM_OPT_IPMP;
572 ipadm_ipmp_members_t *members = NULL;
573 ipmp_handle_t ipmp_handle;
574 int retval;
575
576 retval = ipmp_open(&ipmp_handle);
577 if (retval != IPMP_SUCCESS) {
578 die("Could not create IPMP handle: %s",
579 ipadm_status2str(retval));
580 }
581
582 retval = ipmp_ping_daemon(ipmp_handle);
583 ipmp_close(ipmp_handle);
584
585 if (retval != IPMP_SUCCESS) {
586 die("Cannot ping in.mpathd: %s", ipmp_errmsg(retval));
587 }
588
589 members = get_ipmp_members(argc, argv, use, &flags);
590
591 do_create_ip_common(argc, argv, use, flags);
592
593 if (members != NULL) {
594 do_action_ipmp(argv[optind], members, IPMP_ADD_MEMBER, flags);
595 free_ipmp_members(members);
596 }
597 }
598
599 static void
do_add_ipmp(int argc,char * argv[],const char * use)600 do_add_ipmp(int argc, char *argv[], const char *use)
601 {
602 uint32_t flags = IPADM_OPT_PERSIST | IPADM_OPT_ACTIVE;
603 ipadm_ipmp_members_t *members;
604
605 members = get_ipmp_members(argc, argv, use, &flags);
606
607 if (members == NULL)
608 die_opterr(optopt, ':', use);
609
610 do_action_ipmp(argv[optind], members, IPMP_ADD_MEMBER, flags);
611 free_ipmp_members(members);
612 }
613
614 static void
do_remove_ipmp(int argc,char * argv[],const char * use)615 do_remove_ipmp(int argc, char *argv[], const char *use)
616 {
617 uint32_t flags = IPADM_OPT_PERSIST | IPADM_OPT_ACTIVE;
618 ipadm_ipmp_members_t *members;
619
620 members = get_ipmp_members(argc, argv, use, &flags);
621
622 if (members == NULL)
623 die_opterr(optopt, ':', use);
624
625 do_action_ipmp(argv[optind], members, IPMP_REMOVE_MEMBER, flags);
626 free_ipmp_members(members);
627 }
628
629 static void
do_action_ipmp(char * ipmp,ipadm_ipmp_members_t * members,ipmp_action_t action,uint32_t flags)630 do_action_ipmp(char *ipmp, ipadm_ipmp_members_t *members, ipmp_action_t action,
631 uint32_t flags)
632 {
633 ipadm_status_t (*func)(ipadm_handle_t, const char *, const char *,
634 uint32_t);
635 ipadm_status_t status;
636 ipadm_ipmp_member_t *member;
637 char *ifname;
638 const char *msg;
639
640 if (action == IPMP_ADD_MEMBER) {
641 func = ipadm_add_ipmp_member;
642 msg = "Cannot add interface '%s' to IPMP interface '%s': %s";
643 } else {
644 func = ipadm_remove_ipmp_member;
645 msg = "Cannot remove interface '%s' from IPMP interface '%s': "
646 "%s";
647 }
648
649 while ((member = list_remove_head(members)) != NULL) {
650 ifname = member->if_name;
651
652 status = func(iph, ipmp, ifname, flags);
653 if (status != IPADM_SUCCESS)
654 die(msg, ifname, ipmp, ipadm_status2str(status));
655 }
656 }
657
658 /*
659 * Create an IP interface for which no saved configuration exists in the
660 * persistent store.
661 */
662 static void
do_create_ip(int argc,char * argv[],const char * use)663 do_create_ip(int argc, char *argv[], const char *use)
664 {
665 do_create_ip_common(argc, argv, use,
666 IPADM_OPT_PERSIST | IPADM_OPT_ACTIVE);
667 }
668
669 /*
670 * Enable an IP interface based on the persistent configuration for
671 * that interface.
672 */
673 static void
do_enable_if(int argc,char * argv[],const char * use)674 do_enable_if(int argc, char *argv[], const char *use)
675 {
676 ipadm_status_t status;
677 int index;
678 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
679
680 process_misc_addrargs(argc, argv, use, &index, &flags);
681 if (flags & IPADM_OPT_PERSIST)
682 die("persistent operation not supported for enable-if");
683 status = ipadm_enable_if(iph, argv[index], flags);
684 if (status == IPADM_ALL_ADDRS_NOT_ENABLED) {
685 warn_ipadmerr(status, "");
686 } else if (status != IPADM_SUCCESS) {
687 die("Could not enable %s : %s",
688 argv[optind], ipadm_status2str(status));
689 }
690 }
691
692 /*
693 * Remove an IP interface from both active and persistent configuration.
694 */
695 static void
do_delete_ip(int argc,char * argv[],const char * use)696 do_delete_ip(int argc, char *argv[], const char *use)
697 {
698 ipadm_status_t status;
699 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
700
701 if (argc != 2)
702 die("Usage: %s", use);
703
704 status = ipadm_delete_if(iph, argv[1], AF_UNSPEC, flags);
705 if (status != IPADM_SUCCESS) {
706 die("Could not delete %s: %s",
707 argv[optind], ipadm_status2str(status));
708 }
709 }
710
711 /*
712 * Disable an IP interface by removing it from active configuration.
713 */
714 static void
do_disable_if(int argc,char * argv[],const char * use)715 do_disable_if(int argc, char *argv[], const char *use)
716 {
717 ipadm_status_t status;
718 int index;
719 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
720
721 process_misc_addrargs(argc, argv, use, &index, &flags);
722 if (flags & IPADM_OPT_PERSIST)
723 die("persistent operation not supported for disable-if");
724 status = ipadm_disable_if(iph, argv[index], flags);
725 if (status != IPADM_SUCCESS) {
726 die("Could not disable %s: %s",
727 argv[optind], ipadm_status2str(status));
728 }
729 }
730
731 /*
732 * Print individual columns for the show-*prop subcommands.
733 */
734 static void
print_prop(show_prop_state_t * statep,uint_t flags,char * buf,size_t bufsize)735 print_prop(show_prop_state_t *statep, uint_t flags, char *buf, size_t bufsize)
736 {
737 const char *prop_name = statep->sps_pname;
738 char *ifname = statep->sps_ifname;
739 char *propval = statep->sps_propval;
740 uint_t proto = statep->sps_proto;
741 size_t propsize = MAXPROPVALLEN;
742 ipadm_status_t status;
743
744 if (statep->sps_ifprop) {
745 status = ipadm_get_ifprop(iph, ifname, prop_name, propval,
746 &propsize, proto, flags);
747 } else if (statep->sps_modprop) {
748 status = ipadm_get_prop(iph, prop_name, propval, &propsize,
749 proto, flags);
750 } else {
751 status = ipadm_get_addrprop(iph, prop_name, propval, &propsize,
752 statep->sps_aobjname, flags);
753 }
754
755 if (status != IPADM_SUCCESS) {
756 if ((status == IPADM_NOTFOUND && (flags & IPADM_OPT_PERSIST)) ||
757 status == IPADM_ENXIO) {
758 propval[0] = '\0';
759 goto cont;
760 }
761 statep->sps_status = status;
762 statep->sps_retstatus = status;
763 return;
764 }
765 cont:
766 statep->sps_status = IPADM_SUCCESS;
767 (void) snprintf(buf, bufsize, "%s", propval);
768 }
769
770 /*
771 * Callback function for show-*prop subcommands.
772 */
773 static boolean_t
print_prop_cb(ofmt_arg_t * ofarg,char * buf,size_t bufsize)774 print_prop_cb(ofmt_arg_t *ofarg, char *buf, size_t bufsize)
775 {
776 show_prop_state_t *statep = ofarg->ofmt_cbarg;
777 const char *propname = statep->sps_pname;
778 uint_t proto = statep->sps_proto;
779 boolean_t cont = _B_TRUE;
780
781 /*
782 * Fail retrieving remaining fields, if you fail
783 * to retrieve a field.
784 */
785 if (statep->sps_status != IPADM_SUCCESS)
786 return (_B_FALSE);
787
788 switch (ofarg->ofmt_id) {
789 case IPADM_PROPFIELD_IFNAME:
790 (void) snprintf(buf, bufsize, "%s", statep->sps_ifname);
791 break;
792 case IPADM_PROPFIELD_PROTO:
793 (void) snprintf(buf, bufsize, "%s", ipadm_proto2str(proto));
794 break;
795 case IPADM_PROPFIELD_ADDROBJ:
796 (void) snprintf(buf, bufsize, "%s", statep->sps_aobjname);
797 break;
798 case IPADM_PROPFIELD_PROPERTY:
799 (void) snprintf(buf, bufsize, "%s", propname);
800 break;
801 case IPADM_PROPFIELD_PERM:
802 print_prop(statep, IPADM_OPT_PERM, buf, bufsize);
803 break;
804 case IPADM_PROPFIELD_CURRENT:
805 print_prop(statep, IPADM_OPT_ACTIVE, buf, bufsize);
806 break;
807 case IPADM_PROPFIELD_PERSISTENT:
808 print_prop(statep, IPADM_OPT_PERSIST, buf, bufsize);
809 break;
810 case IPADM_PROPFIELD_DEFAULT:
811 print_prop(statep, IPADM_OPT_DEFAULT, buf, bufsize);
812 break;
813 case IPADM_PROPFIELD_POSSIBLE:
814 print_prop(statep, IPADM_OPT_POSSIBLE, buf, bufsize);
815 break;
816 }
817 if (statep->sps_status != IPADM_SUCCESS)
818 cont = _B_FALSE;
819 return (cont);
820 }
821
822 /*
823 * Callback function called by the property walker (ipadm_walk_prop() or
824 * ipadm_walk_proptbl()), for every matched property. This function in turn
825 * calls ofmt_print() to print property information.
826 */
827 boolean_t
show_property(void * arg,const char * pname,uint_t proto)828 show_property(void *arg, const char *pname, uint_t proto)
829 {
830 show_prop_state_t *statep = arg;
831
832 statep->sps_pname = pname;
833 statep->sps_proto = proto;
834 statep->sps_status = IPADM_SUCCESS;
835 ofmt_print(statep->sps_ofmt, arg);
836
837 /*
838 * if an object is not found or operation is not supported then
839 * stop the walker.
840 */
841 if (statep->sps_status == IPADM_NOTFOUND ||
842 statep->sps_status == IPADM_NOTSUP)
843 return (_B_FALSE);
844 return (_B_TRUE);
845 }
846
847 /*
848 * Properties to be displayed is in `statep->sps_proplist'. If it is NULL,
849 * for all the properties for the specified object, display relevant
850 * information. Otherwise, for the selected property set, display relevant
851 * information
852 */
853 static void
show_properties(void * arg,int prop_class)854 show_properties(void *arg, int prop_class)
855 {
856 show_prop_state_t *statep = arg;
857 nvlist_t *nvl = statep->sps_proplist;
858 uint_t proto = statep->sps_proto;
859 nvpair_t *curr_nvp;
860 char *buf, *name;
861 ipadm_status_t status;
862
863 /* allocate sufficient buffer to hold a property value */
864 if ((buf = malloc(MAXPROPVALLEN)) == NULL)
865 die("insufficient memory");
866 statep->sps_propval = buf;
867
868 /* if no properties were specified, display all the properties */
869 if (nvl == NULL) {
870 (void) ipadm_walk_proptbl(proto, prop_class, show_property,
871 statep);
872 } else {
873 for (curr_nvp = nvlist_next_nvpair(nvl, NULL); curr_nvp;
874 curr_nvp = nvlist_next_nvpair(nvl, curr_nvp)) {
875 name = nvpair_name(curr_nvp);
876 status = ipadm_walk_prop(name, proto, prop_class,
877 show_property, statep);
878 if (status == IPADM_PROP_UNKNOWN)
879 (void) show_property(statep, name, proto);
880 }
881 }
882
883 free(buf);
884 }
885
886 /*
887 * Display information for all or specific interface properties, either for a
888 * given interface or for all the interfaces in the system.
889 */
890 static void
do_show_ifprop(int argc,char ** argv,const char * use)891 do_show_ifprop(int argc, char **argv, const char *use)
892 {
893 int option;
894 nvlist_t *proplist = NULL;
895 char *fields_str = NULL;
896 char *ifname;
897 ofmt_handle_t ofmt;
898 ofmt_status_t oferr;
899 uint_t ofmtflags = 0;
900 uint_t proto;
901 boolean_t m_arg = _B_FALSE;
902 char *protostr;
903 ipadm_if_info_t *ifinfo, *ifp;
904 ipadm_status_t status;
905 show_prop_state_t state;
906
907 protostr = "ip";
908 opterr = 0;
909 bzero(&state, sizeof (state));
910 state.sps_propval = NULL;
911 state.sps_parsable = _B_FALSE;
912 state.sps_ifprop = _B_TRUE;
913 state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
914 while ((option = getopt_long(argc, argv, ":p:m:co:",
915 show_ifprop_longopts, NULL)) != -1) {
916 switch (option) {
917 case 'p':
918 if (ipadm_str2nvlist(optarg, &proplist,
919 IPADM_NORVAL) != 0)
920 die("invalid interface properties specified");
921 break;
922 case 'c':
923 state.sps_parsable = _B_TRUE;
924 break;
925 case 'o':
926 fields_str = optarg;
927 break;
928 case 'm':
929 if (m_arg)
930 die("cannot specify more than one -m");
931 m_arg = _B_TRUE;
932 protostr = optarg;
933 break;
934 default:
935 die_opterr(optopt, option, use);
936 break;
937 }
938 }
939
940 if (optind == argc - 1)
941 ifname = argv[optind];
942 else if (optind != argc)
943 die("Usage: %s", use);
944 else
945 ifname = NULL;
946
947 if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
948 die("invalid protocol '%s' specified", protostr);
949
950 state.sps_proto = proto;
951 state.sps_proplist = proplist;
952
953 if (state.sps_parsable)
954 ofmtflags |= OFMT_PARSABLE;
955 oferr = ofmt_open(fields_str, intfprop_fields, ofmtflags, 0, &ofmt);
956 ofmt_check(oferr, state.sps_parsable, ofmt, die, warn);
957 state.sps_ofmt = ofmt;
958
959 /* retrieve interface(s) and print the properties */
960 status = ipadm_if_info(iph, ifname, &ifinfo, 0, LIFC_DEFAULT);
961 if (ifname != NULL && status == IPADM_ENXIO)
962 die("no such object '%s': %s", ifname,
963 ipadm_status2str(status));
964 if (status != IPADM_SUCCESS)
965 die("Error retrieving interface(s): %s",
966 ipadm_status2str(status));
967 for (ifp = ifinfo; ifp != NULL; ifp = ifp->ifi_next) {
968 (void) strlcpy(state.sps_ifname, ifp->ifi_name, LIFNAMSIZ);
969 state.sps_proto = proto;
970 show_properties(&state, IPADMPROP_CLASS_IF);
971 }
972 if (ifinfo)
973 ipadm_free_if_info(ifinfo);
974
975 nvlist_free(proplist);
976 ofmt_close(ofmt);
977
978 if (state.sps_retstatus != IPADM_SUCCESS) {
979 ipadm_close(iph);
980 exit(EXIT_FAILURE);
981 }
982 }
983
984 /*
985 * set/reset the interface property for a given interface.
986 */
987 static void
set_ifprop(int argc,char ** argv,boolean_t reset,const char * use)988 set_ifprop(int argc, char **argv, boolean_t reset, const char *use)
989 {
990 int option;
991 ipadm_status_t status = IPADM_SUCCESS;
992 boolean_t p_arg = _B_FALSE;
993 boolean_t m_arg = _B_FALSE;
994 char *ifname, *nv, *protostr;
995 char *prop_name, *prop_val;
996 uint_t flags = IPADM_OPT_PERSIST;
997 uint_t proto;
998
999 nv = NULL;
1000 protostr = NULL;
1001 opterr = 0;
1002 while ((option = getopt_long(argc, argv, ":m:p:t",
1003 set_ifprop_longopts, NULL)) != -1) {
1004 switch (option) {
1005 case 'p':
1006 if (p_arg)
1007 die("-p must be specified once only");
1008 p_arg = _B_TRUE;
1009
1010 ipadm_check_propstr(optarg, reset, use);
1011 nv = optarg;
1012 break;
1013 case 'm':
1014 if (m_arg)
1015 die("-m must be specified once only");
1016 m_arg = _B_TRUE;
1017 protostr = optarg;
1018 break;
1019 case 't':
1020 flags &= ~IPADM_OPT_PERSIST;
1021 break;
1022 default:
1023 die_opterr(optopt, option, use);
1024 }
1025 }
1026
1027 if (!m_arg || !p_arg || optind != argc - 1)
1028 die("Usage: %s", use);
1029
1030 ifname = argv[optind];
1031
1032 prop_name = nv;
1033 prop_val = strchr(nv, '=');
1034 if (prop_val != NULL)
1035 *prop_val++ = '\0';
1036
1037 if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
1038 die("invalid protocol '%s' specified", protostr);
1039
1040 if (reset)
1041 flags |= IPADM_OPT_DEFAULT;
1042 else
1043 flags |= IPADM_OPT_ACTIVE;
1044 status = ipadm_set_ifprop(iph, ifname, prop_name, prop_val, proto,
1045 flags);
1046
1047 if (status != IPADM_SUCCESS) {
1048 if (reset)
1049 die("reset-ifprop: %s: %s",
1050 prop_name, ipadm_status2str(status));
1051 else
1052 die("set-ifprop: %s: %s",
1053 prop_name, ipadm_status2str(status));
1054 }
1055 }
1056
1057 static void
do_set_ifprop(int argc,char ** argv,const char * use)1058 do_set_ifprop(int argc, char **argv, const char *use)
1059 {
1060 set_ifprop(argc, argv, _B_FALSE, use);
1061 }
1062
1063 static void
do_reset_ifprop(int argc,char ** argv,const char * use)1064 do_reset_ifprop(int argc, char **argv, const char *use)
1065 {
1066 set_ifprop(argc, argv, _B_TRUE, use);
1067 }
1068
1069 /*
1070 * Display information for all or specific protocol properties, either for a
1071 * given protocol or for supported protocols (IP/IPv4/IPv6/TCP/UDP/SCTP)
1072 */
1073 static void
do_show_prop(int argc,char ** argv,const char * use)1074 do_show_prop(int argc, char **argv, const char *use)
1075 {
1076 int option;
1077 nvlist_t *proplist = NULL;
1078 char *fields_str = NULL;
1079 char *protostr;
1080 show_prop_state_t state;
1081 ofmt_handle_t ofmt;
1082 ofmt_status_t oferr;
1083 uint_t ofmtflags = 0;
1084 uint_t proto;
1085 boolean_t p_arg = _B_FALSE;
1086
1087 opterr = 0;
1088 bzero(&state, sizeof (state));
1089 state.sps_propval = NULL;
1090 state.sps_parsable = _B_FALSE;
1091 state.sps_modprop = _B_TRUE;
1092 state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
1093 while ((option = getopt_long(argc, argv, ":p:co:", show_prop_longopts,
1094 NULL)) != -1) {
1095 switch (option) {
1096 case 'p':
1097 if (p_arg)
1098 die("-p must be specified once only");
1099 p_arg = _B_TRUE;
1100 if (ipadm_str2nvlist(optarg, &proplist,
1101 IPADM_NORVAL) != 0)
1102 die("invalid protocol properties specified");
1103 break;
1104 case 'c':
1105 state.sps_parsable = _B_TRUE;
1106 break;
1107 case 'o':
1108 fields_str = optarg;
1109 break;
1110 default:
1111 die_opterr(optopt, option, use);
1112 break;
1113 }
1114 }
1115 if (optind == argc - 1) {
1116 protostr = argv[optind];
1117 if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
1118 die("invalid protocol '%s' specified", protostr);
1119 state.sps_proto = proto;
1120 } else if (optind != argc) {
1121 die("Usage: %s", use);
1122 } else {
1123 if (p_arg)
1124 die("protocol must be specified when "
1125 "property name is used");
1126 state.sps_proto = MOD_PROTO_NONE;
1127 }
1128
1129 state.sps_proplist = proplist;
1130
1131 if (state.sps_parsable)
1132 ofmtflags |= OFMT_PARSABLE;
1133 else
1134 ofmtflags |= OFMT_WRAP;
1135 oferr = ofmt_open(fields_str, modprop_fields, ofmtflags, 0, &ofmt);
1136 ofmt_check(oferr, state.sps_parsable, ofmt, die, warn);
1137 state.sps_ofmt = ofmt;
1138
1139 /* handles all the errors */
1140 show_properties(&state, IPADMPROP_CLASS_MODULE);
1141
1142 nvlist_free(proplist);
1143 ofmt_close(ofmt);
1144
1145 if (state.sps_retstatus != IPADM_SUCCESS) {
1146 ipadm_close(iph);
1147 exit(EXIT_FAILURE);
1148 }
1149 }
1150
1151 /*
1152 * Checks to see if there are any modifiers, + or -. If there are modifiers
1153 * then sets IPADM_OPT_APPEND or IPADM_OPT_REMOVE, accordingly.
1154 */
1155 static void
parse_modifiers(const char * pstr,uint_t * flags,const char * use)1156 parse_modifiers(const char *pstr, uint_t *flags, const char *use)
1157 {
1158 char *p;
1159
1160 if ((p = strchr(pstr, '=')) == NULL)
1161 return;
1162
1163 if (p == pstr)
1164 die("Invalid prop=val specified\n%s", use);
1165
1166 --p;
1167 if (*p == '+')
1168 *flags |= IPADM_OPT_APPEND;
1169 else if (*p == '-')
1170 *flags |= IPADM_OPT_REMOVE;
1171 }
1172
1173 /*
1174 * set/reset the protocol property for a given protocol.
1175 */
1176 static void
set_prop(int argc,char ** argv,boolean_t reset,const char * use)1177 set_prop(int argc, char **argv, boolean_t reset, const char *use)
1178 {
1179 int option;
1180 ipadm_status_t status = IPADM_SUCCESS;
1181 char *protostr, *nv, *prop_name, *prop_val;
1182 boolean_t p_arg = _B_FALSE;
1183 uint_t proto;
1184 uint_t flags = IPADM_OPT_PERSIST;
1185
1186 nv = NULL;
1187 opterr = 0;
1188 while ((option = getopt_long(argc, argv, ":p:t", set_prop_longopts,
1189 NULL)) != -1) {
1190 switch (option) {
1191 case 'p':
1192 if (p_arg)
1193 die("-p must be specified once only");
1194 p_arg = _B_TRUE;
1195
1196 ipadm_check_propstr(optarg, reset, use);
1197 nv = optarg;
1198 break;
1199 case 't':
1200 flags &= ~IPADM_OPT_PERSIST;
1201 break;
1202 default:
1203 die_opterr(optopt, option, use);
1204 }
1205 }
1206
1207 if (!p_arg || optind != argc - 1)
1208 die("Usage: %s", use);
1209
1210 parse_modifiers(nv, &flags, use);
1211 prop_name = nv;
1212 prop_val = strchr(nv, '=');
1213 if (prop_val != NULL) {
1214 if (flags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))
1215 *(prop_val - 1) = '\0';
1216 *prop_val++ = '\0';
1217 }
1218 protostr = argv[optind];
1219 if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
1220 die("invalid protocol '%s' specified", protostr);
1221
1222 if (reset)
1223 flags |= IPADM_OPT_DEFAULT;
1224 else
1225 flags |= IPADM_OPT_ACTIVE;
1226 status = ipadm_set_prop(iph, prop_name, prop_val, proto, flags);
1227
1228 if (status != IPADM_SUCCESS) {
1229 if (reset)
1230 die("reset-prop: %s: %s",
1231 prop_name, ipadm_status2str(status));
1232 else
1233 die("set-prop: %s: %s",
1234 prop_name, ipadm_status2str(status));
1235 }
1236 }
1237
1238 static void
do_set_prop(int argc,char ** argv,const char * use)1239 do_set_prop(int argc, char **argv, const char *use)
1240 {
1241 set_prop(argc, argv, _B_FALSE, use);
1242 }
1243
1244 static void
do_reset_prop(int argc,char ** argv,const char * use)1245 do_reset_prop(int argc, char **argv, const char *use)
1246 {
1247 set_prop(argc, argv, _B_TRUE, use);
1248 }
1249
1250 /* PRINTFLIKE1 */
1251 static void
warn(const char * format,...)1252 warn(const char *format, ...)
1253 {
1254 va_list alist;
1255
1256 format = gettext(format);
1257 (void) fprintf(stderr, gettext("%s: warning: "), progname);
1258
1259 va_start(alist, format);
1260 (void) vfprintf(stderr, format, alist);
1261 va_end(alist);
1262
1263 (void) fprintf(stderr, "\n");
1264 }
1265
1266 /* PRINTFLIKE1 */
1267 static void
die(const char * format,...)1268 die(const char *format, ...)
1269 {
1270 va_list alist;
1271
1272 if (format != NULL) {
1273 format = gettext(format);
1274 (void) fprintf(stderr, "%s: ", progname);
1275
1276 va_start(alist, format);
1277 (void) vfprintf(stderr, format, alist);
1278 va_end(alist);
1279
1280 (void) putchar('\n');
1281 }
1282
1283 ipadm_destroy_addrobj(ipaddr);
1284 ipadm_close(iph);
1285 exit(EXIT_FAILURE);
1286 }
1287
1288 static void
die_opterr(int opt,int opterr,const char * usage)1289 die_opterr(int opt, int opterr, const char *usage)
1290 {
1291 switch (opterr) {
1292 case ':':
1293 die("option '-%c' requires a value\nusage: %s", opt,
1294 gettext(usage));
1295 break;
1296 case '?':
1297 default:
1298 die("unrecognized option '-%c'\nusage: %s", opt,
1299 gettext(usage));
1300 break;
1301 }
1302 }
1303
1304 /* PRINTFLIKE2 */
1305 static void
warn_ipadmerr(ipadm_status_t err,const char * format,...)1306 warn_ipadmerr(ipadm_status_t err, const char *format, ...)
1307 {
1308 va_list alist;
1309
1310 format = gettext(format);
1311 (void) fprintf(stderr, gettext("%s: warning: "), progname);
1312
1313 va_start(alist, format);
1314 (void) vfprintf(stderr, format, alist);
1315 va_end(alist);
1316
1317 (void) fprintf(stderr, "%s\n", ipadm_status2str(err));
1318 }
1319
1320 static void
process_static_addrargs(const char * use,char * addrarg,const char * aobjname)1321 process_static_addrargs(const char *use, char *addrarg, const char *aobjname)
1322 {
1323 int option;
1324 char *val;
1325 char *laddr = NULL;
1326 char *raddr = NULL;
1327 char *save_input_arg = addrarg;
1328 boolean_t found_mismatch = _B_FALSE;
1329 ipadm_status_t status;
1330 enum { A_LOCAL, A_REMOTE };
1331 static char *addr_optstr[] = {
1332 "local",
1333 "remote",
1334 NULL,
1335 };
1336
1337 while (*addrarg != '\0') {
1338 option = getsubopt(&addrarg, addr_optstr, &val);
1339 switch (option) {
1340 case A_LOCAL:
1341 if (laddr != NULL)
1342 die("Multiple local addresses provided");
1343 laddr = val;
1344 break;
1345 case A_REMOTE:
1346 if (raddr != NULL)
1347 die("Multiple remote addresses provided");
1348 raddr = val;
1349 break;
1350 default:
1351 if (found_mismatch)
1352 die("Invalid address provided\nusage: %s", use);
1353 found_mismatch = _B_TRUE;
1354 break;
1355 }
1356 }
1357 if (raddr != NULL && laddr == NULL)
1358 die("Missing local address\nusage: %s", use);
1359
1360 /* If only one address is provided, it is assumed a local address. */
1361 if (laddr == NULL) {
1362 if (found_mismatch)
1363 laddr = save_input_arg;
1364 else
1365 die("Missing local address\nusage: %s", use);
1366 }
1367
1368 /* Initialize the addrobj for static addresses. */
1369 status = ipadm_create_addrobj(IPADM_ADDR_STATIC, aobjname, &ipaddr);
1370 if (status != IPADM_SUCCESS) {
1371 die("Error in creating address object: %s",
1372 ipadm_status2str(status));
1373 }
1374
1375 /* Set the local and remote addresses */
1376 status = ipadm_set_addr(ipaddr, laddr, AF_UNSPEC);
1377 if (status != IPADM_SUCCESS) {
1378 die("Error in setting local address: %s",
1379 ipadm_status2str(status));
1380 }
1381 if (raddr != NULL) {
1382 status = ipadm_set_dst_addr(ipaddr, raddr, AF_UNSPEC);
1383 if (status != IPADM_SUCCESS) {
1384 die("Error in setting remote address: %s",
1385 ipadm_status2str(status));
1386 }
1387 }
1388 }
1389
1390 static void
process_addrconf_addrargs(const char * use,char * addrarg)1391 process_addrconf_addrargs(const char *use, char *addrarg)
1392 {
1393 int option;
1394 char *val;
1395 enum { P_STATELESS, P_STATEFUL };
1396 static char *addr_optstr[] = {
1397 "stateless",
1398 "stateful",
1399 NULL,
1400 };
1401 boolean_t stateless = _B_FALSE;
1402 boolean_t stateless_arg = _B_FALSE;
1403 boolean_t stateful = _B_FALSE;
1404 boolean_t stateful_arg = _B_FALSE;
1405 ipadm_status_t status;
1406
1407 while (*addrarg != '\0') {
1408 option = getsubopt(&addrarg, addr_optstr, &val);
1409 switch (option) {
1410 case P_STATELESS:
1411 if (stateless_arg)
1412 die("Duplicate option");
1413 if (val == NULL)
1414 die("Invalid argument");
1415 if (strcmp(val, "yes") == 0)
1416 stateless = _B_TRUE;
1417 else if (strcmp(val, "no") == 0)
1418 stateless = _B_FALSE;
1419 else
1420 die("Invalid argument");
1421 stateless_arg = _B_TRUE;
1422 break;
1423 case P_STATEFUL:
1424 if (stateful_arg)
1425 die("Duplicate option");
1426 if (val == NULL)
1427 die("Invalid argument");
1428 if (strcmp(val, "yes") == 0)
1429 stateful = _B_TRUE;
1430 else if (strcmp(val, "no") == 0)
1431 stateful = _B_FALSE;
1432 else
1433 die("Invalid argument");
1434 stateful_arg = _B_TRUE;
1435 break;
1436 default:
1437 die_opterr(optopt, option, use);
1438 }
1439 }
1440
1441 if (!stateless_arg && !stateful_arg)
1442 die("Invalid arguments for option -p");
1443
1444 /* Set the addrobj fields for addrconf */
1445 if (stateless_arg) {
1446 status = ipadm_set_stateless(ipaddr, stateless);
1447 if (status != IPADM_SUCCESS) {
1448 die("Error in setting stateless option: %s",
1449 ipadm_status2str(status));
1450 }
1451 }
1452 if (stateful_arg) {
1453 status = ipadm_set_stateful(ipaddr, stateful);
1454 if (status != IPADM_SUCCESS) {
1455 die("Error in setting stateful option: %s",
1456 ipadm_status2str(status));
1457 }
1458 }
1459 }
1460
1461 /*
1462 * Creates static, dhcp or addrconf addresses and associates the created
1463 * addresses with the specified address object name.
1464 */
1465 static void
do_create_addr(int argc,char * argv[],const char * use)1466 do_create_addr(int argc, char *argv[], const char *use)
1467 {
1468 ipadm_status_t status;
1469 int option;
1470 uint32_t flags =
1471 IPADM_OPT_PERSIST|IPADM_OPT_ACTIVE|IPADM_OPT_UP|IPADM_OPT_V46;
1472 char *cp;
1473 char *atype = NULL;
1474 char *static_arg = NULL;
1475 char *addrconf_arg = NULL;
1476 char *interface_id = NULL;
1477 char *wait = NULL;
1478 char *reqhost = NULL;
1479 boolean_t s_opt = _B_FALSE; /* static addr options */
1480 boolean_t auto_opt = _B_FALSE; /* Addrconf options */
1481 boolean_t dhcp_opt = _B_FALSE; /* dhcp options */
1482 boolean_t primary_opt = _B_FALSE; /* dhcp primary option */
1483
1484 opterr = 0;
1485 while ((option = getopt_long(argc, argv, ":1T:a:dh:i:p:w:t",
1486 addr_longopts, NULL)) != -1) {
1487 switch (option) {
1488 case '1':
1489 primary_opt = _B_TRUE;
1490 break;
1491 case 'T':
1492 atype = optarg;
1493 break;
1494 case 'a':
1495 static_arg = optarg;
1496 s_opt = _B_TRUE;
1497 break;
1498 case 'd':
1499 flags &= ~IPADM_OPT_UP;
1500 s_opt = _B_TRUE;
1501 break;
1502 case 'h':
1503 reqhost = optarg;
1504 break;
1505 case 'i':
1506 interface_id = optarg;
1507 auto_opt = _B_TRUE;
1508 break;
1509 case 'p':
1510 addrconf_arg = optarg;
1511 auto_opt = _B_TRUE;
1512 break;
1513 case 'w':
1514 wait = optarg;
1515 dhcp_opt = _B_TRUE;
1516 break;
1517 case 't':
1518 flags &= ~IPADM_OPT_PERSIST;
1519 break;
1520 default:
1521 die_opterr(optopt, option, use);
1522 }
1523 }
1524 if (atype == NULL || optind != (argc - 1)) {
1525 die("Invalid arguments\nusage: %s", use);
1526 } else if ((cp = strchr(argv[optind], '/')) == NULL ||
1527 strlen(++cp) == 0) {
1528 die("invalid address object name: %s\nusage: %s",
1529 argv[optind], use);
1530 }
1531
1532 /*
1533 * Allocate and initialize the addrobj based on the address type.
1534 */
1535 if (strcmp(atype, "static") == 0) {
1536 if (static_arg == NULL || auto_opt || dhcp_opt ||
1537 reqhost != NULL || primary_opt) {
1538 die("Invalid arguments for type %s\nusage: %s",
1539 atype, use);
1540 }
1541 process_static_addrargs(use, static_arg, argv[optind]);
1542 } else if (strcmp(atype, "dhcp") == 0) {
1543 if (auto_opt || s_opt) {
1544 die("Invalid arguments for type %s\nusage: %s",
1545 atype, use);
1546 }
1547
1548 /* Initialize the addrobj for dhcp addresses. */
1549 status = ipadm_create_addrobj(IPADM_ADDR_DHCP, argv[optind],
1550 &ipaddr);
1551 if (status != IPADM_SUCCESS) {
1552 die("Error in creating address object: %s",
1553 ipadm_status2str(status));
1554 }
1555 if (wait != NULL) {
1556 int32_t ipadm_wait;
1557
1558 if (strcmp(wait, "forever") == 0) {
1559 ipadm_wait = IPADM_DHCP_WAIT_FOREVER;
1560 } else {
1561 char *end;
1562 long timeout = strtol(wait, &end, 10);
1563
1564 if (*end != '\0' || timeout < 0)
1565 die("Invalid argument");
1566 ipadm_wait = (int32_t)timeout;
1567 }
1568 status = ipadm_set_wait_time(ipaddr, ipadm_wait);
1569 if (status != IPADM_SUCCESS) {
1570 die("Error in setting wait time: %s",
1571 ipadm_status2str(status));
1572 }
1573 }
1574 if (primary_opt) {
1575 status = ipadm_set_primary(ipaddr, _B_TRUE);
1576 if (status != IPADM_SUCCESS) {
1577 die("Error in setting primary flag: %s",
1578 ipadm_status2str(status));
1579 }
1580 }
1581 if (reqhost != NULL) {
1582 status = ipadm_set_reqhost(ipaddr, reqhost);
1583 if (status != IPADM_SUCCESS) {
1584 die("Error in setting reqhost: %s",
1585 ipadm_status2str(status));
1586 }
1587 }
1588 } else if (strcmp(atype, "addrconf") == 0) {
1589 if (dhcp_opt || s_opt || reqhost != NULL || primary_opt) {
1590 die("Invalid arguments for type %s\nusage: %s",
1591 atype, use);
1592 }
1593
1594 /* Initialize the addrobj for ipv6-addrconf addresses. */
1595 status = ipadm_create_addrobj(IPADM_ADDR_IPV6_ADDRCONF,
1596 argv[optind], &ipaddr);
1597 if (status != IPADM_SUCCESS) {
1598 die("Error in creating address object: %s",
1599 ipadm_status2str(status));
1600 }
1601 if (interface_id != NULL) {
1602 status = ipadm_set_interface_id(ipaddr, interface_id);
1603 if (status != IPADM_SUCCESS) {
1604 die("Error in setting interface ID: %s",
1605 ipadm_status2str(status));
1606 }
1607 }
1608 if (addrconf_arg)
1609 process_addrconf_addrargs(use, addrconf_arg);
1610 } else {
1611 die("Invalid address type %s", atype);
1612 }
1613
1614 status = ipadm_create_addr(iph, ipaddr, flags);
1615 if (status == IPADM_DHCP_IPC_TIMEOUT)
1616 warn_ipadmerr(status, "");
1617 else if (status != IPADM_SUCCESS)
1618 die("Could not create address: %s", ipadm_status2str(status));
1619 }
1620
1621 /*
1622 * Used by some address management functions to parse the command line
1623 * arguments and create `ipaddr' address object.
1624 */
1625 static void
process_misc_addrargs(int argc,char * argv[],const char * use,int * index,uint32_t * flags)1626 process_misc_addrargs(int argc, char *argv[], const char *use, int *index,
1627 uint32_t *flags)
1628 {
1629 int option;
1630
1631 opterr = 0;
1632 while ((option = getopt_long(argc, argv, ":t", addr_misc_longopts,
1633 NULL)) != -1) {
1634 switch (option) {
1635 case 't':
1636 *flags &= ~IPADM_OPT_PERSIST;
1637 break;
1638 default:
1639 die_opterr(optopt, option, use);
1640 }
1641 }
1642 if (optind != (argc - 1))
1643 die("Usage: %s", use);
1644
1645 *index = optind;
1646 }
1647
1648 /*
1649 * Remove an addrobj from both active and persistent configuration.
1650 */
1651 static void
do_delete_addr(int argc,char * argv[],const char * use)1652 do_delete_addr(int argc, char *argv[], const char *use)
1653 {
1654 ipadm_status_t status;
1655 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1656 int option;
1657
1658 opterr = 0;
1659 while ((option = getopt_long(argc, argv, ":r", addr_misc_longopts,
1660 NULL)) != -1) {
1661 switch (option) {
1662 case 'r':
1663 flags |= IPADM_OPT_RELEASE;
1664 break;
1665 default:
1666 die_opterr(optopt, option, use);
1667 }
1668 }
1669 if (optind != (argc - 1))
1670 die("Usage: %s", use);
1671
1672 status = ipadm_delete_addr(iph, argv[optind], flags);
1673 if (status != IPADM_SUCCESS) {
1674 die("could not delete address: %s",
1675 ipadm_status2str(status));
1676 }
1677 }
1678
1679 /*
1680 * Enable an IP address based on the persistent configuration for that
1681 * IP address
1682 */
1683 static void
do_enable_addr(int argc,char * argv[],const char * use)1684 do_enable_addr(int argc, char *argv[], const char *use)
1685 {
1686 ipadm_status_t status;
1687 int index;
1688 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1689
1690 process_misc_addrargs(argc, argv, use, &index, &flags);
1691 if (flags & IPADM_OPT_PERSIST)
1692 die("persistent operation not supported for enable-addr");
1693
1694 status = ipadm_enable_addr(iph, argv[index], flags);
1695 if (status != IPADM_SUCCESS)
1696 die("could not enable address: %s", ipadm_status2str(status));
1697 }
1698
1699 /*
1700 * Mark the address identified by addrobj 'up'
1701 */
1702 static void
do_up_addr(int argc,char * argv[],const char * use)1703 do_up_addr(int argc, char *argv[], const char *use)
1704 {
1705 ipadm_status_t status;
1706 int index;
1707 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1708
1709 process_misc_addrargs(argc, argv, use, &index, &flags);
1710 status = ipadm_up_addr(iph, argv[index], flags);
1711 if (status != IPADM_SUCCESS) {
1712 die("Could not mark the address up: %s",
1713 ipadm_status2str(status));
1714 }
1715 }
1716
1717 /*
1718 * Disable the specified addrobj by removing it from active cofiguration
1719 */
1720 static void
do_disable_addr(int argc,char * argv[],const char * use)1721 do_disable_addr(int argc, char *argv[], const char *use)
1722 {
1723 ipadm_status_t status;
1724 int index;
1725 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1726
1727 process_misc_addrargs(argc, argv, use, &index, &flags);
1728 if (flags & IPADM_OPT_PERSIST)
1729 die("persistent operation not supported for disable-addr");
1730
1731 status = ipadm_disable_addr(iph, argv[index], flags);
1732 if (status != IPADM_SUCCESS) {
1733 die("could not disable address: %s",
1734 ipadm_status2str(status));
1735 }
1736 }
1737
1738 /*
1739 * Mark the address identified by addrobj 'down'
1740 */
1741 static void
do_down_addr(int argc,char * argv[],const char * use)1742 do_down_addr(int argc, char *argv[], const char *use)
1743 {
1744 ipadm_status_t status;
1745 int index;
1746 uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
1747
1748 process_misc_addrargs(argc, argv, use, &index, &flags);
1749 status = ipadm_down_addr(iph, argv[index], flags);
1750 if (status != IPADM_SUCCESS)
1751 die("Could not mark the address down: %s",
1752 ipadm_status2str(status));
1753 }
1754
1755 /*
1756 * Restart DAD for static address. Extend lease duration for DHCP addresses
1757 */
1758 static void
do_refresh_addr(int argc,char * argv[],const char * use)1759 do_refresh_addr(int argc, char *argv[], const char *use)
1760 {
1761 ipadm_status_t status;
1762 int option;
1763 uint32_t flags = 0;
1764
1765 opterr = 0;
1766 while ((option = getopt_long(argc, argv, ":i", addr_misc_longopts,
1767 NULL)) != -1) {
1768 switch (option) {
1769 case 'i':
1770 flags |= IPADM_OPT_INFORM;
1771 break;
1772 default:
1773 die_opterr(optopt, option, use);
1774 }
1775 }
1776 if (optind != (argc - 1))
1777 die("Usage: %s", use);
1778
1779 status = ipadm_refresh_addr(iph, argv[optind], flags);
1780 if (status == IPADM_DHCP_IPC_TIMEOUT)
1781 warn_ipadmerr(status, "");
1782 else if (status != IPADM_SUCCESS)
1783 die("could not refresh address %s", ipadm_status2str(status));
1784 }
1785
1786 static void
sockaddr2str(const struct sockaddr_storage * ssp,char * buf,uint_t bufsize)1787 sockaddr2str(const struct sockaddr_storage *ssp, char *buf, uint_t bufsize)
1788 {
1789 socklen_t socklen;
1790 struct sockaddr *sp = (struct sockaddr *)ssp;
1791
1792 switch (ssp->ss_family) {
1793 case AF_INET:
1794 socklen = sizeof (struct sockaddr_in);
1795 break;
1796 case AF_INET6:
1797 socklen = sizeof (struct sockaddr_in6);
1798 break;
1799 default:
1800 (void) strlcpy(buf, STR_UNKNOWN_VAL, bufsize);
1801 return;
1802 }
1803
1804 (void) getnameinfo(sp, socklen, buf, bufsize, NULL, 0,
1805 (NI_NOFQDN | NI_NUMERICHOST));
1806 }
1807
1808 static void
flags2str(uint64_t flags,fmask_t * tbl,boolean_t is_bits,char * buf,uint_t bufsize)1809 flags2str(uint64_t flags, fmask_t *tbl, boolean_t is_bits,
1810 char *buf, uint_t bufsize)
1811 {
1812 int i;
1813 boolean_t first = _B_TRUE;
1814
1815 if (is_bits) {
1816 for (i = 0; tbl[i].name; i++) {
1817 if ((flags & tbl[i].mask) == tbl[i].bits)
1818 (void) strlcat(buf, tbl[i].name, bufsize);
1819 else
1820 (void) strlcat(buf, "-", bufsize);
1821 }
1822 } else {
1823 for (i = 0; tbl[i].name; i++) {
1824 if ((flags & tbl[i].mask) == tbl[i].bits) {
1825 if (!first)
1826 (void) strlcat(buf, ",", bufsize);
1827 (void) strlcat(buf, tbl[i].name, bufsize);
1828 first = _B_FALSE;
1829 }
1830 }
1831 }
1832 }
1833
1834 /*
1835 * return true if the address for lifname comes to us from the global zone
1836 * with 'allowed-ips' constraints.
1837 */
1838 static boolean_t
is_from_gz(const char * lifname)1839 is_from_gz(const char *lifname)
1840 {
1841 ipadm_if_info_t *if_info;
1842 char phyname[LIFNAMSIZ], *cp;
1843 boolean_t ret = _B_FALSE;
1844 ipadm_status_t status;
1845 zoneid_t zoneid;
1846 ushort_t zflags;
1847
1848 if ((zoneid = getzoneid()) == GLOBAL_ZONEID)
1849 return (_B_FALSE); /* from-gz only makes sense in a NGZ */
1850
1851 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags, sizeof (zflags)) < 0)
1852 return (_B_FALSE);
1853
1854 if (!(zflags & ZF_NET_EXCL))
1855 return (_B_TRUE); /* everything is from the GZ for shared-ip */
1856
1857 (void) strncpy(phyname, lifname, sizeof (phyname));
1858 if ((cp = strchr(phyname, ':')) != NULL)
1859 *cp = '\0';
1860 status = ipadm_if_info(iph, phyname, &if_info, 0, LIFC_DEFAULT);
1861 if (status != IPADM_SUCCESS)
1862 return (ret);
1863
1864 if (if_info->ifi_cflags & IFIF_L3PROTECT)
1865 ret = _B_TRUE;
1866 ipadm_free_if_info(if_info);
1867 return (ret);
1868 }
1869
1870 static boolean_t
print_sa_cb(ofmt_arg_t * ofarg,char * buf,uint_t bufsize)1871 print_sa_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
1872 {
1873 show_addr_args_t *arg = ofarg->ofmt_cbarg;
1874 ipadm_addr_info_t *ainfo = arg->sa_info;
1875 char interface[LIFNAMSIZ];
1876 char addrbuf[MAXPROPVALLEN];
1877 char dstbuf[MAXPROPVALLEN];
1878 char prefixlenstr[MAXPROPVALLEN];
1879 int prefixlen;
1880 struct sockaddr_in *sin;
1881 struct sockaddr_in6 *sin6;
1882 sa_family_t af;
1883 char *phyname = NULL;
1884 struct ifaddrs *ifa = &ainfo->ia_ifa;
1885 fmask_t cflags_mask[] = {
1886 { "U", IA_UP, IA_UP },
1887 { "u", IA_UNNUMBERED, IA_UNNUMBERED },
1888 { "p", IA_PRIVATE, IA_PRIVATE },
1889 { "t", IA_TEMPORARY, IA_TEMPORARY },
1890 { "d", IA_DEPRECATED, IA_DEPRECATED },
1891 { NULL, 0, 0 }
1892 };
1893 fmask_t pflags_mask[] = {
1894 { "U", IA_UP, IA_UP },
1895 { "p", IA_PRIVATE, IA_PRIVATE },
1896 { "d", IA_DEPRECATED, IA_DEPRECATED },
1897 { NULL, 0, 0 }
1898 };
1899 fmask_t type[] = {
1900 { "static", IPADM_ADDR_STATIC, IPADM_ALL_BITS},
1901 { "addrconf", IPADM_ADDR_IPV6_ADDRCONF, IPADM_ALL_BITS},
1902 { "dhcp", IPADM_ADDR_DHCP, IPADM_ALL_BITS},
1903 { NULL, 0, 0 }
1904 };
1905 fmask_t addr_state[] = {
1906 { "disabled", IFA_DISABLED, IPADM_ALL_BITS},
1907 { "duplicate", IFA_DUPLICATE, IPADM_ALL_BITS},
1908 { "down", IFA_DOWN, IPADM_ALL_BITS},
1909 { "tentative", IFA_TENTATIVE, IPADM_ALL_BITS},
1910 { "ok", IFA_OK, IPADM_ALL_BITS},
1911 { "inaccessible", IFA_INACCESSIBLE, IPADM_ALL_BITS},
1912 { NULL, 0, 0 }
1913 };
1914
1915 buf[0] = '\0';
1916 switch (ofarg->ofmt_id) {
1917 case SA_ADDROBJ:
1918 if (ainfo->ia_aobjname[0] == '\0') {
1919 (void) strncpy(interface, ifa->ifa_name, LIFNAMSIZ);
1920 phyname = strrchr(interface, ':');
1921 if (phyname)
1922 *phyname = '\0';
1923 (void) snprintf(buf, bufsize, "%s/%s", interface,
1924 STR_UNKNOWN_VAL);
1925 } else {
1926 (void) snprintf(buf, bufsize, "%s", ainfo->ia_aobjname);
1927 }
1928 break;
1929 case SA_STATE:
1930 flags2str(ainfo->ia_state, addr_state, _B_FALSE,
1931 buf, bufsize);
1932 break;
1933 case SA_TYPE:
1934 if (is_from_gz(ifa->ifa_name))
1935 (void) snprintf(buf, bufsize, "from-gz");
1936 else
1937 flags2str(ainfo->ia_atype, type, _B_FALSE, buf,
1938 bufsize);
1939 break;
1940 case SA_CURRENT:
1941 flags2str(ainfo->ia_cflags, cflags_mask, _B_TRUE, buf, bufsize);
1942 break;
1943 case SA_PERSISTENT:
1944 flags2str(ainfo->ia_pflags, pflags_mask, _B_TRUE, buf, bufsize);
1945 break;
1946 case SA_ADDR:
1947 af = ifa->ifa_addr->sa_family;
1948 /*
1949 * If the address is 0.0.0.0 or :: and the origin is DHCP,
1950 * print STR_UNKNOWN_VAL.
1951 */
1952 if (ainfo->ia_atype == IPADM_ADDR_DHCP) {
1953 sin = (struct sockaddr_in *)ifa->ifa_addr;
1954 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
1955 if ((af == AF_INET &&
1956 sin->sin_addr.s_addr == INADDR_ANY) ||
1957 (af == AF_INET6 &&
1958 IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) {
1959 (void) snprintf(buf, bufsize, STR_UNKNOWN_VAL);
1960 break;
1961 }
1962 }
1963 if (ifa->ifa_netmask == NULL)
1964 prefixlen = 0;
1965 else
1966 prefixlen = mask2plen(ifa->ifa_netmask);
1967 bzero(prefixlenstr, sizeof (prefixlenstr));
1968 if (prefixlen > 0) {
1969 (void) snprintf(prefixlenstr, sizeof (prefixlenstr),
1970 "/%d", prefixlen);
1971 }
1972 bzero(addrbuf, sizeof (addrbuf));
1973 bzero(dstbuf, sizeof (dstbuf));
1974 if (ainfo->ia_atype == IPADM_ADDR_STATIC) {
1975 /*
1976 * Print the hostname fields if the address is not
1977 * in active configuration.
1978 */
1979 if (ainfo->ia_state == IFA_DISABLED) {
1980 (void) snprintf(buf, bufsize, "%s",
1981 ainfo->ia_sname);
1982 if (ainfo->ia_dname[0] != '\0') {
1983 (void) snprintf(dstbuf, sizeof (dstbuf),
1984 "->%s", ainfo->ia_dname);
1985 (void) strlcat(buf, dstbuf, bufsize);
1986 } else {
1987 (void) strlcat(buf, prefixlenstr,
1988 bufsize);
1989 }
1990 break;
1991 }
1992 }
1993 /*
1994 * For the non-persistent case, we need to show the
1995 * currently configured addresses for source and
1996 * destination.
1997 */
1998 sockaddr2str((struct sockaddr_storage *)ifa->ifa_addr,
1999 addrbuf, sizeof (addrbuf));
2000 if (ifa->ifa_flags & IFF_POINTOPOINT) {
2001 sockaddr2str(
2002 (struct sockaddr_storage *)ifa->ifa_dstaddr,
2003 dstbuf, sizeof (dstbuf));
2004 (void) snprintf(buf, bufsize, "%s->%s", addrbuf,
2005 dstbuf);
2006 } else {
2007 (void) snprintf(buf, bufsize, "%s%s", addrbuf,
2008 prefixlenstr);
2009 }
2010 break;
2011 default:
2012 die("invalid input");
2013 break;
2014 }
2015
2016 return (_B_TRUE);
2017 }
2018
2019 /*
2020 * Display address information, either for the given address or
2021 * for all the addresses managed by ipadm.
2022 */
2023 static void
do_show_addr(int argc,char * argv[],const char * use)2024 do_show_addr(int argc, char *argv[], const char *use)
2025 {
2026 ipadm_status_t status;
2027 show_addr_state_t state;
2028 char *def_fields_str = "addrobj,type,state,addr";
2029 char *fields_str = NULL;
2030 ipadm_addr_info_t *ainfo;
2031 ipadm_addr_info_t *ptr;
2032 show_addr_args_t sargs;
2033 int option;
2034 ofmt_handle_t ofmt;
2035 ofmt_status_t oferr;
2036 uint_t ofmtflags = 0;
2037 char *aname;
2038 char *ifname = NULL;
2039 char *cp;
2040 boolean_t found = _B_FALSE;
2041
2042 opterr = 0;
2043 state.sa_parsable = _B_FALSE;
2044 state.sa_persist = _B_FALSE;
2045 while ((option = getopt_long(argc, argv, "po:", show_addr_longopts,
2046 NULL)) != -1) {
2047 switch (option) {
2048 case 'p':
2049 state.sa_parsable = _B_TRUE;
2050 break;
2051 case 'o':
2052 fields_str = optarg;
2053 break;
2054 default:
2055 die_opterr(optopt, option, use);
2056 break;
2057 }
2058 }
2059 if (state.sa_parsable && fields_str == NULL)
2060 die("-p requires -o");
2061
2062 if (optind == argc - 1) {
2063 aname = argv[optind];
2064 if ((cp = strchr(aname, '/')) == NULL)
2065 die("Invalid address object name provided");
2066 if (*(cp + 1) == '\0') {
2067 ifname = aname;
2068 *cp = '\0';
2069 aname = NULL;
2070 }
2071 } else if (optind == argc) {
2072 aname = NULL;
2073 } else {
2074 die("Usage: %s", use);
2075 }
2076
2077 if (state.sa_parsable)
2078 ofmtflags |= OFMT_PARSABLE;
2079 if (fields_str == NULL)
2080 fields_str = def_fields_str;
2081 oferr = ofmt_open(fields_str, show_addr_fields, ofmtflags, 0, &ofmt);
2082
2083 ofmt_check(oferr, state.sa_parsable, ofmt, die, warn);
2084 state.sa_ofmt = ofmt;
2085
2086 status = ipadm_addr_info(iph, ifname, &ainfo, 0, LIFC_DEFAULT);
2087 /*
2088 * Return without printing any error, if no addresses were found,
2089 * for the case where all addresses are requested.
2090 */
2091 if (status != IPADM_SUCCESS)
2092 die("Could not get address: %s", ipadm_status2str(status));
2093 if (ainfo == NULL) {
2094 ofmt_close(ofmt);
2095 return;
2096 }
2097
2098 bzero(&sargs, sizeof (sargs));
2099 sargs.sa_state = &state;
2100 for (ptr = ainfo; ptr != NULL; ptr = IA_NEXT(ptr)) {
2101 sargs.sa_info = ptr;
2102 if (aname != NULL) {
2103 if (strcmp(sargs.sa_info->ia_aobjname, aname) != 0)
2104 continue;
2105 found = _B_TRUE;
2106 }
2107 ofmt_print(state.sa_ofmt, &sargs);
2108 }
2109 if (ainfo)
2110 ipadm_free_addr_info(ainfo);
2111 if (aname != NULL && !found)
2112 die("Address object not found");
2113 }
2114
2115 static boolean_t
print_si_cb(ofmt_arg_t * ofarg,char * buf,uint_t bufsize)2116 print_si_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2117 {
2118 show_if_args_t *arg = ofarg->ofmt_cbarg;
2119 ipadm_if_info_t *ifinfo = arg->si_info;
2120 char *ifname = ifinfo->ifi_name;
2121 fmask_t intf_state[] = {
2122 { "ok", IFIS_OK, IPADM_ALL_BITS},
2123 { "down", IFIS_DOWN, IPADM_ALL_BITS},
2124 { "disabled", IFIS_DISABLED, IPADM_ALL_BITS},
2125 { "failed", IFIS_FAILED, IPADM_ALL_BITS},
2126 { "offline", IFIS_OFFLINE, IPADM_ALL_BITS},
2127 { NULL, 0, 0 }
2128 };
2129 fmask_t intf_pflags[] = {
2130 { "s", IFIF_STANDBY, IFIF_STANDBY },
2131 { "4", IFIF_IPV4, IFIF_IPV4 },
2132 { "6", IFIF_IPV6, IFIF_IPV6 },
2133 { NULL, 0, 0 }
2134 };
2135 fmask_t intf_cflags[] = {
2136 { "b", IFIF_BROADCAST, IFIF_BROADCAST },
2137 { "m", IFIF_MULTICAST, IFIF_MULTICAST },
2138 { "p", IFIF_POINTOPOINT, IFIF_POINTOPOINT},
2139 { "v", IFIF_VIRTUAL, IFIF_VIRTUAL },
2140 { "I", IFIF_IPMP, IFIF_IPMP },
2141 { "s", IFIF_STANDBY, IFIF_STANDBY },
2142 { "i", IFIF_INACTIVE, IFIF_INACTIVE },
2143 { "V", IFIF_VRRP, IFIF_VRRP },
2144 { "a", IFIF_NOACCEPT, IFIF_NOACCEPT },
2145 { "Z", IFIF_L3PROTECT, IFIF_L3PROTECT },
2146 { "4", IFIF_IPV4, IFIF_IPV4 },
2147 { "6", IFIF_IPV6, IFIF_IPV6 },
2148 { NULL, 0, 0 }
2149 };
2150 fmask_t intf_class[] = {
2151 { "IP", IPADM_IF_CLASS_REGULAR, IPADM_ALL_BITS},
2152 { "IPMP", IPADM_IF_CLASS_IPMP, IPADM_ALL_BITS},
2153 { "VIRTUAL", IPADM_IF_CLASS_VIRTUAL, IPADM_ALL_BITS},
2154 { "UNKNOWN", IPADM_IF_CLASS_UNKNOWN, IPADM_ALL_BITS},
2155 { NULL, 0, 0}
2156 };
2157
2158 buf[0] = '\0';
2159 switch (ofarg->ofmt_id) {
2160 case SI_IFNAME:
2161 (void) snprintf(buf, bufsize, "%s", ifname);
2162 break;
2163 case SI_IFCLASS:
2164 flags2str(ifinfo->ifi_class, intf_class, _B_FALSE,
2165 buf, bufsize);
2166 break;
2167 case SI_STATE:
2168 flags2str(ifinfo->ifi_state, intf_state, _B_FALSE,
2169 buf, bufsize);
2170 break;
2171 case SI_CURRENT:
2172 flags2str(ifinfo->ifi_cflags, intf_cflags, _B_TRUE,
2173 buf, bufsize);
2174 break;
2175 case SI_PERSISTENT:
2176 flags2str(ifinfo->ifi_pflags, intf_pflags, _B_TRUE,
2177 buf, bufsize);
2178 break;
2179 default:
2180 die("invalid input");
2181 break;
2182 }
2183
2184 return (_B_TRUE);
2185 }
2186
2187 /*
2188 * Display interface information, either for the given interface or
2189 * for all the interfaces in the system.
2190 */
2191 static void
do_show_if(int argc,char * argv[],const char * use)2192 do_show_if(int argc, char *argv[], const char *use)
2193 {
2194 ipadm_status_t status;
2195 show_if_state_t state;
2196 char *fields_str = NULL;
2197 ipadm_if_info_t *if_info, *ptr;
2198 show_if_args_t sargs;
2199 int option;
2200 ofmt_handle_t ofmt;
2201 ofmt_status_t oferr;
2202 uint_t ofmtflags = 0;
2203 char *ifname = NULL;
2204
2205 opterr = 0;
2206 state.si_parsable = _B_FALSE;
2207
2208 while ((option = getopt_long(argc, argv, "po:", show_if_longopts,
2209 NULL)) != -1) {
2210 switch (option) {
2211 case 'p':
2212 state.si_parsable = _B_TRUE;
2213 break;
2214 case 'o':
2215 fields_str = optarg;
2216 break;
2217 default:
2218 die_opterr(optopt, option, use);
2219 break;
2220 }
2221 }
2222 if (optind == argc - 1)
2223 ifname = argv[optind];
2224 else if (optind != argc)
2225 die("Usage: %s", use);
2226 if (state.si_parsable)
2227 ofmtflags |= OFMT_PARSABLE;
2228 oferr = ofmt_open(fields_str, show_if_fields, ofmtflags, 0, &ofmt);
2229 ofmt_check(oferr, state.si_parsable, ofmt, die, warn);
2230 state.si_ofmt = ofmt;
2231 bzero(&sargs, sizeof (sargs));
2232 sargs.si_state = &state;
2233 status = ipadm_if_info(iph, ifname, &if_info, 0, LIFC_DEFAULT);
2234 /*
2235 * Return without printing any error, if no addresses were found.
2236 */
2237 if (status != IPADM_SUCCESS) {
2238 die("Could not get interface(s): %s",
2239 ipadm_status2str(status));
2240 }
2241
2242 for (ptr = if_info; ptr != NULL; ptr = ptr->ifi_next) {
2243 sargs.si_info = ptr;
2244 ofmt_print(state.si_ofmt, &sargs);
2245 }
2246 if (if_info)
2247 ipadm_free_if_info(if_info);
2248 }
2249
2250 /*
2251 * set/reset the address property for a given address
2252 */
2253 static void
set_addrprop(int argc,char ** argv,boolean_t reset,const char * use)2254 set_addrprop(int argc, char **argv, boolean_t reset, const char *use)
2255 {
2256 int option;
2257 ipadm_status_t status = IPADM_SUCCESS;
2258 boolean_t p_arg = _B_FALSE;
2259 char *nv, *aobjname;
2260 char *prop_name, *prop_val;
2261 uint_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
2262
2263 nv = NULL;
2264 opterr = 0;
2265 while ((option = getopt_long(argc, argv, ":i:p:t", set_ifprop_longopts,
2266 NULL)) != -1) {
2267 switch (option) {
2268 case 'p':
2269 if (p_arg)
2270 die("-p must be specified once only");
2271 p_arg = _B_TRUE;
2272
2273 ipadm_check_propstr(optarg, reset, use);
2274 nv = optarg;
2275 break;
2276 case 't':
2277 flags &= ~IPADM_OPT_PERSIST;
2278 break;
2279 default:
2280 die_opterr(optopt, option, use);
2281 }
2282 }
2283
2284 if (!p_arg || optind != (argc - 1))
2285 die("Usage: %s", use);
2286
2287 prop_name = nv;
2288 prop_val = strchr(nv, '=');
2289 if (prop_val != NULL)
2290 *prop_val++ = '\0';
2291 aobjname = argv[optind];
2292 if (reset)
2293 flags |= IPADM_OPT_DEFAULT;
2294 status = ipadm_set_addrprop(iph, prop_name, prop_val, aobjname, flags);
2295 if (status != IPADM_SUCCESS) {
2296 if (reset)
2297 die("reset-addrprop: %s: %s", prop_name,
2298 ipadm_status2str(status));
2299 else
2300 die("set-addrprop: %s: %s", prop_name,
2301 ipadm_status2str(status));
2302 }
2303 }
2304
2305 /*
2306 * Sets a property on an address object.
2307 */
2308 static void
do_set_addrprop(int argc,char ** argv,const char * use)2309 do_set_addrprop(int argc, char **argv, const char *use)
2310 {
2311 set_addrprop(argc, argv, _B_FALSE, use);
2312 }
2313
2314 /*
2315 * Resets a property to its default value on an address object.
2316 */
2317 static void
do_reset_addrprop(int argc,char ** argv,const char * use)2318 do_reset_addrprop(int argc, char **argv, const char *use)
2319 {
2320 set_addrprop(argc, argv, _B_TRUE, use);
2321 }
2322
2323 /*
2324 * Display information for all or specific address properties, either for a
2325 * given address or for all the addresses in the system.
2326 */
2327 static void
do_show_addrprop(int argc,char * argv[],const char * use)2328 do_show_addrprop(int argc, char *argv[], const char *use)
2329 {
2330 int option;
2331 nvlist_t *proplist = NULL;
2332 char *fields_str = NULL;
2333 show_prop_state_t state;
2334 ofmt_handle_t ofmt;
2335 ofmt_status_t oferr;
2336 uint_t ofmtflags = 0;
2337 char *aobjname = NULL;
2338 char *ifname = NULL;
2339 char *cp;
2340 ipadm_addr_info_t *ainfop = NULL;
2341 ipadm_addr_info_t *ptr;
2342 ipadm_status_t status;
2343 boolean_t found = _B_FALSE;
2344
2345 opterr = 0;
2346 bzero(&state, sizeof (state));
2347 state.sps_propval = NULL;
2348 state.sps_parsable = _B_FALSE;
2349 state.sps_addrprop = _B_TRUE;
2350 state.sps_proto = MOD_PROTO_NONE;
2351 state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
2352 while ((option = getopt_long(argc, argv, ":p:i:cPo:",
2353 show_prop_longopts, NULL)) != -1) {
2354 switch (option) {
2355 case 'p':
2356 if (ipadm_str2nvlist(optarg, &proplist,
2357 IPADM_NORVAL) != 0)
2358 die("invalid addrobj properties specified");
2359 break;
2360 case 'c':
2361 state.sps_parsable = _B_TRUE;
2362 break;
2363 case 'o':
2364 fields_str = optarg;
2365 break;
2366 default:
2367 die_opterr(optopt, option, use);
2368 break;
2369 }
2370 }
2371 if (optind == argc - 1) {
2372 aobjname = argv[optind];
2373 cp = strchr(aobjname, '/');
2374 if (cp == NULL)
2375 die("invalid addrobj name provided");
2376 if (*(cp + 1) == '\0') {
2377 ifname = aobjname;
2378 *cp = '\0';
2379 aobjname = NULL;
2380 }
2381 } else if (optind != argc) {
2382 die("Usage: %s", use);
2383 }
2384 state.sps_proplist = proplist;
2385 if (state.sps_parsable)
2386 ofmtflags |= OFMT_PARSABLE;
2387 oferr = ofmt_open(fields_str, addrprop_fields, ofmtflags, 0, &ofmt);
2388 ofmt_check(oferr, state.sps_parsable, ofmt, die, warn);
2389 state.sps_ofmt = ofmt;
2390
2391 status = ipadm_addr_info(iph, ifname, &ainfop, 0, LIFC_DEFAULT);
2392 /* Return without printing any error, if no addresses were found */
2393 if (status == IPADM_NOTFOUND)
2394 return;
2395 if (status != IPADM_SUCCESS)
2396 die("error retrieving address: %s", ipadm_status2str(status));
2397
2398 for (ptr = ainfop; ptr != NULL; ptr = IA_NEXT(ptr)) {
2399 char *taobjname = ptr->ia_aobjname;
2400
2401 if (taobjname[0] == '\0')
2402 continue;
2403 if (aobjname != NULL) {
2404 if (strcmp(aobjname, taobjname) == 0)
2405 found = _B_TRUE;
2406 else
2407 continue;
2408 }
2409 if (ptr->ia_atype == IPADM_ADDR_IPV6_ADDRCONF) {
2410 if (found)
2411 break;
2412 else
2413 continue;
2414 }
2415 (void) strlcpy(state.sps_aobjname, taobjname,
2416 sizeof (state.sps_aobjname));
2417 show_properties(&state, IPADMPROP_CLASS_ADDR);
2418 if (found)
2419 break;
2420 }
2421 ipadm_free_addr_info(ainfop);
2422
2423 if (aobjname != NULL && !found)
2424 die("addrobj not found: %s", aobjname);
2425
2426 nvlist_free(proplist);
2427 ofmt_close(ofmt);
2428 if (state.sps_retstatus != IPADM_SUCCESS) {
2429 ipadm_close(iph);
2430 exit(EXIT_FAILURE);
2431 }
2432 }
2433
2434 /*
2435 * check if the `pstr' adheres to following syntax
2436 * - prop=<value[,...]> (for set)
2437 * - prop (for reset)
2438 */
2439 static void
ipadm_check_propstr(const char * pstr,boolean_t reset,const char * use)2440 ipadm_check_propstr(const char *pstr, boolean_t reset, const char *use)
2441 {
2442 char *nv;
2443
2444 nv = strchr(pstr, '=');
2445 if (reset) {
2446 if (nv != NULL)
2447 die("incorrect syntax used for -p.\n%s", use);
2448 } else {
2449 if (nv == NULL || *++nv == '\0')
2450 die("please specify the value to be set.\n%s", use);
2451 nv = strchr(nv, '=');
2452 /* cannot have multiple 'prop=val' for single -p */
2453 if (nv != NULL)
2454 die("cannot specify more than one prop=val at "
2455 "a time.\n%s", use);
2456 }
2457 }
2458