# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2020 Joyent, Inc. # Copyright 2021 Tintri by DDN, Inc. All rights reserved. # # PROG = ipadm ROOTFS_PROG = $(PROG) LOCALOBJS= ipadm.o COMMONOBJS= OBJS= $(LOCALOBJS) $(COMMONOBJS) include ../../../Makefile.cmd include ../../Makefile.cmd-inet XGETFLAGS += -a -x $(PROG).xcl LOCALSRCS= $(LOCALOBJS:%.o=%.c) COMMONSRCS= $(CMDINETCOMMONDIR)/$(COMMONOBJS:%.o=%.c) SRCS= $(LOCALSRCS) $(COMMONSRCS) CPPFLAGS += -I$(CMDINETCOMMONDIR) LDLIBS += -lofmt -linetutil -lipadm -lnvpair -lipmp -lcmdutils LINTFLAGS += -m ROOTUSRSBINLINKS = $(PROG:%=$(ROOTUSRSBIN)/%) # ipadm uses the ancillary data feature which is available only through # UNIX 98 standards version of Socket interface. This interface is supposed to # be accessed by -lxnet. LDLIBS += -lxnet # these #defines are required to use UNIX 98 interfaces _D_UNIX98_EXTN= -D_XOPEN_SOURCE=500 -D__EXTENSIONS__ $(OBJS) : CPPFLAGS += $(_D_UNIX98_EXTN) LINTFLAGS += $(_D_UNIX98_EXTN) # Hammerhead: Suppress ipadm_get_*prop pointer type mismatch warnings CERRWARN += -Wno-incompatible-pointer-types $(ROOTCFGDIR)/ipadm.conf : FILEMODE= 644 # # Instrument ipadm with CTF data to ease debugging. # CTFCONVERT_HOOK = && $(CTFCONVERT_O) CTFMERGE_HOOK = && $(CTFMERGE) -L VERSION -o $@ $(OBJS) $(OBJS) : CFLAGS += $(CTF_FLAGS) .KEEP_STATE: all: $(ROOTFS_PROG) $(PROG): $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(CTFMERGE_HOOK) $(POST_PROCESS) install: all $(ROOTSBINPROG) $(ROOTCFGDIR) $(ROOTCFGFILES) $(ROOTUSRSBINLINKS) $(ROOTUSRSBINLINKS): -$(RM) $@; $(SYMLINK) ../../sbin/$(@F) $@ clean: $(RM) $(OBJS) lint: lint_SRCS $(ROOTCFGDIR): $(INS.dir) # Hammerhead: order-only prerequisite so $< is the file, not the directory $(ROOTCFGDIR)/%: % | $(ROOTCFGDIR) $(INS.file) include ../../../Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, Joyent, Inc. * Copyright 2017 Gary Mills * Copyright (c) 2016, Chris Fraire . * Copyright 2021 Tintri by DDN, Inc. All rights reserved. * Copyright 2021 OmniOS Community Edition (OmniOSce) Association. * Copyright 2024 Oxide Computer Company */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define STR_UNKNOWN_VAL "?" #define LIFC_DEFAULT (LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES |\ LIFC_UNDER_IPMP) static void do_create_ip_common(int, char **, const char *, uint32_t); typedef void cmdfunc_t(int, char **, const char *); static cmdfunc_t do_help; static cmdfunc_t do_create_ip, do_delete_ip; static cmdfunc_t do_create_ipmp, do_add_ipmp, do_remove_ipmp; static cmdfunc_t do_disable_if, do_enable_if, do_show_if; static cmdfunc_t do_set_ifprop, do_reset_ifprop, do_show_ifprop; static cmdfunc_t do_create_addr, do_delete_addr, do_show_addr, do_refresh_addr; static cmdfunc_t do_disable_addr, do_enable_addr, do_down_addr, do_up_addr; static cmdfunc_t do_set_addrprop, do_reset_addrprop, do_show_addrprop; static cmdfunc_t do_set_prop, do_reset_prop, do_show_prop; typedef struct cmd { char *c_name; cmdfunc_t *c_fn; const char *c_usage; } cmd_t; static cmd_t cmds[] = { { "help", do_help, NULL }, /* interface management related sub-commands */ { "create-if", do_create_ip, "\tcreate-if\t[-t] " }, { "create-ip", do_create_ip, "\tcreate-ip\t[-t] " }, { "delete-if", do_delete_ip, "\tdelete-if\t\n" }, { "delete-ip", do_delete_ip, "\tdelete-ip\t\n" }, { "create-ipmp", do_create_ipmp, "\tcreate-ipmp\t[-t] [-i [,]...] " "" }, { "delete-ipmp", do_delete_ip, "\tdelete-ipmp\t" }, { "add-ipmp", do_add_ipmp, "\tadd-ipmp\t[-t] -i [,]... " "" }, { "remove-ipmp", do_remove_ipmp, "\tremove-ipmp\t[-t] -i [,]... " "\n" }, { "disable-if", do_disable_if, "\tdisable-if\t-t " }, { "enable-if", do_enable_if, "\tenable-if\t-t " }, { "show-if", do_show_if, "\tshow-if\t\t[[-p] -o ,...] []\n" }, { "set-ifprop", do_set_ifprop, "\tset-ifprop\t[-t] -p = -m " "" }, { "reset-ifprop", do_reset_ifprop, "\treset-ifprop\t[-t] -p -m " }, { "show-ifprop", do_show_ifprop, "\tshow-ifprop\t[[-c] -o ,...] [-p ,...]\n" "\t\t\t[-m ] [interface]\n" }, /* address management related sub-commands */ { "create-addr", do_create_addr, "\tcreate-addr\t[-t] -T static [-d] " "-a{local|remote}=addr[/prefixlen]\n\t\t\t\n" "\tcreate-addr\t[-t] -T dhcp [-w | forever]\n" "\t\t\t[-1] [-h ] \n" "\tcreate-addr\t[-t] -T addrconf [-i interface-id]\n" "\t\t\t[-p {stateful|stateless}={yes|no}] " }, { "delete-addr", do_delete_addr, "\tdelete-addr\t[-r] " }, { "show-addr", do_show_addr, "\tshow-addr\t[[-p] -o ,...] []" }, { "refresh-addr", do_refresh_addr, "\trefresh-addr\t[-i] " }, { "down-addr", do_down_addr, "\tdown-addr\t[-t] " }, { "up-addr", do_up_addr, "\tup-addr\t\t[-t] " }, { "disable-addr", do_disable_addr, "\tdisable-addr\t-t " }, { "enable-addr", do_enable_addr, "\tenable-addr\t-t \n" }, { "set-addrprop", do_set_addrprop, "\tset-addrprop\t[-t] -p = " }, { "reset-addrprop", do_reset_addrprop, "\treset-addrprop\t[-t] -p " }, { "show-addrprop", do_show_addrprop, "\tshow-addrprop\t[[-c] -o ,...] [-p ,...] " "\n" }, /* protocol properties related sub-commands */ { "set-prop", do_set_prop, "\tset-prop\t[-t] -p [+|-]= " }, { "reset-prop", do_reset_prop, "\treset-prop\t[-t] -p " }, { "show-prop", do_show_prop, "\tshow-prop\t[[-c] -o ,...] [-p ,...]" " [protocol]" } }; static const struct option if_longopts[] = { {"temporary", no_argument, 0, 't' }, { 0, 0, 0, 0 } }; static const struct option show_prop_longopts[] = { {"parsable", no_argument, 0, 'c' }, {"prop", required_argument, 0, 'p' }, {"output", required_argument, 0, 'o' }, { 0, 0, 0, 0 } }; static const struct option show_ifprop_longopts[] = { {"module", required_argument, 0, 'm' }, {"parsable", no_argument, 0, 'c' }, {"prop", required_argument, 0, 'p' }, {"output", required_argument, 0, 'o' }, { 0, 0, 0, 0 } }; static const struct option set_prop_longopts[] = { {"prop", required_argument, 0, 'p' }, {"temporary", no_argument, 0, 't' }, { 0, 0, 0, 0 } }; static const struct option set_ifprop_longopts[] = { {"module", required_argument, 0, 'm' }, {"prop", required_argument, 0, 'p' }, {"temporary", no_argument, 0, 't' }, { 0, 0, 0, 0 } }; static const struct option addr_misc_longopts[] = { {"inform", no_argument, 0, 'i' }, {"release", no_argument, 0, 'r' }, {"temporary", no_argument, 0, 't' }, { 0, 0, 0, 0 } }; static const struct option addr_longopts[] = { {"address", required_argument, 0, 'a' }, {"down", no_argument, 0, 'd' }, {"interface-id", required_argument, 0, 'i' }, {"primary", no_argument, 0, '1' }, {"prop", required_argument, 0, 'p' }, {"reqhost", required_argument, 0, 'h' }, {"temporary", no_argument, 0, 't' }, {"type", required_argument, 0, 'T' }, {"wait", required_argument, 0, 'w' }, { 0, 0, 0, 0 } }; static const struct option show_addr_longopts[] = { {"parsable", no_argument, 0, 'p' }, {"output", required_argument, 0, 'o' }, { 0, 0, 0, 0 } }; static const struct option show_if_longopts[] = { {"parsable", no_argument, 0, 'p' }, {"output", required_argument, 0, 'o' }, { 0, 0, 0, 0 } }; /* callback functions to print show-* subcommands output */ static ofmt_cb_t print_prop_cb; static ofmt_cb_t print_sa_cb; static ofmt_cb_t print_si_cb; /* structures for 'ipadm show-*' subcommands */ typedef enum { IPADM_PROPFIELD_IFNAME, IPADM_PROPFIELD_PROTO, IPADM_PROPFIELD_ADDROBJ, IPADM_PROPFIELD_PROPERTY, IPADM_PROPFIELD_PERM, IPADM_PROPFIELD_CURRENT, IPADM_PROPFIELD_PERSISTENT, IPADM_PROPFIELD_DEFAULT, IPADM_PROPFIELD_POSSIBLE } ipadm_propfield_index_t; static ofmt_field_t intfprop_fields[] = { /* name, field width, index, callback */ { "IFNAME", 12, IPADM_PROPFIELD_IFNAME, print_prop_cb}, { "PROPERTY", 16, IPADM_PROPFIELD_PROPERTY, print_prop_cb}, { "PROTO", 6, IPADM_PROPFIELD_PROTO, print_prop_cb}, { "PERM", 5, IPADM_PROPFIELD_PERM, print_prop_cb}, { "CURRENT", 11, IPADM_PROPFIELD_CURRENT, print_prop_cb}, { "PERSISTENT", 11, IPADM_PROPFIELD_PERSISTENT, print_prop_cb}, { "DEFAULT", 11, IPADM_PROPFIELD_DEFAULT, print_prop_cb}, { "POSSIBLE", 16, IPADM_PROPFIELD_POSSIBLE, print_prop_cb}, { NULL, 0, 0, NULL} }; static ofmt_field_t modprop_fields[] = { /* name, field width, index, callback */ { "PROTO", 6, IPADM_PROPFIELD_PROTO, print_prop_cb}, { "PROPERTY", 22, IPADM_PROPFIELD_PROPERTY, print_prop_cb}, { "PERM", 5, IPADM_PROPFIELD_PERM, print_prop_cb}, { "CURRENT", 13, IPADM_PROPFIELD_CURRENT, print_prop_cb}, { "PERSISTENT", 13, IPADM_PROPFIELD_PERSISTENT, print_prop_cb}, { "DEFAULT", 13, IPADM_PROPFIELD_DEFAULT, print_prop_cb}, { "POSSIBLE", 15, IPADM_PROPFIELD_POSSIBLE, print_prop_cb}, { NULL, 0, 0, NULL} }; static ofmt_field_t addrprop_fields[] = { /* name, field width, index, callback */ { "ADDROBJ", 18, IPADM_PROPFIELD_ADDROBJ, print_prop_cb}, { "PROPERTY", 11, IPADM_PROPFIELD_PROPERTY, print_prop_cb}, { "PERM", 5, IPADM_PROPFIELD_PERM, print_prop_cb}, { "CURRENT", 16, IPADM_PROPFIELD_CURRENT, print_prop_cb}, { "PERSISTENT", 16, IPADM_PROPFIELD_PERSISTENT, print_prop_cb}, { "DEFAULT", 16, IPADM_PROPFIELD_DEFAULT, print_prop_cb}, { "POSSIBLE", 15, IPADM_PROPFIELD_POSSIBLE, print_prop_cb}, { NULL, 0, 0, NULL} }; typedef struct show_prop_state { char sps_ifname[LIFNAMSIZ]; char sps_aobjname[IPADM_AOBJSIZ]; const char *sps_pname; uint_t sps_proto; char *sps_propval; nvlist_t *sps_proplist; boolean_t sps_parsable; boolean_t sps_addrprop; boolean_t sps_ifprop; boolean_t sps_modprop; ipadm_status_t sps_status; ipadm_status_t sps_retstatus; ofmt_handle_t sps_ofmt; } show_prop_state_t; typedef struct show_addr_state { boolean_t sa_parsable; boolean_t sa_persist; ofmt_handle_t sa_ofmt; } show_addr_state_t; typedef struct show_if_state { boolean_t si_parsable; ofmt_handle_t si_ofmt; } show_if_state_t; typedef struct show_addr_args_s { show_addr_state_t *sa_state; ipadm_addr_info_t *sa_info; } show_addr_args_t; typedef struct show_if_args_s { show_if_state_t *si_state; ipadm_if_info_t *si_info; } show_if_args_t; typedef enum { SA_ADDROBJ, SA_TYPE, SA_STATE, SA_CURRENT, SA_PERSISTENT, SA_ADDR } sa_field_index_t; typedef enum { SI_IFNAME, SI_IFCLASS, SI_STATE, SI_CURRENT, SI_PERSISTENT } si_field_index_t; static ofmt_field_t show_addr_fields[] = { /* name, field width, id, callback */ { "ADDROBJ", 18, SA_ADDROBJ, print_sa_cb}, { "TYPE", 9, SA_TYPE, print_sa_cb}, { "STATE", 13, SA_STATE, print_sa_cb}, { "CURRENT", 8, SA_CURRENT, print_sa_cb}, { "PERSISTENT", 11, SA_PERSISTENT, print_sa_cb}, { "ADDR", 46, SA_ADDR, print_sa_cb}, { NULL, 0, 0, NULL} }; static ofmt_field_t show_if_fields[] = { /* name, field width, id, callback */ { "IFNAME", 11, SI_IFNAME, print_si_cb}, { "CLASS", 10, SI_IFCLASS, print_si_cb}, { "STATE", 9, SI_STATE, print_si_cb}, { "CURRENT", 13, SI_CURRENT, print_si_cb}, { "PERSISTENT", 11, SI_PERSISTENT, print_si_cb}, { NULL, 0, 0, NULL} }; #define IPADM_ALL_BITS ((uint_t)-1) typedef struct intf_mask { char *name; uint64_t bits; uint64_t mask; } fmask_t; typedef enum { IPMP_ADD_MEMBER, IPMP_REMOVE_MEMBER } ipmp_action_t; /* * Handle to libipadm. Opened in main() before the sub-command specific * function is called and is closed before the program exits. */ ipadm_handle_t iph = NULL; /* * Opaque ipadm address object. Used by all the address management subcommands. */ ipadm_addrobj_t ipaddr = NULL; static char *progname; static void warn(const char *, ...); static void die(const char *, ...) __NORETURN; static void die_opterr(int, int, const char *) __NORETURN; static void warn_ipadmerr(ipadm_status_t, const char *, ...); static void ipadm_check_propstr(const char *, boolean_t, const char *); static void process_misc_addrargs(int, char **, const char *, int *, uint32_t *); static void do_action_ipmp(char *, ipadm_ipmp_members_t *, ipmp_action_t, uint32_t); static void usage(int ret) { int i; cmd_t *cmdp; (void) fprintf(stderr, gettext("usage: ipadm ...\n")); for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { cmdp = &cmds[i]; if (cmdp->c_usage != NULL) (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage)); } ipadm_destroy_addrobj(ipaddr); ipadm_close(iph); exit(ret); } static void do_help(int argc __unused, char **argv __unused, const char *use __unused) { usage(0); } int main(int argc, char *argv[]) { int i; cmd_t *cmdp; ipadm_status_t status; (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); if ((progname = strrchr(argv[0], '/')) == NULL) progname = argv[0]; else progname++; if (argc < 2) { argv[1] = "show-addr"; argc = 2; } status = ipadm_open(&iph, 0); if (status != IPADM_SUCCESS) { die("Could not open handle to library - %s", ipadm_status2str(status)); } for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { cmdp = &cmds[i]; if (strcmp(argv[1], cmdp->c_name) == 0) { cmdp->c_fn(argc - 1, &argv[1], gettext(cmdp->c_usage)); ipadm_destroy_addrobj(ipaddr); ipadm_close(iph); exit(0); } } (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), progname, argv[1]); usage(1); return (0); } /* * Create regular IP interface or IPMP group interface */ static void do_create_ip_common(int argc, char *argv[], const char *use, uint32_t flags) { ipadm_status_t status; int option; opterr = 0; while ((option = getopt_long(argc, argv, ":t", if_longopts, NULL)) != -1) { switch (option) { case 't': /* * "ifconfig" mode - plumb interface, but do not * restore settings that may exist in db. */ flags &= ~IPADM_OPT_PERSIST; break; default: die_opterr(optopt, option, use); } } if (optind != (argc - 1)) { if (use != NULL) die("usage: %s", use); else die(NULL); } status = ipadm_create_if(iph, argv[optind], AF_UNSPEC, flags); if (status != IPADM_SUCCESS) { die("Could not create %s : %s", argv[optind], ipadm_status2str(status)); } } /* * Helpers to parse options into ipadm_ipmp_members_t list, and to free it. */ static ipadm_ipmp_members_t * get_ipmp_members(int argc, char *argv[], const char *use, uint32_t *flags) { ipadm_ipmp_members_t *members = NULL; ipadm_ipmp_member_t *member; char *ifname; int option; opterr = 0; while ((option = getopt_long(argc, argv, ":i:", if_longopts, NULL)) != -1) { switch (option) { case 't': *flags &= ~IPADM_OPT_PERSIST; break; case 'i': if (members == NULL) { members = calloc(1, sizeof (ipadm_ipmp_members_t)); if (members == NULL) die("insufficient memory"); list_create(members, sizeof (ipadm_ipmp_member_t), offsetof(ipadm_ipmp_member_t, node)); } for (ifname = strtok(optarg, ","); ifname != NULL; ifname = strtok(NULL, ",")) { if ((member = calloc(1, sizeof (ipadm_ipmp_member_t))) == NULL) die("insufficient memory"); if (strlcpy(member->if_name, ifname, sizeof (member->if_name)) >= LIFNAMSIZ) die("Incorrect length of interface " "name: %s", ifname); list_insert_tail(members, member); } break; default: die_opterr(optopt, option, use); } } if (optind != (argc - 1)) die("Usage: %s", use); if (members != NULL && list_is_empty(members)) { free(members); members = NULL; } return (members); } static void free_ipmp_members(ipadm_ipmp_members_t *members) { ipadm_ipmp_member_t *member; while ((member = list_remove_head(members)) != NULL) free(member); list_destroy(members); free(members); } /* * Create an IPMP group interface for which no saved configuration * exists in the persistent store. */ static void do_create_ipmp(int argc, char *argv[], const char *use) { uint32_t flags = IPADM_OPT_PERSIST | IPADM_OPT_ACTIVE | IPADM_OPT_IPMP; ipadm_ipmp_members_t *members = NULL; ipmp_handle_t ipmp_handle; int retval; retval = ipmp_open(&ipmp_handle); if (retval != IPMP_SUCCESS) { die("Could not create IPMP handle: %s", ipadm_status2str(retval)); } retval = ipmp_ping_daemon(ipmp_handle); ipmp_close(ipmp_handle); if (retval != IPMP_SUCCESS) { die("Cannot ping in.mpathd: %s", ipmp_errmsg(retval)); } members = get_ipmp_members(argc, argv, use, &flags); do_create_ip_common(argc, argv, use, flags); if (members != NULL) { do_action_ipmp(argv[optind], members, IPMP_ADD_MEMBER, flags); free_ipmp_members(members); } } static void do_add_ipmp(int argc, char *argv[], const char *use) { uint32_t flags = IPADM_OPT_PERSIST | IPADM_OPT_ACTIVE; ipadm_ipmp_members_t *members; members = get_ipmp_members(argc, argv, use, &flags); if (members == NULL) die_opterr(optopt, ':', use); do_action_ipmp(argv[optind], members, IPMP_ADD_MEMBER, flags); free_ipmp_members(members); } static void do_remove_ipmp(int argc, char *argv[], const char *use) { uint32_t flags = IPADM_OPT_PERSIST | IPADM_OPT_ACTIVE; ipadm_ipmp_members_t *members; members = get_ipmp_members(argc, argv, use, &flags); if (members == NULL) die_opterr(optopt, ':', use); do_action_ipmp(argv[optind], members, IPMP_REMOVE_MEMBER, flags); free_ipmp_members(members); } static void do_action_ipmp(char *ipmp, ipadm_ipmp_members_t *members, ipmp_action_t action, uint32_t flags) { ipadm_status_t (*func)(ipadm_handle_t, const char *, const char *, uint32_t); ipadm_status_t status; ipadm_ipmp_member_t *member; char *ifname; const char *msg; if (action == IPMP_ADD_MEMBER) { func = ipadm_add_ipmp_member; msg = "Cannot add interface '%s' to IPMP interface '%s': %s"; } else { func = ipadm_remove_ipmp_member; msg = "Cannot remove interface '%s' from IPMP interface '%s': " "%s"; } while ((member = list_remove_head(members)) != NULL) { ifname = member->if_name; status = func(iph, ipmp, ifname, flags); if (status != IPADM_SUCCESS) die(msg, ifname, ipmp, ipadm_status2str(status)); } } /* * Create an IP interface for which no saved configuration exists in the * persistent store. */ static void do_create_ip(int argc, char *argv[], const char *use) { do_create_ip_common(argc, argv, use, IPADM_OPT_PERSIST | IPADM_OPT_ACTIVE); } /* * Enable an IP interface based on the persistent configuration for * that interface. */ static void do_enable_if(int argc, char *argv[], const char *use) { ipadm_status_t status; int index; uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST; process_misc_addrargs(argc, argv, use, &index, &flags); if (flags & IPADM_OPT_PERSIST) die("persistent operation not supported for enable-if"); status = ipadm_enable_if(iph, argv[index], flags); if (status == IPADM_ALL_ADDRS_NOT_ENABLED) { warn_ipadmerr(status, ""); } else if (status != IPADM_SUCCESS) { die("Could not enable %s : %s", argv[optind], ipadm_status2str(status)); } } /* * Remove an IP interface from both active and persistent configuration. */ static void do_delete_ip(int argc, char *argv[], const char *use) { ipadm_status_t status; uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST; if (argc != 2) die("Usage: %s", use); status = ipadm_delete_if(iph, argv[1], AF_UNSPEC, flags); if (status != IPADM_SUCCESS) { die("Could not delete %s: %s", argv[optind], ipadm_status2str(status)); } } /* * Disable an IP interface by removing it from active configuration. */ static void do_disable_if(int argc, char *argv[], const char *use) { ipadm_status_t status; int index; uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST; process_misc_addrargs(argc, argv, use, &index, &flags); if (flags & IPADM_OPT_PERSIST) die("persistent operation not supported for disable-if"); status = ipadm_disable_if(iph, argv[index], flags); if (status != IPADM_SUCCESS) { die("Could not disable %s: %s", argv[optind], ipadm_status2str(status)); } } /* * Print individual columns for the show-*prop subcommands. */ static void print_prop(show_prop_state_t *statep, uint_t flags, char *buf, size_t bufsize) { const char *prop_name = statep->sps_pname; char *ifname = statep->sps_ifname; char *propval = statep->sps_propval; uint_t proto = statep->sps_proto; size_t propsize = MAXPROPVALLEN; ipadm_status_t status; if (statep->sps_ifprop) { status = ipadm_get_ifprop(iph, ifname, prop_name, propval, &propsize, proto, flags); } else if (statep->sps_modprop) { status = ipadm_get_prop(iph, prop_name, propval, &propsize, proto, flags); } else { status = ipadm_get_addrprop(iph, prop_name, propval, &propsize, statep->sps_aobjname, flags); } if (status != IPADM_SUCCESS) { if ((status == IPADM_NOTFOUND && (flags & IPADM_OPT_PERSIST)) || status == IPADM_ENXIO) { propval[0] = '\0'; goto cont; } statep->sps_status = status; statep->sps_retstatus = status; return; } cont: statep->sps_status = IPADM_SUCCESS; (void) snprintf(buf, bufsize, "%s", propval); } /* * Callback function for show-*prop subcommands. */ /* Hammerhead: Use uint_t to match ofmt_cb_t typedef in libofmt */ static boolean_t print_prop_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) { show_prop_state_t *statep = ofarg->ofmt_cbarg; const char *propname = statep->sps_pname; uint_t proto = statep->sps_proto; boolean_t cont = _B_TRUE; /* * Fail retrieving remaining fields, if you fail * to retrieve a field. */ if (statep->sps_status != IPADM_SUCCESS) return (_B_FALSE); switch (ofarg->ofmt_id) { case IPADM_PROPFIELD_IFNAME: (void) snprintf(buf, bufsize, "%s", statep->sps_ifname); break; case IPADM_PROPFIELD_PROTO: (void) snprintf(buf, bufsize, "%s", ipadm_proto2str(proto)); break; case IPADM_PROPFIELD_ADDROBJ: (void) snprintf(buf, bufsize, "%s", statep->sps_aobjname); break; case IPADM_PROPFIELD_PROPERTY: (void) snprintf(buf, bufsize, "%s", propname); break; case IPADM_PROPFIELD_PERM: print_prop(statep, IPADM_OPT_PERM, buf, bufsize); break; case IPADM_PROPFIELD_CURRENT: print_prop(statep, IPADM_OPT_ACTIVE, buf, bufsize); break; case IPADM_PROPFIELD_PERSISTENT: print_prop(statep, IPADM_OPT_PERSIST, buf, bufsize); break; case IPADM_PROPFIELD_DEFAULT: print_prop(statep, IPADM_OPT_DEFAULT, buf, bufsize); break; case IPADM_PROPFIELD_POSSIBLE: print_prop(statep, IPADM_OPT_POSSIBLE, buf, bufsize); break; } if (statep->sps_status != IPADM_SUCCESS) cont = _B_FALSE; return (cont); } /* * Callback function called by the property walker (ipadm_walk_prop() or * ipadm_walk_proptbl()), for every matched property. This function in turn * calls ofmt_print() to print property information. */ boolean_t show_property(void *arg, const char *pname, uint_t proto) { show_prop_state_t *statep = arg; statep->sps_pname = pname; statep->sps_proto = proto; statep->sps_status = IPADM_SUCCESS; ofmt_print(statep->sps_ofmt, arg); /* * if an object is not found or operation is not supported then * stop the walker. */ if (statep->sps_status == IPADM_NOTFOUND || statep->sps_status == IPADM_NOTSUP) return (_B_FALSE); return (_B_TRUE); } /* * Properties to be displayed is in `statep->sps_proplist'. If it is NULL, * for all the properties for the specified object, display relevant * information. Otherwise, for the selected property set, display relevant * information */ static void show_properties(void *arg, int prop_class) { show_prop_state_t *statep = arg; nvlist_t *nvl = statep->sps_proplist; uint_t proto = statep->sps_proto; nvpair_t *curr_nvp; char *buf, *name; ipadm_status_t status; /* allocate sufficient buffer to hold a property value */ if ((buf = malloc(MAXPROPVALLEN)) == NULL) die("insufficient memory"); statep->sps_propval = buf; /* if no properties were specified, display all the properties */ if (nvl == NULL) { (void) ipadm_walk_proptbl(proto, prop_class, show_property, statep); } else { for (curr_nvp = nvlist_next_nvpair(nvl, NULL); curr_nvp; curr_nvp = nvlist_next_nvpair(nvl, curr_nvp)) { name = nvpair_name(curr_nvp); status = ipadm_walk_prop(name, proto, prop_class, show_property, statep); if (status == IPADM_PROP_UNKNOWN) (void) show_property(statep, name, proto); } } free(buf); } /* * Display information for all or specific interface properties, either for a * given interface or for all the interfaces in the system. */ static void do_show_ifprop(int argc, char **argv, const char *use) { int option; nvlist_t *proplist = NULL; char *fields_str = NULL; char *ifname; ofmt_handle_t ofmt; ofmt_status_t oferr; uint_t ofmtflags = 0; uint_t proto; boolean_t m_arg = _B_FALSE; char *protostr; ipadm_if_info_t *ifinfo, *ifp; ipadm_status_t status; show_prop_state_t state; protostr = "ip"; opterr = 0; bzero(&state, sizeof (state)); state.sps_propval = NULL; state.sps_parsable = _B_FALSE; state.sps_ifprop = _B_TRUE; state.sps_status = state.sps_retstatus = IPADM_SUCCESS; while ((option = getopt_long(argc, argv, ":p:m:co:", show_ifprop_longopts, NULL)) != -1) { switch (option) { case 'p': if (ipadm_str2nvlist(optarg, &proplist, IPADM_NORVAL) != 0) die("invalid interface properties specified"); break; case 'c': state.sps_parsable = _B_TRUE; break; case 'o': fields_str = optarg; break; case 'm': if (m_arg) die("cannot specify more than one -m"); m_arg = _B_TRUE; protostr = optarg; break; default: die_opterr(optopt, option, use); break; } } if (optind == argc - 1) ifname = argv[optind]; else if (optind != argc) die("Usage: %s", use); else ifname = NULL; if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE) die("invalid protocol '%s' specified", protostr); state.sps_proto = proto; state.sps_proplist = proplist; if (state.sps_parsable) ofmtflags |= OFMT_PARSABLE; oferr = ofmt_open(fields_str, intfprop_fields, ofmtflags, 0, &ofmt); ofmt_check(oferr, state.sps_parsable, ofmt, die, warn); state.sps_ofmt = ofmt; /* retrieve interface(s) and print the properties */ status = ipadm_if_info(iph, ifname, &ifinfo, 0, LIFC_DEFAULT); if (ifname != NULL && status == IPADM_ENXIO) die("no such object '%s': %s", ifname, ipadm_status2str(status)); if (status != IPADM_SUCCESS) die("Error retrieving interface(s): %s", ipadm_status2str(status)); for (ifp = ifinfo; ifp != NULL; ifp = ifp->ifi_next) { (void) strlcpy(state.sps_ifname, ifp->ifi_name, LIFNAMSIZ); state.sps_proto = proto; show_properties(&state, IPADMPROP_CLASS_IF); } if (ifinfo) ipadm_free_if_info(ifinfo); nvlist_free(proplist); ofmt_close(ofmt); if (state.sps_retstatus != IPADM_SUCCESS) { ipadm_close(iph); exit(EXIT_FAILURE); } } /* * set/reset the interface property for a given interface. */ static void set_ifprop(int argc, char **argv, boolean_t reset, const char *use) { int option; ipadm_status_t status = IPADM_SUCCESS; boolean_t p_arg = _B_FALSE; boolean_t m_arg = _B_FALSE; char *ifname, *nv, *protostr; char *prop_name, *prop_val; uint_t flags = IPADM_OPT_PERSIST; uint_t proto; nv = NULL; protostr = NULL; opterr = 0; while ((option = getopt_long(argc, argv, ":m:p:t", set_ifprop_longopts, NULL)) != -1) { switch (option) { case 'p': if (p_arg) die("-p must be specified once only"); p_arg = _B_TRUE; ipadm_check_propstr(optarg, reset, use); nv = optarg; break; case 'm': if (m_arg) die("-m must be specified once only"); m_arg = _B_TRUE; protostr = optarg; break; case 't': flags &= ~IPADM_OPT_PERSIST; break; default: die_opterr(optopt, option, use); } } if (!m_arg || !p_arg || optind != argc - 1) die("Usage: %s", use); ifname = argv[optind]; prop_name = nv; prop_val = strchr(nv, '='); if (prop_val != NULL) *prop_val++ = '\0'; if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE) die("invalid protocol '%s' specified", protostr); if (reset) flags |= IPADM_OPT_DEFAULT; else flags |= IPADM_OPT_ACTIVE; status = ipadm_set_ifprop(iph, ifname, prop_name, prop_val, proto, flags); if (status != IPADM_SUCCESS) { if (reset) die("reset-ifprop: %s: %s", prop_name, ipadm_status2str(status)); else die("set-ifprop: %s: %s", prop_name, ipadm_status2str(status)); } } static void do_set_ifprop(int argc, char **argv, const char *use) { set_ifprop(argc, argv, _B_FALSE, use); } static void do_reset_ifprop(int argc, char **argv, const char *use) { set_ifprop(argc, argv, _B_TRUE, use); } /* * Display information for all or specific protocol properties, either for a * given protocol or for supported protocols (IP/IPv4/IPv6/TCP/UDP/SCTP) */ static void do_show_prop(int argc, char **argv, const char *use) { int option; nvlist_t *proplist = NULL; char *fields_str = NULL; char *protostr; show_prop_state_t state; ofmt_handle_t ofmt; ofmt_status_t oferr; uint_t ofmtflags = 0; uint_t proto; boolean_t p_arg = _B_FALSE; opterr = 0; bzero(&state, sizeof (state)); state.sps_propval = NULL; state.sps_parsable = _B_FALSE; state.sps_modprop = _B_TRUE; state.sps_status = state.sps_retstatus = IPADM_SUCCESS; while ((option = getopt_long(argc, argv, ":p:co:", show_prop_longopts, NULL)) != -1) { switch (option) { case 'p': if (p_arg) die("-p must be specified once only"); p_arg = _B_TRUE; if (ipadm_str2nvlist(optarg, &proplist, IPADM_NORVAL) != 0) die("invalid protocol properties specified"); break; case 'c': state.sps_parsable = _B_TRUE; break; case 'o': fields_str = optarg; break; default: die_opterr(optopt, option, use); break; } } if (optind == argc - 1) { protostr = argv[optind]; if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE) die("invalid protocol '%s' specified", protostr); state.sps_proto = proto; } else if (optind != argc) { die("Usage: %s", use); } else { if (p_arg) die("protocol must be specified when " "property name is used"); state.sps_proto = MOD_PROTO_NONE; } state.sps_proplist = proplist; if (state.sps_parsable) ofmtflags |= OFMT_PARSABLE; else ofmtflags |= OFMT_WRAP; oferr = ofmt_open(fields_str, modprop_fields, ofmtflags, 0, &ofmt); ofmt_check(oferr, state.sps_parsable, ofmt, die, warn); state.sps_ofmt = ofmt; /* handles all the errors */ show_properties(&state, IPADMPROP_CLASS_MODULE); nvlist_free(proplist); ofmt_close(ofmt); if (state.sps_retstatus != IPADM_SUCCESS) { ipadm_close(iph); exit(EXIT_FAILURE); } } /* * Checks to see if there are any modifiers, + or -. If there are modifiers * then sets IPADM_OPT_APPEND or IPADM_OPT_REMOVE, accordingly. */ static void parse_modifiers(const char *pstr, uint_t *flags, const char *use) { char *p; if ((p = strchr(pstr, '=')) == NULL) return; if (p == pstr) die("Invalid prop=val specified\n%s", use); --p; if (*p == '+') *flags |= IPADM_OPT_APPEND; else if (*p == '-') *flags |= IPADM_OPT_REMOVE; } /* * set/reset the protocol property for a given protocol. */ static void set_prop(int argc, char **argv, boolean_t reset, const char *use) { int option; ipadm_status_t status = IPADM_SUCCESS; char *protostr, *nv, *prop_name, *prop_val; boolean_t p_arg = _B_FALSE; uint_t proto; uint_t flags = IPADM_OPT_PERSIST; nv = NULL; opterr = 0; while ((option = getopt_long(argc, argv, ":p:t", set_prop_longopts, NULL)) != -1) { switch (option) { case 'p': if (p_arg) die("-p must be specified once only"); p_arg = _B_TRUE; ipadm_check_propstr(optarg, reset, use); nv = optarg; break; case 't': flags &= ~IPADM_OPT_PERSIST; break; default: die_opterr(optopt, option, use); } } if (!p_arg || optind != argc - 1) die("Usage: %s", use); parse_modifiers(nv, &flags, use); prop_name = nv; prop_val = strchr(nv, '='); if (prop_val != NULL) { if (flags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE)) *(prop_val - 1) = '\0'; *prop_val++ = '\0'; } protostr = argv[optind]; if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE) die("invalid protocol '%s' specified", protostr); if (reset) flags |= IPADM_OPT_DEFAULT; else flags |= IPADM_OPT_ACTIVE; status = ipadm_set_prop(iph, prop_name, prop_val, proto, flags); if (status != IPADM_SUCCESS) { if (reset) die("reset-prop: %s: %s", prop_name, ipadm_status2str(status)); else die("set-prop: %s: %s", prop_name, ipadm_status2str(status)); } } static void do_set_prop(int argc, char **argv, const char *use) { set_prop(argc, argv, _B_FALSE, use); } static void do_reset_prop(int argc, char **argv, const char *use) { set_prop(argc, argv, _B_TRUE, use); } /* PRINTFLIKE1 */ static void warn(const char *format, ...) { va_list alist; format = gettext(format); (void) fprintf(stderr, gettext("%s: warning: "), progname); va_start(alist, format); (void) vfprintf(stderr, format, alist); va_end(alist); (void) fprintf(stderr, "\n"); } /* PRINTFLIKE1 */ static void die(const char *format, ...) { va_list alist; if (format != NULL) { format = gettext(format); (void) fprintf(stderr, "%s: ", progname); va_start(alist, format); (void) vfprintf(stderr, format, alist); va_end(alist); (void) putchar('\n'); } ipadm_destroy_addrobj(ipaddr); ipadm_close(iph); exit(EXIT_FAILURE); } static void die_opterr(int opt, int opterr, const char *usage) { switch (opterr) { case ':': die("option '-%c' requires a value\nusage: %s", opt, gettext(usage)); break; case '?': default: die("unrecognized option '-%c'\nusage: %s", opt, gettext(usage)); break; } } /* PRINTFLIKE2 */ static void warn_ipadmerr(ipadm_status_t err, const char *format, ...) { va_list alist; format = gettext(format); (void) fprintf(stderr, gettext("%s: warning: "), progname); va_start(alist, format); (void) vfprintf(stderr, format, alist); va_end(alist); (void) fprintf(stderr, "%s\n", ipadm_status2str(err)); } static void process_static_addrargs(const char *use, char *addrarg, const char *aobjname) { int option; char *val; char *laddr = NULL; char *raddr = NULL; char *save_input_arg = addrarg; boolean_t found_mismatch = _B_FALSE; ipadm_status_t status; enum { A_LOCAL, A_REMOTE }; static char *addr_optstr[] = { "local", "remote", NULL, }; while (*addrarg != '\0') { option = getsubopt(&addrarg, addr_optstr, &val); switch (option) { case A_LOCAL: if (laddr != NULL) die("Multiple local addresses provided"); laddr = val; break; case A_REMOTE: if (raddr != NULL) die("Multiple remote addresses provided"); raddr = val; break; default: if (found_mismatch) die("Invalid address provided\nusage: %s", use); found_mismatch = _B_TRUE; break; } } if (raddr != NULL && laddr == NULL) die("Missing local address\nusage: %s", use); /* If only one address is provided, it is assumed a local address. */ if (laddr == NULL) { if (found_mismatch) laddr = save_input_arg; else die("Missing local address\nusage: %s", use); } /* Initialize the addrobj for static addresses. */ status = ipadm_create_addrobj(IPADM_ADDR_STATIC, aobjname, &ipaddr); if (status != IPADM_SUCCESS) { die("Error in creating address object: %s", ipadm_status2str(status)); } /* Set the local and remote addresses */ status = ipadm_set_addr(ipaddr, laddr, AF_UNSPEC); if (status != IPADM_SUCCESS) { die("Error in setting local address: %s", ipadm_status2str(status)); } if (raddr != NULL) { status = ipadm_set_dst_addr(ipaddr, raddr, AF_UNSPEC); if (status != IPADM_SUCCESS) { die("Error in setting remote address: %s", ipadm_status2str(status)); } } } static void process_addrconf_addrargs(const char *use, char *addrarg) { int option; char *val; enum { P_STATELESS, P_STATEFUL }; static char *addr_optstr[] = { "stateless", "stateful", NULL, }; boolean_t stateless = _B_FALSE; boolean_t stateless_arg = _B_FALSE; boolean_t stateful = _B_FALSE; boolean_t stateful_arg = _B_FALSE; ipadm_status_t status; while (*addrarg != '\0') { option = getsubopt(&addrarg, addr_optstr, &val); switch (option) { case P_STATELESS: if (stateless_arg) die("Duplicate option"); if (val == NULL) die("Invalid argument"); if (strcmp(val, "yes") == 0) stateless = _B_TRUE; else if (strcmp(val, "no") == 0) stateless = _B_FALSE; else die("Invalid argument"); stateless_arg = _B_TRUE; break; case P_STATEFUL: if (stateful_arg) die("Duplicate option"); if (val == NULL) die("Invalid argument"); if (strcmp(val, "yes") == 0) stateful = _B_TRUE; else if (strcmp(val, "no") == 0) stateful = _B_FALSE; else die("Invalid argument"); stateful_arg = _B_TRUE; break; default: die_opterr(optopt, option, use); } } if (!stateless_arg && !stateful_arg) die("Invalid arguments for option -p"); /* Set the addrobj fields for addrconf */ if (stateless_arg) { status = ipadm_set_stateless(ipaddr, stateless); if (status != IPADM_SUCCESS) { die("Error in setting stateless option: %s", ipadm_status2str(status)); } } if (stateful_arg) { status = ipadm_set_stateful(ipaddr, stateful); if (status != IPADM_SUCCESS) { die("Error in setting stateful option: %s", ipadm_status2str(status)); } } } /* * Creates static, dhcp or addrconf addresses and associates the created * addresses with the specified address object name. */ static void do_create_addr(int argc, char *argv[], const char *use) { ipadm_status_t status; int option; uint32_t flags = IPADM_OPT_PERSIST|IPADM_OPT_ACTIVE|IPADM_OPT_UP|IPADM_OPT_V46; char *cp; char *atype = NULL; char *static_arg = NULL; char *addrconf_arg = NULL; char *interface_id = NULL; char *wait = NULL; char *reqhost = NULL; boolean_t s_opt = _B_FALSE; /* static addr options */ boolean_t auto_opt = _B_FALSE; /* Addrconf options */ boolean_t dhcp_opt = _B_FALSE; /* dhcp options */ boolean_t primary_opt = _B_FALSE; /* dhcp primary option */ opterr = 0; while ((option = getopt_long(argc, argv, ":1T:a:dh:i:p:w:t", addr_longopts, NULL)) != -1) { switch (option) { case '1': primary_opt = _B_TRUE; break; case 'T': atype = optarg; break; case 'a': static_arg = optarg; s_opt = _B_TRUE; break; case 'd': flags &= ~IPADM_OPT_UP; s_opt = _B_TRUE; break; case 'h': reqhost = optarg; break; case 'i': interface_id = optarg; auto_opt = _B_TRUE; break; case 'p': addrconf_arg = optarg; auto_opt = _B_TRUE; break; case 'w': wait = optarg; dhcp_opt = _B_TRUE; break; case 't': flags &= ~IPADM_OPT_PERSIST; break; default: die_opterr(optopt, option, use); } } if (atype == NULL || optind != (argc - 1)) { die("Invalid arguments\nusage: %s", use); } else if ((cp = strchr(argv[optind], '/')) == NULL || strlen(++cp) == 0) { die("invalid address object name: %s\nusage: %s", argv[optind], use); } /* * Allocate and initialize the addrobj based on the address type. */ if (strcmp(atype, "static") == 0) { if (static_arg == NULL || auto_opt || dhcp_opt || reqhost != NULL || primary_opt) { die("Invalid arguments for type %s\nusage: %s", atype, use); } process_static_addrargs(use, static_arg, argv[optind]); } else if (strcmp(atype, "dhcp") == 0) { if (auto_opt || s_opt) { die("Invalid arguments for type %s\nusage: %s", atype, use); } /* Initialize the addrobj for dhcp addresses. */ status = ipadm_create_addrobj(IPADM_ADDR_DHCP, argv[optind], &ipaddr); if (status != IPADM_SUCCESS) { die("Error in creating address object: %s", ipadm_status2str(status)); } if (wait != NULL) { int32_t ipadm_wait; if (strcmp(wait, "forever") == 0) { ipadm_wait = IPADM_DHCP_WAIT_FOREVER; } else { char *end; long timeout = strtol(wait, &end, 10); if (*end != '\0' || timeout < 0) die("Invalid argument"); ipadm_wait = (int32_t)timeout; } status = ipadm_set_wait_time(ipaddr, ipadm_wait); if (status != IPADM_SUCCESS) { die("Error in setting wait time: %s", ipadm_status2str(status)); } } if (primary_opt) { status = ipadm_set_primary(ipaddr, _B_TRUE); if (status != IPADM_SUCCESS) { die("Error in setting primary flag: %s", ipadm_status2str(status)); } } if (reqhost != NULL) { status = ipadm_set_reqhost(ipaddr, reqhost); if (status != IPADM_SUCCESS) { die("Error in setting reqhost: %s", ipadm_status2str(status)); } } } else if (strcmp(atype, "addrconf") == 0) { if (dhcp_opt || s_opt || reqhost != NULL || primary_opt) { die("Invalid arguments for type %s\nusage: %s", atype, use); } /* Initialize the addrobj for ipv6-addrconf addresses. */ status = ipadm_create_addrobj(IPADM_ADDR_IPV6_ADDRCONF, argv[optind], &ipaddr); if (status != IPADM_SUCCESS) { die("Error in creating address object: %s", ipadm_status2str(status)); } if (interface_id != NULL) { status = ipadm_set_interface_id(ipaddr, interface_id); if (status != IPADM_SUCCESS) { die("Error in setting interface ID: %s", ipadm_status2str(status)); } } if (addrconf_arg) process_addrconf_addrargs(use, addrconf_arg); } else { die("Invalid address type %s", atype); } status = ipadm_create_addr(iph, ipaddr, flags); if (status == IPADM_DHCP_IPC_TIMEOUT) warn_ipadmerr(status, ""); else if (status != IPADM_SUCCESS) die("Could not create address: %s", ipadm_status2str(status)); } /* * Used by some address management functions to parse the command line * arguments and create `ipaddr' address object. */ static void process_misc_addrargs(int argc, char *argv[], const char *use, int *index, uint32_t *flags) { int option; opterr = 0; while ((option = getopt_long(argc, argv, ":t", addr_misc_longopts, NULL)) != -1) { switch (option) { case 't': *flags &= ~IPADM_OPT_PERSIST; break; default: die_opterr(optopt, option, use); } } if (optind != (argc - 1)) die("Usage: %s", use); *index = optind; } /* * Remove an addrobj from both active and persistent configuration. */ static void do_delete_addr(int argc, char *argv[], const char *use) { ipadm_status_t status; uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST; int option; opterr = 0; while ((option = getopt_long(argc, argv, ":r", addr_misc_longopts, NULL)) != -1) { switch (option) { case 'r': flags |= IPADM_OPT_RELEASE; break; default: die_opterr(optopt, option, use); } } if (optind != (argc - 1)) die("Usage: %s", use); status = ipadm_delete_addr(iph, argv[optind], flags); if (status != IPADM_SUCCESS) { die("could not delete address: %s", ipadm_status2str(status)); } } /* * Enable an IP address based on the persistent configuration for that * IP address */ static void do_enable_addr(int argc, char *argv[], const char *use) { ipadm_status_t status; int index; uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST; process_misc_addrargs(argc, argv, use, &index, &flags); if (flags & IPADM_OPT_PERSIST) die("persistent operation not supported for enable-addr"); status = ipadm_enable_addr(iph, argv[index], flags); if (status != IPADM_SUCCESS) die("could not enable address: %s", ipadm_status2str(status)); } /* * Mark the address identified by addrobj 'up' */ static void do_up_addr(int argc, char *argv[], const char *use) { ipadm_status_t status; int index; uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST; process_misc_addrargs(argc, argv, use, &index, &flags); status = ipadm_up_addr(iph, argv[index], flags); if (status != IPADM_SUCCESS) { die("Could not mark the address up: %s", ipadm_status2str(status)); } } /* * Disable the specified addrobj by removing it from active cofiguration */ static void do_disable_addr(int argc, char *argv[], const char *use) { ipadm_status_t status; int index; uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST; process_misc_addrargs(argc, argv, use, &index, &flags); if (flags & IPADM_OPT_PERSIST) die("persistent operation not supported for disable-addr"); status = ipadm_disable_addr(iph, argv[index], flags); if (status != IPADM_SUCCESS) { die("could not disable address: %s", ipadm_status2str(status)); } } /* * Mark the address identified by addrobj 'down' */ static void do_down_addr(int argc, char *argv[], const char *use) { ipadm_status_t status; int index; uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST; process_misc_addrargs(argc, argv, use, &index, &flags); status = ipadm_down_addr(iph, argv[index], flags); if (status != IPADM_SUCCESS) die("Could not mark the address down: %s", ipadm_status2str(status)); } /* * Restart DAD for static address. Extend lease duration for DHCP addresses */ static void do_refresh_addr(int argc, char *argv[], const char *use) { ipadm_status_t status; int option; uint32_t flags = 0; opterr = 0; while ((option = getopt_long(argc, argv, ":i", addr_misc_longopts, NULL)) != -1) { switch (option) { case 'i': flags |= IPADM_OPT_INFORM; break; default: die_opterr(optopt, option, use); } } if (optind != (argc - 1)) die("Usage: %s", use); status = ipadm_refresh_addr(iph, argv[optind], flags); if (status == IPADM_DHCP_IPC_TIMEOUT) warn_ipadmerr(status, ""); else if (status != IPADM_SUCCESS) die("could not refresh address %s", ipadm_status2str(status)); } static void sockaddr2str(const struct sockaddr_storage *ssp, char *buf, uint_t bufsize) { socklen_t socklen; struct sockaddr *sp = (struct sockaddr *)ssp; switch (ssp->ss_family) { case AF_INET: socklen = sizeof (struct sockaddr_in); break; case AF_INET6: socklen = sizeof (struct sockaddr_in6); break; default: (void) strlcpy(buf, STR_UNKNOWN_VAL, bufsize); return; } (void) getnameinfo(sp, socklen, buf, bufsize, NULL, 0, (NI_NOFQDN | NI_NUMERICHOST)); } static void flags2str(uint64_t flags, fmask_t *tbl, boolean_t is_bits, char *buf, uint_t bufsize) { int i; boolean_t first = _B_TRUE; if (is_bits) { for (i = 0; tbl[i].name; i++) { if ((flags & tbl[i].mask) == tbl[i].bits) (void) strlcat(buf, tbl[i].name, bufsize); else (void) strlcat(buf, "-", bufsize); } } else { for (i = 0; tbl[i].name; i++) { if ((flags & tbl[i].mask) == tbl[i].bits) { if (!first) (void) strlcat(buf, ",", bufsize); (void) strlcat(buf, tbl[i].name, bufsize); first = _B_FALSE; } } } } /* * return true if the address for lifname comes to us from the global zone * with 'allowed-ips' constraints. */ static boolean_t is_from_gz(const char *lifname) { ipadm_if_info_t *if_info; char phyname[LIFNAMSIZ], *cp; boolean_t ret = _B_FALSE; ipadm_status_t status; zoneid_t zoneid; ushort_t zflags; if ((zoneid = getzoneid()) == GLOBAL_ZONEID) return (_B_FALSE); /* from-gz only makes sense in a NGZ */ if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags, sizeof (zflags)) < 0) return (_B_FALSE); if (!(zflags & ZF_NET_EXCL)) return (_B_TRUE); /* everything is from the GZ for shared-ip */ (void) strncpy(phyname, lifname, sizeof (phyname)); if ((cp = strchr(phyname, ':')) != NULL) *cp = '\0'; status = ipadm_if_info(iph, phyname, &if_info, 0, LIFC_DEFAULT); if (status != IPADM_SUCCESS) return (ret); if (if_info->ifi_cflags & IFIF_L3PROTECT) ret = _B_TRUE; ipadm_free_if_info(if_info); return (ret); } static boolean_t print_sa_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) { show_addr_args_t *arg = ofarg->ofmt_cbarg; ipadm_addr_info_t *ainfo = arg->sa_info; char interface[LIFNAMSIZ]; char addrbuf[MAXPROPVALLEN]; char dstbuf[MAXPROPVALLEN]; char prefixlenstr[MAXPROPVALLEN]; int prefixlen; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; sa_family_t af; char *phyname = NULL; struct ifaddrs *ifa = &ainfo->ia_ifa; fmask_t cflags_mask[] = { { "U", IA_UP, IA_UP }, { "u", IA_UNNUMBERED, IA_UNNUMBERED }, { "p", IA_PRIVATE, IA_PRIVATE }, { "t", IA_TEMPORARY, IA_TEMPORARY }, { "d", IA_DEPRECATED, IA_DEPRECATED }, { NULL, 0, 0 } }; fmask_t pflags_mask[] = { { "U", IA_UP, IA_UP }, { "p", IA_PRIVATE, IA_PRIVATE }, { "d", IA_DEPRECATED, IA_DEPRECATED }, { NULL, 0, 0 } }; fmask_t type[] = { { "static", IPADM_ADDR_STATIC, IPADM_ALL_BITS}, { "addrconf", IPADM_ADDR_IPV6_ADDRCONF, IPADM_ALL_BITS}, { "dhcp", IPADM_ADDR_DHCP, IPADM_ALL_BITS}, { NULL, 0, 0 } }; fmask_t addr_state[] = { { "disabled", IFA_DISABLED, IPADM_ALL_BITS}, { "duplicate", IFA_DUPLICATE, IPADM_ALL_BITS}, { "down", IFA_DOWN, IPADM_ALL_BITS}, { "tentative", IFA_TENTATIVE, IPADM_ALL_BITS}, { "ok", IFA_OK, IPADM_ALL_BITS}, { "inaccessible", IFA_INACCESSIBLE, IPADM_ALL_BITS}, { NULL, 0, 0 } }; buf[0] = '\0'; switch (ofarg->ofmt_id) { case SA_ADDROBJ: if (ainfo->ia_aobjname[0] == '\0') { (void) strncpy(interface, ifa->ifa_name, LIFNAMSIZ); phyname = strrchr(interface, ':'); if (phyname) *phyname = '\0'; (void) snprintf(buf, bufsize, "%s/%s", interface, STR_UNKNOWN_VAL); } else { (void) snprintf(buf, bufsize, "%s", ainfo->ia_aobjname); } break; case SA_STATE: flags2str(ainfo->ia_state, addr_state, _B_FALSE, buf, bufsize); break; case SA_TYPE: if (is_from_gz(ifa->ifa_name)) (void) snprintf(buf, bufsize, "from-gz"); else flags2str(ainfo->ia_atype, type, _B_FALSE, buf, bufsize); break; case SA_CURRENT: flags2str(ainfo->ia_cflags, cflags_mask, _B_TRUE, buf, bufsize); break; case SA_PERSISTENT: flags2str(ainfo->ia_pflags, pflags_mask, _B_TRUE, buf, bufsize); break; case SA_ADDR: af = ifa->ifa_addr->sa_family; /* * If the address is 0.0.0.0 or :: and the origin is DHCP, * print STR_UNKNOWN_VAL. */ if (ainfo->ia_atype == IPADM_ADDR_DHCP) { sin = (struct sockaddr_in *)ifa->ifa_addr; sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; if ((af == AF_INET && sin->sin_addr.s_addr == INADDR_ANY) || (af == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) { (void) snprintf(buf, bufsize, STR_UNKNOWN_VAL); break; } } if (ifa->ifa_netmask == NULL) prefixlen = 0; else prefixlen = mask2plen(ifa->ifa_netmask); bzero(prefixlenstr, sizeof (prefixlenstr)); if (prefixlen > 0) { (void) snprintf(prefixlenstr, sizeof (prefixlenstr), "/%d", prefixlen); } bzero(addrbuf, sizeof (addrbuf)); bzero(dstbuf, sizeof (dstbuf)); if (ainfo->ia_atype == IPADM_ADDR_STATIC) { /* * Print the hostname fields if the address is not * in active configuration. */ if (ainfo->ia_state == IFA_DISABLED) { (void) snprintf(buf, bufsize, "%s", ainfo->ia_sname); if (ainfo->ia_dname[0] != '\0') { (void) snprintf(dstbuf, sizeof (dstbuf), "->%s", ainfo->ia_dname); (void) strlcat(buf, dstbuf, bufsize); } else { (void) strlcat(buf, prefixlenstr, bufsize); } break; } } /* * For the non-persistent case, we need to show the * currently configured addresses for source and * destination. */ sockaddr2str((struct sockaddr_storage *)ifa->ifa_addr, addrbuf, sizeof (addrbuf)); if (ifa->ifa_flags & IFF_POINTOPOINT) { sockaddr2str( (struct sockaddr_storage *)ifa->ifa_dstaddr, dstbuf, sizeof (dstbuf)); (void) snprintf(buf, bufsize, "%s->%s", addrbuf, dstbuf); } else { (void) snprintf(buf, bufsize, "%s%s", addrbuf, prefixlenstr); } break; default: die("invalid input"); break; } return (_B_TRUE); } /* * Display address information, either for the given address or * for all the addresses managed by ipadm. */ static void do_show_addr(int argc, char *argv[], const char *use) { ipadm_status_t status; show_addr_state_t state; char *def_fields_str = "addrobj,type,state,addr"; char *fields_str = NULL; ipadm_addr_info_t *ainfo; ipadm_addr_info_t *ptr; show_addr_args_t sargs; int option; ofmt_handle_t ofmt; ofmt_status_t oferr; uint_t ofmtflags = 0; char *aname = NULL; char *ifname = NULL; char *cp; boolean_t found = _B_FALSE; opterr = 0; state.sa_parsable = _B_FALSE; state.sa_persist = _B_FALSE; while ((option = getopt_long(argc, argv, "po:", show_addr_longopts, NULL)) != -1) { switch (option) { case 'p': state.sa_parsable = _B_TRUE; break; case 'o': fields_str = optarg; break; default: die_opterr(optopt, option, use); break; } } if (state.sa_parsable && fields_str == NULL) die("-p requires -o"); if (optind == argc - 1) { aname = argv[optind]; if ((cp = strchr(aname, '/')) == NULL) die("Invalid address object name provided"); if (*(cp + 1) == '\0') { ifname = aname; *cp = '\0'; aname = NULL; } } else if (optind == argc) { ifname = aname = NULL; } else { die("Usage: %s", use); } if (state.sa_parsable) ofmtflags |= OFMT_PARSABLE; if (fields_str == NULL) fields_str = def_fields_str; oferr = ofmt_open(fields_str, show_addr_fields, ofmtflags, 0, &ofmt); ofmt_check(oferr, state.sa_parsable, ofmt, die, warn); state.sa_ofmt = ofmt; status = ipadm_addr_info(iph, ifname, &ainfo, 0, LIFC_DEFAULT); if (status != IPADM_SUCCESS) die("Could not get address: %s", ipadm_status2str(status)); /* * There is a bit of subtlety to this. If we're here then either: * * - no address object parameter was provided, aname == ifname == NULL; * - an address object was provided and is in aname; ifname == NULL; * - an interface was provided and is in ifname; aname == NULL. * * We can just loop through the returned addresses and see if we found * anything we care about, and the only case in which we need to report * an error is if some parameter was provided - that is if `ifname` or * `aname` are not NULL. * * In fact, if we were provided with an argument of the type * `/` then we will have passed that to * ipadm_addr_info() and if no addresses were found that will have * already returned an error such as IPADM_NOTFOUND if was unable to * find any addresses matching the interface. */ bzero(&sargs, sizeof (sargs)); sargs.sa_state = &state; for (ptr = ainfo; ptr != NULL; ptr = IA_NEXT(ptr)) { sargs.sa_info = ptr; if (aname != NULL) { if (strcmp(sargs.sa_info->ia_aobjname, aname) != 0) continue; } found = _B_TRUE; ofmt_print(state.sa_ofmt, &sargs); } if (ainfo != NULL) ipadm_free_addr_info(ainfo); if ((ifname != NULL || aname != NULL) && !found) { die("Could not get address: %s", ipadm_status2str(IPADM_NOTFOUND)); } ofmt_close(ofmt); } static boolean_t print_si_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) { show_if_args_t *arg = ofarg->ofmt_cbarg; ipadm_if_info_t *ifinfo = arg->si_info; char *ifname = ifinfo->ifi_name; fmask_t intf_state[] = { { "ok", IFIS_OK, IPADM_ALL_BITS}, { "down", IFIS_DOWN, IPADM_ALL_BITS}, { "disabled", IFIS_DISABLED, IPADM_ALL_BITS}, { "failed", IFIS_FAILED, IPADM_ALL_BITS}, { "offline", IFIS_OFFLINE, IPADM_ALL_BITS}, { NULL, 0, 0 } }; fmask_t intf_pflags[] = { { "s", IFIF_STANDBY, IFIF_STANDBY }, { "4", IFIF_IPV4, IFIF_IPV4 }, { "6", IFIF_IPV6, IFIF_IPV6 }, { NULL, 0, 0 } }; fmask_t intf_cflags[] = { { "b", IFIF_BROADCAST, IFIF_BROADCAST }, { "m", IFIF_MULTICAST, IFIF_MULTICAST }, { "p", IFIF_POINTOPOINT, IFIF_POINTOPOINT}, { "v", IFIF_VIRTUAL, IFIF_VIRTUAL }, { "I", IFIF_IPMP, IFIF_IPMP }, { "s", IFIF_STANDBY, IFIF_STANDBY }, { "i", IFIF_INACTIVE, IFIF_INACTIVE }, { "V", IFIF_VRRP, IFIF_VRRP }, { "a", IFIF_NOACCEPT, IFIF_NOACCEPT }, { "Z", IFIF_L3PROTECT, IFIF_L3PROTECT }, { "4", IFIF_IPV4, IFIF_IPV4 }, { "6", IFIF_IPV6, IFIF_IPV6 }, { NULL, 0, 0 } }; fmask_t intf_class[] = { { "IP", IPADM_IF_CLASS_REGULAR, IPADM_ALL_BITS}, { "IPMP", IPADM_IF_CLASS_IPMP, IPADM_ALL_BITS}, { "VIRTUAL", IPADM_IF_CLASS_VIRTUAL, IPADM_ALL_BITS}, { "UNKNOWN", IPADM_IF_CLASS_UNKNOWN, IPADM_ALL_BITS}, { NULL, 0, 0} }; buf[0] = '\0'; switch (ofarg->ofmt_id) { case SI_IFNAME: (void) snprintf(buf, bufsize, "%s", ifname); break; case SI_IFCLASS: flags2str(ifinfo->ifi_class, intf_class, _B_FALSE, buf, bufsize); break; case SI_STATE: flags2str(ifinfo->ifi_state, intf_state, _B_FALSE, buf, bufsize); break; case SI_CURRENT: flags2str(ifinfo->ifi_cflags, intf_cflags, _B_TRUE, buf, bufsize); break; case SI_PERSISTENT: flags2str(ifinfo->ifi_pflags, intf_pflags, _B_TRUE, buf, bufsize); break; default: die("invalid input"); break; } return (_B_TRUE); } /* * Display interface information, either for the given interface or * for all the interfaces in the system. */ static void do_show_if(int argc, char *argv[], const char *use) { ipadm_status_t status; show_if_state_t state; char *fields_str = NULL; ipadm_if_info_t *if_info, *ptr; show_if_args_t sargs; int option; ofmt_handle_t ofmt; ofmt_status_t oferr; uint_t ofmtflags = 0; char *ifname = NULL; opterr = 0; state.si_parsable = _B_FALSE; while ((option = getopt_long(argc, argv, "po:", show_if_longopts, NULL)) != -1) { switch (option) { case 'p': state.si_parsable = _B_TRUE; break; case 'o': fields_str = optarg; break; default: die_opterr(optopt, option, use); break; } } if (optind == argc - 1) ifname = argv[optind]; else if (optind != argc) die("Usage: %s", use); if (state.si_parsable) ofmtflags |= OFMT_PARSABLE; oferr = ofmt_open(fields_str, show_if_fields, ofmtflags, 0, &ofmt); ofmt_check(oferr, state.si_parsable, ofmt, die, warn); state.si_ofmt = ofmt; bzero(&sargs, sizeof (sargs)); sargs.si_state = &state; status = ipadm_if_info(iph, ifname, &if_info, 0, LIFC_DEFAULT); /* * Return without printing any error, if no addresses were found. */ if (status != IPADM_SUCCESS) { die("Could not get interface(s): %s", ipadm_status2str(status)); } for (ptr = if_info; ptr != NULL; ptr = ptr->ifi_next) { sargs.si_info = ptr; ofmt_print(state.si_ofmt, &sargs); } if (if_info) ipadm_free_if_info(if_info); } /* * set/reset the address property for a given address */ static void set_addrprop(int argc, char **argv, boolean_t reset, const char *use) { int option; ipadm_status_t status = IPADM_SUCCESS; boolean_t p_arg = _B_FALSE; char *nv, *aobjname; char *prop_name, *prop_val; uint_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST; nv = NULL; opterr = 0; while ((option = getopt_long(argc, argv, ":i:p:t", set_ifprop_longopts, NULL)) != -1) { switch (option) { case 'p': if (p_arg) die("-p must be specified once only"); p_arg = _B_TRUE; ipadm_check_propstr(optarg, reset, use); nv = optarg; break; case 't': flags &= ~IPADM_OPT_PERSIST; break; default: die_opterr(optopt, option, use); } } if (!p_arg || optind != (argc - 1)) die("Usage: %s", use); prop_name = nv; prop_val = strchr(nv, '='); if (prop_val != NULL) *prop_val++ = '\0'; aobjname = argv[optind]; if (reset) flags |= IPADM_OPT_DEFAULT; status = ipadm_set_addrprop(iph, prop_name, prop_val, aobjname, flags); if (status != IPADM_SUCCESS) { if (reset) die("reset-addrprop: %s: %s", prop_name, ipadm_status2str(status)); else die("set-addrprop: %s: %s", prop_name, ipadm_status2str(status)); } } /* * Sets a property on an address object. */ static void do_set_addrprop(int argc, char **argv, const char *use) { set_addrprop(argc, argv, _B_FALSE, use); } /* * Resets a property to its default value on an address object. */ static void do_reset_addrprop(int argc, char **argv, const char *use) { set_addrprop(argc, argv, _B_TRUE, use); } /* * Display information for all or specific address properties, either for a * given address or for all the addresses in the system. */ static void do_show_addrprop(int argc, char *argv[], const char *use) { int option; nvlist_t *proplist = NULL; char *fields_str = NULL; show_prop_state_t state; ofmt_handle_t ofmt; ofmt_status_t oferr; uint_t ofmtflags = 0; char *aobjname = NULL; char *ifname = NULL; char *cp; ipadm_addr_info_t *ainfop = NULL; ipadm_addr_info_t *ptr; ipadm_status_t status; boolean_t found = _B_FALSE; opterr = 0; bzero(&state, sizeof (state)); state.sps_propval = NULL; state.sps_parsable = _B_FALSE; state.sps_addrprop = _B_TRUE; state.sps_proto = MOD_PROTO_NONE; state.sps_status = state.sps_retstatus = IPADM_SUCCESS; while ((option = getopt_long(argc, argv, ":p:i:cPo:", show_prop_longopts, NULL)) != -1) { switch (option) { case 'p': if (ipadm_str2nvlist(optarg, &proplist, IPADM_NORVAL) != 0) die("invalid addrobj properties specified"); break; case 'c': state.sps_parsable = _B_TRUE; break; case 'o': fields_str = optarg; break; default: die_opterr(optopt, option, use); break; } } if (optind == argc - 1) { aobjname = argv[optind]; cp = strchr(aobjname, '/'); if (cp == NULL) die("invalid addrobj name provided"); if (*(cp + 1) == '\0') { ifname = aobjname; *cp = '\0'; aobjname = NULL; } } else if (optind != argc) { die("Usage: %s", use); } state.sps_proplist = proplist; if (state.sps_parsable) ofmtflags |= OFMT_PARSABLE; oferr = ofmt_open(fields_str, addrprop_fields, ofmtflags, 0, &ofmt); ofmt_check(oferr, state.sps_parsable, ofmt, die, warn); state.sps_ofmt = ofmt; status = ipadm_addr_info(iph, ifname, &ainfop, 0, LIFC_DEFAULT); /* Return without printing any error, if no addresses were found */ if (status == IPADM_NOTFOUND) return; if (status != IPADM_SUCCESS) die("error retrieving address: %s", ipadm_status2str(status)); for (ptr = ainfop; ptr != NULL; ptr = IA_NEXT(ptr)) { char *taobjname = ptr->ia_aobjname; if (taobjname[0] == '\0') continue; if (aobjname != NULL) { if (strcmp(aobjname, taobjname) == 0) found = _B_TRUE; else continue; } if (ptr->ia_atype == IPADM_ADDR_IPV6_ADDRCONF) { if (found) break; else continue; } (void) strlcpy(state.sps_aobjname, taobjname, sizeof (state.sps_aobjname)); show_properties(&state, IPADMPROP_CLASS_ADDR); if (found) break; } ipadm_free_addr_info(ainfop); if (aobjname != NULL && !found) die("addrobj not found: %s", aobjname); nvlist_free(proplist); ofmt_close(ofmt); if (state.sps_retstatus != IPADM_SUCCESS) { ipadm_close(iph); exit(EXIT_FAILURE); } } /* * check if the `pstr' adheres to following syntax * - prop= (for set) * - prop (for reset) */ static void ipadm_check_propstr(const char *pstr, boolean_t reset, const char *use) { char *nv; nv = strchr(pstr, '='); if (reset) { if (nv != NULL) die("incorrect syntax used for -p.\n%s", use); } else { if (nv == NULL || *++nv == '\0') die("please specify the value to be set.\n%s", use); nv = strchr(nv, '='); /* cannot have multiple 'prop=val' for single -p */ if (nv != NULL) die("cannot specify more than one prop=val at " "a time.\n%s", use); } } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # msgid "" msgid "\n" msgid "%s" msgid "%s\n" msgid "%s%s" msgid "%s->%s" msgid "%s/%s" msgid "%s: " msgid "'%s'" msgid "+-" msgid "," msgid "-" msgid "->%s" msgid "/%d" msgid "4" msgid "6" msgid ":T:a:di:p:w:t" msgid ":i" msgid ":i:p:t" msgid ":m:p:t" msgid ":p:co:" msgid ":p:i:cPo:" msgid ":p:m:co:" msgid ":p:t" msgid ":r" msgid ":t" msgid "ADDR" msgid "ADDROBJ" msgid "CURRENT" msgid "DEFAULT" msgid "I" msgid "IFNAME" msgid "PERM" msgid "PERSISTENT" msgid "POSSIBLE" msgid "PROPERTY" msgid "PROTO" msgid "STATE" msgid "TYPE" msgid "U" msgid "V" msgid "a" msgid "addrconf" msgid "address" msgid "addrobj,type,state,addr" msgid "b" msgid "create-addr" msgid "create-if" msgid "d" msgid "delete-addr" msgid "delete-if" msgid "dhcp" msgid "disable-addr" msgid "disable-if" msgid "disabled" msgid "down" msgid "down-addr" msgid "duplicate" msgid "enable-addr" msgid "enable-if" msgid "failed" msgid "forever" msgid "i" msgid "inaccessible" msgid "inform" msgid "init-if" msgid "init-prop" msgid "interface-id" msgid "ip" msgid "local" msgid "m" msgid "module" msgid "no" msgid "offline" msgid "ok" msgid "output" msgid "p" msgid "parsable" msgid "po:" msgid "prop" msgid "refresh-addr" msgid "release" msgid "remote" msgid "reset-addrprop" msgid "reset-addrprop: %s: %s" msgid "reset-ifprop" msgid "reset-ifprop: %s: %s" msgid "reset-prop" msgid "reset-prop: %s: %s" msgid "s" msgid "set-addrprop" msgid "set-addrprop: %s: %s" msgid "set-ifprop" msgid "set-ifprop: %s: %s" msgid "set-prop" msgid "set-prop: %s: %s" msgid "show-addr" msgid "show-addrprop" msgid "show-if" msgid "show-ifprop" msgid "show-prop" msgid "stateful" msgid "stateless" msgid "static" msgid "t" msgid "temporary" msgid "tentative" msgid "type" msgid "u" msgid "up-addr" msgid "v" msgid "wait" msgid "yes"