Blame SOURCES/libvirt-util-replace-macvtap-name-reservation-bitmap-with-a-simple-counter.patch

7548c0
From 4238e5f0783c63802de79bc5ed2a1f49673ef2a3 Mon Sep 17 00:00:00 2001
7548c0
Message-Id: <4238e5f0783c63802de79bc5ed2a1f49673ef2a3@dist-git>
7548c0
From: Laine Stump <laine@redhat.com>
7548c0
Date: Sat, 12 Dec 2020 22:04:51 -0500
7548c0
Subject: [PATCH] util: replace macvtap name reservation bitmap with a simple
7548c0
 counter
7548c0
7548c0
There have been some reports that, due to libvirt always trying to
7548c0
assign the lowest numbered macvtap / tap device name possible, a new
7548c0
guest would sometimes be started using the same tap device name as
7548c0
previously used by another guest that is in the process of being
7548c0
destroyed *as the new guest is starting.
7548c0
7548c0
In some cases this has led to, for example, the old guest's
7548c0
qemuProcessStop() code deleting a port from an OVS switch that had
7548c0
just been re-added by the new guest (because the port name is based on
7548c0
only the device name using the port). Similar problems can happen (and
7548c0
I believe have) with nwfilter rules and bandwidth rules (which are
7548c0
both instantiated based on the name of the tap device).
7548c0
7548c0
A couple patches have been previously proposed to change the ordering
7548c0
of startup and shutdown processing, or to put a mutex around
7548c0
everything related to the tap/macvtap device name usage, but in the
7548c0
end no matter what you do there will still be possible holes, because
7548c0
the device could be deleted outside libvirt's control (for example,
7548c0
regular tap devices are automatically deleted when the qemu process
7548c0
terminates, and that isn't always initiated by libvirt but could
7548c0
instead happen completely asynchronously - libvirt then has no control
7548c0
over the ordering of shutdown operations, and no opportunity to
7548c0
protect it with a mutex.)
7548c0
7548c0
But this only happens if a new device is created at the same time as
7548c0
one is being deleted. We can effectively eliminate the chance of this
7548c0
happening if we end the practice of always looking for the lowest
7548c0
numbered available device name, and instead just keep an integer that
7548c0
is incremented each time we need a new device name. At some point it
7548c0
will need to wrap back around to 0 (in order to avoid the IFNAMSIZ 15
7548c0
character limit if nothing else), and we can't guarantee that the new
7548c0
name really will be the *least* recently used name, but "math"
7548c0
suggests that it will be *much* less common that we'll try to re-use
7548c0
the *most* recently used name.
7548c0
7548c0
This patch implements such a counter for macvtap/macvlan, replacing
7548c0
the existing, and much more complicated, "ID reservation" system. The
7548c0
counter is set according to whatever macvtap/macvlan devices are
7548c0
already in use by guests when libvirtd is started, incremented each
7548c0
time a new device name is needed, and wraps back to 0 when either
7548c0
INT_MAX is reached, or when the resulting device name would be longer
7548c0
than IFNAMSIZ-1 characters (which actually is what happens when the
7548c0
template for the device name is "maccvtap%d"). The result is that no
7548c0
macvtap name will be re-used until the host has created (and possibly
7548c0
destroyed) 99,999,999 devices.
7548c0
7548c0
Signed-off-by: Laine Stump <laine@redhat.com>
7548c0
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
7548c0
(cherry picked from commit d7f38beb2ee072f1f19bb91fbafc9182ce9b069e)
7548c0
7548c0
https://bugzilla.redhat.com/1874304
7548c0
Signed-off-by: Laine Stump <laine@redhat.com>
7548c0
Message-Id: <20201213030453.48851-2-laine@redhat.com>
7548c0
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
7548c0
---
7548c0
 src/libvirt_private.syms    |   1 -
7548c0
 src/libxl/libxl_driver.c    |   2 +-
7548c0
 src/lxc/lxc_process.c       |   2 +-
7548c0
 src/qemu/qemu_process.c     |   2 +-
7548c0
 src/util/virnetdevmacvlan.c | 403 +++++++++++++-----------------------
7548c0
 src/util/virnetdevmacvlan.h |   6 +-
7548c0
 6 files changed, 145 insertions(+), 271 deletions(-)
7548c0
7548c0
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
7548c0
index fdd104cd25..1c66c40f86 100644
7548c0
--- a/src/libvirt_private.syms
7548c0
+++ b/src/libvirt_private.syms
7548c0
@@ -2604,7 +2604,6 @@ virNetDevMacVLanDelete;
7548c0
 virNetDevMacVLanDeleteWithVPortProfile;
7548c0
 virNetDevMacVLanIsMacvtap;
7548c0
 virNetDevMacVLanModeTypeFromString;
7548c0
-virNetDevMacVLanReleaseName;
7548c0
 virNetDevMacVLanReserveName;
7548c0
 virNetDevMacVLanRestartWithVPortProfile;
7548c0
 virNetDevMacVLanTapOpen;
