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