[libvirt] [PATCHv2 9/9] network: internal API functions to manage assignment of physdev to guest

Laine Stump laine at laine.org
Wed Jul 20 06:21:59 UTC 2011


The network driver needs to assign physical devices for use by modes
that use macvtap, keeping track of which physical devices are in use
(and how many instances, when the devices can be shared). Three calls
are added:

networkAllocateActualDevice - finds a physical device for use by the
domain, and sets up the virDomainActualNetDef accordingly.

networkNotifyActualDevice - assumes that the domain was already
running, but libvirtd was restarted, and needs to be notified by each
already-running domain about what interfaces they are using.

networkReleaseActualDevice - decrements the usage count of the
allocated physical device, and frees the virDomainActualNetDef to
avoid later accidentally using the device.

bridge_driver.[hc] - the new APIs. When WITH_NETWORK is false, these
functions are all defined inline static in the .h file (and become a
NOP) to prevent link errors.

qemu_(command|driver|hotplug|process).c - add calls to the above APIs
    in the appropriate places.

tests/Makefile.am - need to include libvirt_driver_network.la whenever
    libvirt_driver_qemu.la is linked, to avoid unreferenced symbols
    (in functions that are never called by the test programs...)
---

Change from V1: rather than making things compile properly when
configured with --without-network by dropping #if WITH_NETWORK all
over in the .c files, in this version I just redefine the functions in
question (network.....()) as static inline in the .h file when
WITH_NETWORK is false:

  https://www.redhat.com/archives/libvir-list/2011-July/msg00534.html

This works perfectly, but "make syntax-check" doesn't like the fact
that I've put ATTRIBUTE_UNUSED on the args of the function
prototype. I think make syntax-check should be changed to allow
ATTRIBUTE_UNUSED in a .h file, as long as it's part of a function
definition (rather than declaration), but could be convinced
otherwise if needed to get this pushed sooner.

 src/libvirt_network.syms    |    3 +
 src/network/bridge_driver.c |  372 +++++++++++++++++++++++++++++++++++++++++++
 src/network/bridge_driver.h |   28 ++++
 src/qemu/qemu_command.c     |   11 ++
 src/qemu/qemu_hotplug.c     |   40 ++++--
 src/qemu/qemu_process.c     |   25 +++-
 tests/Makefile.am           |   15 ++-
 7 files changed, 476 insertions(+), 18 deletions(-)

diff --git a/src/libvirt_network.syms b/src/libvirt_network.syms
index 6be5e45..e402b5f 100644
--- a/src/libvirt_network.syms
+++ b/src/libvirt_network.syms
@@ -3,4 +3,7 @@
 #
 
 # bridge_driver.h
+networkAllocateActualDevice;
 networkBuildDhcpDaemonCommandLine;
+networkNotifyActualDevice;
+networkReleaseActualDevice;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 8767af9..15e0710 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -2715,3 +2715,375 @@ int networkRegister(void) {
     virRegisterStateDriver(&networkStateDriver);
     return 0;
 }
