diff --git a/src/conf/nwfilter_params.c b/src/conf/nwfilter_params.c index 2fba3513908bb875ad8e17aff78aa864a2a34f44..12c65246c3d8e1ce279e77b0bf208e74e596a74b 100644 --- a/src/conf/nwfilter_params.c +++ b/src/conf/nwfilter_params.c @@ -37,7 +37,7 @@ static bool isValidVarValue(const char *value); -static void +void virNWFilterVarValueFree(virNWFilterVarValuePtr val) { unsigned i; @@ -60,7 +60,7 @@ virNWFilterVarValueFree(virNWFilterVarValuePtr val) VIR_FREE(val); } -static virNWFilterVarValuePtr +virNWFilterVarValuePtr virNWFilterVarValueCopy(const virNWFilterVarValuePtr val) { virNWFilterVarValuePtr res; @@ -222,6 +222,56 @@ virNWFilterVarValueAddValue(virNWFilterVarValuePtr val, char *value) return rc; } +static int +virNWFilterVarValueDelNthValue(virNWFilterVarValuePtr val, unsigned int pos) +{ + switch (val->valType) { + case NWFILTER_VALUE_TYPE_SIMPLE: + return -1; + + case NWFILTER_VALUE_TYPE_ARRAY: + if (pos < val->u.array.nValues) { + VIR_FREE(val->u.array.values[pos]); + val->u.array.nValues--; + + if (pos < val->u.array.nValues) + memmove(&val->u.array.values[pos], + &val->u.array.values[pos + 1], + sizeof(val->u.array.values[0]) * + (val->u.array.nValues - pos)); + return 0; + } + break; + + case NWFILTER_VALUE_TYPE_LAST: + break; + } + + return -1; +} + +int +virNWFilterVarValueDelValue(virNWFilterVarValuePtr val, const char *value) +{ + unsigned int i; + + switch (val->valType) { + case NWFILTER_VALUE_TYPE_SIMPLE: + return -1; + + case NWFILTER_VALUE_TYPE_ARRAY: + for (i = 0; i < val->u.array.nValues; i++) + if (STREQ(value, val->u.array.values[i])) + return virNWFilterVarValueDelNthValue(val, i); + break; + + case NWFILTER_VALUE_TYPE_LAST: + break; + } + + return -1; +} + void virNWFilterVarCombIterFree(virNWFilterVarCombIterPtr ci) { @@ -521,14 +571,14 @@ virNWFilterHashTableCreate(int n) { } -int +void * virNWFilterHashTableRemoveEntry(virNWFilterHashTablePtr ht, const char *entry) { int i; - int rc = virHashRemoveEntry(ht->hashTable, entry); + void *value = virHashSteal(ht->hashTable, entry); - if (rc == 0) { + if (value) { for (i = 0; i < ht->nNames; i++) { if (STREQ(ht->names[i], entry)) { VIR_FREE(ht->names[i]); @@ -538,7 +588,7 @@ virNWFilterHashTableRemoveEntry(virNWFilterHashTablePtr ht, } } } - return rc; + return value; } diff --git a/src/conf/nwfilter_params.h b/src/conf/nwfilter_params.h index 57becc17028f707133394f7717e2cdbbee825933..81f104920b300830381743d148e9425ff9c2a501 100644 --- a/src/conf/nwfilter_params.h +++ b/src/conf/nwfilter_params.h @@ -50,11 +50,14 @@ struct _virNWFilterVarValue { virNWFilterVarValuePtr virNWFilterVarValueCreateSimple(char *); virNWFilterVarValuePtr virNWFilterVarValueCreateSimpleCopyValue(const char *); +virNWFilterVarValuePtr virNWFilterVarValueCopy(const virNWFilterVarValuePtr); +void virNWFilterVarValueFree(virNWFilterVarValuePtr val); const char *virNWFilterVarValueGetSimple(const virNWFilterVarValuePtr val); const char *virNWFilterVarValueGetNthValue(virNWFilterVarValuePtr val, unsigned int idx); unsigned int virNWFilterVarValueGetCardinality(const virNWFilterVarValuePtr); int virNWFilterVarValueAddValue(virNWFilterVarValuePtr val, char *value); +int virNWFilterVarValueDelValue(virNWFilterVarValuePtr val, const char *value); typedef struct _virNWFilterHashTable virNWFilterHashTable; typedef virNWFilterHashTable *virNWFilterHashTablePtr; @@ -77,8 +80,8 @@ int virNWFilterHashTablePut(virNWFilterHashTablePtr table, const char *name, virNWFilterVarValuePtr val, int freeName); -int virNWFilterHashTableRemoveEntry(virNWFilterHashTablePtr table, - const char *name); +void *virNWFilterHashTableRemoveEntry(virNWFilterHashTablePtr table, + const char *name); int virNWFilterHashTablePutAll(virNWFilterHashTablePtr src, virNWFilterHashTablePtr dest); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 1c64311e55854a49e71b7c4aea1d6a2c559a518e..687c3795cdcb810f06c22ce2f12a89437e3e7378 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -846,8 +846,14 @@ virNWFilterVarCombIterCreate; virNWFilterVarCombIterFree; virNWFilterVarCombIterGetVarValue; virNWFilterVarCombIterNext; +virNWFilterVarValueAddValue; +virNWFilterVarValueCopy; virNWFilterVarValueCreateSimple; virNWFilterVarValueCreateSimpleCopyValue; +virNWFilterVarValueDelValue; +virNWFilterVarValueFree; +virNWFilterVarValueGetCardinality; +virNWFilterVarValueGetNthValue; virNWFilterVarValueGetSimple; diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter_gentech_driver.c index bba7d0b678db80e9405a425f2cdda8a205053945..84a959b386d9ff60519dd3a7c0ec2a639c90c271 100644 --- a/src/nwfilter/nwfilter_gentech_driver.c +++ b/src/nwfilter/nwfilter_gentech_driver.c @@ -145,7 +145,7 @@ virNWFilterRuleInstFree(virNWFilterRuleInstPtr inst) static int virNWFilterVarHashmapAddStdValues(virNWFilterHashTablePtr table, char *macaddr, - char *ipaddr) + const virNWFilterVarValuePtr ipaddr) { virNWFilterVarValue *val; @@ -164,7 +164,7 @@ virNWFilterVarHashmapAddStdValues(virNWFilterHashTablePtr table, } if (ipaddr) { - val = virNWFilterVarValueCreateSimple(ipaddr); + val = virNWFilterVarValueCopy(ipaddr); if (!val) return 1; @@ -194,7 +194,8 @@ virNWFilterVarHashmapAddStdValues(virNWFilterHashTablePtr table, * is attached to the virConnect object. */ virNWFilterHashTablePtr -virNWFilterCreateVarHashmap(char *macaddr, char *ipaddr) { +virNWFilterCreateVarHashmap(char *macaddr, + const virNWFilterVarValuePtr ipaddr) { virNWFilterHashTablePtr table = virNWFilterHashTableCreate(0); if (!table) { virReportOOMError(); @@ -796,7 +797,7 @@ __virNWFilterInstantiateFilter(virConnectPtr conn, virNWFilterDefPtr filter; char vmmacaddr[VIR_MAC_STRING_BUFLEN] = {0}; char *str_macaddr = NULL; - const char *ipaddr; + virNWFilterVarValuePtr ipaddr; char *str_ipaddr = NULL; techdriver = virNWFilterTechDriverForName(drvname); @@ -836,16 +837,8 @@ __virNWFilterInstantiateFilter(virConnectPtr conn, } ipaddr = virNWFilterGetIpAddrForIfname(ifname); - if (ipaddr) { - str_ipaddr = strdup(ipaddr); - if (!str_ipaddr) { - virReportOOMError(); - rc = 1; - goto err_exit; - } - } - vars1 = virNWFilterCreateVarHashmap(str_macaddr, str_ipaddr); + vars1 = virNWFilterCreateVarHashmap(str_macaddr, ipaddr); if (!vars1) { rc = 1; goto err_exit; @@ -1101,7 +1094,7 @@ _virNWFilterTeardownFilter(const char *ifname) techdriver->allTeardown(ifname); - virNWFilterDelIpAddrForIfname(ifname); + virNWFilterDelIpAddrForIfname(ifname, NULL); virNWFilterUnlockIface(ifname); diff --git a/src/nwfilter/nwfilter_gentech_driver.h b/src/nwfilter/nwfilter_gentech_driver.h index fa8603011bd4e48f418072450c92ef37a84358fd..e057142cdcb98858a9e66f6a85ac3c57b9fa1bdf 100644 --- a/src/nwfilter/nwfilter_gentech_driver.h +++ b/src/nwfilter/nwfilter_gentech_driver.h @@ -61,7 +61,7 @@ int virNWFilterInstantiateFilterLate(virConnectPtr conn, int virNWFilterTeardownFilter(const virDomainNetDefPtr net); virNWFilterHashTablePtr virNWFilterCreateVarHashmap(char *macaddr, - char *ipaddr); + const virNWFilterVarValuePtr); void virNWFilterDomainFWUpdateCB(void *payload, const void *name, diff --git a/src/nwfilter/nwfilter_learnipaddr.c b/src/nwfilter/nwfilter_learnipaddr.c index 6e066eeb5e61e7810b4075338f1be76bb8cb5dc4..675ef5b6f3c3ad081e67fc8e9c0bdfdc69acf3b0 100644 --- a/src/nwfilter/nwfilter_learnipaddr.c +++ b/src/nwfilter/nwfilter_learnipaddr.c @@ -310,41 +310,99 @@ virNWFilterDeregisterLearnReq(int ifindex) { return res; } - - +/* Add an IP address to the list of IP addresses an interface is + * known to use. This function feeds the per-interface cache that + * is used to instantiate filters with variable '$IP'. + * + * @ifname: The name of the (tap) interface + * @addr: An IPv4 address in dotted decimal format that the (tap) + * interface is known to use. + * + * This function returns 0 on success, -1 otherwise + */ static int -virNWFilterAddIpAddrForIfname(const char *ifname, char *addr) { +virNWFilterAddIpAddrForIfname(const char *ifname, char *addr) +{ int ret; - virNWFilterVarValuePtr val = virNWFilterVarValueCreateSimple(addr); - - if (!val) - return 1; + virNWFilterVarValuePtr val; virMutexLock(&ipAddressMapLock); - ret = virNWFilterHashTablePut(ipAddressMap, ifname, val, 1); + val = virHashLookup(ipAddressMap->hashTable, ifname); + if (!val) { + val = virNWFilterVarValueCreateSimple(addr); + if (!val) { + virReportOOMError(); + ret = -1; + goto err_exit; + } + ret = virNWFilterHashTablePut(ipAddressMap, ifname, val, 1); + } else { + if (virNWFilterVarValueAddValue(val, addr) < 0) + ret = -1; + } +err_exit: virMutexUnlock(&ipAddressMapLock); return ret; } #endif - -void -virNWFilterDelIpAddrForIfname(const char *ifname) { +/* Delete all or a specific IP address from an interface. After this + * call either all or the given IP address will not be associated + * with the interface anymore. + * + * @ifname: The name of the (tap) interface + * @addr: An IPv4 address in dotted decimal format that the (tap) + * interface is not using anymore; provide NULL to remove all IP + * addresses associated with the given interface + * + * This function returns the number of IP addresses that are still + * known to be associated with this interface, in case of an error + * -1 is returned. Error conditions are: + * - IP addresses is not known to be associated with the interface + */ +int +virNWFilterDelIpAddrForIfname(const char *ifname, const char *ipaddr) +{ + int ret = -1; + virNWFilterVarValuePtr val = NULL; virMutexLock(&ipAddressMapLock); - if (virHashLookup(ipAddressMap->hashTable, ifname)) - virNWFilterHashTableRemoveEntry(ipAddressMap, ifname); + if (ipaddr != NULL) { + val = virHashLookup(ipAddressMap->hashTable, ifname); + if (val) { + if (virNWFilterVarValueGetCardinality(val) == 1 && + STREQ(ipaddr, + virNWFilterVarValueGetNthValue(val, 0))) + goto remove_entry; + virNWFilterVarValueDelValue(val, ipaddr); + ret = virNWFilterVarValueGetCardinality(val); + } + } else { +remove_entry: + /* remove whole entry */ + val = virNWFilterHashTableRemoveEntry(ipAddressMap, ifname); + virNWFilterVarValueFree(val); + ret = 0; + } virMutexUnlock(&ipAddressMapLock); -} + return ret; +} -const char * -virNWFilterGetIpAddrForIfname(const char *ifname) { +/* Get the list of IP addresses known to be in use by an interface + * + * This function returns NULL in case no IP address is known to be + * associated with the interface, a virNWFilterVarValuePtr otherwise + * that then can contain one or multiple entries. + */ +virNWFilterVarValuePtr +virNWFilterGetIpAddrForIfname(const char *ifname) +{ virNWFilterVarValuePtr res; virMutexLock(&ipAddressMapLock); @@ -353,10 +411,7 @@ virNWFilterGetIpAddrForIfname(const char *ifname) { virMutexUnlock(&ipAddressMapLock); - if (res) - return virNWFilterVarValueGetSimple(res); - - return NULL; + return res; } @@ -642,7 +697,10 @@ learnIPAddressThread(void *arg) char *inetaddr; if ((inetaddr = virSocketAddrFormat(&sa))!= NULL) { - virNWFilterAddIpAddrForIfname(req->ifname, inetaddr); + if (virNWFilterAddIpAddrForIfname(req->ifname, inetaddr) < 0) { + VIR_ERROR(_("Failed to add IP address %s to IP address " + "cache for interface %s"), inetaddr, req->ifname); + } ret = virNWFilterInstantiateFilterLate(NULL, req->ifname, diff --git a/src/nwfilter/nwfilter_learnipaddr.h b/src/nwfilter/nwfilter_learnipaddr.h index e4b9811a4b7a59fd0da2aff073bf23a5458833f7..5db9bf8c4b434b33c3d30dd4b09c3f61acefce65 100644 --- a/src/nwfilter/nwfilter_learnipaddr.h +++ b/src/nwfilter/nwfilter_learnipaddr.h @@ -25,6 +25,8 @@ #ifndef __NWFILTER_LEARNIPADDR_H # define __NWFILTER_LEARNIPADDR_H +# include "conf/nwfilter_params.h" + enum howDetect { DETECT_DHCP = 1, DETECT_STATIC = 2, @@ -63,8 +65,8 @@ int virNWFilterLearnIPAddress(virNWFilterTechDriverPtr techdriver, virNWFilterIPAddrLearnReqPtr virNWFilterLookupLearnReq(int ifindex); int virNWFilterTerminateLearnReq(const char *ifname); -void virNWFilterDelIpAddrForIfname(const char *ifname); -const char *virNWFilterGetIpAddrForIfname(const char *ifname); +int virNWFilterDelIpAddrForIfname(const char *ifname, const char *ipaddr); +virNWFilterVarValuePtr virNWFilterGetIpAddrForIfname(const char *ifname); int virNWFilterLockIface(const char *ifname) ATTRIBUTE_RETURN_CHECK; void virNWFilterUnlockIface(const char *ifname);