Print this page
NEX-9305 libipadm`ipadm_enable_addr() leaks addrnvl
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-8955 creating addresses on underlying IPMP links is broken
NEX-9102 deleting addresses from underlying IPMP interfaces leaves them down
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-6864 cannot create functional link-based IPMP interface
NEX-7793 unable to add/remove interface with existing address to/from IPMP group
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-3908 IPMP group can have only one IP address
Reviewed by: Gordon Ross <gwr@nexenta.com>
OS-161: Integrate IPMP changes (lint)
OS-161: Integrate IPMP changes

@@ -16,13 +16,15 @@
  * 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) 2013 by Delphix. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc.
  * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
  */
 
 /*
  * This file contains functions for address management such as creating

@@ -295,14 +297,16 @@
                         break;
                 }
         }
         assert(af != AF_UNSPEC);
         if (nvpair_value_nvlist(nvp, &nvladdr) != 0 ||
-            nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0 ||
-            ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS) {
+            nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0)
                 goto fail;
-        }
+
+        if (ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS)
+                goto fail;
+
         nvlist_free(onvl);
         return (IPADM_SUCCESS);
 fail:
         nvlist_free(onvl);
         return (IPADM_NOTFOUND);

@@ -381,11 +385,11 @@
 
 /*
  * Gets all the addresses from active configuration and populates the
  * address information in `addrinfo'.
  */
-static ipadm_status_t
+ipadm_status_t
 i_ipadm_active_addr_info(ipadm_handle_t iph, const char *ifname,
     ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
 {
         ipadm_status_t          status;
         struct ifaddrs          *ifap, *ifa;

@@ -1711,11 +1715,10 @@
 
         /* Persistent operation not allowed on a temporary object. */
         if ((pflags & IPADM_OPT_PERSIST) &&
             !(ipaddr.ipadm_flags & IPMGMT_PERSIST))
                 return (IPADM_TEMPORARY_OBJ);
-
         /*
          * Currently, setting an address property on an address object of type
          * IPADM_ADDR_IPV6_ADDRCONF is not supported. Supporting it involves
          * in.ndpd retrieving the address properties from ipmgmtd for given
          * address object and then setting them on auto-configured addresses,

@@ -2407,15 +2410,13 @@
                 *aname++ = '\0';
 
         /* Check if the interface name is valid. */
         if (!ifparse_ifspec(ifname, &ifsp))
                 return (IPADM_INVALID_ARG);
-
         /* Check if the given addrobj name is valid. */
         if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname))
                 return (IPADM_INVALID_ARG);
-
         if ((newaddr = calloc(1, sizeof (struct ipadm_addrobj_s))) == NULL)
                 return (IPADM_NO_MEMORY);
 
         /*
          * If the ifname has logical interface number, extract it and assign

@@ -2593,14 +2594,10 @@
 static ipadm_status_t
 i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname,
     const char *aobjname, nvlist_t **onvl)
 {
         ipmgmt_getaddr_arg_t    garg;
-        ipmgmt_get_rval_t       *rvalp;
-        int                     err;
-        size_t                  nvlsize;
-        char                    *nvlbuf;
 
         /* Populate the door_call argument structure */
         bzero(&garg, sizeof (garg));
         garg.ia_cmd = IPMGMT_CMD_GETADDR;
         if (aobjname != NULL)

@@ -2607,20 +2604,11 @@
                 (void) strlcpy(garg.ia_aobjname, aobjname,
                     sizeof (garg.ia_aobjname));
         if (ifname != NULL)
                 (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
 
-        rvalp = malloc(sizeof (ipmgmt_get_rval_t));
-        err = ipadm_door_call(iph, &garg, sizeof (garg), (void **)&rvalp,
-            sizeof (*rvalp), B_TRUE);
-        if (err == 0) {
-                nvlsize = rvalp->ir_nvlsize;
-                nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
-                err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE);
-        }
-        free(rvalp);
-        return (ipadm_errno2status(err));
+        return (i_ipadm_call_ipmgmtd(iph, (void *) &garg, sizeof (garg), onvl));
 }
 
 /*
  * Adds the IP address contained in the 'ipaddr' argument to the physical
  * interface represented by 'ifname' after doing the required validation.

@@ -2652,20 +2640,21 @@
         boolean_t               aobjfound;
         boolean_t               is_6to4;
         struct lifreq           lifr;
         uint64_t                ifflags;
         boolean_t               is_boot = (iph->iph_flags & IPH_IPMGMTD);
+        boolean_t               is_ipmp;
+        char                    gifname[LIFGRNAMSIZ];
 
         /* check for solaris.network.interface.config authorization */
         if (!ipadm_check_auth())
                 return (IPADM_EAUTH);
 
         /* Validate the addrobj. This also fills in addr->ipadm_ifname. */
         status = i_ipadm_validate_create_addr(iph, addr, flags);
         if (status != IPADM_SUCCESS)
                 return (status);