+
+/********************************************************/
+
+/* Private API to deal with logical switch capabilities.
+ * These functions are exported so that other parts of libvirt can
+ * call them, but are not part of the public API and not in the
+ * driver's function table. If we ever have more than one network
+ * driver, we will need to present these functions via a second
+ * "backend" function table.
+ */
+
+/* networkAllocateActualDevice:
+ * @iface: the original NetDef from the domain
+ *
+ * Looks up the network reference by iface, allocates a physical
+ * device from that network (if appropriate), and returns with the
+ * virDomainActualNetDef filled in accordingly. If there are no
+ * changes to be made in the netdef, then just leave the actualdef
+ * empty.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int
+networkAllocateActualDevice(virDomainNetDefPtr iface)
+{
+    struct network_driver *driver = driverState;
+    virNetworkObjPtr network;
+    virNetworkDefPtr netdef;
+    int ret = -1;
+
+    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
+        return 0;
+
+    virDomainActualNetDefFree(iface->data.network.actual);
+    iface->data.network.actual = NULL;
+
+    networkDriverLock(driver);
+    network = virNetworkFindByName(&driver->networks, iface->data.network.name);
+    networkDriverUnlock(driver);
+    if (!network) {
+        networkReportError(VIR_ERR_NO_NETWORK,
+                           _("no network with matching name '%s'"),
+                           iface->data.network.name);
+        goto cleanup;
+    }
+
+    netdef = network->def;
+    if ((netdef->forwardType == VIR_NETWORK_FORWARD_BRIDGE) &&
+        netdef->bridge) {
+
+        /* <forward type='bridge'/> <bridge name='xxx'/>
+         * is VIR_DOMAIN_NET_TYPE_BRIDGE
+         */
+
+        if (VIR_ALLOC(iface->data.network.actual) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
+        iface->data.network.actual->data.bridge.brname = strdup(netdef->bridge);
+        if (!iface->data.network.actual->data.bridge.brname) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+    } else if ((netdef->forwardType == VIR_NETWORK_FORWARD_BRIDGE) ||
+               (netdef->forwardType == VIR_NETWORK_FORWARD_PRIVATE) ||
+               (netdef->forwardType == VIR_NETWORK_FORWARD_VEPA) ||
+               (netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH)) {
+        virVirtualPortProfileParamsPtr virtport = NULL;
+
+        /* <forward type='bridge|private|vepa|passthrough'> are all
+         * VIR_DOMAIN_NET_TYPE_DIRECT.
+         */
+
+        if (VIR_ALLOC(iface->data.network.actual) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        /* Set type=direct and appropriate <source mode='xxx'/> */
+        iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_DIRECT;
+        switch (netdef->forwardType) {
+        case VIR_NETWORK_FORWARD_BRIDGE:
+            iface->data.network.actual->data.direct.mode = VIR_MACVTAP_MODE_BRIDGE;
+            break;
+        case VIR_NETWORK_FORWARD_PRIVATE:
+            iface->data.network.actual->data.direct.mode = VIR_MACVTAP_MODE_PRIVATE;
+            break;
+        case VIR_NETWORK_FORWARD_VEPA:
+            iface->data.network.actual->data.direct.mode = VIR_MACVTAP_MODE_VEPA;
+            break;
+        case VIR_NETWORK_FORWARD_PASSTHROUGH:
+            iface->data.network.actual->data.direct.mode = VIR_MACVTAP_MODE_PASSTHRU;
+            break;
+        }
+
+        /* Find the most specific virtportprofile and copy it */
+        if (iface->data.network.virtPortProfile) {
+            virtport = iface->data.network.virtPortProfile;
+        } else {
+            virPortGroupDefPtr portgroup
+               = virPortGroupFindByName(netdef, iface->data.network.portgroup);
+            if (portgroup)
+                virtport = portgroup->virtPortProfile;
+            else
+                virtport = netdef->virtPortProfile;
+        }
+        if (virtport) {
+            if (VIR_ALLOC(iface->data.network.actual->data.direct.virtPortProfile) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
+            /* There are no pointers in a virtualPortProfile, so a shallow copy
+             * is sufficient
+             */
+            *iface->data.network.actual->data.direct.virtPortProfile = *virtport;
+        }
+        /* If there is only a single device, just return it (caller will detect
+         * any error if exclusive use is required but could be acquired).
+         */
+        if (netdef->nForwardIfs == 0) {
+            networkReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("network '%s' uses a direct mode, but has no forward dev and no interface pool"),
+                               netdef->name);
+            goto cleanup;
+        } else {
+            int ii;
+            virNetworkForwardIfDefPtr dev = NULL;
+
+            /* pick an interface from the pool */
+
+            /* PASSTHROUGH mode, and PRIVATE Mode + 802.1Qbh both require
+             * exclusive access to a device, so current usageCount must be
+             * 0.  Other modes can share, so just search for the one with
+             * the lowest usageCount.
+             */
+            if ((netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
+                ((netdef->forwardType == VIR_NETWORK_FORWARD_PRIVATE) &&
+                 iface->data.network.actual->data.direct.virtPortProfile &&
+                 (iface->data.network.actual->data.direct.virtPortProfile->virtPortType
+                  == VIR_VIRTUALPORT_8021QBH))) {
+                /* pick first dev with 0 usageCount */
+
+                for (ii = 0; ii < netdef->nForwardIfs; ii++) {
+                    if (netdef->forwardIfs[ii].usageCount == 0) {
+                        dev = &netdef->forwardIfs[ii];
+                        break;
+                    }
+                }
+            } else {
+                /* pick least used dev */
+                dev = &netdef->forwardIfs[0];
+                for (ii = 1; ii < netdef->nForwardIfs; ii++) {
+                    if (netdef->forwardIfs[ii].usageCount < dev->usageCount)
+                        dev = &netdef->forwardIfs[ii];
+                }
+            }
+            /* dev points at the physical device we want to use */
+            if (!dev) {
+                networkReportError(VIR_ERR_INTERNAL_ERROR,
+                                   _("network '%s' requires exclusive access to interfaces, but none are available"),
+                               netdef->name);
+                goto cleanup;
+            }
+            iface->data.network.actual->data.direct.linkdev = strdup(dev->dev);
+            if (!iface->data.network.actual->data.direct.linkdev) {
+                virReportOOMError();
+                goto cleanup;
+            }
+            /* we are now assured of success, so mark the allocation */
+            dev->usageCount++;
+            VIR_DEBUG("Using physical device %s, usageCount %d",
+                      dev->dev, dev->usageCount);
+        }
+    }
+
+    ret = 0;
+cleanup:
+    if (network)
+        virNetworkObjUnlock(network);
+    if (ret < 0) {
+        virDomainActualNetDefFree(iface->data.network.actual);
+        iface->data.network.actual = NULL;
+    }
+    return ret;
+}
+
+/* networkNotifyActualDevice:
+ * @iface:  the domain's NetDef with an "actual" device already filled in.
+ *
+ * Called to notify the network driver when libvirtd is restarted and
+ * finds an already running domain. If appropriate it will force an
+ * allocation of the actual->direct.linkdev to get everything back in
+ * order.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int
+networkNotifyActualDevice(virDomainNetDefPtr iface)
+{
+    struct network_driver *driver = driverState;
+    virNetworkObjPtr network;
+    virNetworkDefPtr netdef;
+    char *actualDev;
+    int ret = -1;
+
+    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
+       return 0;
+
+    if (!iface->data.network.actual ||
+        (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT)) {
+        VIR_DEBUG("Nothing to claim from network %s", iface->data.network.name);
+        return 0;
+    }
+
+    networkDriverLock(driver);
+    network = virNetworkFindByName(&driver->networks, iface->data.network.name);
+    networkDriverUnlock(driver);
+    if (!network) {
+        networkReportError(VIR_ERR_NO_NETWORK,
+                           _("no network with matching name '%s'"),
+                           iface->data.network.name);
+        goto cleanup;
+    }
+
+    actualDev = virDomainNetGetActualDirectDev(iface);
+    if (!actualDev) {
+        networkReportError(VIR_ERR_INTERNAL_ERROR,
+                           "%s", _("the interface uses a direct mode, but has no source dev"));
+            goto cleanup;
+        }
+
+    netdef = network->def;
+    if (netdef->nForwardIfs == 0) {
+        networkReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("network '%s' uses a direct mode, but has no forward dev and no interface pool"),
+                           netdef->name);
+        goto cleanup;
+    } else {
+        int ii;
+        virNetworkForwardIfDefPtr dev = NULL;
+
+        /* find the matching interface in the pool and increment its usageCount */
+
+        for (ii = 0; ii < netdef->nForwardIfs; ii++) {
+            if (STREQ(actualDev, netdef->forwardIfs[ii].dev)) {
+                dev = &netdef->forwardIfs[ii];
+                break;
+            }
+        }
+        /* dev points at the physical device we want to use */
+        if (!dev) {
+            networkReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("network '%s' doesn't have dev='%s' in use by domain"),
+                               netdef->name, actualDev);
+            goto cleanup;
+        }
+
+        /* PASSTHROUGH mode, and PRIVATE Mode + 802.1Qbh both require
+         * exclusive access to a device, so current usageCount must be
+         * 0 in those cases.
+         */
+        if ((dev->usageCount > 0) &&
+            ((netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
+             ((netdef->forwardType == VIR_NETWORK_FORWARD_PRIVATE) &&
+              iface->data.network.actual->data.direct.virtPortProfile &&
+              (iface->data.network.actual->data.direct.virtPortProfile->virtPortType
+               == VIR_VIRTUALPORT_8021QBH)))) {
+            networkReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("network '%s' claims dev='%s' is already in use by a different domain"),
+                               netdef->name, actualDev);
+            goto cleanup;
+        }
+        /* we are now assured of success, so mark the allocation */
+        dev->usageCount++;
+        VIR_DEBUG("Using physical device %s, usageCount %d",
+                  dev->dev, dev->usageCount);
+    }
+
+    ret = 0;
+cleanup:
+    if (network)
+        virNetworkObjUnlock(network);
+    return ret;
+}
+
+
+/* networkReleaseActualDevice:
+ * @iface:  a domain's NetDef (interface definition)
+ *
+ * Given a domain <interface> element that previously had its <actual>
+ * element filled in (and possibly a physical device allocated to it),
+ * free up the physical device for use by someone else, and free the
+ * virDomainActualNetDef.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int
+networkReleaseActualDevice(virDomainNetDefPtr iface)
+{
+    struct network_driver *driver = driverState;
+    virNetworkObjPtr network = NULL;
+    virNetworkDefPtr netdef;
+    char *actualDev;
+    int ret = -1;
+
+    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
+       return 0;
+
+    if (!iface->data.network.actual ||
+        (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT)) {
+        VIR_DEBUG("Nothing to release to network %s", iface->data.network.name);
+        ret = 0;
+        goto cleanup;
+    }
+
+    networkDriverLock(driver);
+    network = virNetworkFindByName(&driver->networks, iface->data.network.name);
+    networkDriverUnlock(driver);
+    if (!network) {
+        networkReportError(VIR_ERR_NO_NETWORK,
+                           _("no network with matching name '%s'"),
+                           iface->data.network.name);
+        goto cleanup;
+    }
+
+    actualDev = virDomainNetGetActualDirectDev(iface);
+    if (!actualDev) {
+        networkReportError(VIR_ERR_INTERNAL_ERROR,
+                           "%s", _("the interface uses a direct mode, but has no source dev"));
+            goto cleanup;
+        }
+
+    netdef = network->def;
+    if (netdef->nForwardIfs == 0) {
+        networkReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("network '%s' uses a direct mode, but has no forward dev and no interface pool"),
+                           netdef->name);
+        goto cleanup;
+    } else {
+        int ii;
+        virNetworkForwardIfDefPtr dev = NULL;
+
+        for (ii = 0; ii < netdef->nForwardIfs; ii++) {
+            if (STREQ(actualDev, netdef->forwardIfs[ii].dev)) {
+                dev = &netdef->forwardIfs[ii];
+                break;
+            }
+        }
+        /* dev points at the physical device we've been using */
+        if (!dev) {
+            networkReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("network '%s' doesn't have dev='%s' in use by domain"),
+                               netdef->name, actualDev);
+            goto cleanup;
+        }
+
+        dev->usageCount--;
+        VIR_DEBUG("Releasing physical device %s, usageCount %d",
+                  dev->dev, dev->usageCount);
+    }
+
+    ret = 0;
+cleanup:
+    if (network)
+        virNetworkObjUnlock(network);
+    virDomainActualNetDefFree(iface->data.network.actual);
+    iface->data.network.actual = NULL;
+    return ret;
+}
diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h
index 2896c84..710d862 100644
--- a/src/network/bridge_driver.h
+++ b/src/network/bridge_driver.h
@@ -29,13 +29,41 @@
 
 # include "internal.h"
 # include "network_conf.h"
