]> xenbits.xensource.com Git - libvirt.git/commitdiff
Enable detection of multiple IP addresses
authorStefan Berger <stefanb@linux.vnet.ibm.com>
Wed, 23 Nov 2011 00:05:45 +0000 (19:05 -0500)
committerStefan Berger <stefanb@us.ibm.com>
Wed, 23 Nov 2011 00:05:45 +0000 (19:05 -0500)
In preparation of DHCP Snooping and the detection of multiple IP
addresses per interface:

The hash table that is used to collect the detected IP address of an
interface can so far only handle one IP address per interface. With
this patch we extend this to allow it to handle a list of IP addresses.

Above changes the returned variable type of virNWFilterGetIpAddrForIfname()
from char * to virNWFilterVarValuePtr; adapt all existing functions calling
this function.

src/conf/nwfilter_params.c
src/conf/nwfilter_params.h
src/libvirt_private.syms
src/nwfilter/nwfilter_gentech_driver.c
src/nwfilter/nwfilter_gentech_driver.h
src/nwfilter/nwfilter_learnipaddr.c
src/nwfilter/nwfilter_learnipaddr.h

index 2fba3513908bb875ad8e17aff78aa864a2a34f44..12c65246c3d8e1ce279e77b0bf208e74e596a74b 100644 (file)
@@ -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;
 }
 
 
index 57becc17028f707133394f7717e2cdbbee825933..81f104920b300830381743d148e9425ff9c2a501 100644 (file)
@@ -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);
 
index 1c64311e55854a49e71b7c4aea1d6a2c559a518e..687c3795cdcb810f06c22ce2f12a89437e3e7378 100644 (file)
@@ -846,8 +846,14 @@ virNWFilterVarCombIterCreate;
 virNWFilterVarCombIterFree;
 virNWFilterVarCombIterGetVarValue;
 virNWFilterVarCombIterNext;
+virNWFilterVarValueAddValue;
+virNWFilterVarValueCopy;
 virNWFilterVarValueCreateSimple;
 virNWFilterVarValueCreateSimpleCopyValue;
+virNWFilterVarValueDelValue;
+virNWFilterVarValueFree;
+virNWFilterVarValueGetCardinality;
+virNWFilterVarValueGetNthValue;
 virNWFilterVarValueGetSimple;
 
 
index bba7d0b678db80e9405a425f2cdda8a205053945..84a959b386d9ff60519dd3a7c0ec2a639c90c271 100644 (file)
@@ -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);
 
index fa8603011bd4e48f418072450c92ef37a84358fd..e057142cdcb98858a9e66f6a85ac3c57b9fa1bdf 100644 (file)
@@ -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,
index 6e066eeb5e61e7810b4075338f1be76bb8cb5dc4..675ef5b6f3c3ad081e67fc8e9c0bdfdc69acf3b0 100644 (file)
@@ -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,
index e4b9811a4b7a59fd0da2aff073bf23a5458833f7..5db9bf8c4b434b33c3d30dd4b09c3f61acefce65 100644 (file)
@@ -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);