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