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