+# include "domain_conf.h"
 # include "command.h"
 # include "dnsmasq.h"
 
 int networkRegister(void);
+
+#if WITH_NETWORK
+int networkAllocateActualDevice(virDomainNetDefPtr iface);
+int networkNotifyActualDevice(virDomainNetDefPtr iface);
+int networkReleaseActualDevice(virDomainNetDefPtr iface);
+
 int networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
                                       virCommandPtr *cmdout, char *pidfile,
                                       dnsmasqContext *dctx);
+#else
+static inline int
+networkAllocateActualDevice(virDomainNetDefPtr iface ATTRIBUTE_UNUSED)
+{ return 0; }
+
+static inline int
+networkNotifyActualDevice(virDomainNetDefPtr iface ATTRIBUTE_UNUSED)
+{ return 0; }
+
+static inline int
+networkReleaseActualDevice(virDomainNetDefPtr iface ATTRIBUTE_UNUSED)
+{ return 0; }
+
+static inline int
+networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network ATTRIBUTE_UNUSED,
+                                  virCommandPtr *cmdout ATTRIBUTE_UNUSED,
+                                  char *pidfile ATTRIBUTE_UNUSED,
+                                  dnsmasqContext *dctx ATTRIBUTE_UNUSED)
+{ return 0; }
+
+#endif
 
 typedef char *(*networkDnsmasqLeaseFileNameFunc)(const char *netname);
 
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 172e394..0ae8d67 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -37,6 +37,7 @@
 #include "domain_nwfilter.h"
 #include "domain_audit.h"
 #include "domain_conf.h"
