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