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