diff options
Diffstat (limited to 'usr/src/lib/libipmp/common/ipmp_query.c')
-rw-r--r-- | usr/src/lib/libipmp/common/ipmp_query.c | 498 |
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; |