Print this page
Commit IPMP changes
*** 18,31 ****
--- 18,33 ----
*
* 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,52 ****
#include <libinetutil.h>
#include <inet/ip.h>
#include <limits.h>
#include <zone.h>
#include <ipadm_ndpd.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);
/*
* Returns B_FALSE if the interface in `ifname' has at least one address that is
* IFF_UP in the addresses in `ifa'.
*/
--- 36,70 ----
#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, 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,134 ****
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;
! }
(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;
--- 138,151 ----
for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) {
if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0)
break;
}
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 `ifi_next' pointer for this new node */
if (*if_info == NULL)
*if_info = ifp;
*** 145,164 ****
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;
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)
ifp->ifi_cflags |= IFIF_VIRTUAL;
! if (lifrl.lifr_flags & IFF_IPMP)
ifp->ifi_cflags |= IFIF_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)
--- 162,189 ----
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) {
ifp->ifi_cflags |= IFIF_VIRTUAL;
! 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,185 ****
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;
}
free(buf);
! return (IPADM_SUCCESS);
! fail:
! free(buf);
ipadm_free_if_info(*if_info);
*if_info = NULL;
return (status);
}
/*
* Returns the interface information for `ifname' in `if_info' from persistent
--- 194,223 ----
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);
! 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,239 ****
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;
- 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)
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));
}
! 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;
}
! (void) bcopy(ifp, curr, sizeof (*curr));
! curr->ifi_next = prev;
! prev = curr;
}
! *if_info = curr;
! free(rvalp);
! return (status);
}
/*
* Collects information for `ifname' if one is specified from both
* active and persistent config in `if_info'. If no `ifname' is specified,
--- 227,383 ----
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;
! nvlist_t *ifs_info_nvl;
*if_info = 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));
!
! (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 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;
}
! 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) strlcpy(ipmp_member->if_name, iflistp->il_ifs[i],
! sizeof (ipmp_member->if_name));
! list_insert_tail(cmembers, ipmp_member);
}
!
! 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,350 ****
* 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);
goto fail;
! }
! *aifp = *pifp;
aifp->ifi_next = NULL;
aifp->ifi_state = IFIS_DISABLED;
if (last != NULL)
last->ifi_next = aifp;
else
aifinfo = aifp;
last = aifp;
}
}
*if_info = aifinfo;
ipadm_free_if_info(pifinfo);
return (IPADM_SUCCESS);
fail:
--- 466,499 ----
* 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) {
break;
}
}
+
if (aifp == NULL) {
! if ((status =
! i_ipadm_allocate_ifinfo(&aifp)) != IPADM_SUCCESS)
goto fail;
!
! (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,361 ****
--- 501,579 ----
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,401 ****
if (status == IPADM_SUCCESS) {
*exists = ((af == AF_INET &&
(ifinfo->ifi_pflags & IFIF_IPV4)) ||
(af == AF_INET6 &&
(ifinfo->ifi_pflags & IFIF_IPV6)));
! free(ifinfo);
} else if (status == IPADM_NOTFOUND) {
status = IPADM_SUCCESS;
*exists = B_FALSE;
}
return (status);
--- 609,619 ----
if (status == IPADM_SUCCESS) {
*exists = ((af == AF_INET &&
(ifinfo->ifi_pflags & IFIF_IPV4)) ||
(af == AF_INET6 &&
(ifinfo->ifi_pflags & IFIF_IPV6)));
! ipadm_free_if_info(ifinfo);
} else if (status == IPADM_NOTFOUND) {
status = IPADM_SUCCESS;
*exists = B_FALSE;
}
return (status);
*** 730,740 ****
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);
if (status != IPADM_SUCCESS) {
(void) i_ipadm_delete_if(iph, ifname,
af, IPADM_OPT_ACTIVE);
}
}
--- 948,959 ----
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, ipadm_flags);
if (status != IPADM_SUCCESS) {
(void) i_ipadm_delete_if(iph, ifname,
af, IPADM_OPT_ACTIVE);
}
}
*** 911,921 ****
/*
* 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);
if (status != IPADM_SUCCESS) {
(void) i_ipadm_delete_if(iph, newif, af,
IPADM_OPT_ACTIVE);
}
}
--- 1130,1141 ----
/*
* 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, ipadm_flags);
if (status != IPADM_SUCCESS) {
(void) i_ipadm_delete_if(iph, newif, af,
IPADM_OPT_ACTIVE);
}
}
*** 1144,1160 ****
/*
* 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)
{
ipmgmt_if_arg_t ifarg;
int err;
(void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname));
ifarg.ia_family = af;
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));
}
--- 1364,1386 ----
/*
* 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, 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,1270 ****
--- 1487,1497 ----
* 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,1283 ****
return (IPADM_OP_DISABLE_OBJ);
else
ipadm_flags &= ~IPADM_OPT_PERSIST;
}
}
!
return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags));
}
/*
* Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
--- 1500,1510 ----
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,1353 ****
--- 1570,1709 ----
}
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,1459 ****
--- 1802,1828 ----
{
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,1563 ****
--- 1927,2009 ----
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);
}