+#include "network/bridge_driver.h"
 
 #include <sys/utsname.h>
 #include <sys/stat.h>
@@ -3697,6 +3698,13 @@ qemuBuildCommandLine(virConnectPtr conn,
             else
                 vlan = i;
 
+            /* If appropriate, grab a physical device from the configured
+             * network's pool of devices, or resolve bridge device name
+             * to the one defined in the network definition.
+             */
+            if (networkAllocateActualDevice(net) < 0)
+               goto error;
+
             actualType = virDomainNetGetActualType(net);
             if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
                 actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
@@ -4693,6 +4701,9 @@ qemuBuildCommandLine(virConnectPtr conn,
  no_memory:
     virReportOOMError();
  error:
+    /* free up any resources in the network driver */
+    for (i = 0 ; i < def->nnets ; i++)
+        networkReleaseActualDevice(def->nets[i]);
     for (i = 0; i <= last_good_net; i++)
         virDomainConfNWFilterTeardown(def->nets[i]);
     virBufferFreeAndReset(&rbd_hosts);
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 128b9ea..74ce9be 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -39,6 +39,7 @@
 #include "files.h"
 #include "qemu_cgroup.h"
 #include "locking/domain_lock.h"
+#include "network/bridge_driver.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -603,7 +604,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
     virDomainDevicePCIAddress guestAddr;
     int vlan;
     bool releaseaddr = false;
-    int actualType = virDomainNetGetActualType(net);
+    bool iface_connected = false;
+    int actualType;
 
     if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_HOST_NET_ADD)) {
         qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
@@ -611,18 +613,28 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
         return -1;
     }
 
