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(a)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