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