+    /* If appropriate, grab a physical device from the configured
+     * network's pool of devices, or resolve bridge device name
+     * to the one defined in the network definition.
+     */
+    if (networkAllocateActualDevice(net) < 0)
+        goto cleanup;
+
+    actualType = virDomainNetGetActualType(net);
     if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
         actualType == VIR_DOMAIN_NET_TYPE_NETWORK) {
         if ((tapfd = qemuNetworkIfaceConnect(vm->def, conn, driver, net,
                                              priv->qemuCaps)) < 0)
-            return -1;
+            goto cleanup;
+        iface_connected = true;
         if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0)
             goto cleanup;
     } else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
         if ((tapfd = qemuPhysIfaceConnect(vm->def, conn, driver, net,
                                           priv->qemuCaps,
                                           VIR_VM_OP_CREATE)) < 0)
-            return -1;
+            goto cleanup;
+        iface_connected = true;
         if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0)
             goto cleanup;
     }
@@ -738,16 +750,19 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
     vm->def->nets[vm->def->nnets++] = net;
 
 cleanup:
-    if ((ret != 0) &&
-        qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
-        (net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
-        releaseaddr &&
-        qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
-                                        net->info.addr.pci.slot) < 0)
-        VIR_WARN("Unable to release PCI address on NIC");
+    if (ret < 0) {
+        if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
+            (net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
+            releaseaddr &&
+            qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
+                                            net->info.addr.pci.slot) < 0)
+            VIR_WARN("Unable to release PCI address on NIC");
 
-    if (ret != 0)
-        virDomainConfNWFilterTeardown(net);
+        if (iface_connected)
+            virDomainConfNWFilterTeardown(net);
+
+        networkReleaseActualDevice(net);
+    }
 
     VIR_FREE(nicstr);
     VIR_FREE(netstr);
@@ -1634,6 +1649,7 @@ int qemuDomainDetachNetDevice(struct qemud_driver *driver,
         }
     }
 
