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