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