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);
}