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