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