Print this page
Commit IPMP changes
@@ -18,14 +18,16 @@
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <errno.h>
#include <sys/sockio.h>
+#include <sys/list.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <stropts.h>
#include <strings.h>
@@ -34,19 +36,35 @@
#include <libinetutil.h>
#include <inet/ip.h>
#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);
static ipadm_status_t i_ipadm_slifname(ipadm_handle_t, char *, char *,
uint64_t, int, uint32_t);
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_operation_t);
+static ipadm_status_t i_ipadm_update_ipmp(ipadm_handle_t, const char *,
+ const char *, uint32_t,
+ ipadm_ipmp_operation_t);
/*
* Returns B_FALSE if the interface in `ifname' has at least one address that is
* IFF_UP in the addresses in `ifa'.
*/
@@ -120,15 +138,14 @@
for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) {
if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0)
break;
}
if (ifp == NULL) {
- ifp = calloc(1, sizeof (ipadm_if_info_t));
- if (ifp == NULL) {
- status = ipadm_errno2status(errno);
- goto fail;
- }
+ if ((status =
+ i_ipadm_allocate_ifinfo(&ifp)) != IPADM_SUCCESS)
+ break;
+
(void) strlcpy(ifp->ifi_name, lifrp->lifr_name,
sizeof (ifp->ifi_name));
/* Update the `ifi_next' pointer for this new node */
if (*if_info == NULL)
*if_info = ifp;
@@ -145,20 +162,28 @@
lifrp->lifr_name, sizeof (lifrl.lifr_name));
s = (lifrp->lifr_addr.ss_family == AF_INET) ?
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)
ifp->ifi_cflags |= IFIF_INACTIVE;
if (lifrl.lifr_flags & IFF_VRRP)
@@ -169,17 +194,30 @@
ifp->ifi_cflags |= IFIF_IPV4;
if (lifrl.lifr_flags & IFF_IPV6)
ifp->ifi_cflags |= IFIF_IPV6;
if (lifrl.lifr_flags & IFF_L3PROTECT)
ifp->ifi_cflags |= IFIF_L3PROTECT;
+
+ /* Retrive active IPMP members */
+ if (ifp->ifi_class == IPADM_IF_CLASS_IPMP) {
+ if (ioctl(s, SIOCGLIFGROUPNAME,
+ (caddr_t)&lifrl) < 0) {
+ status = ipadm_errno2status(errno);
+ break;
}
+
+ if ((status = i_ipadm_fill_cmembers(
+ lifrl.lifr_groupname,
+ &ifp->ifi_ipmp_cmembers)) != IPADM_SUCCESS)
+ break;
+ }
+ }
free(buf);
- return (IPADM_SUCCESS);
-fail:
- free(buf);
+ if (status != IPADM_SUCCESS) {
ipadm_free_if_info(*if_info);
*if_info = NULL;
+ }
return (status);
}
/*
* Returns the interface information for `ifname' in `if_info' from persistent
@@ -189,51 +227,157 @@
static ipadm_status_t
i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname,
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, *curr, *prev = NULL;
- int i = 0, err = 0;
+ nvlist_t *ifs_info_nvl;
- bzero(&getif, sizeof (getif));
- if (ifname != NULL)
- (void) strlcpy(getif.ia_ifname, ifname, LIFNAMSIZ);
- getif.ia_cmd = IPMGMT_CMD_GETIF;
-
*if_info = NULL;
- if ((rvalp = malloc(sizeof (ipmgmt_getif_rval_t))) == NULL)
+ if ((status = i_ipadm_get_db_if(iph,
+ ifname, &ifs_info_nvl)) != IPADM_SUCCESS)
+ return (status);
+
+ 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;
+ }
+ 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--) {
+ if (families[nelem] == AF_INET)
+ ific->ifi_pflags |= IFIF_IPV4;
+ else if (families[nelem] == AF_INET6)
+ ific->ifi_pflags |= IFIF_IPV6;
+ }
+ } else {
+ ipadm_free_if_info(ific);
+ ific = NULL;
+ continue;
+ }
+ 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)
+ 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;
+ }
+
+ 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--) {
+ if ((ipmp_member = calloc(1,
+ sizeof (ipadm_ipmp_member_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));
+
+ (void) strlcpy(ipmp_member->if_name, members[nelem],
+ sizeof (ipmp_member->if_name));
+ list_insert_tail(pmembers, ipmp_member);
+ }
return (IPADM_SUCCESS);
- } else if (err != 0) {
- free(rvalp);
- return (ipadm_errno2status(err));
+}
+
+/*
+ * Fill the ipadm_if_info_t->ifi_ipmp_cmembers by info from
+ * kernel (libipmp is used to retrive the required info)
+ */
+static ipadm_status_t
+i_ipadm_fill_cmembers(char *gropname, 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 ipmp_status;
+ uint_t i;
+
+ if ((ipmp_status = ipmp_open(&ipmp_handle)) != IPMP_SUCCESS)
+ return (IPADM_FAILURE);
+
+ if ((ipmp_status = ipmp_getgroupinfo(ipmp_handle,
+ gropname,
+ &grinfo)) != IPMP_SUCCESS) {
+ ipadm_status = IPADM_FAILURE;
+ goto fail;
}
- 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);
- break;
+ 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 fail;
}
- (void) bcopy(ifp, curr, sizeof (*curr));
- curr->ifi_next = prev;
- prev = curr;
+
+ (void) strlcpy(ipmp_member->if_name, iflistp->il_ifs[i],
+ sizeof (ipmp_member->if_name));
+ list_insert_tail(cmembers, ipmp_member);
}
- *if_info = curr;
- free(rvalp);
- return (status);
+
+fail:
+ ipmp_freegroupinfo(grinfo);
+ 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,
@@ -322,29 +466,34 @@
* add this interface to `aifinfo' and set it state to IFIF_DISABLED.
*/
for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) {
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 (aifp == NULL) {
- aifp = malloc(sizeof (ipadm_if_info_t));
- if (aifp == NULL) {
- status = ipadm_errno2status(errno);
+ if ((status =
+ i_ipadm_allocate_ifinfo(&aifp)) != IPADM_SUCCESS)
goto fail;
- }
- *aifp = *pifp;
+
+ (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->ifi_next = aifp;
else
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);
return (IPADM_SUCCESS);
fail:
@@ -352,10 +501,79 @@
ipadm_free_if_info(aifinfo);
ipadm_free_if_info(pifinfo);
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)
{
char *num = strrchr(ifname, IPADM_LOGICAL_SEP);
@@ -391,11 +609,11 @@
if (status == IPADM_SUCCESS) {
*exists = ((af == AF_INET &&
(ifinfo->ifi_pflags & IFIF_IPV4)) ||
(af == AF_INET6 &&
(ifinfo->ifi_pflags & IFIF_IPV6)));
- free(ifinfo);
+ ipadm_free_if_info(ifinfo);
} else if (status == IPADM_NOTFOUND) {
status = IPADM_SUCCESS;
*exists = B_FALSE;
}
return (status);
@@ -730,11 +948,12 @@
bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
lifr.lifr_addr.ss_family = 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);
}
}
@@ -911,11 +1130,12 @@
/*
* If IPADM_OPT_PERSIST was set in flags, store the
* 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);
}
}
@@ -1144,17 +1364,23 @@
/*
* Saves the given interface name `ifname' with address family `af' in
* 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);
return (ipadm_errno2status(err));
}
@@ -1261,10 +1487,11 @@
* or the persistent configuration.
*/
if (ipadm_if_enabled(iph, ifname, af))
return (IPADM_IF_EXISTS);
+#if 0
if (!(iph->iph_flags & IPH_LEGACY)) {
status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
if (status != IPADM_SUCCESS)
return (status);
other_af = (af == AF_INET ? AF_INET6 : AF_INET);
@@ -1273,11 +1500,11 @@
return (IPADM_OP_DISABLE_OBJ);
else
ipadm_flags &= ~IPADM_OPT_PERSIST;
}
}
-
+#endif
return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags));
}
/*
* Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
@@ -1343,11 +1570,140 @@
}
return (IPADM_SUCCESS);
}
+ipadm_status_t
+ipadm_add_ipmp_member(ipadm_handle_t iph, const char *gifname,
+ const char *mifname, uint32_t flags)
+{
+ return (i_ipadm_update_ipmp(iph, gifname, mifname,
+ flags, IPADM_ADD_IPMP_MEMBER));
+}
+
+ipadm_status_t
+ipadm_remove_ipmp_member(ipadm_handle_t iph, const char *gifname,
+ const char *mifname, uint32_t flags)
+{
+ return (i_ipadm_update_ipmp(iph, gifname, mifname,
+ flags, IPADM_REMOVE_IPMP_MEMBER));
+}
+
/*
+ * Update IPMP configuration according to requested operation,
+ * that can be
+ *
+ * IPADM_ADD_IPMP_MEMBER
+ *
+ * IPADM_REMOVE_IPMP_MEMBER
+ *
+ * At first it update the active config and if IPADM_OPT_PERSIST is set,
+ * then we also update persistent ipadm DB
+ */
+static ipadm_status_t
+i_ipadm_update_ipmp(ipadm_handle_t iph,
+ const char *gifname, const char *mifname,
+ uint32_t flags, ipadm_ipmp_operation_t operation)
+{
+ ipadm_status_t status;
+ char group_name1[LIFGRNAMSIZ];
+ char group_name2[LIFGRNAMSIZ];
+
+ /* Check for the required authorization */
+ if (!ipadm_check_auth())
+ return (IPADM_EAUTH);
+
+ if (!(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 1
+ if (!i_ipadm_is_ipmp(iph, gifname)) {
+ return (IPADM_INVALID_ARG);
+ }
+#endif
+ if (operation == IPADM_ADD_IPMP_MEMBER &&
+ i_ipadm_is_under_ipmp(iph, mifname))
+ return (IPADM_IF_INUSE);
+
+ if ((status = i_ipadm_get_groupname_active(iph, gifname,
+ group_name2, LIFGRNAMSIZ)) != IPADM_SUCCESS)
+ return (status);
+
+ if (operation == IPADM_REMOVE_IPMP_MEMBER) {
+ if ((status = i_ipadm_get_groupname_active(iph, mifname,
+ group_name1, LIFGRNAMSIZ)) != IPADM_SUCCESS)
+ return (status);
+
+ /* FIXME: Need to return something another */
+ if (group_name1[0] == '\0')
+ return (IPADM_INVALID_ARG);
+
+ /* FIXME: Need to return something another */
+ if (strcmp(group_name1, group_name2) != 0)
+ return (IPADM_INVALID_ARG);
+
+ group_name2[0] = '\0';
+ }
+
+ if ((status = i_ipadm_set_groupname_active(iph, mifname,
+ group_name2)) != IPADM_SUCCESS) {
+ return (status);
+ }
+ if (flags & IPADM_OPT_PERSIST) {
+ if ((status = i_ipadm_persist_update_ipmp(iph, gifname,
+ mifname, operation)) != IPADM_SUCCESS) {
+ /* Need to revert the active configuration */
+ if (operation == IPADM_ADD_IPMP_MEMBER) {
+ group_name2[0] = '\0';
+ (void) i_ipadm_set_groupname_active(iph,
+ mifname, group_name2);
+ }
+ }
+ }
+
+ return (status);
+}
+
+/*
+ * 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_operation_t operation)
+{
+ ipmgmt_ipmp_update_arg_t args;
+ int err;
+
+ assert(operation == IPADM_ADD_IPMP_MEMBER ||
+ operation == IPADM_REMOVE_IPMP_MEMBER);
+
+ 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 (operation == IPADM_ADD_IPMP_MEMBER)
+ 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.
*/
ipadm_status_t
ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
@@ -1446,14 +1802,27 @@
{
ipadm_if_info_t *ifinfo_next;
for (; ifinfo != NULL; ifinfo = ifinfo_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'.
*/
ipadm_status_t
@@ -1558,6 +1927,83 @@
void
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;
+
+ 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));
+
+ if (ioctl(iph->iph_sock, SIOCSLIFGROUPNAME, (caddr_t)&lifr) < 0 &&
+ ioctl(iph->iph_sock6, SIOCSLIFGROUPNAME, (caddr_t)&lifr) < 0) {
+ return (ipadm_errno2status(errno));
+ }
+
+ return (IPADM_SUCCESS);
+}
+
+ipadm_status_t
+i_ipadm_get_groupname_active(ipadm_handle_t iph, const char *ifname,
+ char *groupname, size_t size)
+{
+ struct lifreq lifr;
+
+ memset(&lifr, 0, sizeof (lifr));
+
+ (void) strlcpy(lifr.lifr_name, ifname,
+ sizeof (lifr.lifr_name));
+
+ if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0 &&
+ ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0)
+ 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,
+ LIFGRNAMSIZ) != IPADM_SUCCESS ||
+ groupname[0] == '\0')
+ return (B_FALSE);
+
+ if (strcmp(ifname, groupname) == 0)
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+/*
+ * 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);
}