summaryrefslogtreecommitdiff
path: root/usr/src/lib/libipadm
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libipadm')
-rw-r--r--usr/src/lib/libipadm/Makefile.com3
-rw-r--r--usr/src/lib/libipadm/common/ipadm_addr.c169
-rw-r--r--usr/src/lib/libipadm/common/ipadm_if.c706
-rw-r--r--usr/src/lib/libipadm/common/ipadm_ipmgmt.h71
-rw-r--r--usr/src/lib/libipadm/common/ipadm_persist.c236
-rw-r--r--usr/src/lib/libipadm/common/ipadm_prop.c53
-rw-r--r--usr/src/lib/libipadm/common/libipadm.c164
-rw-r--r--usr/src/lib/libipadm/common/libipadm.h46
-rw-r--r--usr/src/lib/libipadm/common/libipadm_impl.h24
-rw-r--r--usr/src/lib/libipadm/common/mapfile-vers3
10 files changed, 1146 insertions, 329 deletions
diff --git a/usr/src/lib/libipadm/Makefile.com b/usr/src/lib/libipadm/Makefile.com
index 80c052fffd..aed875db48 100644
--- a/usr/src/lib/libipadm/Makefile.com
+++ b/usr/src/lib/libipadm/Makefile.com
@@ -22,6 +22,7 @@
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
#
LIBRARY = libipadm.a
@@ -36,7 +37,7 @@ include ../../Makefile.rootfs
LIBS = $(DYNLIB)
LDLIBS += -lc -linetutil -lsocket -ldlpi -lnvpair -ldhcpagent \
- -ldladm -lsecdb -ldhcputil
+ -ldladm -lsecdb -ldhcputil -lipmp -lcmdutils
SRCDIR = ../common
diff --git a/usr/src/lib/libipadm/common/ipadm_addr.c b/usr/src/lib/libipadm/common/ipadm_addr.c
index 4bca7ecb4f..6bdfc487d3 100644
--- a/usr/src/lib/libipadm/common/ipadm_addr.c
+++ b/usr/src/lib/libipadm/common/ipadm_addr.c
@@ -18,10 +18,12 @@
*
* CDDL HEADER END
*/
+
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
+ * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
*/
/*
@@ -282,8 +284,11 @@ i_ipadm_get_static_addr_db(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
nvlist_exists(anvl, IPADM_NVP_IPV6ADDR))
break;
}
+ nvlist_free(onvl);
+
if (nvp == NULL)
- goto fail;
+ return (IPADM_NOTFOUND);
+
for (nvp = nvlist_next_nvpair(anvl, NULL);
nvp != NULL; nvp = nvlist_next_nvpair(anvl, nvp)) {
name = nvpair_name(nvp);
@@ -296,16 +301,13 @@ i_ipadm_get_static_addr_db(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
}
}
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);
+ ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS)
+ return (IPADM_NOTFOUND);
+
return (IPADM_SUCCESS);
-fail:
- nvlist_free(onvl);
- return (IPADM_NOTFOUND);
}
/*
@@ -383,7 +385,7 @@ ipadm_delete_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
* 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)
{
@@ -1713,7 +1715,6 @@ ipadm_set_addrprop(ipadm_handle_t iph, const char *pname,
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
@@ -2409,11 +2410,9 @@ ipadm_create_addrobj(ipadm_addr_type_t type, const char *aobjname,
/* 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);
@@ -2595,10 +2594,6 @@ 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));
@@ -2609,16 +2604,7 @@ i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname,
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, 0);
- }
- free(rvalp);
- return (ipadm_errno2status(err));
+ return (i_ipadm_call_ipmgmtd(iph, (void *) &garg, sizeof (garg), onvl));
}
/*
@@ -2654,6 +2640,8 @@ ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
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())
@@ -2663,7 +2651,6 @@ ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
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,
@@ -2798,6 +2785,17 @@ ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
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) {
@@ -2815,6 +2813,12 @@ ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
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
@@ -2887,25 +2891,10 @@ i_ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr, uint32_t flags)
* 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));
@@ -2929,7 +2918,18 @@ retry:
}
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.
@@ -2964,6 +2964,7 @@ retry:
ret:
if (status != IPADM_SUCCESS && !legacy)
(void) i_ipadm_delete_addr(iph, ipaddr);
+
return (status);
}
@@ -2990,6 +2991,8 @@ ipadm_delete_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
ipadm_status_t status;
struct ipadm_addrobj_s ipaddr;
boolean_t release = ((flags & IPADM_OPT_RELEASE) != 0);
+ boolean_t is_ipmp = B_FALSE;
+ char gifname[LIFGRNAMSIZ];
/* check for solaris.network.interface.config authorization */
if (!ipadm_check_auth())
@@ -3028,6 +3031,19 @@ ipadm_delete_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
* kernel.
*/
if (ipaddr.ipadm_flags & IPMGMT_ACTIVE) {
+
+ /*
+ * 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);
@@ -3056,7 +3072,7 @@ ipadm_delete_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
if (status == IPADM_ENXIO)
status = IPADM_SUCCESS;
else if (status != IPADM_SUCCESS)
- return (status);
+ goto out;
}
if (!(ipaddr.ipadm_flags & IPMGMT_PERSIST) &&
@@ -3064,9 +3080,22 @@ ipadm_delete_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
flags &= ~IPADM_OPT_PERSIST;
}
status = i_ipadm_delete_addrobj(iph, &ipaddr, flags);
- if (status == IPADM_NOTFOUND)
- return (status);
- return (IPADM_SUCCESS);
+
+ if (status != IPADM_NOTFOUND)
+ status = IPADM_SUCCESS;
+
+out:
+ /*
+ * Move the underlying IPMP interface back to the group.
+ * This cannot be done until the persistent configuration has been
+ * deleted as it will otherwise cause the active configuration to be
+ * restored.
+ */
+ if (is_ipmp) {
+ (void) i_ipadm_set_groupname_active(iph,
+ ipaddr.ipadm_ifname, gifname);
+ }
+ return (status);
}
/*
@@ -3568,15 +3597,18 @@ i_ipadm_updown_common(ipadm_handle_t iph, const char *aobjname,
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));
}
@@ -3803,8 +3835,13 @@ i_ipadm_validate_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
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);
@@ -3828,16 +3865,10 @@ i_ipadm_validate_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
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)
@@ -3957,6 +3988,8 @@ ipadm_enable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
for (nvp = nvlist_next_nvpair(addrnvl, NULL); nvp != NULL;
nvp = nvlist_next_nvpair(addrnvl, nvp)) {
+ boolean_t set_init = B_FALSE;
+
if (nvpair_value_nvlist(nvp, &nvl) != 0)
continue;
@@ -3968,9 +4001,27 @@ ipadm_enable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
if (status != IPADM_SUCCESS)
continue;
}
- iph->iph_flags |= IPH_INIT;
+
+ /*
+ * ipadm_enable_addr() is never a persistent operation. We need
+ * to set IPH_INIT because ipmgmtd daemon does not have to write
+ * the address to the persistent db. The address is already
+ * available in the persistent db and we are here to re-enable
+ * the persistent configuration.
+ *
+ * But we need to make sure we're not accidentally clearing an
+ * IPH_INIT flag that was already set when we were called.
+ */
+ if ((iph->iph_flags & IPH_INIT) == 0) {
+ iph->iph_flags |= IPH_INIT;
+ set_init = B_TRUE;
+ }
+
status = i_ipadm_init_addrobj(iph, nvl);
- iph->iph_flags &= ~IPH_INIT;
+
+ if (set_init)
+ iph->iph_flags &= ~IPH_INIT;
+
if (status != IPADM_SUCCESS)
break;
}
diff --git a/usr/src/lib/libipadm/common/ipadm_if.c b/usr/src/lib/libipadm/common/ipadm_if.c
index c140f4ca40..73508c0d34 100644
--- a/usr/src/lib/libipadm/common/ipadm_if.c
+++ b/usr/src/lib/libipadm/common/ipadm_if.c
@@ -18,13 +18,15 @@
*
* CDDL HEADER END
*/
+
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2021, Tintry by DDN. All rights reserved.
+ * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
*/
#include <errno.h>
#include <sys/sockio.h>
+#include <sys/list.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
@@ -37,6 +39,7 @@
#include <limits.h>
#include <zone.h>
#include <ipadm_ndpd.h>
+#include <ipmp_query.h>
#include "libipadm_impl.h"
static ipadm_status_t i_ipadm_slifname_arp(char *, uint64_t, int);
@@ -45,7 +48,22 @@ static ipadm_status_t i_ipadm_slifname(ipadm_handle_t, char *, char *,
static ipadm_status_t i_ipadm_create_ipmp_peer(ipadm_handle_t, char *,
sa_family_t);
static ipadm_status_t i_ipadm_persist_if(ipadm_handle_t, const char *,
- sa_family_t);
+ sa_family_t, uint32_t);
+static ipadm_status_t i_ipadm_allocate_ifinfo(ipadm_if_info_t **);
+static ipadm_status_t i_ipadm_get_db_if(ipadm_handle_t, const char *,
+ nvlist_t **);
+static ipadm_status_t i_ipadm_nvl2ifinfo(nvlist_t *, ipadm_if_info_t **);
+static ipadm_status_t i_ipadm_fill_cmembers(char *, ipadm_ipmp_members_t *);
+static ipadm_status_t i_ipadm_fill_pmembers(nvlist_t *, ipadm_ipmp_members_t *);
+static ipadm_status_t i_ipadm_add_persistent_if_info(ipadm_if_info_t *,
+ ipadm_if_info_t *);
+static void i_ipadm_free_ipmp_members(ipadm_ipmp_members_t *);
+static ipadm_status_t i_ipadm_persist_update_ipmp(ipadm_handle_t, const char *,
+ const char *,
+ ipadm_ipmp_op_t);
+static ipadm_status_t i_ipadm_update_ipmp(ipadm_handle_t, const char *,
+ const char *, uint32_t,
+ ipadm_ipmp_op_t);
/*
* Returns B_FALSE if the interface in `ifname' has at least one address that is
@@ -83,17 +101,17 @@ i_ipadm_is_if_down(char *ifname, struct ifaddrs *ifa)
*/
static ipadm_status_t
i_ipadm_active_if_info(ipadm_handle_t iph, const char *ifname,
- ipadm_if_info_list_t **if_info, int64_t lifc_flags)
+ ipadm_if_info_t **if_info, int64_t lifc_flags)
{
struct lifreq *buf;
struct lifreq *lifrp;
struct lifreq lifrl;
- ipadm_if_info_list_t *ifl, *last = NULL;
+ ipadm_if_info_t *last = NULL;
ipadm_if_info_t *ifp;
int s;
int n;
int numifs;
- ipadm_status_t status;
+ ipadm_status_t status = IPADM_SUCCESS;
*if_info = NULL;
/*
@@ -118,26 +136,23 @@ i_ipadm_active_if_info(ipadm_handle_t iph, const char *ifname,
* Check if the interface already exists in our list.
* If it already exists, we need to update its flags.
*/
- for (ifl = *if_info; ifl != NULL; ifl = ifl->ifil_next) {
- ifp = &ifl->ifil_ifi;
+ for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) {
if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0)
break;
}
- if (ifl == NULL) {
- ifl = calloc(1, sizeof (ipadm_if_info_list_t));
- if (ifl == NULL) {
- status = ipadm_errno2status(errno);
- goto fail;
- }
- ifp = &ifl->ifil_ifi;
+ if (ifp == NULL) {
+ if ((status =
+ i_ipadm_allocate_ifinfo(&ifp)) != IPADM_SUCCESS)
+ break;
+
(void) strlcpy(ifp->ifi_name, lifrp->lifr_name,
sizeof (ifp->ifi_name));
- /* Update the `ifil_next' pointer for this new node */
+ /* Update the `ifi_next' pointer for this new node */
if (*if_info == NULL)
- *if_info = ifl;
+ *if_info = ifp;
else
- last->ifil_next = ifl;
- last = ifl;
+ last->ifi_next = ifp;
+ last = ifp;
}
/*
@@ -150,16 +165,24 @@ i_ipadm_active_if_info(ipadm_handle_t iph, const char *ifname,
iph->iph_sock : iph->iph_sock6;
if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
continue;
+
+ /* a regular interface by default */
+ ifp->ifi_class = IPADM_IF_CLASS_REGULAR;
+
if (lifrl.lifr_flags & IFF_BROADCAST)
ifp->ifi_cflags |= IFIF_BROADCAST;
if (lifrl.lifr_flags & IFF_MULTICAST)
ifp->ifi_cflags |= IFIF_MULTICAST;
if (lifrl.lifr_flags & IFF_POINTOPOINT)
ifp->ifi_cflags |= IFIF_POINTOPOINT;
- if (lifrl.lifr_flags & IFF_VIRTUAL)
+ if (lifrl.lifr_flags & IFF_VIRTUAL) {
ifp->ifi_cflags |= IFIF_VIRTUAL;
- if (lifrl.lifr_flags & IFF_IPMP)
+ ifp->ifi_class = IPADM_IF_CLASS_VIRTUAL;
+ }
+ if (lifrl.lifr_flags & IFF_IPMP) {
ifp->ifi_cflags |= IFIF_IPMP;
+ ifp->ifi_class = IPADM_IF_CLASS_IPMP;
+ }
if (lifrl.lifr_flags & IFF_STANDBY)
ifp->ifi_cflags |= IFIF_STANDBY;
if (lifrl.lifr_flags & IFF_INACTIVE)
@@ -174,13 +197,25 @@ i_ipadm_active_if_info(ipadm_handle_t iph, const char *ifname,
ifp->ifi_cflags |= IFIF_IPV6;
if (lifrl.lifr_flags & IFF_L3PROTECT)
ifp->ifi_cflags |= IFIF_L3PROTECT;
+
+ /*
+ * Retrieve active IPMP members. This may fail in in.mpathd if
+ * the IPMP interface has just been created with no members.
+ * Hence, ignore errors, cmembers will just be empty.
+ */
+ if (ifp->ifi_class == IPADM_IF_CLASS_IPMP) {
+ if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifrl) == 0) {
+ (void) i_ipadm_fill_cmembers(
+ lifrl.lifr_groupname,
+ &ifp->ifi_ipmp_cmembers);
+ }
+ }
}
free(buf);
- return (IPADM_SUCCESS);
-fail:
- free(buf);
- ipadm_free_if_info(*if_info);
- *if_info = NULL;
+ if (status != IPADM_SUCCESS) {
+ ipadm_free_if_info(*if_info);
+ *if_info = NULL;
+ }
return (status);
}
@@ -191,54 +226,153 @@ fail:
*/
static ipadm_status_t
i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname,
- ipadm_if_info_list_t **if_info)
+ ipadm_if_info_t **if_info)
{
- ipadm_status_t status = IPADM_SUCCESS;
- ipmgmt_getif_arg_t getif;
- ipmgmt_getif_rval_t *rvalp;
- ipadm_if_info_t *ifp;
- ipadm_if_info_list_t *curr, *prev = NULL;
- int i = 0, err = 0;
-
- bzero(&getif, sizeof (getif));
- if (ifname != NULL)
- (void) strlcpy(getif.ia_ifname, ifname, LIFNAMSIZ);
- getif.ia_cmd = IPMGMT_CMD_GETIF;
+ ipadm_status_t status = IPADM_SUCCESS;
+ nvlist_t *ifs_info_nvl;
*if_info = NULL;
- if ((rvalp = malloc(sizeof (ipmgmt_getif_rval_t))) == NULL)
- return (ipadm_errno2status(errno));
- err = ipadm_door_call(iph, &getif, sizeof (getif), (void **)&rvalp,
- sizeof (*rvalp), B_TRUE);
- if (err == ENOENT) {
- free(rvalp);
- if (ifname != NULL)
- return (ipadm_errno2status(err));
- return (IPADM_SUCCESS);
- } else if (err != 0) {
- free(rvalp);
- return (ipadm_errno2status(err));
- }
+ if ((status = i_ipadm_get_db_if(iph,
+ ifname, &ifs_info_nvl)) != IPADM_SUCCESS)
+ return (status);
- ifp = rvalp->ir_ifinfo;
- for (i = 0; i < rvalp->ir_ifcnt; i++) {
- ifp = rvalp->ir_ifinfo + i;
- if ((curr = malloc(sizeof (*curr))) == NULL) {
- status = ipadm_errno2status(errno);
- ipadm_free_if_info(prev);
+ assert(ifs_info_nvl != NULL);
+
+ return (i_ipadm_nvl2ifinfo(ifs_info_nvl, if_info));
+}
+
+static ipadm_status_t
+i_ipadm_nvl2ifinfo(nvlist_t *ifs_info_nvl, ipadm_if_info_t **if_info)
+{
+ ipadm_if_info_t *ific = NULL, *ifil = NULL;
+ nvlist_t *if_info_nvl;
+ nvpair_t *nvp;
+ char *strval;
+ ipadm_status_t status = IPADM_SUCCESS;
+ uint16_t *families;
+ uint_t nelem = 0;
+
+ for (nvp = nvlist_next_nvpair(ifs_info_nvl, NULL); nvp != NULL;
+ nvp = nvlist_next_nvpair(ifs_info_nvl, nvp)) {
+ if (nvpair_value_nvlist(nvp, &if_info_nvl) != 0)
+ continue;
+
+ status = i_ipadm_allocate_ifinfo(&ific);
+ if (status != IPADM_SUCCESS) {
+ ipadm_free_if_info(*if_info);
break;
}
- (void) bcopy(ifp, &curr->ifil_ifi, sizeof (*ifp));
- curr->ifil_next = prev;
- prev = curr;
+ if (nvlist_lookup_string(if_info_nvl, IPADM_NVP_IFNAME,
+ &strval) != 0) {
+ ipadm_free_if_info(ific);
+ ific = NULL;
+ continue;
+ }
+ (void) strlcpy(ific->ifi_name, strval,
+ sizeof (ific->ifi_name));
+
+ if (nvlist_lookup_uint16_array(if_info_nvl,
+ IPADM_NVP_FAMILIES, &families, &nelem) == 0) {
+ while (nelem-- > 0) {
+ if (families[nelem] == AF_INET)
+ ific->ifi_pflags |= IFIF_IPV4;
+ else if (families[nelem] == AF_INET6)
+ ific->ifi_pflags |= IFIF_IPV6;
+ }
+ }
+
+ if (nvlist_lookup_string(if_info_nvl,
+ IPADM_NVP_IFCLASS, &strval) == 0)
+ ific->ifi_class = atoi(strval);
+ else
+ ific->ifi_class = IPADM_IF_CLASS_REGULAR;
+
+ if (ific->ifi_class == IPADM_IF_CLASS_IPMP)
+ /* do not expect any failures there */
+ (void) i_ipadm_fill_pmembers(if_info_nvl,
+ &ific->ifi_ipmp_pmembers);
+
+ if (*if_info == NULL)
+ *if_info = ific;
+ else
+ ifil->ifi_next = ific;
+ ifil = ific;
}
- *if_info = curr;
- free(rvalp);
+
+ nvlist_free(ifs_info_nvl);
return (status);
}
/*
+ * Fill the ipadm_if_info_t->ifi_ipmp_pmembers by info from
+ * ipadm DB
+ */
+static ipadm_status_t
+i_ipadm_fill_pmembers(nvlist_t *if_info_nvl, ipadm_ipmp_members_t *pmembers)
+{
+ uint_t nelem = 0;
+ char **members;
+ ipadm_ipmp_member_t *ipmp_member;
+
+ if (nvlist_lookup_string_array(if_info_nvl, IPADM_NVP_MIFNAMES,
+ &members, &nelem) != 0)
+ return (IPADM_SUCCESS);
+
+ while (nelem-- > 0) {
+ if ((ipmp_member = calloc(1,
+ sizeof (ipadm_ipmp_member_t))) == NULL)
+ return (ipadm_errno2status(errno));
+
+ (void) strlcpy(ipmp_member->if_name, members[nelem],
+ sizeof (ipmp_member->if_name));
+ list_insert_tail(pmembers, ipmp_member);
+ }
+ return (IPADM_SUCCESS);
+}
+
+/*
+ * Fill the ipadm_if_info_t->ifi_ipmp_cmembers by info from
+ * kernel (libipmp is used to retrieve the required info)
+ */
+static ipadm_status_t
+i_ipadm_fill_cmembers(char *grname, ipadm_ipmp_members_t *cmembers)
+{
+ ipmp_handle_t ipmp_handle;
+ ipmp_groupinfo_t *grinfo;
+ ipmp_iflist_t *iflistp;
+ ipadm_ipmp_member_t *ipmp_member;
+ ipadm_status_t ipadm_status = IPADM_SUCCESS;
+ int i;
+
+ if (ipmp_open(&ipmp_handle) != IPMP_SUCCESS)
+ return (IPADM_FAILURE);
+
+ if (ipmp_getgroupinfo(ipmp_handle, grname, &grinfo) != IPMP_SUCCESS) {
+ ipadm_status = IPADM_FAILURE;
+ goto fail2;
+ }
+
+ iflistp = grinfo->gr_iflistp;
+ for (i = 0; i < iflistp->il_nif; i++) {
+ if ((ipmp_member = calloc(1,
+ sizeof (ipadm_ipmp_member_t))) == NULL) {
+ ipadm_status = ipadm_errno2status(errno);
+ goto fail1;
+ }
+ (void) strlcpy(ipmp_member->if_name, iflistp->il_ifs[i],
+ sizeof (ipmp_member->if_name));
+ list_insert_tail(cmembers, ipmp_member);
+ }
+
+fail1:
+ ipmp_freegroupinfo(grinfo);
+fail2:
+ ipmp_close(ipmp_handle);
+ return (ipadm_status);
+}
+
+/*
* Collects information for `ifname' if one is specified from both
* active and persistent config in `if_info'. If no `ifname' is specified,
* this returns all the interfaces in active and persistent config in
@@ -246,16 +380,14 @@ i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname,
*/
ipadm_status_t
i_ipadm_get_all_if_info(ipadm_handle_t iph, const char *ifname,
- ipadm_if_info_list_t **if_info, int64_t lifc_flags)
+ ipadm_if_info_t **if_info, int64_t lifc_flags)
{
ipadm_status_t status;
- ipadm_if_info_list_t *aifinfo = NULL;
- ipadm_if_info_list_t *pifinfo = NULL;
- ipadm_if_info_list_t *last = NULL;
- ipadm_if_info_list_t *aifl;
- ipadm_if_info_list_t *pifl;
+ ipadm_if_info_t *aifinfo = NULL;
+ ipadm_if_info_t *pifinfo = NULL;
ipadm_if_info_t *aifp;
ipadm_if_info_t *pifp;
+ ipadm_if_info_t *last = NULL;
struct ifaddrs *ifa;
struct ifaddrs *ifap;
@@ -275,9 +407,7 @@ retry:
status = ipadm_errno2status(errno);
goto fail;
}
- for (aifl = aifinfo; aifl != NULL; aifl = aifl->ifil_next) {
- aifp = &aifl->ifil_ifi;
-
+ for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
/*
* Find the `ifaddrs' structure from `ifa'
* for this interface. We need the IFF_* flags
@@ -307,8 +437,8 @@ retry:
aifp->ifi_state = IFIS_DOWN;
else
aifp->ifi_state = IFIS_OK;
- if (aifl->ifil_next == NULL)
- last = aifl;
+ if (aifp->ifi_next == NULL)
+ last = aifp;
}
freeifaddrs(ifa);
}
@@ -322,37 +452,55 @@ retry:
}
if (status != IPADM_SUCCESS)
goto fail;
+
/*
- * If a persistent interface is also found in `aifinfo', update
+ * Process the persistent interface information.
+ *
+ * First try to get the persistent "standby" property, as that isn't
+ * retrieved by i_ipadm_persist_if_info().
+ *
+ * Next, if a persistent interface is also found in `aifinfo', update
* its entry in `aifinfo' with the persistent information from
* `pifinfo'. If an interface is found in `pifinfo', but not in
* `aifinfo', it means that this interface was disabled. We should
* add this interface to `aifinfo' and set it state to IFIF_DISABLED.
*/
- for (pifl = pifinfo; pifl != NULL; pifl = pifl->ifil_next) {
- pifp = &pifl->ifil_ifi;
- for (aifl = aifinfo; aifl != NULL; aifl = aifl->ifil_next) {
- aifp = &aifl->ifil_ifi;
+ for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) {
+ char buf[10] = "";
+ uint_t bufsize = sizeof (buf);
+
+ status = ipadm_get_ifprop(iph, pifp->ifi_name, "standby", buf,
+ &bufsize, MOD_PROTO_IP, IPADM_OPT_PERSIST);
+
+ if (status == IPADM_SUCCESS && strcmp(buf, "on") == 0)
+ pifp->ifi_pflags |= IFIF_STANDBY;
+
+ for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) {
- aifp->ifi_pflags = pifp->ifi_pflags;
break;
}
}
- if (aifl == NULL) {
- aifl = malloc(sizeof (ipadm_if_info_list_t));
- if (aifl == NULL) {
- status = ipadm_errno2status(errno);
+
+ if (aifp == NULL) {
+ if ((status =
+ i_ipadm_allocate_ifinfo(&aifp)) != IPADM_SUCCESS)
goto fail;
- }
- *aifl = *pifl;
- aifl->ifil_next = NULL;
- aifl->ifil_ifi.ifi_state = IFIS_DISABLED;
+
+ (void) strlcpy(aifp->ifi_name, pifp->ifi_name,
+ sizeof (aifp->ifi_name));
+
+ aifp->ifi_next = NULL;
+ aifp->ifi_state = IFIS_DISABLED;
if (last != NULL)
- last->ifil_next = aifl;
+ last->ifi_next = aifp;
else
- aifinfo = aifl;
- last = aifl;
+ aifinfo = aifp;
+ last = aifp;
}
+
+ if ((status = i_ipadm_add_persistent_if_info(aifp,
+ pifp)) != IPADM_SUCCESS)
+ goto fail;
}
*if_info = aifinfo;
ipadm_free_if_info(pifinfo);
@@ -364,6 +512,75 @@ fail:
return (status);
}
+/*
+ * Updates active if_info by data from persistent if_info
+ */
+static ipadm_status_t
+i_ipadm_add_persistent_if_info(ipadm_if_info_t *aifp, ipadm_if_info_t *pifp)
+{
+ ipadm_ipmp_member_t *pp_ipmp_member, *ap_ipmp_member;
+
+ ipadm_ipmp_members_t *apmembers = &aifp->ifi_ipmp_pmembers;
+ ipadm_ipmp_members_t *ppmembers = &pifp->ifi_ipmp_pmembers;
+
+ aifp->ifi_pflags = pifp->ifi_pflags;
+ aifp->ifi_class = pifp->ifi_class;
+
+ for (pp_ipmp_member = list_head(ppmembers); pp_ipmp_member;
+ pp_ipmp_member = list_next(ppmembers, pp_ipmp_member)) {
+ if ((ap_ipmp_member = calloc(1,
+ sizeof (ipadm_ipmp_member_t))) == NULL)
+ return (ipadm_errno2status(errno));
+
+ (void) strlcpy(ap_ipmp_member->if_name,
+ pp_ipmp_member->if_name,
+ sizeof (ap_ipmp_member->if_name));
+
+ list_insert_tail(apmembers, ap_ipmp_member);
+ }
+ return (IPADM_SUCCESS);
+}
+
+static ipadm_status_t
+i_ipadm_allocate_ifinfo(ipadm_if_info_t **if_info)
+{
+ *if_info = calloc(1, sizeof (ipadm_if_info_t));
+ if (*if_info == NULL)
+ return (ipadm_errno2status(errno));
+
+ /* List of active (current) members */
+ list_create(&((*if_info)->ifi_ipmp_cmembers),
+ sizeof (ipadm_ipmp_member_t),
+ offsetof(ipadm_ipmp_member_t, node));
+
+ /* List of persistent members */
+ list_create(&((*if_info)->ifi_ipmp_pmembers),
+ sizeof (ipadm_ipmp_member_t),
+ offsetof(ipadm_ipmp_member_t, node));
+
+ return (IPADM_SUCCESS);
+}
+
+/*
+ * Reads all the interface lines from the persistent DB into the nvlist `onvl',
+ * when `ifname' is NULL.
+ * If an `ifname' is specified, then the interface line corresponding to
+ * that name will be returned.
+ */
+static ipadm_status_t
+i_ipadm_get_db_if(ipadm_handle_t iph, const char *ifname, nvlist_t **onvl)
+{
+ ipmgmt_getif_arg_t garg;
+
+ /* Populate the door_call argument structure */
+ bzero(&garg, sizeof (garg));
+ garg.ia_cmd = IPMGMT_CMD_GETIF;
+ if (ifname != NULL)
+ (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
+
+ return (i_ipadm_call_ipmgmtd(iph, (void *) &garg, sizeof (garg), onvl));
+}
+
int
i_ipadm_get_lnum(const char *ifname)
{
@@ -385,7 +602,7 @@ ipadm_status_t
i_ipadm_if_pexists(ipadm_handle_t iph, const char *ifname, sa_family_t af,
boolean_t *exists)
{
- ipadm_if_info_list_t *ifinfo;
+ ipadm_if_info_t *ifinfo;
ipadm_status_t status;
/*
@@ -400,10 +617,10 @@ i_ipadm_if_pexists(ipadm_handle_t iph, const char *ifname, sa_family_t af,
status = i_ipadm_persist_if_info(iph, ifname, &ifinfo);
if (status == IPADM_SUCCESS) {
*exists = ((af == AF_INET &&
- (ifinfo->ifil_ifi.ifi_pflags & IFIF_IPV4)) ||
+ (ifinfo->ifi_pflags & IFIF_IPV4)) ||
(af == AF_INET6 &&
- (ifinfo->ifil_ifi.ifi_pflags & IFIF_IPV6)));
- free(ifinfo);
+ (ifinfo->ifi_pflags & IFIF_IPV6)));
+ ipadm_free_if_info(ifinfo);
} else if (status == IPADM_NOTFOUND) {
status = IPADM_SUCCESS;
*exists = B_FALSE;
@@ -742,7 +959,8 @@ i_ipadm_plumb_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
return (ipadm_errno2status(errno));
if (is_persistent) {
- status = i_ipadm_persist_if(iph, ifname, af);
+ status = i_ipadm_persist_if(iph,
+ ifname, af, ipadm_flags);
if (status != IPADM_SUCCESS) {
(void) i_ipadm_delete_if(iph, ifname,
af, IPADM_OPT_ACTIVE);
@@ -923,7 +1141,8 @@ done:
* interface in persistent DB.
*/
if (is_persistent) {
- status = i_ipadm_persist_if(iph, newif, af);
+ status = i_ipadm_persist_if(iph,
+ newif, af, ipadm_flags);
if (status != IPADM_SUCCESS) {
(void) i_ipadm_delete_if(iph, newif, af,
IPADM_OPT_ACTIVE);
@@ -1156,13 +1375,19 @@ done:
* persistent DB.
*/
static ipadm_status_t
-i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
+i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
+ uint32_t ipadm_flags)
{
ipmgmt_if_arg_t ifarg;
int err;
(void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname));
ifarg.ia_family = af;
+ if (ipadm_flags & IPADM_OPT_IPMP)
+ ifarg.ia_ifclass = IPADM_IF_CLASS_IPMP;
+ else
+ ifarg.ia_ifclass = IPADM_IF_CLASS_REGULAR;
+
ifarg.ia_cmd = IPMGMT_CMD_SETIF;
ifarg.ia_flags = IPMGMT_PERSIST;
err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
@@ -1355,6 +1580,109 @@ ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
return (IPADM_SUCCESS);
}
+ipadm_status_t
+ipadm_add_ipmp_member(ipadm_handle_t iph, const char *gifname,
+ const char *mifname, uint32_t ipadm_flags)
+{
+ return (i_ipadm_update_ipmp(iph, gifname, mifname,
+ ipadm_flags, IPADM_ADD_IPMP));
+}
+
+ipadm_status_t
+ipadm_remove_ipmp_member(ipadm_handle_t iph, const char *gifname,
+ const char *mifname, uint32_t ipadm_flags)
+{
+ return (i_ipadm_update_ipmp(iph, gifname, mifname,
+ ipadm_flags, IPADM_REMOVE_IPMP));
+}
+
+/*
+ * Updates active IPMP configuration according to the specified
+ * command. It also persists the configuration if IPADM_OPT_PERSIST
+ * is set in `ipadm_flags'.
+ */
+static ipadm_status_t
+i_ipadm_update_ipmp(ipadm_handle_t iph, const char *gifname,
+ const char *mifname, uint32_t ipadm_flags, ipadm_ipmp_op_t op)
+{
+ ipadm_status_t status;
+ char groupname1[LIFGRNAMSIZ];
+ char groupname2[LIFGRNAMSIZ];
+
+ /* Check for the required authorization */
+ if (!ipadm_check_auth())
+ return (IPADM_EAUTH);
+
+ if (!(ipadm_flags & IPADM_OPT_ACTIVE) ||
+ gifname == NULL || mifname == NULL)
+ return (IPADM_INVALID_ARG);
+
+ if (!ipadm_if_enabled(iph, gifname, AF_UNSPEC) ||
+ !ipadm_if_enabled(iph, mifname, AF_UNSPEC))
+ return (IPADM_OP_DISABLE_OBJ);
+
+ if (!i_ipadm_is_ipmp(iph, gifname))
+ return (IPADM_INVALID_ARG);
+
+ if (op == IPADM_ADD_IPMP && i_ipadm_is_under_ipmp(iph, mifname))
+ return (IPADM_IF_INUSE);
+
+ if ((status = i_ipadm_get_groupname_active(iph, gifname,
+ groupname2, sizeof (groupname2))) != IPADM_SUCCESS)
+ return (status);
+
+ if (op == IPADM_REMOVE_IPMP) {
+ if ((status = i_ipadm_get_groupname_active(iph, mifname,
+ groupname1, sizeof (groupname1))) != IPADM_SUCCESS)
+ return (status);
+
+ if (groupname1[0] == '\0' ||
+ strcmp(groupname1, groupname2) != 0)
+ return (IPADM_INVALID_ARG);
+
+ groupname2[0] = '\0';
+ }
+
+ if ((ipadm_flags & IPADM_OPT_PERSIST) &&
+ (status = i_ipadm_persist_update_ipmp(iph, gifname,
+ mifname, op)) != IPADM_SUCCESS)
+ return (status);
+
+ return (i_ipadm_set_groupname_active(iph, mifname, groupname2));
+}
+
+/*
+ * Call the ipmgmtd to update the IPMP configuration in ipadm DB.
+ * After this call the DB will know that mifname is under gifname and
+ * gifname has a member, which name is mifname.
+ */
+static ipadm_status_t
+i_ipadm_persist_update_ipmp(ipadm_handle_t iph, const char *gifname,
+ const char *mifname, ipadm_ipmp_op_t op)
+{
+ ipmgmt_ipmp_update_arg_t args;
+ int err;
+
+ assert(op == IPADM_ADD_IPMP || op == IPADM_REMOVE_IPMP);
+
+ bzero(&args, sizeof (ipmgmt_ipmp_update_arg_t));
+
+ args.ia_cmd = IPMGMT_CMD_IPMP_UPDATE;
+
+ (void) strlcpy(args.ia_gifname, gifname, sizeof (args.ia_gifname));
+ (void) strlcpy(args.ia_mifname, mifname, sizeof (args.ia_mifname));
+
+ if (op == IPADM_ADD_IPMP)
+ args.ia_flags = IPMGMT_APPEND;
+ else
+ args.ia_flags = IPMGMT_REMOVE;
+
+ args.ia_flags |= IPMGMT_PERSIST;
+
+ err = ipadm_door_call(iph, &args, sizeof (args), NULL, 0, B_FALSE);
+ return (ipadm_errno2status(err));
+}
+
/*
* Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
* when `af' = AF_UNSPEC.
@@ -1426,7 +1754,7 @@ ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
*/
ipadm_status_t
ipadm_if_info(ipadm_handle_t iph, const char *ifname,
- ipadm_if_info_list_t **if_info, uint32_t flags, int64_t lifc_flags)
+ ipadm_if_info_t **if_info, uint32_t flags, int64_t lifc_flags)
{
ipadm_status_t status;
ifspec_t ifsp;
@@ -1452,16 +1780,29 @@ ipadm_if_info(ipadm_handle_t iph, const char *ifname,
* Frees the linked list allocated by ipadm_if_info().
*/
void
-ipadm_free_if_info(ipadm_if_info_list_t *ifinfo)
+ipadm_free_if_info(ipadm_if_info_t *ifinfo)
{
- ipadm_if_info_list_t *ifinfo_next;
+ ipadm_if_info_t *ifinfo_next;
for (; ifinfo != NULL; ifinfo = ifinfo_next) {
- ifinfo_next = ifinfo->ifil_next;
+ ifinfo_next = ifinfo->ifi_next;
+ i_ipadm_free_ipmp_members(&ifinfo->ifi_ipmp_cmembers);
+ i_ipadm_free_ipmp_members(&ifinfo->ifi_ipmp_pmembers);
free(ifinfo);
}
}
+static void
+i_ipadm_free_ipmp_members(ipadm_ipmp_members_t *ipmp_members)
+{
+ ipadm_ipmp_member_t *ipmp_member;
+
+ while ((ipmp_member = list_remove_head(ipmp_members)) != NULL)
+ free(ipmp_member);
+
+ list_destroy(ipmp_members);
+}
+
/*
* Re-enable the interface `ifname' based on the saved configuration
* for `ifname'.
@@ -1469,6 +1810,7 @@ ipadm_free_if_info(ipadm_if_info_list_t *ifinfo)
ipadm_status_t
ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
{
+ boolean_t set_init = B_FALSE;
nvlist_t *ifnvl;
ipadm_status_t status;
ifspec_t ifsp;
@@ -1489,9 +1831,9 @@ ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
* Return early by checking if the interface is already enabled.
*/
if (ipadm_if_enabled(iph, ifname, AF_INET) &&
- ipadm_if_enabled(iph, ifname, AF_INET6)) {
+ ipadm_if_enabled(iph, ifname, AF_INET6))
return (IPADM_IF_EXISTS);
- }
+
/*
* Enable the interface and restore all its interface properties
* and address objects.
@@ -1504,13 +1846,23 @@ ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
/*
* ipadm_enable_if() does exactly what ipadm_init_ifs() does,
* but only for one interface. We need to set IPH_INIT because
- * ipmgmtd daemon does not have to write the interface to persistent
- * db. The interface is already available in persistent db
- * and we are here to re-enable the persistent configuration.
+ * ipmgmtd daemon does not have to write the interface to the
+ * persistent db. The interface is already available in the
+ * persistent db and we are here to re-enable the persistent
+ * configuration.
+ *
+ * But we need to make sure we're not accidentally clearing an
+ * IPH_INIT flag that was already set when we were called.
*/
- iph->iph_flags |= IPH_INIT;
+ if ((iph->iph_flags & IPH_INIT) == 0) {
+ iph->iph_flags |= IPH_INIT;
+ set_init = B_TRUE;
+ }
+
status = i_ipadm_init_ifobj(iph, ifname, ifnvl);
- iph->iph_flags &= ~IPH_INIT;
+
+ if (set_init)
+ iph->iph_flags &= ~IPH_INIT;
nvlist_free(ifnvl);
return (status);
@@ -1558,10 +1910,13 @@ ipadm_disable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
}
/*
- * This workaround is until libipadm supports IPMP and is required whenever an
- * interface is moved into an IPMP group. Since libipadm doesn't support IPMP
- * yet, we will have to update the daemon's in-memory mapping of
- * `aobjname' to 'lifnum'.
+ * FIXME Remove this when ifconfig(1M) is updated to use IPMP support
+ * in libipadm.
+ */
+/*
+ * This workaround is required by ifconfig(1M) whenever an
+ * interface is moved into an IPMP group to update the daemon's
+ * in-memory mapping of `aobjname' to 'lifnum'.
*
* For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if
* door_call(3C) fails. Also, there is no use in returning error because
@@ -1573,3 +1928,132 @@ ipadm_if_move(ipadm_handle_t iph, const char *ifname)
(void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
(void) i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);
}
+
+ipadm_status_t
+i_ipadm_set_groupname_active(ipadm_handle_t iph, const char *ifname,
+ const char *groupname)
+{
+ struct lifreq lifr;
+ ipadm_addr_info_t *addrinfo, *ia;
+ ipadm_status_t status = IPADM_SUCCESS;
+
+ (void) memset(&lifr, 0, sizeof (lifr));
+
+ (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+ (void) strlcpy(lifr.lifr_groupname, groupname,
+ sizeof (lifr.lifr_groupname));
+
+ /* Disable all addresses on the interface */
+ (void) i_ipadm_active_addr_info(iph, ifname, &addrinfo,
+ IPADM_OPT_ACTIVE | IPADM_OPT_ZEROADDR, IFF_UP | IFF_DUPLICATE);
+
+ for (ia = addrinfo; ia != NULL; ia = IA_NEXT(ia)) {
+ if (strlen(ia->ia_aobjname) > 0) {
+ (void) ipadm_disable_addr(iph, ia->ia_aobjname, 0);
+ } else {
+ /*
+ * There's an address on this interfaces with no
+ * corresponding addrobj. Just clear IFF_UP.
+ */
+ (void) i_ipadm_set_flags(iph, ifname,
+ addrinfo->ia_ifa.ifa_addr->sa_family, 0, IFF_UP);
+ }
+ }
+
+ if (ioctl(iph->iph_sock, SIOCSLIFGROUPNAME, (caddr_t)&lifr) == -1 &&
+ ioctl(iph->iph_sock6, SIOCSLIFGROUPNAME, (caddr_t)&lifr) == -1)
+ status = ipadm_errno2status(errno);
+
+ /* Enable all addresses on the interface */
+ for (ia = addrinfo; ia != NULL; ia = IA_NEXT(ia)) {
+ if (strlen(ia->ia_aobjname) > 0) {
+ (void) ipadm_enable_addr(iph, ia->ia_aobjname, 0);
+ } else {
+ /*
+ * There's an address on this interfaces with no
+ * corresponding addrobj. Just set IFF_UP.
+ */
+ (void) i_ipadm_set_flags(iph, ifname,
+ addrinfo->ia_ifa.ifa_addr->sa_family, IFF_UP, 0);
+ }
+ }
+
+ if (status == IPADM_SUCCESS) {
+ if (groupname[0] == '\0') {
+ /*
+ * If interface was removed from IPMP group, unset the
+ * DEPRECATED and NOFAILOVER flags.
+ */
+ (void) i_ipadm_set_flags(iph, ifname, AF_INET, 0,
+ IFF_DEPRECATED | IFF_NOFAILOVER);
+ (void) i_ipadm_set_flags(iph, ifname, AF_INET6, 0,
+ IFF_DEPRECATED | IFF_NOFAILOVER);
+ } else if (addrinfo == NULL) {
+ /*
+ * If interface was added to IPMP group and there are no
+ * active addresses, explicitly bring it up to be used
+ * for link-based IPMP configuration.
+ */
+ (void) i_ipadm_set_flags(iph, ifname, AF_INET,
+ IFF_UP, 0);
+ (void) i_ipadm_set_flags(iph, ifname, AF_INET6,
+ IFF_UP, 0);
+ }
+ }
+
+ ipadm_free_addr_info(addrinfo);
+
+ return (status);
+}
+
+ipadm_status_t
+i_ipadm_get_groupname_active(ipadm_handle_t iph, const char *ifname,
+ char *groupname, size_t size)
+{
+ struct lifreq lifr;
+
+ (void) memset(&lifr, 0, sizeof (lifr));
+
+ (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+
+ if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) == -1 &&
+ ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME, (caddr_t)&lifr) == -1)
+ return (ipadm_errno2status(errno));
+
+ (void) strlcpy(groupname, lifr.lifr_groupname, size);
+
+ return (IPADM_SUCCESS);
+}
+
+/*
+ * Returns B_TRUE if `ifname' represents an IPMP underlying interface.
+ */
+boolean_t
+i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname)
+{
+
+ char groupname[LIFGRNAMSIZ];
+
+ if (i_ipadm_get_groupname_active(iph, ifname, groupname,
+ sizeof (groupname)) != IPADM_SUCCESS ||
+ groupname[0] == '\0' ||
+ strcmp(ifname, groupname) == 0)
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+/*
+ * Returns B_TRUE if `ifname' represents an IPMP group 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);
+}
diff --git a/usr/src/lib/libipadm/common/ipadm_ipmgmt.h b/usr/src/lib/libipadm/common/ipadm_ipmgmt.h
index 4c6c66de96..4a5c408b57 100644
--- a/usr/src/lib/libipadm/common/ipadm_ipmgmt.h
+++ b/usr/src/lib/libipadm/common/ipadm_ipmgmt.h
@@ -58,6 +58,10 @@ extern "C" {
*/
#define IPADM_NVP_PROTONAME "_protocol" /* protocol name */
#define IPADM_NVP_IFNAME "_ifname" /* interface name */
+#define IPADM_NVP_IFCLASS "_ifclass" /* interface class */
+#define IPADM_NVP_FAMILIES "_families" /* interface families */
+#define IPADM_NVP_GIFNAME "_gifname" /* IPMP group interface name */
+#define IPADM_NVP_MIFNAMES "_mifnames" /* IPMP group members */
#define IPADM_NVP_AOBJNAME "_aobjname" /* addrobj name */
#define IPADM_NVP_FAMILY "_family" /* address family */
#define IPADM_NVP_IPV4ADDR "_ipv4addr" /* name of IPv4 addr nvlist */
@@ -109,6 +113,38 @@ typedef struct ipadm_dbwrite_cbarg_s {
#define IPMGMT_DOOR "/etc/svc/volatile/ipadm/ipmgmt_door"
#define MAXPROTONAMELEN 32
+/*
+ * ia_flags used inside the arguments for interface/address commands
+ *
+ * - APPEND updates the multi-valued ipadm DB entry with a new value
+ * - REMOVE updates the multi-valued ipadm DB entry by removing a value
+ * - ACTIVE updates the running configuration
+ * - PERSIST updates the permanent data store
+ * - INIT indicates that operation being performed is under init context
+ * - PROPS_ONLY indicates the update changes the running configuration of
+ * "props" data on the interface/address object. The props are cached
+ * there on the parent, so a PROPS_ONLY change does not affect the
+ * ACTIVE/PERSIST state of the parent.
+ *
+ * These two flags are used by ipmgmt_db_update_if function,
+ * because it can be used to update more that one DB line
+ * and we need to be sure that we finished all operations,
+ * after the operation has finished the related flag is cleared
+ *
+ * - UPDATE_IF - used when we need to update IPADM_NVP_FAMILIES and
+ * IPADM_NVP_MIFNAMES fields
+ * - UPDATE_IPMP - used when we need to update IPADM_NVP_GIFNAME
+ */
+#define IPMGMT_APPEND 0x00000001
+#define IPMGMT_REMOVE 0x00000002
+#define IPMGMT_ACTIVE 0x00000004
+#define IPMGMT_PERSIST 0x00000008
+#define IPMGMT_INIT 0x00000010
+#define IPMGMT_PROPS_ONLY 0x00000020
+#define IPMGMT_UPDATE_IF 0x00000040
+#define IPMGMT_UPDATE_IPMP 0x00000080
+
+
/* door call command type */
typedef enum {
IPMGMT_CMD_SETPROP = 1, /* persist property */
@@ -125,7 +161,8 @@ typedef enum {
IPMGMT_CMD_ADDROBJ_SETLIFNUM, /* set lifnum on the addrobj */
IPMGMT_CMD_ADDROBJ_ADD, /* add addr. object to addrobj map */
IPMGMT_CMD_LIF2ADDROBJ, /* lifname to addrobj mapping */
- IPMGMT_CMD_AOBJNAME2ADDROBJ /* aobjname to addrobj mapping */
+ IPMGMT_CMD_AOBJNAME2ADDROBJ, /* aobjname to addrobj mapping */
+ IPMGMT_CMD_IPMP_UPDATE /* update IPMP group members */
} ipmgmt_door_cmd_type_t;
/*
@@ -147,13 +184,6 @@ typedef struct ipmgmt_prop_arg_s {
char ia_pname[MAXPROPNAMELEN];
char ia_pval[MAXPROPVALLEN];
} ipmgmt_prop_arg_t;
-/*
- * ia_flags used in ipmgmt_prop_arg_t.
- * - APPEND updates the multi-valued property entry with a new value
- * - REDUCE updates the multi-valued property entry by removing a value
- */
-#define IPMGMT_APPEND 0x00000001
-#define IPMGMT_REMOVE 0x00000002
/*
* ipadm_addr_type_t-specific values that are cached in ipmgmtd and can
@@ -182,6 +212,7 @@ typedef struct ipmgmt_if_arg_s {
uint32_t ia_flags;
char ia_ifname[LIFNAMSIZ];
sa_family_t ia_family;
+ ipadm_if_class_t ia_ifclass;
} ipmgmt_if_arg_t;
/* IPMGMT_CMD_INITIF door_call argument structure */
@@ -193,6 +224,14 @@ typedef struct ipmgmt_initif_arg_s {
/* packed nvl follows */
} ipmgmt_initif_arg_t;
+/* IPMGMT_CMD_IPMP_UPDATE door_call argument structure */
+typedef struct ipmgmt_ipmp_update_arg_s {
+ ipmgmt_door_cmd_type_t ia_cmd;
+ uint32_t ia_flags;
+ char ia_gifname[LIFNAMSIZ]; /* group interface name */
+ char ia_mifname[LIFNAMSIZ]; /* group's member interface name */
+} ipmgmt_ipmp_update_arg_t;
+
/* IPMGMT_CMD_SETADDR door_call argument */
typedef struct ipmgmt_setaddr_arg_s {
ipmgmt_door_cmd_type_t ia_cmd;
@@ -232,22 +271,6 @@ typedef struct ipmgmt_aobjop_arg_s {
ipadm_addr_type_t ia_atype;
} ipmgmt_aobjop_arg_t;
-/*
- * ia_flags used inside the arguments for interface/address commands
- * - ACTIVE updates the running configuration
- * - PERSIST updates the permanent data store
- * - INIT indicates that operation being performed is under init
- * context
- * - PROPS_ONLY indicates the update changes the running configuration of
- * "props" data on the interface/address object. The props are
- * cached there on the parent, so a PROPS_ONLY change does not
- * affect the ACTIVE/PERSIST state of the parent.
- */
-#define IPMGMT_ACTIVE 0x00000001
-#define IPMGMT_PERSIST 0x00000002
-#define IPMGMT_INIT 0x00000004
-#define IPMGMT_PROPS_ONLY 0x00000008
-
/* door call return value */
typedef struct ipmgmt_retval_s {
int32_t ir_err;
diff --git a/usr/src/lib/libipadm/common/ipadm_persist.c b/usr/src/lib/libipadm/common/ipadm_persist.c
index 3043d5e51e..557e29fb3e 100644
--- a/usr/src/lib/libipadm/common/ipadm_persist.c
+++ b/usr/src/lib/libipadm/common/ipadm_persist.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
*/
/*
@@ -51,6 +52,12 @@
* wait: DATA_TYPE_INT32
* primary: DATA_TYPE_BOOLEAN
*
+ * IPADM_NVP_FAMILIES - value holds interface families and when converted
+ * to nvlist, will be a DATA_TYPE_UINT16_ARRAY
+ *
+ * IPADM_NVP_MIFNAMES - value holds IPMP group members and when converted
+ * to nvlist, will be a DATA_TYPE_STRING_ARRAY
+ *
* default - value is a single entity and when converted to nvlist, will
* contain nvpair of type DATA_TYPE_STRING. nvpairs private to
* ipadm are of this type. Further the property name and property
@@ -88,21 +95,23 @@ static int ipadm_process_db_line(db_wfunc_t *, void *, FILE *fp, FILE *nfp,
/*
* convert nvpair to a "name=value" string for writing to the DB.
*/
-typedef size_t ipadm_wfunc_t(nvpair_t *, char *, size_t);
+typedef size_t ipadm_wfunc_t(nvpair_t *, char *, size_t);
/*
* ipadm_rfunc_t takes (`name', `value') and adds the appropriately typed
* nvpair to the nvlist.
*/
-typedef void ipadm_rfunc_t(nvlist_t *, char *name, char *value);
+typedef ipadm_status_t ipadm_rfunc_t(nvlist_t *, char *, char *);
static ipadm_rfunc_t i_ipadm_str_dbline2nvl, i_ipadm_ip4_dbline2nvl,
i_ipadm_ip6_dbline2nvl, i_ipadm_intfid_dbline2nvl,
- i_ipadm_dhcp_dbline2nvl;
+ i_ipadm_dhcp_dbline2nvl, i_ipadm_families_dbline2nvl,
+ i_ipadm_groupmembers_dbline2nvl;
static ipadm_wfunc_t i_ipadm_str_nvp2dbline, i_ipadm_ip4_nvp2dbline,
i_ipadm_ip6_nvp2dbline, i_ipadm_intfid_nvp2dbline,
- i_ipadm_dhcp_nvp2dbline;
+ i_ipadm_dhcp_nvp2dbline, i_ipadm_families_nvp2dbline,
+ i_ipadm_groupmembers_nvp2dbline;
/*
* table of function pointers to read/write formatted entries from/to
@@ -120,6 +129,10 @@ static ipadm_conf_ent_t ipadm_conf_ent[] = {
{ IPADM_NVP_INTFID, i_ipadm_intfid_nvp2dbline,
i_ipadm_intfid_dbline2nvl },
{ IPADM_NVP_DHCP, i_ipadm_dhcp_nvp2dbline, i_ipadm_dhcp_dbline2nvl },
+ { IPADM_NVP_FAMILIES, i_ipadm_families_nvp2dbline,
+ i_ipadm_families_dbline2nvl },
+ { IPADM_NVP_MIFNAMES, i_ipadm_groupmembers_nvp2dbline,
+ i_ipadm_groupmembers_dbline2nvl},
{ NULL, i_ipadm_str_nvp2dbline, i_ipadm_str_dbline2nvl }
};
@@ -259,7 +272,7 @@ static size_t
i_ipadm_dhcp_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
{
char addrbuf[IPADM_STRSIZE];
- int32_t wait;
+ int32_t wait;
boolean_t primary;
nvlist_t *v;
@@ -328,13 +341,13 @@ ipadm_nvlist2str(nvlist_t *nvl, char *buf, size_t buflen)
* Adds a nvpair, using the `name' and `value', to the nvlist in `nvl'.
* The value will be interpreted as explained at the top of this file.
*/
-static void
+static ipadm_status_t
i_ipadm_add_nvpair(nvlist_t *nvl, char *name, char *value)
{
ipadm_conf_ent_t *ipent;
ipent = i_ipadm_find_conf_type(name);
- (*ipent->ipent_rfunc)(nvl, name, value);
+ return ((*ipent->ipent_rfunc)(nvl, name, value));
}
/*
@@ -467,14 +480,18 @@ i_ipadm_add_dhcp2nvl(nvlist_t *nvl, boolean_t primary, int32_t wait)
/*
* Add (name, value) as an nvpair of type DATA_TYPE_STRING to nvlist.
*/
-static void
+static ipadm_status_t
i_ipadm_str_dbline2nvl(nvlist_t *nvl, char *name, char *value)
{
+ int err;
+
/* if value is NULL create an empty node */
if (value == NULL)
- (void) nvlist_add_string(nvl, name, "");
+ err = nvlist_add_string(nvl, name, "");
else
- (void) nvlist_add_string(nvl, name, value);
+ err = nvlist_add_string(nvl, name, value);
+
+ return (ipadm_errno2status(err));
}
/*
@@ -484,7 +501,7 @@ i_ipadm_str_dbline2nvl(nvlist_t *nvl, char *name, char *value)
* This function will add an nvlist with the hostname information in
* nvpairs to the nvlist in `nvl'.
*/
-static void
+static ipadm_status_t
i_ipadm_ip4_dbline2nvl(nvlist_t *nvl, char *name, char *value)
{
char *cp, *hname;
@@ -507,7 +524,7 @@ i_ipadm_ip4_dbline2nvl(nvlist_t *nvl, char *name, char *value)
(void) strlcpy(ipaddr.ipadm_static_dname, cp,
sizeof (ipaddr.ipadm_static_dname));
}
- (void) i_ipadm_add_ipaddr2nvl(nvl, &ipaddr);
+ return (i_ipadm_add_ipaddr2nvl(nvl, &ipaddr));
}
/*
@@ -517,7 +534,7 @@ i_ipadm_ip4_dbline2nvl(nvlist_t *nvl, char *name, char *value)
* This function will add an nvlist with the hostname information in
* nvpairs to the nvlist in `nvl'.
*/
-static void
+static ipadm_status_t
i_ipadm_ip6_dbline2nvl(nvlist_t *nvl, char *name, char *value)
{
char *cp, *hname;
@@ -540,7 +557,7 @@ i_ipadm_ip6_dbline2nvl(nvlist_t *nvl, char *name, char *value)
(void) strlcpy(ipaddr.ipadm_static_dname, cp,
sizeof (ipaddr.ipadm_static_dname));
}
- (void) i_ipadm_add_ipaddr2nvl(nvl, &ipaddr);
+ return (i_ipadm_add_ipaddr2nvl(nvl, &ipaddr));
}
/*
@@ -548,7 +565,7 @@ i_ipadm_ip6_dbline2nvl(nvlist_t *nvl, char *name, char *value)
* This function will add an nvlist with the address object information in
* nvpairs to the nvlist in `nvl'.
*/
-static void
+static ipadm_status_t
i_ipadm_intfid_dbline2nvl(nvlist_t *nvl, char *name, char *value)
{
char *cp;
@@ -577,7 +594,7 @@ i_ipadm_intfid_dbline2nvl(nvlist_t *nvl, char *name, char *value)
errno = 0;
ipaddr.ipadm_intfidlen = (uint32_t)strtoul(prefixlen, &endp, 10);
if (*endp != '\0' || errno != 0)
- return;
+ return (ipadm_errno2status(errno));
stateless = cp;
stateful = strchr(stateless, ',');
@@ -587,7 +604,7 @@ i_ipadm_intfid_dbline2nvl(nvlist_t *nvl, char *name, char *value)
ipaddr.ipadm_stateful = (strcmp(stateful, "yes") == 0);
/* Add all of it to the given nvlist */
- (void) i_ipadm_add_intfid2nvl(nvl, &ipaddr);
+ return (i_ipadm_add_intfid2nvl(nvl, &ipaddr));
}
/*
@@ -595,7 +612,7 @@ i_ipadm_intfid_dbline2nvl(nvlist_t *nvl, char *name, char *value)
* This function will add an nvlist with the dhcp address object information in
* nvpairs to the nvlist in `nvl'.
*/
-static void
+static ipadm_status_t
i_ipadm_dhcp_dbline2nvl(nvlist_t *nvl, char *name, char *value)
{
char *cp;
@@ -610,39 +627,194 @@ i_ipadm_dhcp_dbline2nvl(nvlist_t *nvl, char *name, char *value)
errno = 0;
wait_time = strtol(value, &endp, 10);
if (*endp != '\0' || errno != 0)
- return;
+ return (ipadm_errno2status(errno));
primary = (strcmp(cp, "yes") == 0);
- (void) i_ipadm_add_dhcp2nvl(nvl, primary, (int32_t)wait_time);
+ return (i_ipadm_add_dhcp2nvl(nvl, primary, (int32_t)wait_time));
+}
+
+/*
+ * Input 'nvp': name = IPADM_NVP_FAMILIES and value = array of 'uint16_t'
+ *
+ *
+ */
+static size_t
+i_ipadm_families_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
+{
+ uint_t nelem = 0;
+ uint16_t *elem;
+
+ assert(nvpair_type(nvp) == DATA_TYPE_UINT16_ARRAY);
+
+ if (nvpair_value_uint16_array(nvp,
+ &elem, &nelem) != 0) {
+ buf[0] = '\0';
+ return (0);
+ }
+
+ assert(nelem != 0 || nelem > 2);
+
+ if (nelem == 1) {
+ return (snprintf(buf, buflen, "%s=%d",
+ nvpair_name(nvp), elem[0]));
+ } else {
+ return (snprintf(buf, buflen, "%s=%d,%d",
+ nvpair_name(nvp), elem[0], elem[1]));
+ }
+}
+
+/*
+ * name = IPADM_NVP_FAMILIES and value = <FAMILY>[,FAMILY]
+ *
+ * output nvp: name = IPADM_NVP_FAMILIES and value = array of 'uint16_t'
+ *
+ */
+static ipadm_status_t
+i_ipadm_families_dbline2nvl(nvlist_t *nvl, char *name, char *value)
+{
+ uint16_t families[2];
+ uint_t nelem = 0;
+ char *val, *lasts;
+
+ if ((val = strtok_r(value,
+ ",", &lasts)) != NULL) {
+ families[0] = atoi(val);
+ nelem++;
+ if ((val = strtok_r(NULL,
+ ",", &lasts)) != NULL) {
+ families[1] = atoi(val);
+ nelem++;
+ }
+ return (ipadm_errno2status(nvlist_add_uint16_array(nvl,
+ IPADM_NVP_FAMILIES, families, nelem)));
+ }
+
+ return (IPADM_INVALID_ARG);
+}
+
+/*
+ * input nvp: name = IPADM_NVP_MIFNAMES and value = array of 'char *'
+ *
+ *
+ */
+static size_t
+i_ipadm_groupmembers_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
+{
+ uint_t nelem = 0;
+ char **elem;
+ size_t n;
+
+ assert(nvpair_type(nvp) == DATA_TYPE_STRING_ARRAY);
+
+ if (nvpair_value_string_array(nvp,
+ &elem, &nelem) != 0) {
+ buf[0] = '\0';
+ return (0);
+ }
+
+ assert(nelem != 0);
+
+ n = snprintf(buf, buflen, "%s=", IPADM_NVP_MIFNAMES);
+ if (n >= buflen)
+ return (n);
+
+ while (nelem-- > 0) {
+ n = strlcat(buf, elem[nelem], buflen);
+ if (nelem > 0)
+ n = strlcat(buf, ",", buflen);
+
+ if (n > buflen)
+ return (n);
+ }
+
+ return (n);
+}
+
+/*
+ * name = IPADM_NVP_MIFNAMES and value = <if_name>[,if_name]
+ *
+ * output nvp: name = IPADM_NVP_MIFNAMES and value = array of 'char *'
+ */
+static ipadm_status_t
+i_ipadm_groupmembers_dbline2nvl(nvlist_t *nvl, char *name, char *value)
+{
+ char **members = NULL;
+ char *member = NULL;
+ char *val, *lasts;
+ uint_t m_cnt = 0;
+ ipadm_status_t ret = IPADM_SUCCESS;
+
+ assert(strcmp(name, IPADM_NVP_MIFNAMES) == 0 && value != NULL);
+
+ for (val = strtok_r(value, ",", &lasts);
+ val != NULL;
+ val = strtok_r(NULL, ",", &lasts)) {
+ if ((m_cnt % 4) == 0) {
+ char **tmp = recallocarray(members, m_cnt, m_cnt + 4,
+ sizeof (char *));
+
+ if (tmp == NULL) {
+ ret = IPADM_NO_MEMORY;
+ goto fail;
+ }
+
+ members = tmp;
+ }
+
+ member = calloc(1, LIFNAMSIZ);
+
+ if (member == NULL) {
+ ret = IPADM_NO_MEMORY;
+ goto fail;
+ }
+
+ (void) strlcpy(member, val, LIFNAMSIZ);
+ members[m_cnt++] = member;
+
+ }
+
+ if ((ret = ipadm_errno2status(nvlist_add_string_array(nvl,
+ IPADM_NVP_MIFNAMES, members, m_cnt))) != IPADM_SUCCESS)
+ goto fail;
+
+fail:
+ while (m_cnt-- > 0) {
+ free(members[m_cnt]);
+ }
+
+ free(members);
+
+ return (ret);
}
/*
* Parses the buffer, for name-value pairs and creates nvlist. The value
* is always considered to be a string.
*/
-int
+ipadm_status_t
ipadm_str2nvlist(const char *inbuf, nvlist_t **ipnvl, uint_t flags)
{
+ ipadm_status_t status;
char *nv, *name, *val, *buf, *cp, *sep;
int err;
if (inbuf == NULL || inbuf[0] == '\0' || ipnvl == NULL)
- return (EINVAL);
+ return (IPADM_INVALID_ARG);
*ipnvl = NULL;
/*
* If IPADM_NORVAL is set, then `inbuf' should be comma delimited values
*/
if ((flags & IPADM_NORVAL) && strchr(inbuf, '=') != NULL)
- return (EINVAL);
+ return (IPADM_INVALID_ARG);
if ((cp = buf = strdup(inbuf)) == NULL)
- return (errno);
+ return (ipadm_errno2status(errno));
while (isspace(*buf))
buf++;
if (*buf == '\0') {
- err = EINVAL;
+ status = IPADM_INVALID_ARG;
goto fail;
}
@@ -658,22 +830,26 @@ ipadm_str2nvlist(const char *inbuf, nvlist_t **ipnvl, uint_t flags)
if ((val = strchr(nv, '=')) != NULL)
*val++ = '\0';
if (*ipnvl == NULL &&
- (err = nvlist_alloc(ipnvl, NV_UNIQUE_NAME, 0)) != 0)
+ (err = nvlist_alloc(ipnvl, NV_UNIQUE_NAME, 0)) != 0) {
+ status = ipadm_errno2status(err);
goto fail;
+ }
if (nvlist_exists(*ipnvl, name)) {
- err = EEXIST;
+ status = IPADM_EXISTS;
goto fail;
}
/* Add the extracted nvpair to the nvlist `ipnvl'. */
- (void) i_ipadm_add_nvpair(*ipnvl, name, val);
+ status = i_ipadm_add_nvpair(*ipnvl, name, val);
+ if (status != IPADM_SUCCESS)
+ goto fail;
}
free(cp);
- return (0);
+ return (IPADM_SUCCESS);
fail:
free(cp);
nvlist_free(*ipnvl);
*ipnvl = NULL;
- return (err);
+ return (status);
}
/*
diff --git a/usr/src/lib/libipadm/common/ipadm_prop.c b/usr/src/lib/libipadm/common/ipadm_prop.c
index 4fc0dc0851..889e5e2ca2 100644
--- a/usr/src/lib/libipadm/common/ipadm_prop.c
+++ b/usr/src/lib/libipadm/common/ipadm_prop.c
@@ -18,9 +18,11 @@
*
* CDDL HEADER END
*/
+
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2017 by Delphix. All rights reserved.
+ * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
*/
/*
@@ -145,6 +147,11 @@ static ipadm_prop_desc_t ipadm_ip_prop_table[] = {
i_ipadm_set_hostmodel, i_ipadm_get_hostmodel,
i_ipadm_get_hostmodel },
+ { "standby", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IP, 0,
+ i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
+ i_ipadm_get_ifprop_flags },
+
+
{ NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
};
@@ -598,7 +605,8 @@ i_ipadm_set_ifprop_flags(ipadm_handle_t iph, const void *arg,
strcmp(pdp->ipd_name, "arp") == 0 ||
strcmp(pdp->ipd_name, "nud") == 0) {
pval = IPADM_ONSTR;
- } else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
+ } else if (strcmp(pdp->ipd_name, "forwarding") == 0 ||
+ strcmp(pdp->ipd_name, "standby") == 0) {
pval = IPADM_OFFSTR;
} else {
return (IPADM_PROP_UNKNOWN);
@@ -632,6 +640,11 @@ i_ipadm_set_ifprop_flags(ipadm_handle_t iph, const void *arg,
on_flags = IFF_ROUTER;
else
off_flags = IFF_ROUTER;
+ } else if (strcmp(pdp->ipd_name, "standby") == 0) {
+ if (on)
+ on_flags = IFF_STANDBY;
+ else
+ off_flags = IFF_STANDBY;
}
if (on_flags || off_flags) {
@@ -649,7 +662,6 @@ i_ipadm_set_eprivport(ipadm_handle_t iph, const void *arg,
nvlist_t *portsnvl = NULL;
nvpair_t *nvp;
ipadm_status_t status = IPADM_SUCCESS;
- int err;
uint_t count = 0;
if (flags & IPADM_OPT_DEFAULT) {
@@ -657,8 +669,8 @@ i_ipadm_set_eprivport(ipadm_handle_t iph, const void *arg,
return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
}
- if ((err = ipadm_str2nvlist(pval, &portsnvl, IPADM_NORVAL)) != 0)
- return (ipadm_errno2status(err));
+ if ((status = ipadm_str2nvlist(pval, &portsnvl, IPADM_NORVAL)) != 0)
+ return (status);
/* count the number of ports */
for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
@@ -941,7 +953,7 @@ i_ipadm_get_usesrc(ipadm_handle_t iph, const void *arg,
struct lifreq lifr;
const char *ifname = arg;
int s;
- char if_name[IF_NAMESIZE];
+ char if_name[IF_NAMESIZE];
size_t nbytes;
switch (valtype) {
@@ -984,8 +996,8 @@ i_ipadm_get_ifprop_flags(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
uint_t valtype)
{
- uint64_t intf_flags;
- char *val;
+ uint64_t intf_flags;
+ char *val;
size_t nbytes;
const char *ifname = arg;
sa_family_t af;
@@ -1000,7 +1012,8 @@ i_ipadm_get_ifprop_flags(ipadm_handle_t iph, const void *arg,
strcmp(pdp->ipd_name, "arp") == 0 ||
strcmp(pdp->ipd_name, "nud") == 0) {
val = IPADM_ONSTR;
- } else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
+ } else if (strcmp(pdp->ipd_name, "forwarding") == 0 ||
+ strcmp(pdp->ipd_name, "standby") == 0) {
val = IPADM_OFFSTR;
} else {
return (IPADM_PROP_UNKNOWN);
@@ -1026,6 +1039,9 @@ i_ipadm_get_ifprop_flags(ipadm_handle_t iph, const void *arg,
} else if (strcmp(pdp->ipd_name, "nud") == 0) {
if (!(intf_flags & IFF_NONUD))
val = IPADM_ONSTR;
+ } else if (strcmp(pdp->ipd_name, "standby") == 0) {
+ if (intf_flags & IFF_STANDBY)
+ val = IPADM_ONSTR;
}
nbytes = snprintf(buf, *bufsize, "%s", val);
break;
@@ -1060,7 +1076,7 @@ i_ipadm_get_prop(ipadm_handle_t iph, const void *arg,
ipadm_status_t status = IPADM_SUCCESS;
const char *ifname = arg;
mod_ioc_prop_t *mip;
- char *pname = pdp->ipd_name;
+ char *pname = pdp->ipd_name;
uint_t iocsize;
/* allocate sufficient ioctl buffer to retrieve value */
@@ -1154,7 +1170,7 @@ i_ipadm_populate_proparg(ipmgmt_prop_arg_t *pargp, ipadm_prop_desc_t *pdp,
* for a given protocol `proto'. The property name is in `pname'.
*
* `valtype' determines the type of value that will be retrieved.
- * IPADM_OPT_ACTIVE - current value of the property (active config)
+ * IPADM_OPT_ACTIVE - current value of the property (active config)
* IPADM_OPT_PERSIST - value of the property from persistent store
* IPADM_OPT_DEFAULT - default hard coded value (boot-time value)
* IPADM_OPT_PERM - read/write permissions for the value
@@ -1302,9 +1318,9 @@ i_ipadm_set_prop(ipadm_handle_t iph, const void *arg,
{
ipadm_status_t status = IPADM_SUCCESS;
const char *ifname = arg;
- mod_ioc_prop_t *mip;
- char *pname = pdp->ipd_name;
- uint_t valsize, iocsize;
+ mod_ioc_prop_t *mip;
+ char *pname = pdp->ipd_name;
+ uint_t valsize, iocsize;
uint_t iocflags = 0;
if (flags & IPADM_OPT_DEFAULT) {
@@ -1365,7 +1381,7 @@ i_ipadm_setprop_common(ipadm_handle_t iph, const char *ifname,
const char *pname, const char *buf, uint_t proto, uint_t pflags)
{
ipadm_status_t status = IPADM_SUCCESS;
- boolean_t persist = (pflags & IPADM_OPT_PERSIST);
+ boolean_t persist = (pflags & IPADM_OPT_PERSIST);
boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
ipadm_prop_desc_t *pdp;
boolean_t is_if = (ifname != NULL);
@@ -1701,8 +1717,7 @@ i_ipadm_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
* This is called from ipadm_set_ifprop() to validate the set operation.
* It does the following steps:
* 1. Validates the interface name.
- * 2. Fails if it is an IPMP meta-interface or an underlying interface.
- * 3. In case of a persistent operation, verifies that the
+ * 2. In case of a persistent operation, verifies that the
* interface is persistent.
*/
static ipadm_status_t
@@ -1719,12 +1734,6 @@ i_ipadm_validate_if(ipadm_handle_t iph, const char *ifname,
return (IPADM_INVALID_ARG);
af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
- /*
- * Setting properties on an IPMP meta-interface or underlying
- * interface is not supported.
- */
- if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname))
- return (IPADM_NOTSUP);
/* Check if interface exists in the persistent configuration. */
status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
diff --git a/usr/src/lib/libipadm/common/libipadm.c b/usr/src/lib/libipadm/common/libipadm.c
index 5d72275f34..972c45630b 100644
--- a/usr/src/lib/libipadm/common/libipadm.c
+++ b/usr/src/lib/libipadm/common/libipadm.c
@@ -21,8 +21,8 @@
/*
* 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>.
+ * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
*/
#include <stdio.h>
@@ -528,39 +528,6 @@ i_ipadm_is_6to4(ipadm_handle_t iph, char *ifname)
}
/*
- * 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.
*/
@@ -693,40 +660,82 @@ 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 status = IPADM_ENXIO;
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);
+ 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 plumb the given interface and then apply all the persistent
- * interface properties and then instantiate any persistent addresses
- * objects on that interface.
+ * 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)) {
- if (nvpair_value_nvlist(nvp, &nvl) != 0)
+ 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;
- 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.
- */
+ /* 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 (is_ngz)
- af = atoi(afstr);
- } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
+ 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
@@ -737,10 +746,12 @@ i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
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
@@ -751,15 +762,17 @@ i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
status = IPADM_SUCCESS;
}
- } else {
- assert(nvlist_exists(nvl, IPADM_NVP_PROTONAME));
+ } else if (nvlist_exists(nvl, IPADM_NVP_PROTONAME) == B_TRUE) {
status = i_ipadm_init_ifprop(iph, nvl);
}
if (status != IPADM_SUCCESS)
return (status);
}
-
- if (is_ngz && af != AF_UNSPEC)
+ 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);
}
@@ -779,8 +792,9 @@ i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs)
int err;
ipadm_status_t status = IPADM_SUCCESS;
- if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0)
- return (ipadm_errno2status(err));
+ status = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL);
+ if (status != IPADM_SUCCESS)
+ return (status);
err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
if (err != 0) {
@@ -960,6 +974,36 @@ reopen:
}
/*
+ * 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));
+ if (rvalp == NULL)
+ return (IPADM_NO_MEMORY);
+
+ 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, 0);
+ }
+ 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).
diff --git a/usr/src/lib/libipadm/common/libipadm.h b/usr/src/lib/libipadm/common/libipadm.h
index 0ae9d89e4b..66e7888d2b 100644
--- a/usr/src/lib/libipadm/common/libipadm.h
+++ b/usr/src/lib/libipadm/common/libipadm.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
- * Copyright 2021, Tintri by DDN. All rights reserved.
+ * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
*/
#ifndef _LIBIPADM_H
#define _LIBIPADM_H
@@ -39,6 +39,8 @@ extern "C" {
#include <libnvpair.h>
#include <netinet/tcp.h>
#include <sys/stropts.h>
+#include <sys/list.h>
+#include <stddef.h>
#define IPADM_AOBJ_USTRSIZ 32
#define IPADM_AOBJSIZ (LIFNAMSIZ + IPADM_AOBJ_USTRSIZ)
@@ -206,27 +208,31 @@ typedef enum {
IFIS_DISABLED /* Interface has been disabled. */
} ipadm_if_state_t;
-/*
- * Declare ipadm_if_info_list_t as a container for ipadm_if_info_t.
- *
- * ipadm_if_info_t used to have a list pointer ifi_next for linking a number
- * of ipadm_if_info_t's together. Even though this linking wasn't used in the
- * data exchange between ipmgmtd and libipadm, this meant the structure wasn't
- * safe for passing through the door between 32bit and 64bit processes.
- */
+typedef list_t ipadm_ipmp_members_t;
+
+typedef struct {
+ list_node_t node;
+ char if_name[LIFNAMSIZ];
+} ipadm_ipmp_member_t;
+
+typedef enum {
+ IPADM_IF_CLASS_REGULAR,
+ IPADM_IF_CLASS_IPMP,
+ IPADM_IF_CLASS_VIRTUAL,
+ IPADM_IF_CLASS_UNKNOWN
+} ipadm_if_class_t;
+
typedef struct ipadm_if_info_s {
+ struct ipadm_if_info_s *ifi_next;
char ifi_name[LIFNAMSIZ]; /* interface name */
+ ipadm_if_class_t ifi_class; /* interface class */
ipadm_if_state_t ifi_state; /* see above */
uint_t ifi_cflags; /* current flags */
uint_t ifi_pflags; /* persistent flags */
+ ipadm_ipmp_members_t ifi_ipmp_cmembers; /* current IPMP members */
+ ipadm_ipmp_members_t ifi_ipmp_pmembers; /* persistent IPMP members */
} ipadm_if_info_t;
-typedef struct ipadm_if_info_list_s {
- struct ipadm_if_info_list_s *ifil_next;
- ipadm_if_info_t ifil_ifi;
-} ipadm_if_info_list_t;
-
-
/* ipadm_if_info_t flags */
#define IFIF_BROADCAST 0x00000001
#define IFIF_MULTICAST 0x00000002
@@ -293,11 +299,15 @@ extern ipadm_status_t ipadm_disable_if(ipadm_handle_t, const char *,
uint32_t);
extern ipadm_status_t ipadm_enable_if(ipadm_handle_t, const char *, uint32_t);
extern ipadm_status_t ipadm_if_info(ipadm_handle_t, const char *,
- ipadm_if_info_list_t **, uint32_t, int64_t);
-extern void ipadm_free_if_info(ipadm_if_info_list_t *);
+ ipadm_if_info_t **, uint32_t, int64_t);
+extern void ipadm_free_if_info(ipadm_if_info_t *);
extern ipadm_status_t ipadm_delete_if(ipadm_handle_t, const char *,
sa_family_t, uint32_t);
extern void ipadm_if_move(ipadm_handle_t, const char *);
+extern ipadm_status_t ipadm_add_ipmp_member(ipadm_handle_t, const char *,
+ const char *, uint32_t);
+extern ipadm_status_t ipadm_remove_ipmp_member(ipadm_handle_t, const char *,
+ const char *, uint32_t);
/*
* Address management functions
@@ -377,7 +387,7 @@ extern ipadm_status_t ipadm_get_prop(ipadm_handle_t, const char *, char *,
* miscellaneous helper functions.
*/
extern const char *ipadm_status2str(ipadm_status_t);
-extern int ipadm_str2nvlist(const char *, nvlist_t **, uint_t);
+extern ipadm_status_t ipadm_str2nvlist(const char *, nvlist_t **, uint_t);
extern size_t ipadm_nvlist2str(nvlist_t *, char *, size_t);
extern char *ipadm_proto2str(uint_t);
extern uint_t ipadm_str2proto(const char *);
diff --git a/usr/src/lib/libipadm/common/libipadm_impl.h b/usr/src/lib/libipadm/common/libipadm_impl.h
index 98b95092d9..1766558db6 100644
--- a/usr/src/lib/libipadm/common/libipadm_impl.h
+++ b/usr/src/lib/libipadm/common/libipadm_impl.h
@@ -18,10 +18,12 @@
*
* CDDL HEADER END
*/
+
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
+ * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
*/
#ifndef _LIBIPADM_IMPL_H
@@ -32,6 +34,7 @@ extern "C" {
#endif
#include <sys/socket.h>
+#include <sys/list.h>
#include <net/if.h>
#include <libipadm.h>
#include <libdladm.h>
@@ -52,6 +55,11 @@ extern "C" {
/* mask for flags accepted by libipadm functions */
#define IPADM_COMMON_OPT_MASK (IPADM_OPT_ACTIVE | IPADM_OPT_PERSIST)
+typedef enum {
+ IPADM_ADD_IPMP,
+ IPADM_REMOVE_IPMP
+} ipadm_ipmp_op_t;
+
/* Opaque library handle */
struct ipadm_handle {
int iph_sock; /* socket to interface */
@@ -65,7 +73,7 @@ struct ipadm_handle {
};
struct ipadm_addrobj_s {
- char ipadm_ifname[LIFNAMSIZ];
+ char ipadm_ifname[LIFNAMSIZ];
int32_t ipadm_lifnum;
char ipadm_aobjname[IPADM_AOBJSIZ];
ipadm_addr_type_t ipadm_atype;
@@ -154,15 +162,15 @@ extern ipadm_status_t i_ipadm_delete_addr(ipadm_handle_t, ipadm_addrobj_t);
extern int i_ipadm_strioctl(int, int, char *, int);
extern boolean_t i_ipadm_is_loopback(const char *);
extern boolean_t i_ipadm_is_vni(const char *);
-extern boolean_t i_ipadm_is_ipmp(ipadm_handle_t, const char *);
-extern boolean_t i_ipadm_is_under_ipmp(ipadm_handle_t, const char *);
extern boolean_t i_ipadm_is_6to4(ipadm_handle_t, char *);
extern boolean_t i_ipadm_validate_ifname(ipadm_handle_t, const char *);
extern ipadm_status_t ipadm_errno2status(int);
extern int ipadm_door_call(ipadm_handle_t, void *, size_t, void **,
size_t, boolean_t);
-extern boolean_t ipadm_if_enabled(ipadm_handle_t, const char *,
+extern boolean_t ipadm_if_enabled(ipadm_handle_t, const char *,
sa_family_t);
+extern ipadm_status_t i_ipadm_call_ipmgmtd(ipadm_handle_t, void *,
+ size_t, nvlist_t **);
/* ipadm_ndpd.c */
extern ipadm_status_t i_ipadm_create_ipv6addrs(ipadm_handle_t,
@@ -187,6 +195,8 @@ extern ipadm_status_t i_ipadm_get_persist_propval(ipadm_handle_t,
const void *);
/* ipadm_addr.c */
+extern ipadm_status_t i_ipadm_active_addr_info(ipadm_handle_t, const char *,
+ ipadm_addr_info_t **, uint32_t, int64_t);
extern void i_ipadm_init_addr(ipadm_addrobj_t, const char *,
const char *, ipadm_addr_type_t);
extern ipadm_status_t i_ipadm_merge_addrprops_from_nvl(nvlist_t *, nvlist_t *,
@@ -230,6 +240,12 @@ extern ipadm_status_t i_ipadm_delete_ifobj(ipadm_handle_t, const char *,
sa_family_t, boolean_t);
extern int i_ipadm_get_lnum(const char *);
+extern ipadm_status_t i_ipadm_set_groupname_active(ipadm_handle_t,
+ const char *, const char *);
+extern ipadm_status_t i_ipadm_get_groupname_active(ipadm_handle_t,
+ const char *, char *, size_t);
+extern boolean_t i_ipadm_is_under_ipmp(ipadm_handle_t, const char *);
+extern boolean_t i_ipadm_is_ipmp(ipadm_handle_t, const char *);
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libipadm/common/mapfile-vers b/usr/src/lib/libipadm/common/mapfile-vers
index 7b03b77f33..7e2becc2bc 100644
--- a/usr/src/lib/libipadm/common/mapfile-vers
+++ b/usr/src/lib/libipadm/common/mapfile-vers
@@ -21,6 +21,7 @@
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
+# Copyright 2021 Tintri by DDN, Inc. All rights reserved.
#
#
@@ -41,6 +42,7 @@ $mapfile_version 2
SYMBOL_VERSION SUNWprivate_1.1 {
global:
+ ipadm_add_ipmp_member;
ipadm_add_aobjname;
ipadm_addr_info;
ipadm_check_auth;
@@ -79,6 +81,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
ipadm_open_arp_on_udp;
ipadm_proto2str;
ipadm_refresh_addr;
+ ipadm_remove_ipmp_member;
ipadm_rw_db;
ipadm_set_addr;
ipadm_set_addrprop;