mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-22 12:35:17 +00:00
network: internal API functions to manage assignment of physdev to guest
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 to be "0" in the .h file (effectively becoming 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 - we 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...)
This commit is contained in:
parent
e9949a586a
commit
04711a0f32
@ -3,4 +3,7 @@
|
||||
#
|
||||
|
||||
# bridge_driver.h
|
||||
networkAllocateActualDevice;
|
||||
networkBuildDhcpDaemonCommandLine;
|
||||
networkNotifyActualDevice;
|
||||
networkReleaseActualDevice;
|
||||
|
@ -2718,3 +2718,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 not 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;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* network_driver.h: core driver methods for managing networks
|
||||
*
|
||||
* Copyright (C) 2006, 2007 Red Hat, Inc.
|
||||
* Copyright (C) 2006, 2007, 2011 Red Hat, Inc.
|
||||
* Copyright (C) 2006 Daniel P. Berrange
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
@ -29,13 +29,31 @@
|
||||
|
||||
# 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)
|
||||
ATTRIBUTE_NONNULL(1);
|
||||
int networkNotifyActualDevice(virDomainNetDefPtr iface)
|
||||
ATTRIBUTE_NONNULL(1);
|
||||
int networkReleaseActualDevice(virDomainNetDefPtr iface)
|
||||
ATTRIBUTE_NONNULL(1);
|
||||
|
||||
int networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
|
||||
virCommandPtr *cmdout, char *pidfile,
|
||||
dnsmasqContext *dctx);
|
||||
dnsmasqContext *dctx)
|
||||
;
|
||||
# else
|
||||
/* Define no-op replacements that don't drag in any link dependencies. */
|
||||
# define networkAllocateActualDevice(iface) 0
|
||||
# define networkNotifyActualDevice(iface) 0
|
||||
# define networkReleaseActualDevice(iface) 0
|
||||
# define networkBuildDhcpDaemonCommandLine(network, cmdout, pidfile, dctx) 0
|
||||
# endif
|
||||
|
||||
typedef char *(*networkDnsmasqLeaseFileNameFunc)(const char *netname);
|
||||
|
||||
|
@ -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) {
|
||||
@ -4677,6 +4685,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);
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "virfile.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,
|
||||
|
@ -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
|
||||
@ -2177,6 +2178,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;
|
||||
|
||||
@ -3014,10 +3031,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),
|
||||
@ -3026,8 +3043,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) {
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user