-
         /*
          * For Legacy case, check if an addrobj already exists for the
          * given logical interface name. If one does not exist,
          * a default name will be generated and added to the daemon's
          * aobjmap.

@@ -2796,10 +2785,21 @@
                 }
                 if (sockaddrcmp(&lifr.lifr_addr, &addr->ipadm_static_addr))
                         return (IPADM_SUCCESS);
         }
 
+        /*
+         * If interface is an IPMP group member, move it out of the group before
+         * performing any operations on it.
+         */
+        if ((is_ipmp = i_ipadm_is_under_ipmp(iph, addr->ipadm_ifname))) {
+                (void) i_ipadm_get_groupname_active(iph, addr->ipadm_ifname,
+                    gifname, sizeof (gifname));
+                (void) i_ipadm_set_groupname_active(iph, addr->ipadm_ifname,
+                    "");
+        }
+
         /* Create the address. */
         type = addr->ipadm_atype;
         switch (type) {
         case IPADM_ADDR_STATIC:
                 status = i_ipadm_create_addr(iph, addr, flags);

@@ -2813,10 +2813,16 @@
         default:
                 status = IPADM_INVALID_ARG;
                 break;
         }
 
+        /* Move the underlying IPMP interface back to the group */
+        if (is_ipmp) {
+                (void) i_ipadm_set_groupname_active(iph, addr->ipadm_ifname,
+                    gifname);
+        }
+
         /*
          * If address was not created successfully, unplumb the interface
          * if it was plumbed implicitly in this function and remove the
          * addrobj created by the ipmgmtd daemon as a placeholder.
          * If IPH_LEGACY is set, then remove the addrobj only if it was

@@ -2885,30 +2891,15 @@
 
         /*
          * Create a new logical interface if needed; otherwise, just
          * use the 0th logical interface.
          */
-retry:
         if (!(iph->iph_flags & IPH_LEGACY)) {
                 status = i_ipadm_do_addif(iph, ipaddr);
                 if (status != IPADM_SUCCESS)
                         return (status);
-                /*
-                 * We don't have to set the lifnum for IPH_INIT case, because
-                 * there is no placeholder created for the address object in
-                 * this case. For IPH_LEGACY, we don't do this because the
-                 * lifnum is given by the caller and it will be set in the
-                 * end while we call the i_ipadm_addr_persist().
-                 */
-                if (!(iph->iph_flags & IPH_INIT)) {
-                        status = i_ipadm_setlifnum_addrobj(iph, ipaddr);
-                        if (status == IPADM_ADDROBJ_EXISTS)
-                                goto retry;
-                        if (status != IPADM_SUCCESS)
-                                return (status);
                 }
-        }
         i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
             sizeof (lifr.lifr_name));
         lifr.lifr_addr = *mask;
         if (ioctl(sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) {
                 status = ipadm_errno2status(errno);

@@ -2927,13 +2918,23 @@
                         goto ret;
                 }
         }
 
         if (flags & IPADM_OPT_UP) {
-                status = i_ipadm_set_flags(iph, lifr.lifr_name, af, IFF_UP, 0);
+                uint32_t        iff_flags = IFF_UP;
 
                 /*
+                 * Set the NOFAILOVER flag only on underlying IPMP interface
+                 * and not the IPMP group interface itself.
+                 */
+                if (i_ipadm_is_under_ipmp(iph, lifr.lifr_name) &&
+                    !i_ipadm_is_ipmp(iph, lifr.lifr_name))
+                        iff_flags |= IFF_NOFAILOVER;
+                status = i_ipadm_set_flags(iph, lifr.lifr_name,
+                    af, iff_flags, 0);
+
+                /*
                  * IPADM_DAD_FOUND is a soft-error for create-addr.
                  * No need to tear down the address.
                  */
                 if (status == IPADM_DAD_FOUND)
                         status = IPADM_SUCCESS;

@@ -2962,10 +2963,11 @@
                     flags, NULL);
         }
 ret:
         if (status != IPADM_SUCCESS && !legacy)
                 (void) i_ipadm_delete_addr(iph, ipaddr);
