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,28 ****
--- 16,30 ----
   * 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,308 ****
                          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) {
                  goto fail;
!         }
          nvlist_free(onvl);
          return (IPADM_SUCCESS);
  fail:
          nvlist_free(onvl);
          return (IPADM_NOTFOUND);
--- 297,312 ----
                          break;
                  }
          }
          assert(af != AF_UNSPEC);
          if (nvpair_value_nvlist(nvp, &nvladdr) != 0 ||
!             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,391 ****
  
  /*
   * Gets all the addresses from active configuration and populates the
   * address information in `addrinfo'.
   */
! static 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;
--- 385,395 ----
  
  /*
   * Gets all the addresses from active configuration and populates the
   * address information in `addrinfo'.
   */
! 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,1721 ****
  
          /* 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,
--- 1715,1724 ----
*** 2407,2421 ****
                  *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
--- 2410,2422 ----
*** 2593,2606 ****
  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)
--- 2594,2603 ----
*** 2607,2626 ****
                  (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));
  }
  
  /*
   * Adds the IP address contained in the 'ipaddr' argument to the physical
   * interface represented by 'ifname' after doing the required validation.
--- 2604,2614 ----
                  (void) strlcpy(garg.ia_aobjname, aobjname,
                      sizeof (garg.ia_aobjname));
          if (ifname != NULL)
                  (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
  
!         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,2671 ****
          boolean_t               aobjfound;
          boolean_t               is_6to4;
          struct lifreq           lifr;
          uint64_t                ifflags;
          boolean_t               is_boot = (iph->iph_flags & IPH_IPMGMTD);
  
          /* 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.
--- 2640,2660 ----
          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,2805 ****
--- 2785,2805 ----
                  }
                  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,2822 ****
--- 2813,2828 ----
          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,2914 ****
  
          /*
           * 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);
--- 2891,2905 ----
*** 2927,2939 ****
                          goto ret;
                  }
          }
  
          if (flags & IPADM_OPT_UP) {
!                 status = i_ipadm_set_flags(iph, lifr.lifr_name, af, IFF_UP, 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;
--- 2918,2940 ----
                          goto ret;
                  }
          }
  
          if (flags & IPADM_OPT_UP) {
!                 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,2971 ****
--- 2963,2973 ----
                      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,3035 ****
--- 3028,3052 ----
          /*
           * 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,3054 ****
--- 3062,3077 ----
                           * 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,3584 ****
--- 3589,3610 ----
          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,3812 ****
          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);
  
          af = ipaddr->ipadm_af;
          af_exists = ipadm_if_enabled(iph, ifname, af);
          /*
           * For legacy case, interfaces are not implicitly plumbed. We need to
--- 3827,3843 ----
          if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC)
                  return (IPADM_NOTSUP);
  
          ifname = ipaddr->ipadm_ifname;
  
!         /*
!          * 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,3845 ****
  
          /* 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);
          }
--- 3857,3870 ----
  
          /* 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 (af_exists) {
                  status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
                  if (status != IPADM_SUCCESS)
                          return (status);
          }