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