Print this page
NEX-7823 ipmgmtd can't properly remove interface from the old ipadm.conf format
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Jean McCormack <jean.mccormack@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-2991 leaked buffer in libipadm`i_ipadm_init_ifs()
NEX-2395: new libipadm/ipadm/ipmgmtd shall be backward compatible with old ipadm.conf format
OS-161: Integrate IPMP changes
        
*** 19,29 ****
   * CDDL HEADER END
   */
  
  /*
   * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
!  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
   * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
   */
  
  #include <stdio.h>
  #include <stdlib.h>
--- 19,29 ----
   * CDDL HEADER END
   */
  
  /*
   * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
!  * Copyright 2016 Nexenta Systems, Inc.
   * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
   */
  
  #include <stdio.h>
  #include <stdlib.h>
*** 526,568 ****
          }
          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)
--- 526,535 ----
*** 691,734 ****
  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;
!         boolean_t       is_ngz = (iph->iph_zoneid != GLOBAL_ZONEID);
  
          (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 (status == IPADM_IF_EXISTS)
                                  status = IPADM_SUCCESS;
  
!                         if (is_ngz)
!                                 af = atoi(afstr);
!                 } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
                      &aobjstr) == 0) {
                          /*
                           * For addresses, we need to relocate addrprops from the
                           * nvlist `ifnvl'.
                           */
--- 658,743 ----
  ipadm_status_t
  i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
  {
          nvlist_t        *nvl = NULL;
          nvpair_t        *nvp;
!         ipadm_status_t  status = IPADM_ENXIO;
          ipadm_status_t  ret_status = IPADM_SUCCESS;
          char            newifname[LIFNAMSIZ];
          char            *aobjstr;
!         uint16_t        *afs;
!         char            *gifname;
!         uint_t          nelem = 0;
!         boolean_t       init_from_gz = B_FALSE;
!         boolean_t       move_to_group = B_FALSE;
  
          (void) strlcpy(newifname, ifname, sizeof (newifname));
+ 
          /*
!          * First go through the ifnvl nvlist looking for nested nvlist
!          * containing interface class and address families.
           */
          for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
              nvp = nvlist_next_nvpair(ifnvl, nvp)) {
!                 char *icstr;
!                 char **mifnames;
!                 uint32_t ipadm_flags = IPADM_OPT_ACTIVE;
! 
!                 if (nvpair_value_nvlist(nvp, &nvl) != 0 ||
!                     nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
!                     &afs, &nelem) != 0)
                          continue;
  
!                 /* Check if this is IPMP group interface */
!                 if (nvlist_lookup_string(nvl, IPADM_NVP_IFCLASS,
!                     &icstr) == 0 && atoi(icstr) == IPADM_IF_CLASS_IPMP)
!                         ipadm_flags |= IPADM_OPT_IPMP;
! 
!                 /* Create interfaces for address families specified */
!                 while (nelem-- > 0) {
!                         uint16_t af = afs[nelem];
! 
!                         assert(af == AF_INET || af == AF_INET6);
! 
!                         status = i_ipadm_plumb_if(iph, newifname, af,
!                             ipadm_flags);
                          if (status == IPADM_IF_EXISTS)
                                  status = IPADM_SUCCESS;
+                         if (status != IPADM_SUCCESS)
+                                 return (status);
+                 }
+                 if (nvlist_lookup_string(nvl, IPADM_NVP_GIFNAME,
+                     &gifname) == 0) {
+                         /*
+                          * IPMP underlying interface. Move to the
+                          * specified IPMP group.
+                          */
+                         move_to_group = B_TRUE;
+                 } else if ((ipadm_flags & IPADM_OPT_IPMP) &&
+                     nvlist_lookup_string_array(nvl, IPADM_NVP_MIFNAMES,
+                     &mifnames, &nelem) == 0) {
+                         /* Non-empty IPMP group interface */
+                         while (nelem-- > 0) {
+                                 (void) ipadm_add_ipmp_member(iph, newifname,
+                                     mifnames[nelem], IPADM_OPT_ACTIVE);
+                         }
+                 }
+                 if (iph->iph_zoneid != GLOBAL_ZONEID)
+                         init_from_gz = B_TRUE;
+         }
  
!         if (status != IPADM_SUCCESS)
!                 return (status);
! 
!         /*
!          * Go through the ifnvl nvlist again, applying persistent configuration.
!          */
!         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_AOBJNAME,
                      &aobjstr) == 0) {
                          /*
                           * For addresses, we need to relocate addrprops from the
                           * nvlist `ifnvl'.
                           */
*** 735,748 ****
--- 744,759 ----
                          if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
                              nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
                              nvlist_exists(nvl, IPADM_NVP_DHCP)) {
                                  status = i_ipadm_merge_addrprops_from_nvl(ifnvl,
                                      nvl, aobjstr);
+ 
                                  if (status != IPADM_SUCCESS)
                                          continue;
                          }
                          status = i_ipadm_init_addrobj(iph, nvl);
+ 
                          /*
                           * If this address is in use on some other interface,
                           * we want to record an error to be returned as
                           * a soft error and continue processing the rest of
                           * the addresses.
*** 749,767 ****
                           */
                          if (status == IPADM_ADDR_NOTAVAIL) {
                                  ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
                                  status = IPADM_SUCCESS;
                          }
!                 } else {
!                         assert(nvlist_exists(nvl, IPADM_NVP_PROTONAME));
                          status = i_ipadm_init_ifprop(iph, nvl);
                  }
                  if (status != IPADM_SUCCESS)
                          return (status);
          }
! 
!         if (is_ngz && af != AF_UNSPEC)
                  ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
          return (ret_status);
  }
  
  /*
--- 760,780 ----
                           */
                          if (status == IPADM_ADDR_NOTAVAIL) {
                                  ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
                                  status = IPADM_SUCCESS;
                          }
!                 } else if (nvlist_exists(nvl, IPADM_NVP_PROTONAME) == B_TRUE) {
                          status = i_ipadm_init_ifprop(iph, nvl);
                  }
                  if (status != IPADM_SUCCESS)
                          return (status);
          }
!         if (move_to_group) {
!                 (void) ipadm_add_ipmp_member(iph, gifname, newifname,
!                     IPADM_OPT_ACTIVE);
!         }
!         if (init_from_gz)
                  ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
          return (ret_status);
  }
  
  /*
*** 957,966 ****
--- 970,1006 ----
                          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));
+ }
+ 
  /*
   * ipadm_is_nil_hostname() : Determine if the `hostname' is nil: i.e.,
   *                      NULL, empty, or a single space (e.g., as returned by
   *                      domainname(1M)/sysinfo).
   *