]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
qemu: support live update of an interface's filter
authorLaine Stump <laine@laine.org>
Mon, 12 Nov 2012 16:21:10 +0000 (11:21 -0500)
committerLaine Stump <laine@laine.org>
Mon, 3 Dec 2012 19:35:58 +0000 (14:35 -0500)
Since we can't (currently) rely on the ability to provide blanket
support for all possible network changes by calling the toplevel
netdev hostside disconnect/connect functions (due to qemu only
supporting a lockstep between initialization of host side and guest
side of devices), in order to support live change of an interface's
nwfilter we need to make a special purpose function to only call the
nwfilter teardown and setup functions if the filter for an interface
(or its parameters) changes. The pattern is nearly identical to that
used to change the bridge that an interface is connected to.

This patch was inspired by a request from Guido Winkelmann
<guido@sagersystems.de>, who tested an earlier version.

src/conf/nwfilter_params.c
src/conf/nwfilter_params.h
src/libvirt_private.syms
src/qemu/qemu_hotplug.c

index 3ac130390b6a10b6b42b0bd4de9d62d2e81e8561..7254519a2c9061b27048f3d894ac0bc6e8a173ba 100644 (file)
@@ -795,6 +795,27 @@ err_exit:
     return -1;
 }
 
+/* The general purpose function virNWFilterVarValueEqual returns a
+ * bool, but the comparison callback for virHashEqual (called below)
+ * needs to return an int of 0 for == and non-0 for !=
+ */
+static int
+virNWFilterVarValueCompare(const void *a, const void *b)
+{
+    return virNWFilterVarValueEqual((const virNWFilterVarValuePtr) a,
+                                    (const virNWFilterVarValuePtr) b) ? 0 : 1;
+}
+
+bool
+virNWFilterHashTableEqual(virNWFilterHashTablePtr a,
+                          virNWFilterHashTablePtr b)
+{
+    if (!(a || b))
+        return true;
+    if (!(a && b))
+        return false;
+    return virHashEqual(a->hashTable, b->hashTable, virNWFilterVarValueCompare);
+}
 
 static bool
 isValidVarName(const char *var)
index 96d3033ecbd2ff2ef38086e42ad26b05382725db..6c3ce54352193cc212b696481b3c1f8b4231af33 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * nwfilter_params.h: parsing and data maintenance of filter parameters
  *
- * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2011-2012 Red Hat, Inc.
  * Copyright (C) 2010 IBM Corporation
  *
  * This library is free software; you can redistribute it and/or
@@ -87,6 +87,8 @@ void *virNWFilterHashTableRemoveEntry(virNWFilterHashTablePtr table,
                                       const char *name);
 int virNWFilterHashTablePutAll(virNWFilterHashTablePtr src,
                                virNWFilterHashTablePtr dest);
+bool virNWFilterHashTableEqual(virNWFilterHashTablePtr a,
+                               virNWFilterHashTablePtr b);
 
 # define VALID_VARNAME \
   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"
index 51c76a549b8eb95da32ec5904b066ac090b4f733..41e262900caf5e42a85703d6da11b09e821e92fc 100644 (file)
@@ -959,6 +959,7 @@ virNWFilterIPAddrMapShutdown;
 
 # nwfilter_params.h
 virNWFilterHashTableCreate;
+virNWFilterHashTableEqual;
 virNWFilterHashTableFree;
 virNWFilterHashTablePut;
 virNWFilterHashTablePutAll;
index 2d4a822416cb7da2cafbb0fdbc9230173116775f..fbd60de5bbe678b64301d6ec6dcbf2294960c4d3 100644 (file)
@@ -1330,6 +1330,43 @@ cleanup:
     return ret;
 }
 
+static int
+qemuDomainChangeNetFilter(virConnectPtr conn,
+                          virDomainObjPtr vm,
+                          virDomainNetDefPtr olddev,
+                          virDomainNetDefPtr newdev)
+{
+    /* make sure this type of device supports filters. */
+    switch (virDomainNetGetActualType(newdev)) {
+    case VIR_DOMAIN_NET_TYPE_ETHERNET:
+    case VIR_DOMAIN_NET_TYPE_BRIDGE:
+    case VIR_DOMAIN_NET_TYPE_NETWORK:
+        break;
+    default:
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("filters not supported on interfaces of type %s"),
+                       virDomainNetTypeToString(virDomainNetGetActualType(newdev)));
+        return -1;
+    }
+
+    virDomainConfNWFilterTeardown(olddev);
+
+    if (virDomainConfNWFilterInstantiate(conn, vm->def->uuid, newdev) < 0) {
+        virErrorPtr errobj;
+
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       _("failed to add new filter rules to '%s' "
+                         "- attempting to restore old rules"),
+                       olddev->ifname);
+        errobj = virSaveLastError();
+        ignore_value(virDomainConfNWFilterInstantiate(conn, vm->def->uuid, olddev));
+        virSetError(errobj);
+        virFreeError(errobj);
+        return -1;
+    }
+    return 0;
+}
+
 int qemuDomainChangeNetLinkState(virQEMUDriverPtr driver,
                                  virDomainObjPtr vm,
                                  virDomainNetDefPtr dev,
@@ -1373,6 +1410,7 @@ qemuDomainChangeNet(virQEMUDriverPtr driver,
     int oldType, newType;
     bool needReconnect = false;
     bool needBridgeChange = false;
+    bool needFilterChange = false;
     bool needLinkStateChange = false;
     bool needReplaceDevDef = false;
     int ret = -1;
@@ -1506,8 +1544,10 @@ qemuDomainChangeNet(virQEMUDriverPtr driver,
     }
     /* (end of device info checks) */
 
-    if (STRNEQ_NULLABLE(olddev->filter, newdev->filter))
-        needReconnect = true;
+    if (STRNEQ_NULLABLE(olddev->filter, newdev->filter) ||
+        !virNWFilterHashTableEqual(olddev->filterparams, newdev->filterparams)) {
+        needFilterChange = true;
+    }
 
     /* bandwidth can be modified, and will be checked later */
     /* vlan can be modified, and will be checked later */
@@ -1665,7 +1705,16 @@ qemuDomainChangeNet(virQEMUDriverPtr driver,
             goto cleanup;
         /* we successfully switched to the new bridge, and we've
          * determined that the rest of newdev is equivalent to olddev,
-         * so move newdev into place, so that the  */
+         * so move newdev into place */
+        needReplaceDevDef = true;
+    }
+
+    if (needFilterChange) {
+        if (qemuDomainChangeNetFilter(dom->conn, vm, olddev, newdev) < 0)
+            goto cleanup;
+        /* we successfully switched to the new filter, and we've
+         * determined that the rest of newdev is equivalent to olddev,
+         * so move newdev into place */
         needReplaceDevDef = true;
     }