render / rpms / libvirt

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