Print this page
Commit IPMP changes

@@ -18,10 +18,11 @@
  *
  * CDDL HEADER END
  */
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>

@@ -523,43 +524,10 @@
         }
         return (B_FALSE);
 }
 
 /*
- * Returns B_TRUE if `ifname' represents an IPMP underlying interface.
- */
-boolean_t
-i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname)
-{
-        struct lifreq   lifr;
-
-        (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
-        if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0) {
-                if (ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME,
-                    (caddr_t)&lifr) < 0) {
-                        return (B_FALSE);
-                }
-        }
-        return (lifr.lifr_groupname[0] != '\0');
-}
-
-/*
- * Returns B_TRUE if `ifname' represents an IPMP meta-interface.
- */
-boolean_t
-i_ipadm_is_ipmp(ipadm_handle_t iph, const char *ifname)
-{
-        uint64_t flags;
-
-        if (i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS &&
-            i_ipadm_get_flags(iph, ifname, AF_INET6, &flags) != IPADM_SUCCESS)
-                return (B_FALSE);
-
-        return ((flags & IFF_IPMP) != 0);
-}
-
-/*
  * For a given interface name, ipadm_if_enabled() checks if v4
  * or v6 or both IP interfaces exist in the active configuration.
  */
 boolean_t
 ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af)

@@ -688,43 +656,71 @@
 ipadm_status_t
 i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
 {
         nvlist_t        *nvl = NULL;
         nvpair_t        *nvp;
-        char            *afstr;
         ipadm_status_t  status;
         ipadm_status_t  ret_status = IPADM_SUCCESS;
         char            newifname[LIFNAMSIZ];
         char            *aobjstr;
-        sa_family_t     af = AF_UNSPEC;
+        char    *ifclass_str, *gif_name;
+        uint16_t        *families;
+        uint_t  nelem = 0;
+        char **members;
+        uint32_t        ipadm_flags;
         boolean_t       is_ngz = (iph->iph_zoneid != GLOBAL_ZONEID);
+        boolean_t   init_from_gz = B_FALSE;
 
         (void) strlcpy(newifname, ifname, sizeof (newifname));
         /*
          * First plumb the given interface and then apply all the persistent
          * interface properties and then instantiate any persistent addresses
          * objects on that interface.
          */
         for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
             nvp = nvlist_next_nvpair(ifnvl, nvp)) {
+
                 if (nvpair_value_nvlist(nvp, &nvl) != 0)
                         continue;
 
-                if (nvlist_lookup_string(nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
-                        status = i_ipadm_plumb_if(iph, newifname, atoi(afstr),
-                            IPADM_OPT_ACTIVE);
-                        /*
-                         * If the interface is already plumbed, we should
-                         * ignore this error because there might be address
-                         * address objects on that interface that needs to
-                         * be enabled again.
-                         */
+
+                if (nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
+                    &families, &nelem) == 0) {
+
+                        ipadm_flags = IPADM_OPT_ACTIVE;
+
+                        if (nvlist_lookup_string(nvl, IPADM_NVP_IFCLASS, &ifclass_str) == 0 &&
+                            atoi(ifclass_str) == IPADM_IF_CLASS_IPMP)
+                                ipadm_flags |= IPADM_OPT_IPMP;
+
+                        while (nelem--) {
+                                assert(families[nelem] == AF_INET ||
+                                    families[nelem] == AF_INET6);
+
+                                status = i_ipadm_plumb_if(iph, newifname, families[nelem],
+                                    ipadm_flags);
+
                         if (status == IPADM_IF_EXISTS)
                                 status = IPADM_SUCCESS;
 
+                                /* plumbing can fail for ipmp, this is expected */
+                                if (status != IPADM_SUCCESS && !(ipadm_flags & IPADM_OPT_IPMP))
+                                        break;
+                        }
+                        /* does this interface belong to ipmp ? */
+                        if (nvlist_lookup_string(nvl, IPADM_NVP_GIFNAME, &gif_name) == 0) {
+                                (void) ipadm_create_if(iph, gif_name, AF_INET, IPADM_OPT_IPMP |
+                                    IPADM_OPT_ACTIVE);
+                                (void) ipadm_create_if(iph, gif_name, AF_INET6, IPADM_OPT_IPMP |
+                                   IPADM_OPT_ACTIVE);
+                                /** add itself to the group */
+                                status = ipadm_add_ipmp_member(iph, gif_name, newifname, IPADM_OPT_ACTIVE);
+                                if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS)
+                                        break;
+                        }
                         if (is_ngz)
-                                af = atoi(afstr);
+                                init_from_gz = B_TRUE;
                 } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
                     &aobjstr) == 0) {
                         /*
                          * For a static address, we need to search for
                          * the prefixlen in the nvlist `ifnvl'.

@@ -731,10 +727,11 @@
                          */
                         if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
                             nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
                                 status = i_ipadm_merge_prefixlen_from_nvl(ifnvl,
                                     nvl, aobjstr);
+
                                 if (status != IPADM_SUCCESS)
                                         continue;
                         }
                         status = i_ipadm_init_addrobj(iph, nvl);
                         /*

@@ -752,13 +749,13 @@
                         status = i_ipadm_init_ifprop(iph, nvl);
                 }
                 if (status != IPADM_SUCCESS)
                         return (status);
         }
-
-        if (is_ngz && af != AF_UNSPEC)
+        if (init_from_gz)
                 ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
+
         return (ret_status);
 }
 
 /*
  * Retrieves the persistent configuration for the given interface(s) in `ifs'

@@ -951,6 +948,33 @@
         } else {
                 if (darg.rsize != rsize)
                         err = EBADE;
         }
         return (err);
+}
+
+/*
+ * A helper that is used by i_ipadm_get_db_addr and i_ipadm_get_db_if
+ * to do a door_call to ipmgmtd, that should return persistent information
+ * about interfaces or/and addresses from ipadm DB
+ */
+ipadm_status_t
+i_ipadm_call_ipmgmtd(ipadm_handle_t iph, void *garg,
+        size_t garg_size, nvlist_t **onvl)
+{
+        ipmgmt_get_rval_t       *rvalp;
+        int                     err;
+        size_t                  nvlsize;
+        char                    *nvlbuf;
+
+        rvalp = malloc(sizeof (ipmgmt_get_rval_t));
+        err = ipadm_door_call(iph, garg, garg_size, (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));
 }