+    networkReleaseActualDevice(detach);
     if (vm->def->nnets > 1) {
         memmove(vm->def->nets + i,
                 vm->def->nets + i + 1,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 3c57a2a..8a8beb1 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -56,6 +56,7 @@
 #include "domain_audit.h"
 #include "domain_nwfilter.h"
 #include "locking/domain_lock.h"
+#include "network/bridge_driver.h"
 #include "uuid.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
@@ -2178,6 +2179,19 @@ int qemuProcessStopCPUs(struct qemud_driver *driver, virDomainObjPtr vm,
 
 
 static int
+qemuProcessNotifyNets(virDomainDefPtr def)
+{
+    int ii;
+
+    for (ii = 0 ; ii < def->nnets ; ii++) {
+        virDomainNetDefPtr net = def->nets[ii];
+        if (networkNotifyActualDevice(net) < 0)
+            return -1;
+    }
+    return 0;
+}
+
+static int
 qemuProcessFiltersInstantiate(virConnectPtr conn,
                               virDomainDefPtr def)
 {
@@ -2379,6 +2393,9 @@ qemuProcessReconnect(void *payload, const void *name ATTRIBUTE_UNUSED, void *opa
     if (virSecurityManagerReserveLabel(driver->securityManager, obj) < 0)
         goto error;
 
+    if (qemuProcessNotifyNets(obj->def) < 0)
+        goto error;
+
     if (qemuProcessFiltersInstantiate(conn, obj->def))
         goto error;
 
@@ -3010,10 +3027,10 @@ void qemuProcessStop(struct qemud_driver *driver,
 
     qemuDomainReAttachHostDevices(driver, vm->def);
 
-#if WITH_MACVTAP
     def = vm->def;
     for (i = 0; i < def->nnets; i++) {
         virDomainNetDefPtr net = def->nets[i];
+#if WITH_MACVTAP
         if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) {
             delMacvtap(net->ifname, net->mac,
                        virDomainNetGetActualDirectDev(net),
@@ -3022,8 +3039,12 @@ void qemuProcessStop(struct qemud_driver *driver,
                        driver->stateDir);
             VIR_FREE(net->ifname);
         }
-    }
 #endif
+        /* release the physical device (or any other resources used by
+         * this interface in the network driver
+         */
+        networkReleaseActualDevice(net);
+    }
 
 retry:
     if ((ret = qemuRemoveCgroup(driver, vm, 0)) < 0) {
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e9a445e..971ab70 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -314,23 +314,30 @@ EXTRA_DIST += xml2sexprtest.c sexpr2xmltest.c xmconfigtest.c \
 endif
 
 if WITH_QEMU
+
+qemu_LDADDS = ../src/libvirt_driver_qemu.la
+
+if WITH_NETWORK
+qemu_LDADDS += ../src/libvirt_driver_network.la
+endif
+
 qemuxml2argvtest_SOURCES = \
 	qemuxml2argvtest.c testutilsqemu.c testutilsqemu.h \
 	testutils.c testutils.h
-qemuxml2argvtest_LDADD = ../src/libvirt_driver_qemu.la $(LDADDS)
+qemuxml2argvtest_LDADD = $(qemu_LDADDS)  $(LDADDS)
 
 qemuxml2xmltest_SOURCES = \
 	qemuxml2xmltest.c testutilsqemu.c testutilsqemu.h \
 	testutils.c testutils.h
-qemuxml2xmltest_LDADD = ../src/libvirt_driver_qemu.la $(LDADDS)
+qemuxml2xmltest_LDADD = $(qemu_LDADDS) $(LDADDS)
 
 qemuargv2xmltest_SOURCES = \
 	qemuargv2xmltest.c testutilsqemu.c testutilsqemu.h \
 	testutils.c testutils.h
-qemuargv2xmltest_LDADD = ../src/libvirt_driver_qemu.la $(LDADDS)
+qemuargv2xmltest_LDADD = $(qemu_LDADDS) $(LDADDS)
 
 qemuhelptest_SOURCES = qemuhelptest.c testutils.c testutils.h
-qemuhelptest_LDADD = ../src/libvirt_driver_qemu.la $(LDADDS)
+qemuhelptest_LDADD = $(qemu_LDADDS) $(LDADDS)
 else
 EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c qemuargv2xmltest.c qemuhelptest.c testutilsqemu.c testutilsqemu.h
 endif
-- 
1.7.3.4




More information about the libvir-list mailing list