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