7548c0
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
7548c0
index 1449795494..9269e9b475 100644
7548c0
--- a/src/libxl/libxl_driver.c
7548c0
+++ b/src/libxl/libxl_driver.c
7548c0
@@ -367,7 +367,7 @@ libxlReconnectNotifyNets(virDomainDefPtr def)
7548c0
          * impolite.
7548c0
          */
7548c0
         if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT)
7548c0
-           ignore_value(virNetDevMacVLanReserveName(net->ifname, false));
7548c0
+            virNetDevMacVLanReserveName(net->ifname);
7548c0
 
7548c0
         if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
7548c0
             if (!conn && !(conn = virGetConnectNetwork()))
7548c0
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
7548c0
index 0a9ccdf9ec..114c40b0ea 100644
7548c0
--- a/src/lxc/lxc_process.c
7548c0
+++ b/src/lxc/lxc_process.c
7548c0
@@ -1638,7 +1638,7 @@ virLXCProcessReconnectNotifyNets(virDomainDefPtr def)
7548c0
          * impolite.
7548c0
          */
7548c0
         if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT)
7548c0
-           ignore_value(virNetDevMacVLanReserveName(net->ifname, false));
7548c0
+            virNetDevMacVLanReserveName(net->ifname);
7548c0
 
7548c0
         if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
7548c0
             if (!conn && !(conn = virGetConnectNetwork()))
7548c0
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
7548c0
index 95c0315e53..b49a463c02 100644
7548c0
--- a/src/qemu/qemu_process.c
7548c0
+++ b/src/qemu/qemu_process.c
7548c0
@@ -3288,7 +3288,7 @@ qemuProcessNotifyNets(virDomainDefPtr def)
7548c0
          * impolite.
7548c0
          */
7548c0
         if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT)
7548c0
-           ignore_value(virNetDevMacVLanReserveName(net->ifname, false));
7548c0
+            virNetDevMacVLanReserveName(net->ifname);
7548c0
 
7548c0
         if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
7548c0
             if (!conn && !(conn = virGetConnectNetwork()))
7548c0
diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
7548c0
index 3ca568fb44..7046cbb04e 100644
7548c0
--- a/src/util/virnetdevmacvlan.c
7548c0
+++ b/src/util/virnetdevmacvlan.c
7548c0
@@ -47,6 +47,7 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode,
7548c0
 
7548c0
 # include <net/if.h>
7548c0
 # include <linux/if_tun.h>
7548c0
+# include <math.h>
7548c0
 
7548c0
 /* Older kernels lacked this enum value.  */
7548c0
 # if !HAVE_DECL_MACVLAN_MODE_PASSTHRU
7548c0
@@ -70,211 +71,121 @@ VIR_LOG_INIT("util.netdevmacvlan");
7548c0
     ((flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP) ? \
7548c0
      VIR_NET_GENERATED_MACVTAP_PREFIX : VIR_NET_GENERATED_MACVLAN_PREFIX)
7548c0
 
7548c0
-# define MACVLAN_MAX_ID 8191
7548c0
 
7548c0
 virMutex virNetDevMacVLanCreateMutex = VIR_MUTEX_INITIALIZER;
7548c0
-virBitmapPtr macvtapIDs = NULL;
7548c0
-virBitmapPtr macvlanIDs = NULL;
7548c0
-
7548c0
-static int
7548c0
-virNetDevMacVLanOnceInit(void)
7548c0
-{
7548c0
-    if (!macvtapIDs &&
7548c0
-        !(macvtapIDs = virBitmapNew(MACVLAN_MAX_ID + 1)))
7548c0
-        return -1;
7548c0
-    if (!macvlanIDs &&
7548c0
-        !(macvlanIDs = virBitmapNew(MACVLAN_MAX_ID + 1)))
7548c0
-        return -1;
7548c0
-    return 0;
7548c0
-}
7548c0
-
7548c0
-VIR_ONCE_GLOBAL_INIT(virNetDevMacVLan);
7548c0
+static int virNetDevMacVTapLastID = -1;
7548c0
+static int virNetDevMacVLanLastID = -1;
7548c0
 
7548c0
 
