diff options
Diffstat (limited to 'usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c')
| -rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c | 333 |
1 files changed, 279 insertions, 54 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c index e48b32733f..1a1aa5e5ac 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c @@ -21,11 +21,10 @@ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. * Copyright (c) 2018, Joyent, Inc. * Copyright 2017 Gary Mills * Copyright (c) 2016, Chris Fraire <cfraire@me.com>. - * Copyright 2021, Tintri by DDN. All rights reserved. + * Copyright 2021 Tintri by DDN, Inc. All rights reserved. * Copyright 2021 OmniOS Community Edition (OmniOSce) Association. */ @@ -40,6 +39,8 @@ #include <libdllink.h> #include <libinetutil.h> #include <libipadm.h> +#include <ipmp.h> +#include <ipmp_admin.h> #include <locale.h> #include <netdb.h> #include <netinet/in.h> @@ -53,21 +54,25 @@ #include <sys/stat.h> #include <sys/types.h> #include <zone.h> +#include <sys/list.h> +#include <stddef.h> #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_if, do_delete_if, do_enable_if, do_disable_if; -static cmdfunc_t do_show_if; -static cmdfunc_t do_set_prop, do_show_prop, do_set_ifprop; -static cmdfunc_t do_show_ifprop, do_reset_ifprop, do_reset_prop; -static cmdfunc_t do_show_addrprop, do_set_addrprop, do_reset_addrprop; -static cmdfunc_t do_create_addr, do_delete_addr, do_show_addr; -static cmdfunc_t do_enable_addr, do_disable_addr; -static cmdfunc_t do_up_addr, do_down_addr, do_refresh_addr; +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; @@ -78,12 +83,28 @@ typedef struct cmd { static cmd_t cmds[] = { { "help", do_help, NULL }, /* interface management related sub-commands */ - { "create-if", do_create_if, "\tcreate-if\t[-t] <interface>" }, - { "disable-if", do_disable_if, "\tdisable-if\t-t <interface>" }, - { "enable-if", do_enable_if, "\tenable-if\t-t <interface>" }, - { "delete-if", do_delete_if, "\tdelete-if\t<interface>" }, - { "show-if", do_show_if, + { "create-if", do_create_ip, "\tcreate-if\t[-t] <interface>" }, + { "create-ip", do_create_ip, "\tcreate-ip\t[-t] <interface>" }, + { "delete-if", do_delete_ip, "\tdelete-if\t<interface>\n" }, + { "delete-ip", do_delete_ip, "\tdelete-ip\t<interface>\n" }, + + { "create-ipmp", do_create_ipmp, + "\tcreate-ipmp\t[-t] [-i <interface>[,<interface>]...] " + "<ipmp-interface>" }, + { "delete-ipmp", do_delete_ip, + "\tdelete-ipmp\t<ipmp-interface>" }, + { "add-ipmp", do_add_ipmp, + "\tadd-ipmp\t[-t] -i <interface>[,<interface>]... " + "<ipmp-interface>" }, + { "remove-ipmp", do_remove_ipmp, + "\tremove-ipmp\t[-t] -i <interface>[,<interface>]... " + "<ipmp-interface>\n" }, + + { "disable-if", do_disable_if, "\tdisable-if\t-t <interface>" }, + { "enable-if", do_enable_if, "\tenable-if\t-t <interface>" }, + { "show-if", do_show_if, "\tshow-if\t\t[[-p] -o <field>,...] [<interface>]\n" }, + { "set-ifprop", do_set_ifprop, "\tset-ifprop\t[-t] -p <prop>=<value[,...]> -m <protocol> " "<interface>" }, @@ -101,14 +122,15 @@ static cmd_t cmds[] = { "\t\t\t[-1] [-h <hostname>] <addrobj>\n" "\tcreate-addr\t[-t] -T addrconf [-i interface-id]\n" "\t\t\t[-p {stateful|stateless}={yes|no}] <addrobj>" }, - { "down-addr", do_down_addr, "\tdown-addr\t[-t] <addrobj>" }, - { "up-addr", do_up_addr, "\tup-addr\t\t[-t] <addrobj>" }, - { "disable-addr", do_disable_addr, "\tdisable-addr\t-t <addrobj>" }, - { "enable-addr", do_enable_addr, "\tenable-addr\t-t <addrobj>" }, - { "refresh-addr", do_refresh_addr, "\trefresh-addr\t[-i] <addrobj>" }, { "delete-addr", do_delete_addr, "\tdelete-addr\t[-r] <addrobj>" }, - { "show-addr", do_show_addr, - "\tshow-addr\t[[-p] -o <field>,...] [<addrobj>]\n" }, + { "show-addr", do_show_addr, + "\tshow-addr\t[[-p] -o <field>,...] [<addrobj>]" }, + { "refresh-addr", do_refresh_addr, "\trefresh-addr\t[-i] <addrobj>" }, + { "down-addr", do_down_addr, "\tdown-addr\t[-t] <addrobj>" }, + { "up-addr", do_up_addr, "\tup-addr\t\t[-t] <addrobj>" }, + { "disable-addr", do_disable_addr, "\tdisable-addr\t-t <addrobj>" }, + { "enable-addr", do_enable_addr, "\tenable-addr\t-t <addrobj>\n" }, + { "set-addrprop", do_set_addrprop, "\tset-addrprop\t[-t] -p <prop>=<value[,...]> <addrobj>" }, { "reset-addrprop", do_reset_addrprop, @@ -118,11 +140,11 @@ static cmd_t cmds[] = { "<addrobj>\n" }, /* protocol properties related sub-commands */ - { "set-prop", do_set_prop, + { "set-prop", do_set_prop, "\tset-prop\t[-t] -p <prop>[+|-]=<value[,...]> <protocol>" }, - { "reset-prop", do_reset_prop, + { "reset-prop", do_reset_prop, "\treset-prop\t[-t] -p <prop> <protocol>" }, - { "show-prop", do_show_prop, + { "show-prop", do_show_prop, "\tshow-prop\t[[-c] -o <field>,...] [-p <prop>,...]" " [protocol]" } }; @@ -282,7 +304,7 @@ typedef struct show_addr_args_s { typedef struct show_if_args_s { show_if_state_t *si_state; - ipadm_if_info_list_t *si_info; + ipadm_if_info_t *si_info; } show_if_args_t; typedef enum { @@ -296,6 +318,7 @@ typedef enum { typedef enum { SI_IFNAME, + SI_IFCLASS, SI_STATE, SI_CURRENT, SI_PERSISTENT @@ -315,6 +338,7 @@ static ofmt_field_t show_addr_fields[] = { 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}, @@ -328,6 +352,11 @@ typedef struct intf_mask { 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. @@ -349,6 +378,9 @@ 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) @@ -419,19 +451,17 @@ main(int argc, char *argv[]) } /* - * Create an IP interface for which no saved configuration exists in the - * persistent store. + * Create regular IP interface or IPMP group interface */ static void -do_create_if(int argc, char *argv[], const char *use) +do_create_ip_common(int argc, char *argv[], const char *use, uint32_t flags) { ipadm_status_t status; int option; - uint32_t flags = IPADM_OPT_PERSIST|IPADM_OPT_ACTIVE; opterr = 0; - while ((option = getopt_long(argc, argv, ":t", if_longopts, - NULL)) != -1) { + while ((option = getopt_long(argc, argv, + ":t", if_longopts, NULL)) != -1) { switch (option) { case 't': /* @@ -444,8 +474,12 @@ do_create_if(int argc, char *argv[], const char *use) die_opterr(optopt, option, use); } } - if (optind != (argc - 1)) - die("Usage: %s", 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", @@ -454,6 +488,185 @@ do_create_if(int argc, char *argv[], const char *use) } /* + * 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. */ @@ -480,7 +693,7 @@ do_enable_if(int argc, char *argv[], const char *use) * Remove an IP interface from both active and persistent configuration. */ static void -do_delete_if(int argc, char *argv[], const char *use) +do_delete_ip(int argc, char *argv[], const char *use) { ipadm_status_t status; uint32_t flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST; @@ -687,7 +900,7 @@ do_show_ifprop(int argc, char **argv, const char *use) uint_t proto; boolean_t m_arg = _B_FALSE; char *protostr; - ipadm_if_info_list_t *ifinfo, *ifl; + ipadm_if_info_t *ifinfo, *ifp; ipadm_status_t status; show_prop_state_t state; @@ -751,9 +964,8 @@ do_show_ifprop(int argc, char **argv, const char *use) if (status != IPADM_SUCCESS) die("Error retrieving interface(s): %s", ipadm_status2str(status)); - for (ifl = ifinfo; ifl != NULL; ifl = ifl->ifil_next) { - (void) strlcpy(state.sps_ifname, ifl->ifil_ifi.ifi_name, - LIFNAMSIZ); + 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); } @@ -1057,14 +1269,16 @@ die(const char *format, ...) { va_list alist; - format = gettext(format); - (void) fprintf(stderr, "%s: ", progname); + if (format != NULL) { + format = gettext(format); + (void) fprintf(stderr, "%s: ", progname); - va_start(alist, format); - (void) vfprintf(stderr, format, alist); - va_end(alist); + va_start(alist, format); + (void) vfprintf(stderr, format, alist); + va_end(alist); - (void) putchar('\n'); + (void) putchar('\n'); + } ipadm_destroy_addrobj(ipaddr); ipadm_close(iph); @@ -1624,7 +1838,7 @@ flags2str(uint64_t flags, fmask_t *tbl, boolean_t is_bits, static boolean_t is_from_gz(const char *lifname) { - ipadm_if_info_list_t *if_info; + ipadm_if_info_t *if_info; char phyname[LIFNAMSIZ], *cp; boolean_t ret = _B_FALSE; ipadm_status_t status; @@ -1647,7 +1861,7 @@ is_from_gz(const char *lifname) if (status != IPADM_SUCCESS) return (ret); - if (if_info->ifil_ifi.ifi_cflags & IFIF_L3PROTECT) + if (if_info->ifi_cflags & IFIF_L3PROTECT) ret = _B_TRUE; ipadm_free_if_info(if_info); return (ret); @@ -1902,8 +2116,8 @@ 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_list_t *ifinfo = arg->si_info; - char *ifname = ifinfo->ifil_ifi.ifi_name; + 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}, @@ -1933,22 +2147,33 @@ print_si_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) { "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->ifil_ifi.ifi_state, intf_state, _B_FALSE, + flags2str(ifinfo->ifi_state, intf_state, _B_FALSE, buf, bufsize); break; case SI_CURRENT: - flags2str(ifinfo->ifil_ifi.ifi_cflags, intf_cflags, _B_TRUE, + flags2str(ifinfo->ifi_cflags, intf_cflags, _B_TRUE, buf, bufsize); break; case SI_PERSISTENT: - flags2str(ifinfo->ifil_ifi.ifi_pflags, intf_pflags, _B_TRUE, + flags2str(ifinfo->ifi_pflags, intf_pflags, _B_TRUE, buf, bufsize); break; default: @@ -1969,7 +2194,7 @@ 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_list_t *if_info, *ptr; + ipadm_if_info_t *if_info, *ptr; show_if_args_t sargs; int option; ofmt_handle_t ofmt; @@ -2014,7 +2239,7 @@ do_show_if(int argc, char *argv[], const char *use) ipadm_status2str(status)); } - for (ptr = if_info; ptr != NULL; ptr = ptr->ifil_next) { + for (ptr = if_info; ptr != NULL; ptr = ptr->ifi_next) { sargs.si_info = ptr; ofmt_print(state.si_ofmt, &sargs); } |
