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