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@xxxxxxxxx> --- 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