+
         return (status);
 }
 
 /*
  * Removes the address object identified by `aobjname' from both active and

@@ -3026,10 +3028,25 @@
         /*
          * If address is present in active config, remove it from
          * kernel.
          */
         if (ipaddr.ipadm_flags & IPMGMT_ACTIVE) {
+                boolean_t       is_ipmp;
+                char            gifname[LIFGRNAMSIZ];
+
+                /*
+                 * If interface is an IPMP group member, move it out of the
+                 * group before performing any operations on it.
+                 */
+                if ((is_ipmp = i_ipadm_is_under_ipmp(iph,
+                    ipaddr.ipadm_ifname))) {
+                        (void) i_ipadm_get_groupname_active(iph,
+                            ipaddr.ipadm_ifname, gifname, sizeof (gifname));
+                        (void) i_ipadm_set_groupname_active(iph,
+                            ipaddr.ipadm_ifname, "");
+                }
+
                 switch (ipaddr.ipadm_atype) {
                 case IPADM_ADDR_STATIC:
                         status = i_ipadm_delete_addr(iph, &ipaddr);
                         break;
                 case IPADM_ADDR_DHCP:

@@ -3045,10 +3062,16 @@
                          * through and delete that address object.
                          */
                         break;
                 }
 
+                /* Move the underlying IPMP interface back to the group */
+                if (is_ipmp) {
+                        (void) i_ipadm_set_groupname_active(iph,
+                            ipaddr.ipadm_ifname, gifname);
+                }
+
                 /*
                  * If the address was previously deleted from the active
                  * config, we will get a IPADM_ENXIO from kernel.
                  * We will still proceed and purge the address information
                  * in the DB.

@@ -3566,19 +3589,22 @@
         if (status != IPADM_SUCCESS)
                 return (status);
 
         if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE))
                 return (IPADM_OP_DISABLE_OBJ);
+
         if ((ipadm_flags & IPADM_OPT_PERSIST) &&
             !(ipaddr->ipadm_flags & IPMGMT_PERSIST))
                 return (IPADM_TEMPORARY_OBJ);
+
         if (ipaddr->ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF ||
             (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
             (ipadm_flags & IPADM_OPT_PERSIST)))
                 return (IPADM_NOTSUP);
 
         i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
+
         return (i_ipadm_get_flags(iph, lifname, ipaddr->ipadm_af, ifflags));
 }
 
 /*
  * Marks the address in the address object `aobjname' up. This operation is

@@ -3801,12 +3827,17 @@
         if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC)
                 return (IPADM_NOTSUP);
 
         ifname = ipaddr->ipadm_ifname;
 
-        if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname))
-                return (IPADM_NOTSUP);
+        /*
+         * Do not go further when we are under ipmp.
+         * The interface is plumbed up and we are going to add
+         * NOFAILOVER address to make in.mpathd happy.
+         */
+        if (i_ipadm_is_under_ipmp(iph, ifname))
+                return (IPADM_SUCCESS);
 
         af = ipaddr->ipadm_af;
         af_exists = ipadm_if_enabled(iph, ifname, af);
         /*
          * For legacy case, interfaces are not implicitly plumbed. We need to

@@ -3826,20 +3857,14 @@
 
         /* Check if interface exists in the persistent configuration. */
         status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
         if (status != IPADM_SUCCESS)
                 return (status);
+
         if (!a_exists && p_exists)
                 return (IPADM_OP_DISABLE_OBJ);
-        if ((flags & IPADM_OPT_PERSIST) && a_exists && !p_exists) {
-                /*
-                 * If address has to be created persistently,
-                 * and the interface does not exist in the persistent
-                 * store but in active config, fail.
-                 */
-                return (IPADM_TEMPORARY_OBJ);
-        }
+
         if (af_exists) {
                 status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
                 if (status != IPADM_SUCCESS)
                         return (status);
         }