To avoid race-conditions, the tear down of a filter has to happen before
the tap interface disappears and another tap interface with the same
name can re-appear. This patch tries to fix this. In one place, where
communication with the qemu monitor may fail, I am only tearing the
filters down after knowing that the function did not fail.
I am also moving the tear down functions into an include file for other
drivers to reuse.
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
---
src/nwfilter/nwfilter_gentech_driver.h | 14 ++++++++++++++
src/qemu/qemu_conf.c | 13 ++++++++-----
src/qemu/qemu_driver.c | 28 +++++++---------------------
3 files changed, 29 insertions(+), 26 deletions(-)
Index: libvirt-acl/src/qemu/qemu_conf.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_conf.c
+++ libvirt-acl/src/qemu/qemu_conf.c
@@ -4074,10 +4074,13 @@ int qemudBuildCommandLine(virConnectPtr
goto error;
if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0) {
+ virNWFilterTearNWFilter(net);
close(tapfd);
goto no_memory;
}
+ last_good_net = i;
+
(*tapfds)[(*ntapfds)++] = tapfd;
if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", tapfd) >=
sizeof(tapfd_name))
@@ -4091,10 +4094,13 @@ int qemudBuildCommandLine(virConnectPtr
goto error;
if (VIR_REALLOC_N(*tapfds, (*ntapfds)+1) < 0) {
+ virNWFilterTearNWFilter(net);
close(tapfd);
goto no_memory;
}
+ last_good_net = i;
+
(*tapfds)[(*ntapfds)++] = tapfd;
if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", tapfd) >=
sizeof(tapfd_name))
@@ -4154,7 +4160,6 @@ int qemudBuildCommandLine(virConnectPtr
goto error;
ADD_ARG(host);
}
- last_good_net = i;
}
}
@@ -4603,6 +4608,8 @@ int qemudBuildCommandLine(virConnectPtr
no_memory:
virReportOOMError();
error:
+ for (i = 0; i <= last_good_net; i++)
+ virNWFilterTearNWFilter(def->nets[i]);
if (tapfds &&
*tapfds) {
for (i = 0; i < *ntapfds; i++)
@@ -4620,11 +4627,6 @@ int qemudBuildCommandLine(virConnectPtr
VIR_FREE((qenv)[i]);
VIR_FREE(qenv);
}
- for (i = 0; i <= last_good_net; i++) {
- virDomainNetDefPtr net = def->nets[i];
- if ((net->filter) && (net->ifname))
- virNWFilterTeardownFilter(net);
- }
return -1;
#undef ADD_ARG
Index: libvirt-acl/src/qemu/qemu_driver.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_driver.c
+++ libvirt-acl/src/qemu/qemu_driver.c
@@ -3070,21 +3070,6 @@ cleanup:
}
-static void
-qemuTearNWFilter(virDomainNetDefPtr net) {
- if ((net->filter) && (net->ifname))
- virNWFilterTeardownFilter(net);
-}
-
-
-static void
-qemuTearVMNWFilters(virDomainObjPtr vm) {
- int i;
- for (i = 0; i < vm->def->nnets; i++)
- qemuTearNWFilter(vm->def->nets[i]);
-}
-
-
struct qemudHookData {
virConnectPtr conn;
virDomainObjPtr vm;
@@ -3397,6 +3382,9 @@ static int qemudStartVMDaemon(virConnect
VIR_FREE(progenv[i]);
VIR_FREE(progenv);
+ if (ret == -1) /* The VM failed to start; tear filters before taps */
+ virNWFilterTearVMNWFilters(vm);
+
if (tapfds) {
for (i = 0 ; i < ntapfds ; i++) {
close(tapfds[i]);
@@ -3461,8 +3449,6 @@ cleanup:
/* We jump here if we failed to start the VM for any reason
* XXX investigate if we can kill this block and safely call
* qemudShutdownVMDaemon even though no PID is running */
- qemuTearVMNWFilters(vm);
-
qemuDomainReAttachHostDevices(driver, vm->def);
if (driver->securityDriver &&
@@ -3511,7 +3497,7 @@ static void qemudShutdownVMDaemon(struct
* reporting so we don't squash a legit error. */
orig_err = virSaveLastError();
- qemuTearVMNWFilters(vm);
+ virNWFilterTearVMNWFilters(vm);
if (driver->macFilter) {
def = vm->def;
@@ -7153,7 +7139,8 @@ cleanup:
qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &net->info) < 0)
VIR_WARN0("Unable to release PCI address on NIC");
- qemuTearNWFilter(net);
+ if (ret != 0)
+ virNWFilterTearNWFilter(net);
VIR_FREE(nicstr);
VIR_FREE(netstr);
@@ -7953,6 +7940,8 @@ qemudDomainDetachNetDevice(struct qemud_
}
qemuDomainObjExitMonitorWithDriver(driver, vm);
+ virNWFilterTearNWFilter(detach);
+
#if WITH_MACVTAP
if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
if (detach->ifname)
@@ -7970,8 +7959,6 @@ qemudDomainDetachNetDevice(struct qemud_
}
}
- qemuTearNWFilter(detach);
-
if (vm->def->nnets > 1) {
memmove(vm->def->nets + i,
vm->def->nets + i + 1,
Index: libvirt-acl/src/nwfilter/nwfilter_gentech_driver.h
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_gentech_driver.h
+++ libvirt-acl/src/nwfilter/nwfilter_gentech_driver.h
@@ -65,4 +65,20 @@ void virNWFilterDomainFWUpdateCB(void *p
const char *name ATTRIBUTE_UNUSED,
void *data);
+
+/* tear down an interface's filter before tearing down the interface */
+static inline void
+virNWFilterTearNWFilter(virDomainNetDefPtr net) {
+ if ((net->filter) && (net->ifname))
+ virNWFilterTeardownFilter(net);
+}
+
+
+static inline void
+virNWFilterTearVMNWFilters(virDomainObjPtr vm) {
+ int i;
+ for (i = 0; i < vm->def->nnets; i++)
+ virNWFilterTearNWFilter(vm->def->nets[i]);
+}
+
#endif