[PATCH 1/5] netdev: Introduce several helper functions for generating unique netdev name

Shi Lei shi_lei at massclouds.com
Fri Dec 4 07:01:31 UTC 2020


Extract ReserveName/GenerateName from netdevtap and netdevmacvlan as
common helper functions. Along with them, export Lock/Unlock functions
to protect these processes.

Signed-off-by: Shi Lei <shi_lei at massclouds.com>
---
 src/libvirt_private.syms |   4 ++
 src/util/virnetdev.c     | 140 +++++++++++++++++++++++++++++++++++++++
 src/util/virnetdev.h     |  33 +++++++++
 3 files changed, 177 insertions(+)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 2f640ef1..be3148c9 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2551,6 +2551,7 @@ virNetDevDelMulti;
 virNetDevExists;
 virNetDevFeatureTypeFromString;
 virNetDevFeatureTypeToString;
+virNetDevGenerateName;
 virNetDevGetFeatures;
 virNetDevGetIndex;
 virNetDevGetLinkInfo;
@@ -2572,8 +2573,10 @@ virNetDevGetVLanID;
 virNetDevIfStateTypeFromString;
 virNetDevIfStateTypeToString;
 virNetDevIsVirtualFunction;
+virNetDevLockGenName;
 virNetDevPFGetVF;
 virNetDevReadNetConfig;
+virNetDevReserveName;
 virNetDevRunEthernetScript;
 virNetDevRxFilterFree;
 virNetDevRxFilterModeTypeFromString;
@@ -2594,6 +2597,7 @@ virNetDevSetRcvMulti;
 virNetDevSetRootQDisc;
 virNetDevSetupControl;
 virNetDevSysfsFile;
+virNetDevUnlockGenName;
 virNetDevValidateConfig;
 virNetDevVFInterfaceStats;
 
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index 5104bbe7..5ff8e35f 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -17,6 +17,7 @@
  */
 
 #include <config.h>
+#include <math.h>
 
 #include "virnetdev.h"
 #include "viralloc.h"
@@ -95,6 +96,22 @@ VIR_LOG_INIT("util.netdev");
     (FEATURE_WORD(blocks, index, field) & FEATURE_FIELD_FLAG(index))
 #endif
 
