[PATCHv2] network: Fix a race condition when shutdown & start vm at the same time

Bingsong Si owen.si at ucloud.cn
Thu Jun 18 03:43:22 UTC 2020


When shutdown vm, the qemuProcessStop cleanup virtual interface in two steps:
1. qemuProcessKill kill qemu process, and vif disappeared
2. ovs-vsctl del-port from the ovs bridge

If start a vm in the middle of the two steps, the new vm will reused the vif,
but removed from ovs bridge by step 2

https://www.redhat.com/archives/libvir-list/2020-June/msg00681.html

Signed-off-by: Bingsong Si <owen.si at ucloud.cn>
---
 src/libvirt_private.syms |  1 +
 src/qemu/qemu_process.c  |  9 ++++++---
 src/util/virnetdevtap.c  | 12 ++++++++++--
 src/util/virnetdevtap.h  |  2 ++
 4 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index fc7406f2b7..5258c07368 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2655,6 +2655,7 @@ virNetDevTapDelete;
 virNetDevTapGetName;
 virNetDevTapGetRealDeviceName;
 virNetDevTapInterfaceStats;
+virNetDevTapMutex;
 virNetDevTapReattachBridge;
 
 
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index d36088ba98..2493b092b1 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -7483,9 +7483,12 @@ void qemuProcessStop(virQEMUDriverPtr driver,
             if (vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_MIDONET) {
                 ignore_value(virNetDevMidonetUnbindPort(vport));
             } else if (vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
-                ignore_value(virNetDevOpenvswitchRemovePort(
-                                 virDomainNetGetActualBridgeName(net),
-                                 net->ifname));
+                virMutexLock(&virNetDevTapMutex);
+                if (!virNetDevExists(net->ifname))
+                    ignore_value(virNetDevOpenvswitchRemovePort(
+                                     virDomainNetGetActualBridgeName(net),
+                                     net->ifname));
+                virMutexUnlock(&virNetDevTapMutex);
             }
         }
 
diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c
index 7bd30ea0f9..d685e30a50 100644
--- a/src/util/virnetdevtap.c
+++ b/src/util/virnetdevtap.c
@@ -54,6 +54,8 @@
 
 VIR_LOG_INIT("util.netdevtap");
 
+virMutex virNetDevTapMutex = VIR_MUTEX_INITIALIZER;
+
 /**
  * virNetDevTapGetName:
  * @tapfd: a tun/tap file descriptor
@@ -238,6 +240,7 @@ int virNetDevTapCreate(char **ifname,
     if (!tunpath)
         tunpath = "/dev/net/tun";
 
+    virMutexLock(&virNetDevTapMutex);
     memset(&ifr, 0, sizeof(ifr));
     for (i = 0; i < tapfdSize; i++) {
         if ((fd = open(tunpath, O_RDWR)) < 0) {
@@ -302,6 +305,7 @@ int virNetDevTapCreate(char **ifname,
     ret = 0;
 
  cleanup:
+    virMutexUnlock(&virNetDevTapMutex);
     if (ret < 0) {
         VIR_FORCE_CLOSE(fd);
         while (i--)
@@ -369,6 +373,7 @@ int virNetDevTapCreate(char **ifname,
     int ret = -1;
     char *newifname = NULL;
 
+    virMutexLock(&virNetDevTapMutex);
     if (tapfdSize > 1) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("Multiqueue devices are not supported on this system"));
@@ -379,8 +384,10 @@ int virNetDevTapCreate(char **ifname,
      * we have to create 'tap' interface first and
      * then rename it to 'vnet'
      */
-    if ((s = virNetDevSetupControl("tap", &ifr)) < 0)
+    if ((s = virNetDevSetupControl("tap", &ifr)) < 0) {
+        virMutexUnlock(&virNetDevTapMutex);
         return -1;
+    }
 
     if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) {
         virReportSystemError(errno, "%s",
@@ -434,6 +441,7 @@ int virNetDevTapCreate(char **ifname,
 
     ret = 0;
  cleanup:
+    virMutexUnlock(&virNetDevTapMutex);
     VIR_FORCE_CLOSE(s);
 
     return ret;
@@ -710,7 +718,7 @@ int virNetDevTapCreateInBridgePort(const char *brname,
     if (virNetDevSetMAC(*ifname, &tapmac) < 0)
         goto error;
 
-    if (virNetDevTapAttachBridge(*ifname, brname, macaddr, vmuuid,
+    if (virNetDevTapReattachBridge(*ifname, brname, macaddr, vmuuid,
                                  virtPortProfile, virtVlan,
                                  isolatedPort, mtu, actualMTU) < 0) {
         goto error;
diff --git a/src/util/virnetdevtap.h b/src/util/virnetdevtap.h
index c6bd9285ba..f2d332e5aa 100644
--- a/src/util/virnetdevtap.h
+++ b/src/util/virnetdevtap.h
@@ -29,6 +29,8 @@
 # define VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP 1
 #endif
 
+extern virMutex virNetDevTapMutex;
+
 int virNetDevTapCreate(char **ifname,
                        const char *tunpath,
                        int *tapfd,
-- 
2.18.4




More information about the libvir-list mailing list