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