summaryrefslogtreecommitdiff
path: root/usr/src/lib/libipmp/common/ipmp_query.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libipmp/common/ipmp_query.c')
-rw-r--r--usr/src/lib/libipmp/common/ipmp_query.c498
1 files changed, 431 insertions, 67 deletions
diff --git a/usr/src/lib/libipmp/common/ipmp_query.c b/usr/src/lib/libipmp/common/ipmp_query.c
index 8a7dc7ee69..a0af2da578 100644
--- a/usr/src/lib/libipmp/common/ipmp_query.c
+++ b/usr/src/lib/libipmp/common/ipmp_query.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -18,20 +17,18 @@
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
- */
-/*
- * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
- * IPMP query interfaces (PSARC/2002/615).
+ * IPMP query interfaces (see PSARC/2002/615 and PSARC/2007/272).
*/
#include <assert.h>
#include <errno.h>
+#include <libinetutil.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
@@ -41,13 +38,19 @@
#include "ipmp_mpathd.h"
#include "ipmp_query_impl.h"
-#define IPMP_REQTIMEOUT 5 /* seconds */
-
static ipmp_ifinfo_t *ipmp_ifinfo_clone(ipmp_ifinfo_t *);
+static ipmp_addrinfo_t *ipmp_addrinfo_clone(ipmp_addrinfo_t *);
+static ipmp_addrlist_t *ipmp_addrlist_clone(ipmp_addrlist_t *);
static ipmp_grouplist_t *ipmp_grouplist_clone(ipmp_grouplist_t *);
static ipmp_groupinfo_t *ipmp_groupinfo_clone(ipmp_groupinfo_t *);
+static ipmp_iflist_t *ipmp_iflist_create(uint_t, char (*)[LIFNAMSIZ]);
+static void ipmp_freeiflist(ipmp_iflist_t *);
+static ipmp_addrlist_t *ipmp_addrlist_create(uint_t, struct sockaddr_storage *);
+static void ipmp_freeaddrlist(ipmp_addrlist_t *);
static ipmp_groupinfo_t *ipmp_snap_getgroupinfo(ipmp_snap_t *, const char *);
static ipmp_ifinfo_t *ipmp_snap_getifinfo(ipmp_snap_t *, const char *);
+static ipmp_addrinfo_t *ipmp_snap_getaddrinfo(ipmp_snap_t *, const char *,
+ struct sockaddr_storage *);
static int ipmp_snap_take(ipmp_state_t *, ipmp_snap_t **);
static boolean_t ipmp_checktlv(ipmp_infotype_t, size_t, void *);
static int ipmp_querydone(ipmp_state_t *, int);
@@ -62,7 +65,7 @@ static int ipmp_querydone(ipmp_state_t *, int);
*/
static int
ipmp_sendquery(ipmp_state_t *statep, ipmp_infotype_t type, const char *name,
- struct timeval *endtp)
+ const void *addr, struct timeval *endtp)
{
mi_query_t query;
mi_result_t result;
@@ -72,6 +75,11 @@ ipmp_sendquery(ipmp_state_t *statep, ipmp_infotype_t type, const char *name,
query.miq_inforeq = type;
switch (type) {
+ case IPMP_ADDRINFO:
+ (void) strlcpy(query.miq_grname, name, LIFGRNAMSIZ);
+ query.miq_addr = *(struct sockaddr_storage *)addr;
+ break;
+
case IPMP_GROUPINFO:
(void) strlcpy(query.miq_grname, name, LIFGRNAMSIZ);
break;
@@ -138,6 +146,61 @@ ipmp_readinfo(ipmp_state_t *statep, ipmp_infotype_t infotype, void **infop,
}
/*
+ * Using `statep', read in the remaining IPMP group information TLVs from
+ * in.mpathd into `grinfop' before the current time becomes `endtp'. Returns
+ * an IPMP error code. On failure, `grinfop' will have its original contents.
+ */
+static int
+ipmp_readgroupinfo_lists(ipmp_state_t *statep, ipmp_groupinfo_t *grinfop,
+ const struct timeval *endtp)
+{
+ int retval;
+ ipmp_iflist_t *iflistp;
+ ipmp_addrlist_t *adlistp;
+
+ retval = ipmp_readinfo(statep, IPMP_IFLIST, (void **)&iflistp, endtp);
+ if (retval != IPMP_SUCCESS)
+ return (retval);
+
+ retval = ipmp_readinfo(statep, IPMP_ADDRLIST, (void **)&adlistp, endtp);
+ if (retval != IPMP_SUCCESS) {
+ ipmp_freeiflist(iflistp);
+ return (retval);
+ }
+
+ grinfop->gr_iflistp = iflistp;
+ grinfop->gr_adlistp = adlistp;
+ return (IPMP_SUCCESS);
+}
+
+/*
+ * Using `statep', read in the remaining IPMP interface information TLVs from
+ * in.mpathd into `ifinfop' before the current time becomes `endtp'. Returns
+ * an IPMP error code. On failure, `ifinfop' will have its original contents.
+ */
+static int
+ipmp_readifinfo_lists(ipmp_state_t *statep, ipmp_ifinfo_t *ifinfop,
+ const struct timeval *endtp)
+{
+ int retval;
+ ipmp_addrlist_t *tlist4p, *tlist6p;
+
+ retval = ipmp_readinfo(statep, IPMP_ADDRLIST, (void **)&tlist4p, endtp);
+ if (retval != IPMP_SUCCESS)
+ return (retval);
+
+ retval = ipmp_readinfo(statep, IPMP_ADDRLIST, (void **)&tlist6p, endtp);
+ if (retval != IPMP_SUCCESS) {
+ ipmp_freeaddrlist(tlist4p);
+ return (retval);
+ }
+
+ ifinfop->if_targinfo4.it_targlistp = tlist4p;
+ ifinfop->if_targinfo6.it_targlistp = tlist6p;
+ return (IPMP_SUCCESS);
+}
+
+/*
* Complete the query operation started in ipmp_sendquery(). The interface is
* designed to be easy to use in the `return' statement of a function, and
* thus returns the passed in `retval' and preserves `errno'.
@@ -169,7 +232,7 @@ ipmp_getgrouplist(ipmp_handle_t handle, ipmp_grouplist_t **grlistpp)
return (*grlistpp != NULL ? IPMP_SUCCESS : IPMP_ENOMEM);
}
- retval = ipmp_sendquery(statep, IPMP_GROUPLIST, NULL, &end);
+ retval = ipmp_sendquery(statep, IPMP_GROUPLIST, NULL, NULL, &end);
if (retval != IPMP_SUCCESS)
return (retval);
@@ -196,7 +259,6 @@ ipmp_getgroupinfo(ipmp_handle_t handle, const char *name,
ipmp_groupinfo_t **grinfopp)
{
ipmp_state_t *statep = handle;
- ipmp_iflist_t *iflistp;
int retval;
struct timeval end;
ipmp_groupinfo_t *grinfop;
@@ -210,7 +272,7 @@ ipmp_getgroupinfo(ipmp_handle_t handle, const char *name,
return (*grinfopp != NULL ? IPMP_SUCCESS : IPMP_ENOMEM);
}
- retval = ipmp_sendquery(statep, IPMP_GROUPINFO, name, &end);
+ retval = ipmp_sendquery(statep, IPMP_GROUPINFO, name, NULL, &end);
if (retval != IPMP_SUCCESS)
return (retval);
@@ -218,11 +280,9 @@ ipmp_getgroupinfo(ipmp_handle_t handle, const char *name,
if (retval != IPMP_SUCCESS)
return (ipmp_querydone(statep, retval));
- retval = ipmp_readinfo(statep, IPMP_IFLIST, (void **)&iflistp, &end);
+ retval = ipmp_readgroupinfo_lists(statep, *grinfopp, &end);
if (retval != IPMP_SUCCESS)
free(*grinfopp);
- else
- (*grinfopp)->gr_iflistp = iflistp;
return (ipmp_querydone(statep, retval));
}
@@ -233,7 +293,8 @@ ipmp_getgroupinfo(ipmp_handle_t handle, const char *name,
void
ipmp_freegroupinfo(ipmp_groupinfo_t *grinfop)
{
- free(grinfop->gr_iflistp);
+ ipmp_freeaddrlist(grinfop->gr_adlistp);
+ ipmp_freeiflist(grinfop->gr_iflistp);
free(grinfop);
}
@@ -259,11 +320,18 @@ ipmp_getifinfo(ipmp_handle_t handle, const char *name, ipmp_ifinfo_t **ifinfopp)
return (*ifinfopp != NULL ? IPMP_SUCCESS : IPMP_ENOMEM);
}
- retval = ipmp_sendquery(statep, IPMP_IFINFO, name, &end);
+ retval = ipmp_sendquery(statep, IPMP_IFINFO, name, NULL, &end);
if (retval != IPMP_SUCCESS)
return (retval);
retval = ipmp_readinfo(statep, IPMP_IFINFO, (void **)ifinfopp, &end);
+ if (retval != IPMP_SUCCESS)
+ return (ipmp_querydone(statep, retval));
+
+ retval = ipmp_readifinfo_lists(statep, *ifinfopp, &end);
+ if (retval != IPMP_SUCCESS)
+ free(*ifinfopp);
+
return (ipmp_querydone(statep, retval));
}
@@ -273,10 +341,52 @@ ipmp_getifinfo(ipmp_handle_t handle, const char *name, ipmp_ifinfo_t **ifinfopp)
void
ipmp_freeifinfo(ipmp_ifinfo_t *ifinfop)
{
+ ipmp_freeaddrlist(ifinfop->if_targinfo4.it_targlistp);
+ ipmp_freeaddrlist(ifinfop->if_targinfo6.it_targlistp);
free(ifinfop);
}
/*
+ * Using `handle', get the address information associated with address `addrp'
+ * on group `grname' and store the results in a dynamically allocated buffer
+ * pointed to by `*adinfopp'. Returns an IPMP error code.
+ */
+int
+ipmp_getaddrinfo(ipmp_handle_t handle, const char *grname,
+ struct sockaddr_storage *addrp, ipmp_addrinfo_t **adinfopp)
+{
+ ipmp_state_t *statep = handle;
+ ipmp_addrinfo_t *adinfop;
+ int retval;
+ struct timeval end;
+
+ if (statep->st_snap != NULL) {
+ adinfop = ipmp_snap_getaddrinfo(statep->st_snap, grname, addrp);
+ if (adinfop == NULL)
+ return (IPMP_EUNKADDR);
+
+ *adinfopp = ipmp_addrinfo_clone(adinfop);
+ return (*adinfopp != NULL ? IPMP_SUCCESS : IPMP_ENOMEM);
+ }
+
+ retval = ipmp_sendquery(statep, IPMP_ADDRINFO, grname, addrp, &end);
+ if (retval != IPMP_SUCCESS)
+ return (retval);
+
+ retval = ipmp_readinfo(statep, IPMP_ADDRINFO, (void **)adinfopp, &end);
+ return (ipmp_querydone(statep, retval));
+}
+
+/*
+ * Free the address information pointed to by `adinfop'.
+ */
+void
+ipmp_freeaddrinfo(ipmp_addrinfo_t *adinfop)
+{
+ free(adinfop);
+}
+
+/*
* Check if `buf' has a NUL byte in its first `bufsize' bytes.
*/
static boolean_t
@@ -300,12 +410,25 @@ ipmp_checktlv(ipmp_infotype_t type, size_t len, void *value)
ipmp_ifinfo_t *ifinfop;
ipmp_grouplist_t *grlistp;
ipmp_groupinfo_t *grinfop;
+ ipmp_addrlist_t *adlistp;
unsigned int i;
switch (type) {
+ case IPMP_ADDRINFO:
+ if (len != sizeof (ipmp_addrinfo_t))
+ return (B_FALSE);
+ break;
+
+ case IPMP_ADDRLIST:
+ adlistp = (ipmp_addrlist_t *)value;
+ if (len < IPMP_ADDRLIST_SIZE(0) ||
+ len < IPMP_ADDRLIST_SIZE(adlistp->al_naddr))
+ return (B_FALSE);
+ break;
+
case IPMP_IFLIST:
iflistp = (ipmp_iflist_t *)value;
- if (len < IPMP_IFLIST_MINSIZE ||
+ if (len < IPMP_IFLIST_SIZE(0) ||
len < IPMP_IFLIST_SIZE(iflistp->il_nif))
return (B_FALSE);
@@ -326,7 +449,7 @@ ipmp_checktlv(ipmp_infotype_t type, size_t len, void *value)
case IPMP_GROUPLIST:
grlistp = (ipmp_grouplist_t *)value;
- if (len < IPMP_GROUPLIST_MINSIZE ||
+ if (len < IPMP_GROUPLIST_SIZE(0) ||
len < IPMP_GROUPLIST_SIZE(grlistp->gl_ngroup))
return (B_FALSE);
@@ -357,9 +480,8 @@ ipmp_checktlv(ipmp_infotype_t type, size_t len, void *value)
}
/*
- * Create a group list with signature `sig' containing `ngroup' groups named
- * by `groups'. Returns a pointer to the new group list on success, or NULL
- * on failure.
+ * Create a group list; arguments match ipmp_grouplist_t fields. Returns a
+ * pointer to the new group list on success, or NULL on failure.
*/
ipmp_grouplist_t *
ipmp_grouplist_create(uint64_t sig, unsigned int ngroup,
@@ -392,13 +514,80 @@ ipmp_grouplist_clone(ipmp_grouplist_t *grlistp)
}
/*
- * Create an interface information structure for interface `name' and
- * associate `group', `state' and `type' with it. Returns a pointer to the
- * interface information on success, or NULL on failure.
+ * Create target information; arguments match ipmp_targinfo_t fields. Returns
+ * a pointer to the new target info on success, or NULL on failure.
+ */
+ipmp_targinfo_t *
+ipmp_targinfo_create(const char *name, struct sockaddr_storage *testaddrp,
+ ipmp_if_targmode_t targmode, uint_t ntarg, struct sockaddr_storage *targs)
+{
+ ipmp_targinfo_t *targinfop;
+
+ targinfop = malloc(sizeof (ipmp_targinfo_t));
+ if (targinfop == NULL)
+ return (NULL);
+
+ targinfop->it_testaddr = *testaddrp;
+ targinfop->it_targmode = targmode;
+ targinfop->it_targlistp = ipmp_addrlist_create(ntarg, targs);
+ if (targinfop->it_targlistp == NULL) {
+ ipmp_freetarginfo(targinfop);
+ return (NULL);
+ }
+ (void) strlcpy(targinfop->it_name, name, LIFNAMSIZ);
+
+ return (targinfop);
+}
+
+/*
+ * Free the target information pointed to by `targinfop'.
+ */
+void
+ipmp_freetarginfo(ipmp_targinfo_t *targinfop)
+{
+ free(targinfop->it_targlistp);
+ free(targinfop);
+}
+
+/*
+ * Create an interface list; arguments match ipmp_iflist_t fields. Returns a
+ * pointer to the new interface list on success, or NULL on failure.
+ */
+static ipmp_iflist_t *
+ipmp_iflist_create(uint_t nif, char (*ifs)[LIFNAMSIZ])
+{
+ unsigned int i;
+ ipmp_iflist_t *iflistp;
+
+ iflistp = malloc(IPMP_IFLIST_SIZE(nif));
+ if (iflistp == NULL)
+ return (NULL);
+
+ iflistp->il_nif = nif;
+ for (i = 0; i < nif; i++)
+ (void) strlcpy(iflistp->il_ifs[i], ifs[i], LIFNAMSIZ);
+
+ return (iflistp);
+}
+
+/*
+ * Free the interface list pointed to by `iflistp'.
+ */
+static void
+ipmp_freeiflist(ipmp_iflist_t *iflistp)
+{
+ free(iflistp);
+}
+
+/*
+ * Create an interface; arguments match ipmp_ifinfo_t fields. Returns a
+ * pointer to the new interface on success, or NULL on failure.
*/
ipmp_ifinfo_t *
ipmp_ifinfo_create(const char *name, const char *group, ipmp_if_state_t state,
- ipmp_if_type_t type)
+ ipmp_if_type_t type, ipmp_if_linkstate_t linkstate,
+ ipmp_if_probestate_t probestate, ipmp_if_flags_t flags,
+ ipmp_targinfo_t *targinfo4p, ipmp_targinfo_t *targinfo6p)
{
ipmp_ifinfo_t *ifinfop;
@@ -408,8 +597,25 @@ ipmp_ifinfo_create(const char *name, const char *group, ipmp_if_state_t state,
(void) strlcpy(ifinfop->if_name, name, LIFNAMSIZ);
(void) strlcpy(ifinfop->if_group, group, LIFGRNAMSIZ);
- ifinfop->if_state = state;
- ifinfop->if_type = type;
+
+ ifinfop->if_state = state;
+ ifinfop->if_type = type;
+ ifinfop->if_linkstate = linkstate;
+ ifinfop->if_probestate = probestate;
+ ifinfop->if_flags = flags;
+ ifinfop->if_targinfo4 = *targinfo4p;
+ ifinfop->if_targinfo6 = *targinfo6p;
+
+ ifinfop->if_targinfo4.it_targlistp =
+ ipmp_addrlist_clone(targinfo4p->it_targlistp);
+ ifinfop->if_targinfo6.it_targlistp =
+ ipmp_addrlist_clone(targinfo6p->it_targlistp);
+
+ if (ifinfop->if_targinfo4.it_targlistp == NULL ||
+ ifinfop->if_targinfo6.it_targlistp == NULL) {
+ ipmp_freeifinfo(ifinfop);
+ return (NULL);
+ }
return (ifinfop);
}
@@ -422,40 +628,41 @@ ipmp_ifinfo_t *
ipmp_ifinfo_clone(ipmp_ifinfo_t *ifinfop)
{
return (ipmp_ifinfo_create(ifinfop->if_name, ifinfop->if_group,
- ifinfop->if_state, ifinfop->if_type));
+ ifinfop->if_state, ifinfop->if_type, ifinfop->if_linkstate,
+ ifinfop->if_probestate, ifinfop->if_flags, &ifinfop->if_targinfo4,
+ &ifinfop->if_targinfo6));
}
/*
- * Create a group named `name' with signature `sig', in state `state', and
- * with the `nif' interfaces named by `ifs' as members. Returns a pointer
+ * Create a group; arguments match ipmp_groupinfo_t fields. Returns a pointer
* to the new group on success, or NULL on failure.
*/
ipmp_groupinfo_t *
-ipmp_groupinfo_create(const char *name, uint64_t sig, ipmp_group_state_t state,
- unsigned int nif, char (*ifs)[LIFNAMSIZ])
+ipmp_groupinfo_create(const char *name, uint64_t sig, uint_t fdt,
+ ipmp_group_state_t state, uint_t nif, char (*ifs)[LIFNAMSIZ],
+ const char *grifname, const char *m4ifname, const char *m6ifname,
+ const char *bcifname, uint_t naddr, struct sockaddr_storage *addrs)
{
ipmp_groupinfo_t *grinfop;
- ipmp_iflist_t *iflistp;
- unsigned int i;
grinfop = malloc(sizeof (ipmp_groupinfo_t));
if (grinfop == NULL)
return (NULL);
- iflistp = malloc(IPMP_IFLIST_SIZE(nif));
- if (iflistp == NULL) {
- free(grinfop);
+ grinfop->gr_sig = sig;
+ grinfop->gr_fdt = fdt;
+ grinfop->gr_state = state;
+ grinfop->gr_iflistp = ipmp_iflist_create(nif, ifs);
+ grinfop->gr_adlistp = ipmp_addrlist_create(naddr, addrs);
+ if (grinfop->gr_iflistp == NULL || grinfop->gr_adlistp == NULL) {
+ ipmp_freegroupinfo(grinfop);
return (NULL);
}
-
- grinfop->gr_sig = sig;
- grinfop->gr_state = state;
- grinfop->gr_iflistp = iflistp;
(void) strlcpy(grinfop->gr_name, name, LIFGRNAMSIZ);
-
- iflistp->il_nif = nif;
- for (i = 0; i < nif; i++)
- (void) strlcpy(iflistp->il_ifs[i], ifs[i], LIFNAMSIZ);
+ (void) strlcpy(grinfop->gr_ifname, grifname, LIFNAMSIZ);
+ (void) strlcpy(grinfop->gr_m4ifname, m4ifname, LIFNAMSIZ);
+ (void) strlcpy(grinfop->gr_m6ifname, m6ifname, LIFNAMSIZ);
+ (void) strlcpy(grinfop->gr_bcifname, bcifname, LIFNAMSIZ);
return (grinfop);
}
@@ -467,9 +674,86 @@ ipmp_groupinfo_create(const char *name, uint64_t sig, ipmp_group_state_t state,
ipmp_groupinfo_t *
ipmp_groupinfo_clone(ipmp_groupinfo_t *grinfop)
{
+ ipmp_addrlist_t *adlistp = grinfop->gr_adlistp;
+
return (ipmp_groupinfo_create(grinfop->gr_name, grinfop->gr_sig,
- grinfop->gr_state, grinfop->gr_iflistp->il_nif,
- grinfop->gr_iflistp->il_ifs));
+ grinfop->gr_fdt, grinfop->gr_state, grinfop->gr_iflistp->il_nif,
+ grinfop->gr_iflistp->il_ifs, grinfop->gr_ifname,
+ grinfop->gr_m4ifname, grinfop->gr_m6ifname, grinfop->gr_bcifname,
+ adlistp->al_naddr, adlistp->al_addrs));
+}
+
+/*
+ * Create an address list; arguments match ipmp_addrlist_t fields. Returns
+ * a pointer to the new address list on success, or NULL on failure.
+ */
+static ipmp_addrlist_t *
+ipmp_addrlist_create(uint_t naddr, struct sockaddr_storage *addrs)
+{
+ unsigned int i;
+ ipmp_addrlist_t *adlistp;
+
+ adlistp = malloc(IPMP_ADDRLIST_SIZE(naddr));
+ if (adlistp == NULL)
+ return (NULL);
+
+ adlistp->al_naddr = naddr;
+ for (i = 0; i < naddr; i++)
+ adlistp->al_addrs[i] = addrs[i];
+
+ return (adlistp);
+}
+
+/*
+ * Clone the address list named by `adlistp'. Returns a pointer to the clone
+ * on success, or NULL on failure.
+ */
+static ipmp_addrlist_t *
+ipmp_addrlist_clone(ipmp_addrlist_t *adlistp)
+{
+ return (ipmp_addrlist_create(adlistp->al_naddr, adlistp->al_addrs));
+}
+
+/*
+ * Free the address list pointed to by `adlistp'.
+ */
+static void
+ipmp_freeaddrlist(ipmp_addrlist_t *adlistp)
+{
+ free(adlistp);
+}
+
+/*
+ * Create an address; arguments match ipmp_addrinfo_t fields. Returns a
+ * pointer to the new address on success, or NULL on failure.
+ */
+ipmp_addrinfo_t *
+ipmp_addrinfo_create(struct sockaddr_storage *addrp, ipmp_addr_state_t state,
+ const char *group, const char *binding)
+{
+ ipmp_addrinfo_t *adinfop;
+
+ adinfop = malloc(sizeof (ipmp_addrinfo_t));
+ if (adinfop == NULL)
+ return (NULL);
+
+ adinfop->ad_addr = *addrp;
+ adinfop->ad_state = state;
+ (void) strlcpy(adinfop->ad_group, group, LIFGRNAMSIZ);
+ (void) strlcpy(adinfop->ad_binding, binding, LIFNAMSIZ);
+
+ return (adinfop);
+}
+
+/*
+ * Clone the address information named by `adinfop'. Returns a pointer to
+ * the clone on success, or NULL on failure.
+ */
+ipmp_addrinfo_t *
+ipmp_addrinfo_clone(ipmp_addrinfo_t *adinfop)
+{
+ return (ipmp_addrinfo_create(&adinfop->ad_addr, adinfop->ad_state,
+ adinfop->ad_group, adinfop->ad_binding));
}
/*
@@ -523,8 +807,10 @@ ipmp_snap_create(void)
snap->sn_grlistp = NULL;
snap->sn_grinfolistp = NULL;
snap->sn_ifinfolistp = NULL;
+ snap->sn_adinfolistp = NULL;
snap->sn_ngroup = 0;
snap->sn_nif = 0;
+ snap->sn_naddr = 0;
return (snap);
}
@@ -536,6 +822,7 @@ void
ipmp_snap_free(ipmp_snap_t *snap)
{
ipmp_ifinfolist_t *iflp, *ifnext;
+ ipmp_addrinfolist_t *adlp, *adnext;
ipmp_groupinfolist_t *grlp, *grnext;
ipmp_freegrouplist(snap->sn_grlistp);
@@ -552,6 +839,12 @@ ipmp_snap_free(ipmp_snap_t *snap)
free(iflp);
}
+ for (adlp = snap->sn_adinfolistp; adlp != NULL; adlp = adnext) {
+ adnext = adlp->adl_next;
+ ipmp_freeaddrinfo(adlp->adl_adinfop);
+ free(adlp);
+ }
+
free(snap);
}
@@ -612,6 +905,34 @@ ipmp_snap_addifinfo(ipmp_snap_t *snap, ipmp_ifinfo_t *ifinfop)
}
/*
+ * Add the address information in `adinfop' to the snapshot named by `snap'.
+ * Returns an IPMP error code.
+ */
+int
+ipmp_snap_addaddrinfo(ipmp_snap_t *snap, ipmp_addrinfo_t *adinfop)
+{
+ ipmp_addrinfolist_t *adlp;
+
+ /*
+ * Any duplicate addresses should've already been weeded by in.mpathd.
+ */
+ if (ipmp_snap_getaddrinfo(snap, adinfop->ad_group,
+ &adinfop->ad_addr) != NULL)
+ return (IPMP_EPROTO);
+
+ adlp = malloc(sizeof (ipmp_addrinfolist_t));
+ if (adlp == NULL)
+ return (IPMP_ENOMEM);
+
+ adlp->adl_adinfop = adinfop;
+ adlp->adl_next = snap->sn_adinfolistp;
+ snap->sn_adinfolistp = adlp;
+ snap->sn_naddr++;
+
+ return (IPMP_SUCCESS);
+}
+
+/*
* Retrieve the information for the group `name' in snapshot `snap'.
* Returns a pointer to the group information on success, or NULL on failure.
*/
@@ -647,6 +968,26 @@ ipmp_snap_getifinfo(ipmp_snap_t *snap, const char *name)
}
/*
+ * Retrieve the information for the address `addrp' on group `grname' in
+ * snapshot `snap'. Returns a pointer to the address information on success,
+ * or NULL on failure.
+ */
+static ipmp_addrinfo_t *
+ipmp_snap_getaddrinfo(ipmp_snap_t *snap, const char *grname,
+ struct sockaddr_storage *addrp)
+{
+ ipmp_addrinfolist_t *adlp;
+
+ for (adlp = snap->sn_adinfolistp; adlp != NULL; adlp = adlp->adl_next) {
+ if (strcmp(grname, adlp->adl_adinfop->ad_group) == 0 &&
+ sockaddrcmp(addrp, &adlp->adl_adinfop->ad_addr))
+ break;
+ }
+
+ return (adlp != NULL ? adlp->adl_adinfop : NULL);
+}
+
+/*
* Using `statep', take a snapshot of the IPMP subsystem and if successful
* return it in a dynamically allocated snapshot pointed to by `*snapp'.
* Returns an IPMP error code.
@@ -656,7 +997,6 @@ ipmp_snap_take(ipmp_state_t *statep, ipmp_snap_t **snapp)
{
ipmp_snap_t *snap, *osnap;
ipmp_infotype_t type;
- ipmp_iflist_t *iflistp;
int retval;
size_t len;
void *infop;
@@ -666,7 +1006,7 @@ ipmp_snap_take(ipmp_state_t *statep, ipmp_snap_t **snapp)
if (snap == NULL)
return (IPMP_ENOMEM);
- retval = ipmp_sendquery(statep, IPMP_SNAP, NULL, &end);
+ retval = ipmp_sendquery(statep, IPMP_SNAP, NULL, NULL, &end);
if (retval != IPMP_SUCCESS) {
ipmp_snap_free(snap);
return (retval);
@@ -679,12 +1019,11 @@ ipmp_snap_take(ipmp_state_t *statep, ipmp_snap_t **snapp)
}
/*
- * Using the information in the passed `osnap' snapshot, build up our
- * own snapshot. If we receive more than one grouplist, or more than
- * the expected number of interfaces or groups, then bail out. Note
- * that there's only so much we can do to check that the information
- * sent by in.mpathd makes sense. We know there will always be at
- * least one TLV (IPMP_GROUPLIST).
+ * Using the information in the `osnap' snapshot, build up our own
+ * snapshot. We know there will always be at least one TLV (for
+ * IPMP_GROUPLIST). If we receive anything illogical (e.g., more than
+ * the expected number of interfaces), then bail out. However, to a
+ * large extent we have to trust the information sent by in.mpathd.
*/
do {
infop = NULL;
@@ -711,7 +1050,32 @@ ipmp_snap_take(ipmp_state_t *statep, ipmp_snap_t **snapp)
retval = IPMP_EPROTO;
break;
}
+
+ /*
+ * Read in V4 and V6 targlist TLVs that follow.
+ */
+ retval = ipmp_readifinfo_lists(statep, infop, &end);
+ if (retval != IPMP_SUCCESS)
+ break;
+
retval = ipmp_snap_addifinfo(snap, infop);
+ if (retval != IPMP_SUCCESS) {
+ ipmp_freeifinfo(infop);
+ infop = NULL;
+ }
+ break;
+
+ case IPMP_ADDRINFO:
+ if (snap->sn_naddr == osnap->sn_naddr) {
+ retval = IPMP_EPROTO;
+ break;
+ }
+
+ retval = ipmp_snap_addaddrinfo(snap, infop);
+ /*
+ * NOTE: since we didn't call ipmp_read*info_lists(),
+ * no need to use ipmp_freeaddrinfo() on failure.
+ */
break;
case IPMP_GROUPINFO:
@@ -721,18 +1085,17 @@ ipmp_snap_take(ipmp_state_t *statep, ipmp_snap_t **snapp)
}
/*
- * An IPMP_IFLIST TLV always follows the
- * IPMP_GROUPINFO TLV; read it in.
+ * Read in IPMP groupinfo list TLVs that follow.
*/
- retval = ipmp_readinfo(statep, IPMP_IFLIST,
- (void **)&iflistp, &end);
+ retval = ipmp_readgroupinfo_lists(statep, infop, &end);
if (retval != IPMP_SUCCESS)
break;
- ((ipmp_groupinfo_t *)infop)->gr_iflistp = iflistp;
retval = ipmp_snap_addgroupinfo(snap, infop);
- if (retval != IPMP_SUCCESS)
- free(iflistp);
+ if (retval != IPMP_SUCCESS) {
+ ipmp_freegroupinfo(infop);
+ infop = NULL;
+ }
break;
default:
@@ -747,7 +1110,8 @@ fail:
return (ipmp_querydone(statep, retval));
}
} while (snap->sn_grlistp == NULL || snap->sn_nif < osnap->sn_nif ||
- snap->sn_ngroup < osnap->sn_ngroup);
+ snap->sn_ngroup < osnap->sn_ngroup ||
+ snap->sn_naddr < osnap->sn_naddr);
free(osnap);
*snapp = snap;