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