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