+VIR_ENUM_IMPL(virNetDevGenNameType,
+              VIR_NET_DEV_GEN_NAME_LAST,
+              "none",
+              "tap",
+              "macvtap",
+              "macvlan",
+);
+
+static virNetDevGenName
+virNetDevGenNames[VIR_NET_DEV_GEN_NAME_LAST] = {
+    {0, NULL, VIR_MUTEX_INITIALIZER},
+    {-1, VIR_NET_GENERATED_TAP_PREFIX, VIR_MUTEX_INITIALIZER},
+    {-1, VIR_NET_GENERATED_MACVTAP_PREFIX, VIR_MUTEX_INITIALIZER},
+    {-1, VIR_NET_GENERATED_MACVLAN_PREFIX, VIR_MUTEX_INITIALIZER},
+};
+
 typedef enum {
     VIR_MCAST_TYPE_INDEX_TOKEN,
     VIR_MCAST_TYPE_NAME_TOKEN,
@@ -3516,3 +3533,126 @@ virNetDevSetRootQDisc(const char *ifname,
 
     return 0;
 }
+
+
+/**
+ * virNetDevReserveName:
+ * @name: name of an existing network device
+ * @type: type of the network device
+ * @locked: whether this process is locked by the internal mutex
+ *
+ * Reserve a network device name, so that any new network device
+ * created with an autogenerated name will use a number higher
+ * than the number in the given device name.
+ *
+ * Returns nothing.
+ */
+void
+virNetDevReserveName(const char *name,
+                     virNetDevGenNameType type,
+                     bool locked)
+{
+    unsigned int id;
+    const char *idstr = NULL;
+
+    if (type && STRPREFIX(name, virNetDevGenNames[type].prefix)) {
+
+        VIR_INFO("marking device in use: '%s'", name);
+
+        idstr = name + strlen(virNetDevGenNames[type].prefix);
+
+        if (virStrToLong_ui(idstr, NULL, 10, &id) >= 0) {
+            if (locked)
+                virMutexLock(&virNetDevGenNames[type].mutex);
+
+            if (virNetDevGenNames[type].lastID < (int)id)
+                virNetDevGenNames[type].lastID = id;
+
+            if (locked)
+                virMutexUnlock(&virNetDevGenNames[type].mutex);
+        }
+    }
+}
+
+
+/**
+ * virNetDevGenerateName:
+ * @ifname: pointer to pointer to string containing template
+ *
+ * generate a new (currently unused) name for a new network device based
+ * on the templace string in @ifname - replace %d with the reserved id,
+ * and keep trying new values until one is found
+ * that doesn't already exist, or we've tried 10000 different
+ * names. Once a usable name is found, replace the template with the
+ * actual name.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int
+virNetDevGenerateName(char **ifname, virNetDevGenNameType type)
+{
+    int id;
+    const char *prefix = virNetDevGenNames[type].prefix;
+    double maxIDd = pow(10, IFNAMSIZ - 1 - strlen(prefix));
+    int maxID = INT_MAX;
+    int attempts = 0;
+
+    if (maxIDd <= (double)INT_MAX)
+        maxID = (int)maxIDd;
+
+    do {
+        g_autofree char *try = NULL;
+
+        id = ++virNetDevGenNames[type].lastID;
+
+        /* reset before overflow */
+        if (virNetDevGenNames[type].lastID >= maxID)
+            virNetDevGenNames[type].lastID = -1;
+
+        if (*ifname)
+            try = g_strdup_printf(*ifname, id);
+        else
+            try = g_strdup_printf("%s%d", prefix, id);
+
+        if (!virNetDevExists(try)) {
+            g_free(*ifname);
+            *ifname = g_steal_pointer(&try);
+            return 0;
+        }
+    } while (++attempts < 10000);
+
+    virReportError(VIR_ERR_INTERNAL_ERROR,
+                   _("no unused %s names available"),
+                   prefix);
+    return -1;
+}
+
+
+/**
+ * virNetDevLockGenName:
+ * @type: type of the network device
+ *
+ * Lock the internal mutex for creation for this network device type.
+ *
+ * Returns nothing.
+ */
+void
+virNetDevLockGenName(virNetDevGenNameType type)
+{
+    virMutexLock(&virNetDevGenNames[type].mutex);
+}
+
+
+/**
+ * virNetDevUnlockGenName:
+ * @type: type of the network device
+ *
+ * Unlock the internal mutex for creation for this network device type.
+ *
+ * Returns nothing.
+ */
+void
+virNetDevUnlockGenName(virNetDevGenNameType type)
+{
+    virMutexUnlock(&virNetDevGenNames[type].mutex);
+}
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
index 53e606c6..19f37b61 100644
--- a/src/util/virnetdev.h
+++ b/src/util/virnetdev.h
@@ -40,6 +40,12 @@ typedef void virIfreq;
  */
 #define VIR_NET_GENERATED_TAP_PREFIX "vnet"
 
+/* libvirt will start macvtap/macvlan interface names with one of
+ * these prefixes when it auto-generates the name
+ */
+#define VIR_NET_GENERATED_MACVTAP_PREFIX "macvtap"
+#define VIR_NET_GENERATED_MACVLAN_PREFIX "macvlan"
+
 typedef enum {
    VIR_NETDEV_RX_FILTER_MODE_NONE = 0,
    VIR_NETDEV_RX_FILTER_MODE_NORMAL,
@@ -145,6 +151,24 @@ struct _virNetDevCoalesce {
     uint32_t rate_sample_interval;
 };
 
+typedef enum {
+    VIR_NET_DEV_GEN_NAME_NONE = 0,
+    VIR_NET_DEV_GEN_NAME_TAP,
+    VIR_NET_DEV_GEN_NAME_MACVTAP,
+    VIR_NET_DEV_GEN_NAME_MACVLAN,
+    VIR_NET_DEV_GEN_NAME_LAST
+} virNetDevGenNameType;
+
+VIR_ENUM_DECL(virNetDevGenNameType);
+
+typedef struct _virNetDevGenName virNetDevGenName;
+typedef virNetDevGenName *virNetDevGenNamePtr;
+struct _virNetDevGenName {
+    int lastID;         /* not "unsigned" because callers use %d */
+    const char *prefix;
+    virMutex mutex;
+};
+
 
 int virNetDevSetupControl(const char *ifname,
                           virIfreq *ifr)
@@ -321,3 +345,12 @@ int virNetDevVFInterfaceStats(virPCIDeviceAddressPtr vfAddr,
 ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNetDevRxFilter, virNetDevRxFilterFree);
+
+void virNetDevReserveName(const char *name,
+                          virNetDevGenNameType type,
+                          bool locked);
+
+int virNetDevGenerateName(char **ifname, virNetDevGenNameType type);
+
+void virNetDevLockGenName(virNetDevGenNameType type);
+void virNetDevUnlockGenName(virNetDevGenNameType type);
-- 
2.25.1





More information about the libvir-list mailing list