Mercurial > illumos > illumos-gate
diff usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c @ 12016:0248e987199b
PSARC 2009/306 Brussels II - ipadm and libipadm
PSARC 2010/080 Brussels II addendum
6827318 Brussels Phase II aka ipadm(1m)
6731945 need BSD getifaddrs() API
6909065 explicitly disallow non-contiguous netmasks in the next minor release
6853922 ifconfig dumps core when ether address is non-hexadecimal.
6815806 ipReasmTimeout value should be variable
6567083 nd_getset has some dead and confusing code.
6884466 remove unused tcp/sctp ndd tunables
6928813 Comments at odds with default value of tcp_time_wait_interval
6236982 ifconfig usesrc lets adapter use itself as source address
6936855 modifying the ip6_strict_src_multihoming to non-zero value will unbind V4 IREs
author | Girish Moodalbail <Girish.Moodalbail@Sun.COM> |
---|---|
date | Fri, 26 Mar 2010 17:53:11 -0400 |
parents | b7ebfbf2359e |
children | 162e93ccf12f |
line wrap: on
line diff
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c Fri Mar 26 14:31:08 2010 -0700 +++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c Fri Mar 26 17:53:11 2010 -0400 @@ -1,5 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* @@ -18,11 +18,15 @@ #include <libdllink.h> #include <inet/ip.h> #include <inet/ipsec_impl.h> +#include <libipadm.h> +#include <ifaddrs.h> +#include <libsocket_priv.h> #define LOOPBACK_IF "lo0" #define NONE_STR "none" #define ARP_MOD_NAME "arp" -#define IPMPSTUB (void *)-1 +#define LIFC_DEFAULT (LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES |\ + LIFC_UNDER_IPMP) typedef struct if_flags { uint64_t iff_value; @@ -93,8 +97,11 @@ /* foreach interface saved name */ static char origname[LIFNAMSIZ]; static int setaddr; +static boolean_t setaddr_done = _B_FALSE; static boolean_t ipsec_policy_set; static boolean_t ipsec_auth_covered; +static ipadm_handle_t iph; +static ipadm_addrobj_t ipaddr; /* * Make sure the algorithm variables hold more than the sizeof an algorithm @@ -149,7 +156,7 @@ static int configinfo(char *arg, int64_t param); static void print_config_flags(int af, uint64_t flags); static void print_flags(uint64_t flags); -static void print_ifether(char *ifname); +static void print_ifether(const char *ifname); static int set_tun_encap_limit(char *arg, int64_t param); static int clr_tun_encap_limit(char *arg, int64_t param); static int set_tun_hop_limit(char *arg, int64_t param); @@ -157,6 +164,7 @@ static int setallzones(char *arg, int64_t param); static int setifsrc(char *arg, int64_t param); static int lifnum(const char *ifname); +static void plumball(int, char **, int64_t, int64_t, int64_t); /* * Address family specific function prototypes. @@ -172,36 +180,37 @@ * Misc support functions */ static boolean_t ni_entry(const char *, void *); -static void foreachinterface(void (*func)(), int argc, char *argv[], - int af, int64_t onflags, int64_t offflags, - int64_t lifc_flags); -static void ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp); +static void foreachinterface(int argc, char *argv[], + int af, int64_t onflags, int64_t offflags, + int64_t lifc_flags); +static void ifconfig(int argc, char *argv[], int af, + struct ifaddrs *ifa); static boolean_t in_getmask(struct sockaddr_in *saddr, boolean_t addr_set); -static int in_getprefixlen(char *addr, boolean_t slash, int plen); +static int in_getprefixlen(char *addr, boolean_t slash, int plen); static boolean_t in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask); -static void status(void); -static void ifstatus(const char *); -static void tun_status(datalink_id_t); -static void usage(void); -static int strioctl(int s, int cmd, void *buf, int buflen); -static int setifdhcp(const char *caller, const char *ifname, - int argc, char *argv[]); -static int ip_domux2fd(int *, int *, int *, int *, int *); -static int ip_plink(int, int, int, int, int); -static int modop(char *arg, char op); -static int find_all_interfaces(struct lifconf *lifcp, char **buf, - int64_t lifc_flags); -static int create_ipmp(const char *grname, int af, const char *ifname, - boolean_t implicit); -static int create_ipmp_peer(int af, const char *ifname); -static void start_ipmp_daemon(void); -static boolean_t ifaddr_up(ifaddrlistx_t *ifaddrp); -static boolean_t ifaddr_down(ifaddrlistx_t *ifaddrp); +static void status(void); +static void ifstatus(const char *ifname); +static void tun_status(datalink_id_t); +static void usage(void); +static int setifdhcp(const char *caller, const char *ifname, + int argc, char *argv[]); +static int ip_domux2fd(int *, int *, int *, int *, int *); +static int ip_plink(int, int, int, int, int); +static int modop(char *arg, char op); +static int find_all_interfaces(struct lifconf *lifcp, char **buf, + int64_t lifc_flags); +static int create_ipmp(const char *grname, int af, + const char *ifname, boolean_t implicit); +static void start_ipmp_daemon(void); +static boolean_t ifaddr_up(ifaddrlistx_t *ifaddrp); +static boolean_t ifaddr_down(ifaddrlistx_t *ifaddrp); static dladm_status_t ifconfig_dladm_open(const char *, datalink_class_t, - datalink_id_t *); -static void dladmerr_exit(dladm_status_t status, const char *str); + datalink_id_t *); +static void dladmerr_exit(dladm_status_t status, const char *str); +static void ipadmerr_exit(ipadm_status_t status, const char *str); +static boolean_t ifconfig_use_libipadm(int, const char *); #define max(a, b) ((a) < (b) ? (b) : (a)) @@ -366,8 +375,9 @@ { int64_t lifc_flags; char *default_ip_str; - - lifc_flags = LIFC_NOXMIT|LIFC_TEMPORARY|LIFC_ALLZONES|LIFC_UNDER_IPMP; + ipadm_status_t istatus; + + lifc_flags = LIFC_DEFAULT; if (argc < 2) { usage(); @@ -412,6 +422,13 @@ s6 = socket(AF_INET6, SOCK_DGRAM, 0); if (s == -1 || s4 == -1 || s6 == -1) Perror0_exit("socket"); + /* + * Open the global libipadm handle. The flag IPH_LEGACY has to + * be specified to indicate that logical interface names will + * be used during interface creation and address creation. + */ + if ((istatus = ipadm_open(&iph, IPH_LEGACY)) != IPADM_SUCCESS) + ipadmerr_exit(istatus, "unable to open handle to libipadm"); /* * Special interface names is any combination of these flags. @@ -484,157 +501,89 @@ "ifconfig: %s: no such interface\n", name); exit(1); } - foreachinterface(ifconfig, argc, argv, af, onflags, offflags, + foreachinterface(argc, argv, af, onflags, offflags, lifc_flags); } else { - ifconfig(argc, argv, af, (struct lifreq *)NULL); + ifconfig(argc, argv, af, NULL); } + ipadm_close(iph); return (0); } /* - * For each interface, call (*func)(argc, argv, af, lifrp). + * For each interface, call ifconfig(argc, argv, af, ifa). * Only call function if onflags and offflags are set or clear, respectively, * in the interfaces flags field. */ static void -foreachinterface(void (*func)(), int argc, char *argv[], int af, +foreachinterface(int argc, char *argv[], int af, int64_t onflags, int64_t offflags, int64_t lifc_flags) { - int n; - char *buf; - struct lifnum lifn; - struct lifconf lifc; - struct lifreq *lifrp; - struct lifreq lifrl; /* Local lifreq struct */ - int numifs; - unsigned bufsize; - int plumball = 0; - int save_af = af; - - buf = NULL; + ipadm_addr_info_t *ainfo, *ainfop; + struct ifaddrs *ifa; + ipadm_status_t istatus; + /* * Special case: * ifconfig -a plumb should find all network interfaces in the current * zone. */ if (argc > 0 && (strcmp(*argv, "plumb") == 0)) { - if (find_all_interfaces(&lifc, &buf, lifc_flags) != 0 || - lifc.lifc_len == 0) - return; - plumball = 1; - } else { - lifn.lifn_family = AF_UNSPEC; - lifn.lifn_flags = lifc_flags; - if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) { - Perror0_exit("Could not determine number" - " of interfaces"); + plumball(argc, argv, onflags, offflags, lifc_flags); + return; + } + /* Get all addresses in kernel including addresses that are zero. */ + istatus = ipadm_addr_info(iph, NULL, &ainfo, IPADM_OPT_ZEROADDR, + lifc_flags); + if (istatus != IPADM_SUCCESS) + ipadmerr_exit(istatus, "could not get addresses from kernel"); + + /* + * For each logical interface, call ifconfig() with the + * given arguments. + */ + for (ainfop = ainfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) { + if (ainfop->ia_state == IFA_DISABLED) + continue; + ifa = &ainfop->ia_ifa; + if (onflags || offflags) { + if ((ifa->ifa_flags & onflags) != onflags) + continue; + if ((~ifa->ifa_flags & offflags) != offflags) + continue; } - numifs = lifn.lifn_count; - if (debug) - (void) printf("ifconfig: %d interfaces\n", numifs); - - bufsize = numifs * sizeof (struct lifreq); - if ((buf = malloc(bufsize)) == NULL) { - Perror0("out of memory\n"); - (void) close(s); - return; - } - - lifc.lifc_family = AF_UNSPEC; - lifc.lifc_flags = lifc_flags; - lifc.lifc_len = bufsize; - lifc.lifc_buf = buf; - - if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) { - Perror0("SIOCGLIFCONF"); - (void) close(s); - free(buf); - return; - } + s = (ifa->ifa_addr->ss_family == AF_INET ? s4 : s6); + (void) strncpy(name, ifa->ifa_name, sizeof (name)); + (void) strncpy(origname, name, sizeof (origname)); + ifconfig(argc, argv, af, ifa); } + ipadm_free_addr_info(ainfo); +} + +/* + * Used for `ifconfig -a plumb'. Finds all datalinks and plumbs the interface. + */ +static void +plumball(int argc, char *argv[], int64_t onflags, int64_t offflags, + int64_t lifc_flags) +{ + int n; + struct lifreq *lifrp; + struct lifconf lifc; + char *buf; + + if (onflags != 0 || offflags != 0) { + (void) fprintf(stderr, "ifconfig: invalid syntax used to " + "plumb all interfaces.\n"); + exit(1); + } + + if (find_all_interfaces(&lifc, &buf, lifc_flags) != 0 || + lifc.lifc_len == 0) + return; lifrp = lifc.lifc_req; for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) { - - if (!plumball) { - /* - * We must close and recreate the socket each time - * since we don't know what type of socket it is now - * (each status function may change it). - */ - - (void) close(s); - - af = lifrp->lifr_addr.ss_family; - s = socket(SOCKET_AF(af), SOCK_DGRAM, 0); - if (s == -1) { - /* - * Perror0() assumes the name to be in the - * globally defined lifreq structure. - */ - (void) strncpy(lifr.lifr_name, - lifrp->lifr_name, sizeof (lifr.lifr_name)); - Perror0_exit("socket"); - } - } - - /* - * Only service interfaces that match the on and off - * flags masks. - */ - if (onflags || offflags) { - (void) memset(&lifrl, 0, sizeof (lifrl)); - (void) strncpy(lifrl.lifr_name, lifrp->lifr_name, - sizeof (lifrl.lifr_name)); - if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) { - /* - * Perror0() assumes the name to be in the - * globally defined lifreq structure. - */ - (void) strncpy(lifr.lifr_name, - lifrp->lifr_name, sizeof (lifr.lifr_name)); - Perror0_exit("foreachinterface: SIOCGLIFFLAGS"); - } - if ((lifrl.lifr_flags & onflags) != onflags) - continue; - if ((~lifrl.lifr_flags & offflags) != offflags) - continue; - } - - if (!plumball) { - (void) strncpy(lifrl.lifr_name, lifrp->lifr_name, - sizeof (lifrl.lifr_name)); - if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifrl) < 0) { - /* - * Perror0() assumes the name to be in the - * globally defined lifreq structure. - */ - (void) strncpy(lifr.lifr_name, - lifrp->lifr_name, sizeof (lifr.lifr_name)); - Perror0("foreachinterface: SIOCGLIFADDR"); - continue; - } - if (lifrl.lifr_addr.ss_family != af) { - /* Switch address family */ - af = lifrl.lifr_addr.ss_family; - (void) close(s); - - s = socket(SOCKET_AF(af), SOCK_DGRAM, 0); - if (s == -1) { - /* - * Perror0() assumes the name to be in - * the globally defined lifreq - * structure. - */ - (void) strncpy(lifr.lifr_name, - lifrp->lifr_name, - sizeof (lifr.lifr_name)); - Perror0_exit("socket"); - } - } - } - /* * Reset global state * setaddr: Used by parser to tear apart source and dest @@ -644,24 +593,23 @@ setaddr = 0; (void) strncpy(name, lifrp->lifr_name, sizeof (name)); (void) strncpy(origname, name, sizeof (origname)); - - (*func)(argc, argv, save_af, lifrp); - /* the func could have overwritten origname, so restore */ - (void) strncpy(name, origname, sizeof (name)); + ifconfig(argc, argv, af, NULL); } - if (buf != NULL) - free(buf); } /* - * for the specified interface call (*func)(argc, argv, af, lifrp). + * Parses the interface name and the command in argv[]. Calls the + * appropriate callback function for the given command from `cmds[]' + * table. + * If there is no command specified, it prints all addresses. */ - static void -ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp) +ifconfig(int argc, char *argv[], int af, struct ifaddrs *ifa) { static boolean_t scan_netmask = _B_FALSE; int ret; + ipadm_status_t istatus; + struct lifreq lifr; if (argc == 0) { status(); @@ -782,8 +730,52 @@ * else (no keyword found), we assume it's an address * of some sort */ - if (p->c_name == 0 && setaddr) - p++; /* got src, do dst */ + if (setaddr && ipaddr != NULL) { + /* + * We must have already filled in a source address in + * `ipaddr' and we now got a destination address. + * Fill it in `ipaddr' and call libipadm to create + * the static address. + */ + if (p->c_name == 0) { + istatus = ipadm_set_dst_addr(ipaddr, *argv, + (p->c_af == AF_ANY ? AF_UNSPEC : af)); + if (istatus != IPADM_SUCCESS) { + ipadmerr_exit(istatus, "could not " + "set destination address"); + } + /* + * finished processing dstaddr, so reset setaddr + */ + setaddr = 0; + } + /* + * Both source and destination address are in `ipaddr'. + * Add the address by calling libipadm. + */ + istatus = ipadm_create_addr(iph, ipaddr, + IPADM_OPT_ACTIVE); + if (istatus != IPADM_SUCCESS) + goto createfailed; + ipadm_destroy_addrobj(ipaddr); + ipaddr = NULL; + setaddr_done = _B_TRUE; + if (p->c_name == 0) { + /* move parser along */ + argc--, argv++; + continue; + } + } + if (p->c_name == 0 && setaddr_done) { + /* + * catch odd commands like + * "ifconfig <intf> addr1 addr2 addr3 addr4 up" + */ + (void) fprintf(stderr, "%s", + "ifconfig: cannot configure more than two " + "addresses in one command\n"); + exit(1); + } if (p->c_func) { if (p->c_af == AF_INET6) { v4compat = 0; @@ -812,8 +804,8 @@ * the address families match */ if ((p->c_af == AF_ANY) || - (lifrp == (struct lifreq *)NULL) || - (lifrp->lifr_addr.ss_family == p->c_af)) { + (ifa == NULL) || + (ifa->ifa_addr->ss_family == p->c_af)) { ret = (*p->c_func)(*argv, p->c_parameter); /* * If c_func failed and we should @@ -830,11 +822,36 @@ argc--, argv++; } + if (setaddr && ipaddr != NULL) { + /* + * Only the source address was provided, which was already + * set in `ipaddr'. Add the address by calling libipadm. + */ + istatus = ipadm_create_addr(iph, ipaddr, IPADM_OPT_ACTIVE); + if (istatus != IPADM_SUCCESS) + goto createfailed; + ipadm_destroy_addrobj(ipaddr); + ipaddr = NULL; + setaddr_done = _B_TRUE; + } + /* Check to see if there's a security hole in the tunnel setup. */ if (ipsec_policy_set && !ipsec_auth_covered) { (void) fprintf(stderr, "ifconfig: WARNING: tunnel with only " "ESP and no authentication.\n"); } + return; + +createfailed: + (void) fprintf(stderr, "ifconfig: could not create address:% s\n", + ipadm_status2str(istatus)); + /* Remove the newly created logical interface. */ + if (strcmp(name, origname) != 0) { + assert(strchr(name, ':') != NULL); + (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); + (void) ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr); + } + exit(1); } /* ARGSUSED */ @@ -902,12 +919,15 @@ static int setifaddr(char *addr, int64_t param) { + ipadm_status_t istatus; int prefixlen = 0; + struct lifreq lifr1; struct sockaddr_storage laddr; struct sockaddr_storage netmask; struct sockaddr_in6 *sin6; struct sockaddr_in *sin; struct sockaddr_storage sav_netmask; + char cidraddr[BUFSIZ]; if (addr[0] == '/') return (setifprefixlen(addr, 0)); @@ -951,13 +971,53 @@ g_netmask_set = G_NETMASK_NIL; break; } + + /* + * Check and see if any "netmask" command is used and perform the + * necessary operation. + */ + set_mask_lifreq(&lifr, &laddr, &netmask); + + /* This check is temporary until libipadm supports IPMP interfaces. */ + if (ifconfig_use_libipadm(s, name)) { + istatus = ipadm_create_addrobj(IPADM_ADDR_STATIC, name, + &ipaddr); + if (istatus != IPADM_SUCCESS) + ipadmerr_exit(istatus, "setifaddr"); + + if (strchr(addr, '/') == NULL) { + /* + * lifr.lifr_addr, which is updated by set_mask_lifreq() + * will contain the right mask to use. + */ + prefixlen = mask2plen(&lifr.lifr_addr); + (void) snprintf(cidraddr, sizeof (cidraddr), "%s/%d", + addr, prefixlen); + addr = cidraddr; + } + istatus = ipadm_set_addr(ipaddr, addr, af); + if (istatus != IPADM_SUCCESS) + ipadmerr_exit(istatus, "could not set address"); + /* + * let parser know we got a source. + * Next address, if given, should be dest + */ + setaddr++; + + /* + * address will be set by the parser after nextarg has + * been scanned + */ + return (0); + } + /* Tell parser that an address was set */ setaddr++; /* save copy of netmask to restore in case of error */ - (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); - if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) + (void) strncpy(lifr1.lifr_name, name, sizeof (lifr1.lifr_name)); + if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr1) < 0) Perror0_exit("SIOCGLIFNETMASK"); - sav_netmask = lifr.lifr_addr; + sav_netmask = lifr1.lifr_addr; /* * If setting the address and not the mask, clear any existing mask @@ -966,7 +1026,8 @@ * using the netmask command), set the mask first, so the address will * be interpreted correctly. */ - set_mask_lifreq(&lifr, &laddr, &netmask); + (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); + /* lifr.lifr_addr already contains netmask from set_mask_lifreq() */ if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) Perror0_exit("SIOCSLIFNETMASK"); @@ -1567,7 +1628,7 @@ if ((hwaddr = _link_aton(addr, &hwaddrlen)) == NULL) { if (hwaddrlen == -1) (void) fprintf(stderr, - "ifconfig: %s: bad address\n", hwaddr); + "ifconfig: bad ethernet address\n"); else (void) fprintf(stderr, "ifconfig: malloc() failed\n"); exit(1); @@ -1631,7 +1692,7 @@ * Print an interface's Ethernet address, if it has one. */ static void -print_ifether(char *ifname) +print_ifether(const char *ifname) { int fd; @@ -1739,6 +1800,8 @@ int prefixlen = 0; struct sockaddr_storage laddr; struct sockaddr_storage mask; + ipadm_status_t istatus; + char cidraddr[BUFSIZ]; (void) strncpy(name, origname, sizeof (name)); @@ -1818,11 +1881,54 @@ * necessary operation. */ set_mask_lifreq(&lifr, &laddr, &mask); + + /* This check is temporary until libipadm supports IPMP interfaces. */ + if (ifconfig_use_libipadm(s, name)) { + /* + * We added the logical interface above before calling + * ipadm_create_addr(), because, with IPH_LEGACY, we need + * to do an addif for `ifconfig ce0 addif <addr>' but not for + * `ifconfig ce0 <addr>'. libipadm does not have a flag to + * to differentiate between these two cases. To keep it simple, + * we always create the logical interface and pass it to + * libipadm instead of requiring libipadm to addif for some + * cases and not do addif for other cases. + */ + istatus = ipadm_create_addrobj(IPADM_ADDR_STATIC, name, + &ipaddr); + if (istatus != IPADM_SUCCESS) + ipadmerr_exit(istatus, "addif"); + + if (strchr(str, '/') == NULL) { + /* + * lifr.lifr_addr, which is updated by set_mask_lifreq() + * will contain the right mask to use. + */ + prefixlen = mask2plen(&lifr.lifr_addr); + (void) snprintf(cidraddr, sizeof (cidraddr), "%s/%d", + str, prefixlen); + str = cidraddr; + } + istatus = ipadm_set_addr(ipaddr, str, af); + if (istatus != IPADM_SUCCESS) + ipadmerr_exit(istatus, "could not set address"); + setaddr++; + /* + * address will be set by the parser after nextarg + * has been scanned + */ + return (0); + } + /* * Only set the netmask if "netmask" command is used or a prefix is * provided. */ if (g_netmask_set == G_NETMASK_SET || prefixlen >= 0) { + /* + * lifr.lifr_addr already contains netmask from + * set_mask_lifreq(). + */ if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) Perror0_exit("addif: SIOCSLIFNETMASK"); } @@ -1850,6 +1956,8 @@ removeif(char *str, int64_t param) { struct sockaddr_storage laddr; + ipadm_status_t istatus; + ipadm_addr_info_t *ainfo, *ainfop; if (strchr(name, ':') != NULL) { (void) fprintf(stderr, @@ -1859,8 +1967,43 @@ } (*afp->af_getaddr)(str, &laddr, NULL); + + /* + * Following check is temporary until libipadm supports + * IPMP interfaces. + */ + if (!ifconfig_use_libipadm(s, name)) + goto delete; + + /* + * Get all addresses and search this address among the active + * addresses. If an address object was found, delete using + * ipadm_delete_addr(). + */ + istatus = ipadm_addr_info(iph, name, &ainfo, 0, LIFC_DEFAULT); + if (istatus != IPADM_SUCCESS) + ipadmerr_exit(istatus, "removeif"); + + for (ainfop = ainfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) + if (sockaddrcmp(ainfop->ia_ifa.ifa_addr, &laddr)) + break; + + if (ainfop != NULL && ainfop->ia_aobjname[0] != '\0') { + istatus = ipadm_delete_addr(iph, ainfop->ia_aobjname, + IPADM_OPT_ACTIVE); + if (istatus != IPADM_SUCCESS) + ipadmerr_exit(istatus, "could not delete address"); + ipadm_free_addr_info(ainfo); + return (0); + } + ipadm_free_addr_info(ainfo); + +delete: + /* + * An address object for this address was not found in ipadm. + * Delete with SIOCLIFREMOVEIF. + */ lifr.lifr_addr = laddr; - (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) { if (errno == EBUSY) { @@ -2202,37 +2345,6 @@ } /* - * Open a stream on /dev/udp{,6}, pop off all undesired modules (note that - * the user may have configured autopush to add modules above - * udp), and push the arp module onto the resulting stream. - * This is used to make IP+ARP be able to atomically track the muxid - * for the I_PLINKed STREAMS, thus it isn't related to ARP running the ARP - * protocol. - */ -static int -open_arp_on_udp(char *udp_dev_name) -{ - int fd; - - if ((fd = open(udp_dev_name, O_RDWR)) == -1) { - Perror2("open", udp_dev_name); - return (-1); - } - errno = 0; - while (ioctl(fd, I_POP, 0) != -1) - ; - if (errno != EINVAL) { - Perror2("pop", udp_dev_name); - } else if (ioctl(fd, I_PUSH, ARP_MOD_NAME) == -1) { - Perror2("arp PUSH", udp_dev_name); - } else { - return (fd); - } - (void) close(fd); - return (-1); -} - -/* * Helper function for mod*() functions. It gets a fd to the lower IP * stream and I_PUNLINK's the lower stream. It also initializes the * global variable lifr. @@ -2286,7 +2398,7 @@ /* * Use /dev/udp{,6} as the mux to avoid linkcycles. */ - if ((*muxfd = open_arp_on_udp(udp_dev_name)) == -1) + if (ipadm_open_arp_on_udp(udp_dev_name, muxfd) != IPADM_SUCCESS) return (-1); if (lifr.lifr_arp_muxid != 0) { @@ -2636,11 +2748,9 @@ * that any previous selection is cleared. */ - rval = strcmp(arg, name); - if (rval == 0) { + if (strchr(arg, ':') != NULL) { (void) fprintf(stderr, - "ifconfig: Cannot specify same interface for usesrc" - " group\n"); + "ifconfig: Cannot specify logical interface for usesrc \n"); exit(1); } @@ -2805,7 +2915,6 @@ (void) putchar('\n'); } - /* * Print the status of the interface. If an address family was * specified, show it and it only; otherwise, show them all. @@ -2850,13 +2959,8 @@ (*p->af_status)(1, flags); } else { for (p = afs; p->af_name; p++) { - (void) close(s); - s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0); /* set global af for use in p->af_status */ af = p->af_af; - if (s == -1) { - Perror0_exit("socket"); - } (*p->af_status)(0, flags); } @@ -3471,277 +3575,6 @@ } /* - * We need to plink both the arp-device stream and the arp-ip-device stream. - * However the muxid is stored only in IP. Plumbing 2 streams individually - * is not atomic, and if ifconfig is killed, the resulting plumbing can - * be inconsistent. For eg. if only the arp stream is plumbed, we have lost - * the muxid, and the half-baked plumbing can neither be unplumbed nor - * replumbed, thus requiring a reboot. To avoid the above the following - * scheme is used. - * - * Ifconfig asks IP to enforce atomicity of plumbing the arp and IP streams. - * This is done by pushing arp on to the mux (/dev/udp). ARP adds some - * extra information in the I_PLINK and I_PUNLINK ioctls to let IP know - * that the plumbing/unplumbing has to be done atomically. Ifconfig plumbs - * the IP stream first, and unplumbs it last. The kernel (IP) does not - * allow IP stream to be unplumbed without unplumbing arp stream. Similarly - * it does not allow arp stream to be plumbed before IP stream is plumbed. - * There is no need to use SIOCSLIFMUXID, since the whole operation is atomic, - * and IP uses the info in the I_PLINK message to get the muxid. - * - * a. STREAMS does not allow us to use /dev/ip itself as the mux. So we use - * /dev/udp{,6}. - * b. SIOCGLIFMUXID returns the muxid corresponding to the V4 or V6 stream - * depending on the open i.e. V4 vs V6 open. So we need to use /dev/udp - * or /dev/udp6 for SIOCGLIFMUXID and SIOCSLIFMUXID. - * c. We need to push ARP in order to get the required kernel support for - * atomic plumbings. The actual work done by ARP is explained in arp.c - * Without pushing ARP, we will still be able to plumb/unplumb. But - * it is not atomic, and is supported by the kernel for backward - * compatibility for other utilities like atmifconfig etc. In this case - * the utility must use SIOCSLIFMUXID. - */ -static int -ifplumb(const char *linkname, const char *ifname, boolean_t genppa, int af) -{ - int arp_muxid = -1, ip_muxid; - int mux_fd, ip_fd, arp_fd; - int retval; - char *udp_dev_name; - uint64_t flags; - uint_t dlpi_flags; - dlpi_handle_t dh_arp, dh_ip; - - /* - * Always dlpi_open() with DLPI_NOATTACH because the IP and ARP module - * will do the attach themselves for DLPI style-2 links. - */ - dlpi_flags = DLPI_NOATTACH; - - /* - * If `linkname' is the special token IPMPSTUB, then this is a request - * to create an IPMP interface atop /dev/ipmpstub0. (We can't simply - * pass "ipmpstub0" as `linkname' since an admin *could* have a normal - * vanity-named link named "ipmpstub0" that they'd like to plumb.) - */ - if (linkname == IPMPSTUB) { - linkname = "ipmpstub0"; - dlpi_flags |= DLPI_DEVONLY; - } - - retval = dlpi_open(linkname, &dh_ip, dlpi_flags); - if (retval != DLPI_SUCCESS) - Perrdlpi_exit("cannot open link", linkname, retval); - - if (debug) { - (void) printf("ifconfig: ifplumb: link %s, ifname %s, " - "genppa %u\n", linkname, ifname, genppa); - } - - ip_fd = dlpi_fd(dh_ip); - if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1) - Perror2_exit("I_PUSH", IP_MOD_NAME); - - /* - * Prepare to set IFF_IPV4/IFF_IPV6 flags as part of SIOCSLIFNAME. - * (At this point in time the kernel also allows an override of the - * IFF_CANTCHANGE flags.) - */ - lifr.lifr_name[0] = '\0'; - if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1) - Perror0_exit("ifplumb: SIOCGLIFFLAGS"); - - if (af == AF_INET6) { - flags = lifr.lifr_flags | IFF_IPV6; - flags &= ~(IFF_BROADCAST | IFF_IPV4); - } else { - flags = lifr.lifr_flags | IFF_IPV4; - flags &= ~IFF_IPV6; - } - - /* - * Set the interface name. If we've been asked to generate the PPA, - * then find the lowest available PPA (only currently used for IPMP - * interfaces). Otherwise, use the interface name as-is. - */ - if (genppa) { - int ppa; - - /* - * We'd like to just set lifr_ppa to UINT_MAX and have the - * kernel pick a PPA. Unfortunately, that would mishandle - * two cases: - * - * 1. If the PPA is available but the groupname is taken - * (e.g., the "ipmp2" IP interface name is available - * but the "ipmp2" groupname is taken) then the - * auto-assignment by the kernel will fail. - * - * 2. If we're creating (e.g.) an IPv6-only IPMP - * interface, and there's already an IPv4-only IPMP - * interface, the kernel will allow us to accidentally - * reuse the IPv6 IPMP interface name (since - * SIOCSLIFNAME uniqueness is per-interface-type). - * This will cause administrative confusion. - * - * Thus, we instead take a brute-force approach of checking - * whether the IPv4 or IPv6 name is already in-use before - * attempting the SIOCSLIFNAME. As per (1) above, the - * SIOCSLIFNAME may still fail, in which case we just proceed - * to the next one. If this approach becomes too slow, we - * can add a new SIOC* to handle this case in the kernel. - */ - for (ppa = 0; ppa < UINT_MAX; ppa++) { - (void) snprintf(lifr.lifr_name, LIFNAMSIZ, "%s%d", - ifname, ppa); - - if (ioctl(s4, SIOCGLIFFLAGS, &lifr) != -1 || - errno != ENXIO) - continue; - - if (ioctl(s6, SIOCGLIFFLAGS, &lifr) != -1 || - errno != ENXIO) - continue; - - lifr.lifr_ppa = ppa; - lifr.lifr_flags = flags; - retval = ioctl(ip_fd, SIOCSLIFNAME, &lifr); - if (retval != -1 || errno != EEXIST) - break; - } - } else { - ifspec_t ifsp; - - /* - * The interface name could have come from the command-line; - * check it. - */ - if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid) - Perror2_exit("invalid IP interface name", ifname); - - /* - * Before we call SIOCSLIFNAME, ensure that the IPMP group - * interface for this address family exists. Otherwise, the - * kernel will kick the interface out of the group when we do - * the SIOCSLIFNAME. - * - * Example: suppose bge0 is plumbed for IPv4 and in group "a". - * If we're now plumbing bge0 for IPv6, but the IPMP group - * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME - * will kick bge0 out of group "a", which is undesired. - */ - if (create_ipmp_peer(af, ifname) == -1) { - (void) fprintf(stderr, "ifconfig: warning: cannot " - "create %s IPMP group; %s will be removed from " - "group\n", af == AF_INET ? "IPv4" : "IPv6", ifname); - } - - lifr.lifr_ppa = ifsp.ifsp_ppa; - lifr.lifr_flags = flags; - (void) strlcpy(lifr.lifr_name, ifname, LIFNAMSIZ); - retval = ioctl(ip_fd, SIOCSLIFNAME, &lifr); - } - - if (retval == -1) { - if (errno != EEXIST) - Perror0_exit("SIOCSLIFNAME for ip"); - /* - * This difference between the way we behave for EEXIST - * and that with other errors exists to preserve legacy - * behaviour. Earlier when foreachinterface() and matchif() - * were doing the duplicate interface name checks, for - * already existing interfaces, inetplumb() returned "0". - * To preserve this behaviour, Perror0() and return are - * called for EEXIST. - */ - Perror0("SIOCSLIFNAME for ip"); - return (-1); - } - - /* Get the full set of existing flags for this stream */ - if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1) - Perror0_exit("ifplumb: SIOCGLIFFLAGS"); - - if (debug) { - (void) printf("ifconfig: ifplumb: %s got flags:\n", - lifr.lifr_name); - print_flags(lifr.lifr_flags); - (void) putchar('\n'); - } - - /* - * Open "/dev/udp" for use as a multiplexor to PLINK the - * interface stream under. We use "/dev/udp" instead of "/dev/ip" - * since STREAMS will not let you PLINK a driver under itself, - * and "/dev/ip" is typically the driver at the bottom of - * the stream for tunneling interfaces. - */ - if (af == AF_INET6) - udp_dev_name = UDP6_DEV_NAME; - else - udp_dev_name = UDP_DEV_NAME; - if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1) - exit(EXIT_FAILURE); - - /* Check if arp is not needed */ - if (lifr.lifr_flags & (IFF_NOARP|IFF_IPV6)) { - /* - * PLINK the interface stream so that ifconfig can exit - * without tearing down the stream. - */ - if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) - Perror0_exit("I_PLINK for ip"); - (void) close(mux_fd); - return (lifr.lifr_ppa); - } - - /* - * This interface does use ARP, so set up a separate stream - * from the interface to ARP. - */ - if (debug) - (void) printf("ifconfig: ifplumb: interface %s", ifname); - - retval = dlpi_open(linkname, &dh_arp, dlpi_flags); - if (retval != DLPI_SUCCESS) - Perrdlpi_exit("cannot open link", linkname, retval); - - arp_fd = dlpi_fd(dh_arp); - if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1) - Perror2_exit("I_PUSH", ARP_MOD_NAME); - - /* - * Tell ARP the name and unit number for this interface. - * Note that arp has no support for transparent ioctls. - */ - if (strioctl(arp_fd, SIOCSLIFNAME, &lifr, sizeof (lifr)) == -1) { - if (errno != EEXIST) - Perror0_exit("SIOCSLIFNAME for arp"); - Perror0("SIOCSLIFNAME for arp"); - goto out; - } - - /* - * PLINK the IP and ARP streams so that ifconfig can exit - * without tearing down the stream. - */ - if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) - Perror0_exit("I_PLINK for ip"); - if ((arp_muxid = ioctl(mux_fd, I_PLINK, arp_fd)) == -1) { - (void) ioctl(mux_fd, I_PUNLINK, ip_muxid); - Perror0_exit("I_PLINK for arp"); - } - - if (debug) - (void) printf("arp muxid = %d\n", arp_muxid); -out: - dlpi_close(dh_ip); - dlpi_close(dh_arp); - (void) close(mux_fd); - return (lifr.lifr_ppa); -} - -/* * If this is a physical interface then remove it. * If it is a logical interface name use SIOCLIFREMOVEIF to * remove it. In both cases fail if it doesn't exist. @@ -3750,245 +3583,36 @@ static int inetunplumb(char *arg, int64_t param) { - int ip_muxid, arp_muxid; - int mux_fd; - int muxid_fd; - char *udp_dev_name; - char *strptr; - uint64_t flags; - boolean_t changed_arp_muxid = _B_FALSE; - int save_errno; - boolean_t v6 = (afp->af_af == AF_INET6); - - strptr = strchr(name, ':'); - if (strptr != NULL || strcmp(name, LOOPBACK_IF) == 0) { - /* Can't unplumb logical interface zero */ - if (strptr != NULL && strcmp(strptr, ":0") == 0) { - (void) fprintf(stderr, "ifconfig: unplumb:" - " Cannot unplumb %s: Invalid interface\n", name); - exit(1); - } - (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); - (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); - - if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) - Perror0_exit("unplumb: SIOCLIFREMOVEIF"); - return (0); - } - - /* - * We used /dev/udp or udp6 to set up the mux. So we have to use - * the same now for PUNLINK also. - */ - if (v6) - udp_dev_name = UDP6_DEV_NAME; - else - udp_dev_name = UDP_DEV_NAME; - - if ((muxid_fd = open(udp_dev_name, O_RDWR)) == -1) - exit(EXIT_FAILURE); - - if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1) - exit(EXIT_FAILURE); - - (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); - if (ioctl(muxid_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { - Perror0_exit("unplumb: SIOCGLIFFLAGS"); + ipadm_status_t istatus; + + istatus = ipadm_delete_if(iph, name, afp->af_af, IPADM_OPT_ACTIVE); + if (istatus != IPADM_SUCCESS) { + (void) fprintf(stderr, "ifconfig: cannot unplumb %s: %s\n", + name, ipadm_status2str(istatus)); + exit(1); } - flags = lifr.lifr_flags; -again: - if (flags & IFF_IPMP) { - lifgroupinfo_t lifgr; - ifaddrlistx_t *ifaddrs, *ifaddrp; - - /* - * There are two reasons the I_PUNLINK can fail with EBUSY: - * (1) if IP interfaces are in the group, or (2) if IPMP data - * addresses are administratively up. For case (1), we fail - * here with a specific error message. For case (2), we bring - * down the addresses prior to doing the I_PUNLINK. If the - * I_PUNLINK still fails with EBUSY then the configuration - * must have changed after our checks, in which case we branch - * back up to `again' and rerun this logic. The net effect is - * that unplumbing an IPMP interface will only fail with EBUSY - * if IP interfaces are in the group. - */ - if (ioctl(s, SIOCGLIFGROUPNAME, &lifr) == -1) - Perror0_exit("unplumb: SIOCGLIFGROUPNAME"); - - (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, - LIFGRNAMSIZ); - if (ioctl(s, SIOCGLIFGROUPINFO, &lifgr) == -1) - Perror0_exit("unplumb: SIOCGLIFGROUPINFO"); - - if ((v6 && lifgr.gi_nv6 != 0) || (!v6 && lifgr.gi_nv4 != 0)) { - (void) fprintf(stderr, "ifconfig: %s: cannot unplumb:" - " IPMP group is not empty\n", name); - exit(1); - } - - /* - * The kernel will fail the I_PUNLINK if the IPMP interface - * has administratively up addresses; bring 'em down. - */ - if (ifaddrlistx(name, IFF_UP|IFF_DUPLICATE, 0, &ifaddrs) == -1) - Perror2_exit(name, "cannot get address list"); - - ifaddrp = ifaddrs; - for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) { - if (((ifaddrp->ia_flags & IFF_IPV6) && !v6) || - (!(ifaddrp->ia_flags & IFF_IPV6) && v6)) - continue; - - if (!ifaddr_down(ifaddrp)) { - Perror2_exit(ifaddrp->ia_name, - "cannot bring down"); - } - } - ifaddrlistx_free(ifaddrs); - } - - if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) { - Perror0_exit("unplumb: SIOCGLIFMUXID"); - } - arp_muxid = lifr.lifr_arp_muxid; - ip_muxid = lifr.lifr_ip_muxid; - /* - * We don't have a good way of knowing whether the arp stream is - * plumbed. We can't rely on IFF_NOARP because someone could - * have turned it off later using "ifconfig xxx -arp". - */ - if (arp_muxid != 0) { - if (debug) - (void) printf("arp_muxid %d\n", arp_muxid); - if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) { - /* - * See the comment before the SIOCGLIFGROUPNAME call. - */ - if (errno == EBUSY && (flags & IFF_IPMP)) - goto again; - - if ((errno == EINVAL) && - (flags & (IFF_NOARP | IFF_IPV6))) { - /* - * Some plumbing utilities set the muxid to - * -1 or some invalid value to signify that - * there is no arp stream. Set the muxid to 0 - * before trying to unplumb the IP stream. - * IP does not allow the IP stream to be - * unplumbed if it sees a non-null arp muxid, - * for consistency of IP-ARP streams. - */ - lifr.lifr_arp_muxid = 0; - (void) ioctl(muxid_fd, SIOCSLIFMUXID, - (caddr_t)&lifr); - changed_arp_muxid = _B_TRUE; - } else { - Perror0("I_PUNLINK for arp"); - } - } - } - if (debug) - (void) printf("ip_muxid %d\n", ip_muxid); - - if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) { - if (changed_arp_muxid) { - /* - * Some error occurred, and we need to restore - * everything back to what it was. - */ - save_errno = errno; - lifr.lifr_arp_muxid = arp_muxid; - lifr.lifr_ip_muxid = ip_muxid; - (void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr); - errno = save_errno; - } - - /* - * See the comment before the SIOCGLIFGROUPNAME call. - */ - if (errno == EBUSY && (flags & IFF_IPMP)) - goto again; - - Perror0_exit("I_PUNLINK for ip"); - } - (void) close(mux_fd); - (void) close(muxid_fd); + return (0); } /* - * If this is a physical interface then create it unless it is already - * present. If it is a logical interface name use SIOCLIFADDIF to - * create and (and fail it if already exists.) - * As a special case send SIOCLIFADDIF for the loopback interface. This - * is needed since there is no other notion of plumbing the loopback - * interface. + * Create the interface in `name', using ipadm_create_if(). If `name' is a + * logical interface or loopback interface, ipadm_create_if() uses + * SIOCLIFADDIF to create it. */ /* ARGSUSED */ static int inetplumb(char *arg, int64_t param) { - char *strptr; - boolean_t islo; - zoneid_t zoneid; - datalink_id_t linkid; - - strptr = strchr(name, ':'); - islo = (strcmp(name, LOOPBACK_IF) == 0); - - if (strptr != NULL || islo) { - (void) memset(&lifr, 0, sizeof (lifr)); - (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); - if (islo && ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) >= 0) { - if (debug) { - (void) fprintf(stderr, - "ifconfig: %s already exists\n", name); - } - return (0); - } - if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) { - if (errno == EEXIST) { - if (debug) { - (void) fprintf(stderr, - "ifconfig: %s already exists\n", - name); - } - } else { - Perror2_exit("plumb: SIOCLIFADDIF", name); - } - } - return (0); + ipadm_status_t istatus; + + istatus = ipadm_create_if(iph, name, afp->af_af, IPADM_OPT_ACTIVE); + if (istatus != IPADM_SUCCESS) { + (void) fprintf(stderr, "ifconfig: cannot plumb %s: %s\n", + name, ipadm_status2str(istatus)); + if (istatus != IPADM_IF_EXISTS) + exit(1); } - - /* - * If we're in the global zone and we're plumbing a datalink, make - * sure that the datalink is not assigned to a non-global zone. Note - * that the non-global zones don't need this check, because zoneadm - * has taken care of this when the zones boot. - */ - zoneid = getzoneid(); - if (zoneid == GLOBAL_ZONEID && - ifconfig_dladm_open(name, DATALINK_CLASS_ALL, &linkid) == - DLADM_STATUS_OK) { - int ret; - - zoneid = ALL_ZONES; - ret = zone_check_datalink(&zoneid, linkid); - if (ret == 0) { - char zonename[ZONENAME_MAX]; - - (void) getzonenamebyid(zoneid, zonename, ZONENAME_MAX); - (void) fprintf(stderr, "%s is used by non-global" - "zone: %s\n", name, zonename); - return (1); - } - } - - if (debug) - (void) printf("inetplumb: %s af %d\n", name, afp->af_af); - - (void) ifplumb(name, name, _B_FALSE, afp->af_af); return (0); } @@ -4026,29 +3650,30 @@ static int create_ipmp(const char *grname, int af, const char *ifname, boolean_t implicit) { - int ppa; static int ipmp_daemon_started; + uint32_t flags = IPADM_OPT_IPMP|IPADM_OPT_ACTIVE; + ipadm_status_t istatus; if (debug) { (void) printf("create_ipmp: ifname %s grname %s af %d\n", ifname != NULL ? ifname : "NULL", grname, af); } - if (ifname != NULL) - ppa = ifplumb(IPMPSTUB, ifname, _B_FALSE, af); - else - ppa = ifplumb(IPMPSTUB, "ipmp", _B_TRUE, af); - - if (ppa == -1) { - Perror2(grname, "cannot create IPMP interface"); + /* + * ipadm_create_if() creates the IPMP interface and fills in the + * ppa in lifr.lifr_name, if `ifname'="ipmp". + */ + (void) strlcpy(lifr.lifr_name, (ifname ? ifname : "ipmp"), + sizeof (lifr.lifr_name)); + if (ifname == NULL) + flags |= IPADM_OPT_GENPPA; + istatus = ipadm_create_if(iph, lifr.lifr_name, af, flags); + if (istatus != IPADM_SUCCESS) { + (void) fprintf(stderr, "ifconfig: cannot create IPMP interface " + "%s: %s\n", grname, ipadm_status2str(istatus)); return (-1); } - if (ifname != NULL) - (void) strlcpy(lifr.lifr_name, ifname, LIFNAMSIZ); - else - (void) snprintf(lifr.lifr_name, LIFNAMSIZ, "ipmp%d", ppa); - /* * To preserve backward-compatibility, always bring up the link-local * address for implicitly-created IPv6 IPMP interfaces. @@ -4082,42 +3707,6 @@ } /* - * Check if `ifname' is plumbed and in an IPMP group on its "other" address - * family. If so, create a matching IPMP group for address family `af'. - */ -static int -create_ipmp_peer(int af, const char *ifname) -{ - int fd; - lifgroupinfo_t lifgr; - - assert(af == AF_INET || af == AF_INET6); - - /* - * Get the socket for the "other" address family. - */ - fd = (af == AF_INET) ? s6 : s4; - - (void) strlcpy(lifr.lifr_name, ifname, LIFNAMSIZ); - if (ioctl(fd, SIOCGLIFGROUPNAME, &lifr) != 0) - return (0); - - (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, LIFGRNAMSIZ); - if (ioctl(fd, SIOCGLIFGROUPINFO, &lifgr) != 0) - return (0); - - /* - * If `ifname' *is* the IPMP group interface, or if the relevant - * address family is already configured, then there's nothing to do. - */ - if (strcmp(lifgr.gi_grifname, ifname) == 0 || - (af == AF_INET && lifgr.gi_v4) || (af == AF_INET6 && lifgr.gi_v6)) - return (0); - - return (create_ipmp(lifgr.gi_grname, af, lifgr.gi_grifname, _B_TRUE)); -} - -/* * Start in.mpathd if it's not already running. */ static void @@ -4244,7 +3833,35 @@ return (status); } -void +/* + * This function checks if we can use libipadm API's. We will only + * call libipadm functions for non-IPMP interfaces. This check is + * temporary until libipadm supports IPMP interfaces. + */ +static boolean_t +ifconfig_use_libipadm(int s, const char *lifname) +{ + struct lifreq lifr1; + + (void) strlcpy(lifr1.lifr_name, lifname, sizeof (lifr1.lifr_name)); + if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr1) < 0) { + (void) strncpy(lifr.lifr_name, lifname, + sizeof (lifr.lifr_name)); + Perror0_exit("error"); + } + + return (lifr1.lifr_groupname[0] == '\0'); +} + +static void +ipadmerr_exit(ipadm_status_t status, const char *str) +{ + (void) fprintf(stderr, "ifconfig: %s: %s\n", str, + ipadm_status2str(status)); + exit(1); +} + +static void dladmerr_exit(dladm_status_t status, const char *str) { char errstr[DLADM_STRSIZE]; @@ -4589,19 +4206,6 @@ return (atoi(cp + 1)); } -static int -strioctl(int s, int cmd, void *buf, int buflen) -{ - struct strioctl ioc; - - (void) memset(&ioc, 0, sizeof (ioc)); - ioc.ic_cmd = cmd; - ioc.ic_timout = 0; - ioc.ic_len = buflen; - ioc.ic_dp = buf; - return (ioctl(s, I_STR, (char *)&ioc)); -} - static void add_ni(const char *name) {