7548c0
-/**
7548c0
- * virNetDevMacVLanReserveID:
7548c0
- *
7548c0
- *  @id: id 0 - MACVLAN_MAX_ID+1 to reserve (or -1 for "first free")
7548c0
- *  @flags: set VIR_NETDEV_MACVLAN_CREATE_WITH_TAP for macvtapN else macvlanN
7548c0
- *  @quietFail: don't log an error if this name is already in-use
7548c0
- *  @nextFree: reserve the next free ID *after* @id rather than @id itself
7548c0
- *
7548c0
- *  Reserve the indicated ID in the appropriate bitmap, or find the
7548c0
- *  first free ID if @id is -1.
7548c0
- *
7548c0
- *  Returns newly reserved ID# on success, or -1 to indicate failure.
7548c0
- */
7548c0
-static int
7548c0
-virNetDevMacVLanReserveID(int id, unsigned int flags,
7548c0
-                          bool quietFail, bool nextFree)
7548c0
+static void
7548c0
+virNetDevMacVLanReserveNameInternal(const char *name)
7548c0
 {
7548c0
-    virBitmapPtr bitmap;
7548c0
-
7548c0
-    if (virNetDevMacVLanInitialize() < 0)
7548c0
-       return -1;
7548c0
-
7548c0
-    bitmap = (flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP) ?
7548c0
-        macvtapIDs :  macvlanIDs;
7548c0
+    unsigned int id;
7548c0
+    const char *idstr = NULL;
7548c0
+    int *lastID = NULL;
7548c0
+    int len;
7548c0
 
7548c0
-    if (id > MACVLAN_MAX_ID) {
7548c0
-        virReportError(VIR_ERR_INTERNAL_ERROR,
7548c0
-                       _("can't use name %s%d - out of range 0-%d"),
7548c0
-                       VIR_NET_GENERATED_PREFIX, id, MACVLAN_MAX_ID);
7548c0
-        return -1;
7548c0
+    if (STRPREFIX(name, VIR_NET_GENERATED_MACVTAP_PREFIX)) {
7548c0
+        lastID = &virNetDevMacVTapLastID;
7548c0
+        len = strlen(VIR_NET_GENERATED_MACVTAP_PREFIX);
7548c0
+    } else if (STRPREFIX(name, VIR_NET_GENERATED_MACVLAN_PREFIX)) {
7548c0
+        lastID = &virNetDevMacVTapLastID;
7548c0
+        len = strlen(VIR_NET_GENERATED_MACVLAN_PREFIX);
7548c0
+    } else {
7548c0
+        return;
7548c0
     }
7548c0
 
7548c0
-    if ((id < 0 || nextFree) &&
7548c0
-        (id = virBitmapNextClearBit(bitmap, id)) < 0) {
7548c0
-        virReportError(VIR_ERR_INTERNAL_ERROR,
7548c0
-                       _("no unused %s names available"),
7548c0
-                       VIR_NET_GENERATED_PREFIX);
7548c0
-        return -1;
7548c0
-    }
7548c0
+    VIR_INFO("marking device in use: '%s'", name);
7548c0
 
7548c0
-    if (virBitmapIsBitSet(bitmap, id)) {
7548c0
-        if (quietFail) {
7548c0
-            VIR_INFO("couldn't reserve name %s%d - already in use",
7548c0
-                     VIR_NET_GENERATED_PREFIX, id);
7548c0
-        } else {
7548c0
-            virReportError(VIR_ERR_INTERNAL_ERROR,
7548c0
-                           _("couldn't reserve name %s%d - already in use"),
7548c0
-                           VIR_NET_GENERATED_PREFIX, id);
7548c0
-        }
7548c0
-        return -1;
7548c0
-    }
7548c0
+    idstr = name + len;
7548c0
 
7548c0
-    if (virBitmapSetBit(bitmap, id) < 0) {
7548c0
-        virReportError(VIR_ERR_INTERNAL_ERROR,
7548c0
-                       _("couldn't mark %s%d as used"),
7548c0
-                       VIR_NET_GENERATED_PREFIX, id);
7548c0
-        return -1;
7548c0
+    if (virStrToLong_ui(idstr, NULL, 10, &id) >= 0) {
7548c0
+        if (*lastID < (int)id)
7548c0
+            *lastID = id;
7548c0
     }
7548c0
-
7548c0
-    VIR_INFO("reserving device %s%d", VIR_NET_GENERATED_PREFIX, id);
7548c0
-    return id;
7548c0
 }
7548c0
 
7548c0
 
7548c0
 /**
7548c0
- * virNetDevMacVLanReleaseID:
7548c0
- *  @id: id 0 - MACVLAN_MAX_ID+1 to release
7548c0
+ * virNetDevMacVLanReserveName:
7548c0
+ * @name: name of an existing macvtap/macvlan device
7548c0
  *
7548c0
- *  Returns 0 for success or -1 for failure.
7548c0
+ * Set the value of virNetDevMacV(Lan|Tap)LastID to assure that any
7548c0
+ * new device created with an autogenerated name will use a number
7548c0
+ * higher than the number in the given device name.
7548c0
+ *
7548c0
+ * Returns nothing.
7548c0
  */
7548c0
-static int
7548c0
-virNetDevMacVLanReleaseID(int id, unsigned int flags)
7548c0
+void
7548c0
+virNetDevMacVLanReserveName(const char *name)
7548c0
 {
7548c0
-    virBitmapPtr bitmap;
7548c0
-
7548c0
-    if (virNetDevMacVLanInitialize() < 0)
7548c0
-        return 0;
7548c0
-
7548c0
-    bitmap = (flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP) ?
7548c0
-        macvtapIDs :  macvlanIDs;
7548c0
-
7548c0
-    if (id > MACVLAN_MAX_ID) {
7548c0
-        virReportError(VIR_ERR_INTERNAL_ERROR,
7548c0
-                       _("can't free name %s%d - out of range 0-%d"),
7548c0
-                       VIR_NET_GENERATED_PREFIX, id, MACVLAN_MAX_ID);
7548c0
-        return -1;
7548c0
-    }
7548c0
-
7548c0
-    if (id < 0)
7548c0
-        return 0;
7548c0
-
7548c0
-    VIR_INFO("releasing %sdevice %s%d",
7548c0
-             virBitmapIsBitSet(bitmap, id) ? "" : "unreserved",
7548c0
-             VIR_NET_GENERATED_PREFIX, id);
7548c0
-
7548c0
-    if (virBitmapClearBit(bitmap, id) < 0) {
7548c0
-        virReportError(VIR_ERR_INTERNAL_ERROR,
7548c0
-                       _("couldn't mark %s%d as unused"),
7548c0
-                       VIR_NET_GENERATED_PREFIX, id);
7548c0
-        return -1;
7548c0
-    }
7548c0
-    return 0;
7548c0
+    virMutexLock(&virNetDevMacVLanCreateMutex);
7548c0
+    virNetDevMacVLanReserveNameInternal(name);
7548c0
+    virMutexUnlock(&virNetDevMacVLanCreateMutex);
7548c0
 }
7548c0
 
7548c0
 
7548c0
 /**
7548c0
- * virNetDevMacVLanReserveName:
7548c0
- *
7548c0
- *  @name: already-known name of device
7548c0
- *  @quietFail: don't log an error if this name is already in-use
7548c0
+ * virNetDevMacVLanGenerateName:
7548c0
+ * @ifname: pointer to pointer to string containing template
7548c0
+ * @lastID: counter to add to the template to form the name
7548c0
  *
7548c0
- *  Extract the device type and id from a macvtap/macvlan device name
7548c0
- *  and mark the appropriate position as in-use in the appropriate
7548c0
- *  bitmap.
7548c0
+ * generate a new (currently unused) name for a new macvtap/macvlan
7548c0
+ * device based on the template string in @ifname - replace %d with
7548c0
+ * ++(*counter), and keep trying new values until one is found
7548c0
+ * that doesn't already exist, or we've tried 10000 different
7548c0
+ * names. Once a usable name is found, replace the template with the
7548c0
+ * actual name.
7548c0
  *
7548c0
- *  Returns reserved ID# on success, -1 on failure, -2 if the name
7548c0
- *  doesn't fit the auto-pattern (so not reserveable).
7548c0
+ * Returns 0 on success, -1 on failure.
7548c0
  */
7548c0
-int
7548c0
-virNetDevMacVLanReserveName(const char *name, bool quietFail)
7548c0
+static int
7548c0
+virNetDevMacVLanGenerateName(char **ifname, unsigned int flags)
7548c0
 {
7548c0
-    unsigned int id;
7548c0
-    unsigned int flags = 0;
7548c0
-    const char *idstr = NULL;
7548c0
+    const char *prefix;
7548c0
+    const char *iftemplate;
7548c0
+    int *lastID;
7548c0
+    int id;
7548c0
+    double maxIDd;
7548c0
+    int maxID = INT_MAX;
7548c0
+    int attempts = 0;
7548c0
 
7548c0
-    if (virNetDevMacVLanInitialize() < 0)
7548c0
-       return -1;
7548c0
-
7548c0
-    if (STRPREFIX(name, VIR_NET_GENERATED_MACVTAP_PREFIX)) {
7548c0
-        idstr = name + strlen(VIR_NET_GENERATED_MACVTAP_PREFIX);
7548c0
-        flags |= VIR_NETDEV_MACVLAN_CREATE_WITH_TAP;
7548c0
-    } else if (STRPREFIX(name, VIR_NET_GENERATED_MACVLAN_PREFIX)) {
7548c0
-        idstr = name + strlen(VIR_NET_GENERATED_MACVLAN_PREFIX);
7548c0
+    if (flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP) {
7548c0
+        prefix = VIR_NET_GENERATED_MACVTAP_PREFIX;
7548c0
+        iftemplate = VIR_NET_GENERATED_MACVTAP_PREFIX "%d";
7548c0
+        lastID = &virNetDevMacVTapLastID;
7548c0
     } else {
7548c0
-        return -2;
7548c0
+        prefix = VIR_NET_GENERATED_MACVLAN_PREFIX;
7548c0
+        iftemplate = VIR_NET_GENERATED_MACVLAN_PREFIX "%d";
7548c0
+        lastID = &virNetDevMacVLanLastID;
7548c0
     }
7548c0
 
7548c0
-    if (virStrToLong_ui(idstr, NULL, 10, &id) < 0) {
7548c0
-        virReportError(VIR_ERR_INTERNAL_ERROR,
7548c0
-                       _("couldn't get id value from macvtap device name %s"),
7548c0
-                       name);
7548c0
-        return -1;
7548c0
-    }
7548c0
-    return virNetDevMacVLanReserveID(id, flags, quietFail, false);
7548c0
-}
7548c0
+    maxIDd = pow(10, IFNAMSIZ - 1 - strlen(prefix));
7548c0
+    if (maxIDd <= (double)INT_MAX)
7548c0
+        maxID = (int)maxIDd;
7548c0
 
7548c0
+    do {
7548c0
+        g_autofree char *try = NULL;
7548c0
 
7548c0
-/**
7548c0
- * virNetDevMacVLanReleaseName:
7548c0
- *
7548c0
- *  @name: already-known name of device
7548c0
- *
7548c0
- *  Extract the device type and id from a macvtap/macvlan device name
7548c0
- *  and mark the appropriate position as in-use in the appropriate
7548c0
- *  bitmap.
7548c0
- *
7548c0
- *  returns 0 on success, -1 on failure
7548c0
- */
7548c0
-int
7548c0
-virNetDevMacVLanReleaseName(const char *name)
7548c0
-{
7548c0
-    unsigned int id;
7548c0
-    unsigned int flags = 0;
7548c0
-    const char *idstr = NULL;
7548c0
+        id = ++(*lastID);
7548c0
 
7548c0
-    if (virNetDevMacVLanInitialize() < 0)
7548c0
-       return -1;
7548c0
+        /* reset before overflow */
7548c0
+        if (*lastID == maxID)
7548c0
+            *lastID = -1;
7548c0
 
7548c0
-    if (STRPREFIX(name, VIR_NET_GENERATED_MACVTAP_PREFIX)) {
7548c0
-        idstr = name + strlen(VIR_NET_GENERATED_MACVTAP_PREFIX);
7548c0
-        flags |= VIR_NETDEV_MACVLAN_CREATE_WITH_TAP;
7548c0
-    } else if (STRPREFIX(name, VIR_NET_GENERATED_MACVLAN_PREFIX)) {
7548c0
-        idstr = name + strlen(VIR_NET_GENERATED_MACVLAN_PREFIX);
7548c0
-    } else {
7548c0
-        return 0;
7548c0
-    }
7548c0
+        try = g_strdup_printf(iftemplate, id);
7548c0
 
7548c0
-    if (virStrToLong_ui(idstr, NULL, 10, &id) < 0) {
7548c0
-        virReportError(VIR_ERR_INTERNAL_ERROR,
7548c0
-                       _("couldn't get id value from macvtap device name %s"),
7548c0
-                       name);
7548c0
-        return -1;
7548c0
-    }
7548c0
-    return virNetDevMacVLanReleaseID(id, flags);
7548c0
+        if (!virNetDevExists(try)) {
7548c0
+            g_free(*ifname);
7548c0
+            *ifname = g_steal_pointer(&try;;
7548c0
+            return 0;
7548c0
+        }
7548c0
+    } while (++attempts < 10000);
7548c0
+
7548c0
+    virReportError(VIR_ERR_INTERNAL_ERROR,
7548c0
+                   _("no unused %s names available"),
7548c0
+                   *ifname);
7548c0
+    return -1;
7548c0
 }
7548c0
 
7548c0
 
7548c0
@@ -321,8 +232,7 @@ virNetDevMacVLanCreate(const char *ifname,
7548c0
                        const char *type,
7548c0
                        const virMacAddr *macaddress,
7548c0
                        const char *srcdev,
7548c0
-                       uint32_t macvlan_mode,
7548c0
-                       int *retry)
7548c0
+                       uint32_t macvlan_mode)
7548c0
 {
7548c0
     int error = 0;
7548c0
     int ifindex = 0;
7548c0
@@ -331,7 +241,6 @@ virNetDevMacVLanCreate(const char *ifname,
7548c0
         .mac = macaddress,
7548c0
     };
7548c0
 
7548c0
-    *retry = 0;
7548c0
 
7548c0
     if (virNetDevGetIndex(srcdev, &ifindex) < 0)
7548c0
         return -1;
7548c0
@@ -339,17 +248,15 @@ virNetDevMacVLanCreate(const char *ifname,
7548c0
     data.ifindex = &ifindex;
7548c0
     if (virNetlinkNewLink(ifname, type, &data, &error) < 0) {
7548c0
         char macstr[VIR_MAC_STRING_BUFLEN];
7548c0
-        if (error == -EEXIST)
7548c0
-            *retry = 1;
7548c0
-        else if (error < 0)
7548c0
-            virReportSystemError(-error,
7548c0
-                                 _("error creating %s interface %s@%s (%s)"),
7548c0
-                                 type, ifname, srcdev,
7548c0
-                                 virMacAddrFormat(macaddress, macstr));
7548c0
 
7548c0
+        virReportSystemError(-error,
7548c0
+                             _("error creating %s interface %s@%s (%s)"),
7548c0
+                             type, ifname, srcdev,
7548c0
+                             virMacAddrFormat(macaddress, macstr));
7548c0
         return -1;
7548c0
     }
7548c0
 
7548c0
+    VIR_INFO("created device: '%s'", ifname);
7548c0
     return 0;
7548c0
 }
7548c0
 
7548c0
@@ -364,6 +271,7 @@ virNetDevMacVLanCreate(const char *ifname,
7548c0
  */
7548c0
 int virNetDevMacVLanDelete(const char *ifname)
7548c0
 {
7548c0
+    VIR_INFO("delete device: '%s'", ifname);
7548c0
     return virNetlinkDelLink(ifname, NULL);
7548c0
 }
7548c0
 
7548c0
@@ -904,13 +812,8 @@ virNetDevMacVLanCreateWithVPortProfile(const char *ifnameRequested,
7548c0
                                        unsigned int flags)
7548c0
 {
7548c0
     const char *type = VIR_NET_GENERATED_PREFIX;
7548c0
-    const char *pattern = (flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP) ?
7548c0
-        VIR_NET_GENERATED_MACVTAP_PATTERN : VIR_NET_GENERATED_MACVLAN_PATTERN;
7548c0
-    int reservedID = -1;
7548c0
-    char ifname[IFNAMSIZ];
7548c0
-    int retries, do_retry = 0;
7548c0
+    g_autofree char *ifname = NULL;
7548c0
     uint32_t macvtapMode;
7548c0
-    const char *ifnameCreated = NULL;
7548c0
     int vf = -1;
7548c0
     bool vnet_hdr = flags & VIR_NETDEV_MACVLAN_VNET_HDR;
7548c0
 
7548c0
@@ -945,6 +848,8 @@ virNetDevMacVLanCreateWithVPortProfile(const char *ifnameRequested,
7548c0
            return -1;
7548c0
     }
7548c0
 
7548c0
+    virMutexLock(&virNetDevMacVLanCreateMutex);
7548c0
+
7548c0
     if (ifnameRequested) {
7548c0
         int rc;
7548c0
         bool isAutoName
7548c0
@@ -952,97 +857,81 @@ virNetDevMacVLanCreateWithVPortProfile(const char *ifnameRequested,
7548c0
                STRPREFIX(ifnameRequested, VIR_NET_GENERATED_MACVLAN_PREFIX));
7548c0
 
7548c0
         VIR_INFO("Requested macvtap device name: %s", ifnameRequested);
7548c0
-        virMutexLock(&virNetDevMacVLanCreateMutex);
7548c0
 
7548c0
         if ((rc = virNetDevExists(ifnameRequested)) < 0) {
7548c0
             virMutexUnlock(&virNetDevMacVLanCreateMutex);
7548c0
             return -1;
7548c0
         }
7548c0
+
7548c0
         if (rc) {
7548c0
-            if (isAutoName)
7548c0
-                goto create_name;
7548c0
-            virReportSystemError(EEXIST,
7548c0
-                                 _("Unable to create %s device %s"),
7548c0
-                                 type, ifnameRequested);
7548c0
-            virMutexUnlock(&virNetDevMacVLanCreateMutex);
7548c0
-            return -1;
7548c0
-        }
7548c0
-        if (isAutoName &&
7548c0
-            (reservedID = virNetDevMacVLanReserveName(ifnameRequested, true)) < 0) {
7548c0
-            reservedID = -1;
7548c0
-            goto create_name;
7548c0
-        }
7548c0
+            /* ifnameRequested is already being used */
7548c0
 
7548c0
-        if (virNetDevMacVLanCreate(ifnameRequested, type, macaddress,
7548c0
-                                   linkdev, macvtapMode, &do_retry) < 0) {
7548c0
-            if (isAutoName) {
7548c0
-                virNetDevMacVLanReleaseName(ifnameRequested);
7548c0
-                reservedID = -1;
7548c0
-                goto create_name;
7548c0
+            if (!isAutoName) {
7548c0
+                virReportSystemError(EEXIST,
7548c0
+                                     _("Unable to create device '%s'"),
7548c0
+                                     ifnameRequested);
7548c0
+                virMutexUnlock(&virNetDevMacVLanCreateMutex);
7548c0
+                return -1;
7548c0
+            }
7548c0
+        } else {
7548c0
+
7548c0
+            /* ifnameRequested is available. try to open it */
7548c0
+
7548c0
+            virNetDevMacVLanReserveNameInternal(ifnameRequested);
7548c0
+
7548c0
+            if (virNetDevMacVLanCreate(ifnameRequested, type, macaddress,
7548c0
+                                       linkdev, macvtapMode) == 0) {
7548c0
+
7548c0
+                /* virNetDevMacVLanCreate() was successful - use this name */
7548c0
+                ifname = g_strdup(ifnameRequested);
7548c0
+
7548c0
+            } else if (!isAutoName) {
7548c0
+                /* coudn't open ifnameRequested, but it wasn't an
7548c0
+                 * autogenerated named, so there is nothing else to
7548c0
+                 * try - fail and return.
7548c0
+                 */
7548c0
+                virMutexUnlock(&virNetDevMacVLanCreateMutex);
7548c0
+                return -1;
7548c0
             }
7548c0
-            virMutexUnlock(&virNetDevMacVLanCreateMutex);
7548c0
-            return -1;
7548c0
         }
7548c0
-        /* virNetDevMacVLanCreate() was successful - use this name */
7548c0
-        ifnameCreated = ifnameRequested;
7548c0
- create_name:
7548c0
-        virMutexUnlock(&virNetDevMacVLanCreateMutex);
7548c0
     }
7548c0
 
7548c0
-    retries = MACVLAN_MAX_ID;
7548c0
-    while (!ifnameCreated && retries) {
7548c0
-        virMutexLock(&virNetDevMacVLanCreateMutex);
7548c0
-        reservedID = virNetDevMacVLanReserveID(reservedID, flags, false, true);
7548c0
-        if (reservedID < 0) {
7548c0
+    if (!ifname) {
7548c0
+        /* ifnameRequested was NULL, or it was an already in use
7548c0
+         * autogenerated name, so now we look for an unused
7548c0
+         * autogenerated name.
7548c0
+         */
7548c0
+        if (virNetDevMacVLanGenerateName(&ifname, flags) < 0 ||
7548c0
+            virNetDevMacVLanCreate(ifname, type, macaddress,
7548c0
+                                   linkdev, macvtapMode) < 0) {
7548c0
             virMutexUnlock(&virNetDevMacVLanCreateMutex);
7548c0
             return -1;
7548c0
         }
7548c0
-        g_snprintf(ifname, sizeof(ifname), pattern, reservedID);
7548c0
-        if (virNetDevMacVLanCreate(ifname, type, macaddress, linkdev,
7548c0
-                                   macvtapMode, &do_retry) < 0) {
7548c0
-            virNetDevMacVLanReleaseID(reservedID, flags);
7548c0
-            virMutexUnlock(&virNetDevMacVLanCreateMutex);
7548c0
-            if (!do_retry)
7548c0
-                return -1;
7548c0
-            VIR_INFO("Device %s wasn't reserved but already existed, skipping",
7548c0
-                     ifname);
7548c0
-            retries--;
7548c0
-            continue;
7548c0
-        }
7548c0
-        ifnameCreated = ifname;
7548c0
-        virMutexUnlock(&virNetDevMacVLanCreateMutex);
7548c0
     }
7548c0
 
7548c0
-    if (!ifnameCreated) {
7548c0
-        virReportError(VIR_ERR_INTERNAL_ERROR,
7548c0
-                       _("Too many unreserved %s devices in use"),
7548c0
-                       type);
7548c0
-        return -1;
7548c0
-    }
7548c0
+    /* all done creating the device */
7548c0
+    virMutexUnlock(&virNetDevMacVLanCreateMutex);
7548c0
 
7548c0
-    if (virNetDevVPortProfileAssociate(ifnameCreated,
7548c0
+    if (virNetDevVPortProfileAssociate(ifname,
7548c0
                                        virtPortProfile,
7548c0
                                        macaddress,
7548c0
                                        linkdev,
7548c0
                                        vf,
7548c0
-                                       vmuuid, vmOp, false) < 0)
7548c0
+                                       vmuuid, vmOp, false) < 0) {
7548c0
         goto link_del_exit;
7548c0
+    }
7548c0
 
7548c0
     if (flags & VIR_NETDEV_MACVLAN_CREATE_IFUP) {
7548c0
-        if (virNetDevSetOnline(ifnameCreated, true) < 0)
7548c0
+        if (virNetDevSetOnline(ifname, true) < 0)
7548c0
             goto disassociate_exit;
7548c0
     }
7548c0
 
7548c0
     if (flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP) {
7548c0
-        if (virNetDevMacVLanTapOpen(ifnameCreated, tapfd, tapfdSize) < 0)
7548c0
+        if (virNetDevMacVLanTapOpen(ifname, tapfd, tapfdSize) < 0)
7548c0
             goto disassociate_exit;
7548c0
 
7548c0
         if (virNetDevMacVLanTapSetup(tapfd, tapfdSize, vnet_hdr) < 0)
7548c0
             goto disassociate_exit;
7548c0
-
7548c0
-        *ifnameResult = g_strdup(ifnameCreated);
7548c0
-    } else {
7548c0
-        *ifnameResult = g_strdup(ifnameCreated);
7548c0
     }
7548c0
 
7548c0
     if (vmOp == VIR_NETDEV_VPORT_PROFILE_OP_CREATE ||
7548c0
@@ -1051,17 +940,18 @@ virNetDevMacVLanCreateWithVPortProfile(const char *ifnameRequested,
7548c0
          * a saved image) - migration and libvirtd restart are handled
7548c0
          * elsewhere.
7548c0
          */
7548c0
-        if (virNetDevMacVLanVPortProfileRegisterCallback(ifnameCreated, macaddress,
7548c0
+        if (virNetDevMacVLanVPortProfileRegisterCallback(ifname, macaddress,
7548c0
                                                          linkdev, vmuuid,
7548c0
                                                          virtPortProfile,
7548c0
                                                          vmOp) < 0)
7548c0
             goto disassociate_exit;
7548c0
     }
7548c0
 
7548c0
+    *ifnameResult = g_steal_pointer(&ifname);
7548c0
     return 0;
7548c0
 
7548c0
  disassociate_exit:
7548c0
-    ignore_value(virNetDevVPortProfileDisassociate(ifnameCreated,
7548c0
+    ignore_value(virNetDevVPortProfileDisassociate(ifname,
7548c0
                                                    virtPortProfile,
7548c0
                                                    macaddress,
7548c0
                                                    linkdev,
7548c0
@@ -1071,9 +961,7 @@ virNetDevMacVLanCreateWithVPortProfile(const char *ifnameRequested,
7548c0
         VIR_FORCE_CLOSE(tapfd[tapfdSize]);
7548c0
 
7548c0
  link_del_exit:
7548c0
-    ignore_value(virNetDevMacVLanDelete(ifnameCreated));
7548c0
-    virNetDevMacVLanReleaseName(ifnameCreated);
7548c0
-
7548c0
+    ignore_value(virNetDevMacVLanDelete(ifname));
7548c0
     return -1;
7548c0
 }
7548c0
 
7548c0
@@ -1107,7 +995,6 @@ int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname,
7548c0
             ret = -1;
7548c0
         if (virNetDevMacVLanDelete(ifname) < 0)
7548c0
             ret = -1;
7548c0
-        virNetDevMacVLanReleaseName(ifname);
7548c0
     }
7548c0
 
7548c0
     if (mode == VIR_NETDEV_MACVLAN_MODE_PASSTHRU) {
7548c0
@@ -1182,8 +1069,7 @@ int virNetDevMacVLanCreate(const char *ifname G_GNUC_UNUSED,
7548c0
                            const char *type G_GNUC_UNUSED,
7548c0
                            const virMacAddr *macaddress G_GNUC_UNUSED,
7548c0
                            const char *srcdev G_GNUC_UNUSED,
7548c0
-                           uint32_t macvlan_mode G_GNUC_UNUSED,
7548c0
-                           int *retry G_GNUC_UNUSED)
7548c0
+                           uint32_t macvlan_mode G_GNUC_UNUSED)
7548c0
 {
7548c0
     virReportSystemError(ENOSYS, "%s",
7548c0
                          _("Cannot create macvlan devices on this platform"));
7548c0
@@ -1272,18 +1158,9 @@ int virNetDevMacVLanVPortProfileRegisterCallback(const char *ifname G_GNUC_UNUSE
7548c0
     return -1;
7548c0
 }
7548c0
 
7548c0
-int virNetDevMacVLanReleaseName(const char *name G_GNUC_UNUSED)
7548c0
+void virNetDevMacVLanReserveName(const char *name G_GNUC_UNUSED)
7548c0
 {
7548c0
     virReportSystemError(ENOSYS, "%s",
7548c0
                          _("Cannot create macvlan devices on this platform"));
7548c0
-    return -1;
7548c0
-}
7548c0
-
7548c0
-int virNetDevMacVLanReserveName(const char *name G_GNUC_UNUSED,
7548c0
-                                bool quietFail G_GNUC_UNUSED)
7548c0
-{
7548c0
-    virReportSystemError(ENOSYS, "%s",
7548c0
-                         _("Cannot create macvlan devices on this platform"));
7548c0
-    return -1;
7548c0
 }
7548c0
 #endif /* ! WITH_MACVTAP */
7548c0
diff --git a/src/util/virnetdevmacvlan.h b/src/util/virnetdevmacvlan.h
7548c0
index fc1bb018a2..48800a8fcf 100644
7548c0
--- a/src/util/virnetdevmacvlan.h
7548c0
+++ b/src/util/virnetdevmacvlan.h
7548c0
@@ -54,8 +54,7 @@ typedef enum {
7548c0
 #define VIR_NET_GENERATED_MACVTAP_PREFIX "macvtap"
7548c0
 #define VIR_NET_GENERATED_MACVLAN_PREFIX "macvlan"
7548c0
 
7548c0
-int virNetDevMacVLanReserveName(const char *name, bool quietfail);
7548c0
-int virNetDevMacVLanReleaseName(const char *name);
7548c0
+void virNetDevMacVLanReserveName(const char *name);
7548c0
 
7548c0
 bool virNetDevMacVLanIsMacvtap(const char *ifname)
7548c0
    ATTRIBUTE_NONNULL(1) G_GNUC_WARN_UNUSED_RESULT G_GNUC_NO_INLINE;
7548c0
@@ -64,8 +63,7 @@ int virNetDevMacVLanCreate(const char *ifname,
7548c0
                            const char *type,
7548c0
                            const virMacAddr *macaddress,
7548c0
                            const char *srcdev,
7548c0
-                           uint32_t macvlan_mode,
7548c0
-                           int *retry)
7548c0
+                           uint32_t macvlan_mode)
7548c0
     ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
7548c0
     G_GNUC_WARN_UNUSED_RESULT;
7548c0
 
7548c0
-- 
7548c0
2.29.2
7548c0