mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-10-05 22:05:47 +00:00
util: Introduce helper functions for generating unique netdev name
Extract ReserveName/GenerateName from netdevtap and netdevmacvlan as common helper functions. Signed-off-by: Shi Lei <shi_lei@massclouds.com> Reviewed-by: Laine Stump <laine@redhat.com>
This commit is contained in:
parent
84dc367e2a
commit
294fd4bd80
@ -80,10 +80,10 @@ bhyveBuildNetArgStr(const virDomainDef *def,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!net->ifname ||
|
if (!net->ifname ||
|
||||||
STRPREFIX(net->ifname, VIR_NET_GENERATED_TAP_PREFIX) ||
|
STRPREFIX(net->ifname, VIR_NET_GENERATED_VNET_PREFIX) ||
|
||||||
strchr(net->ifname, '%')) {
|
strchr(net->ifname, '%')) {
|
||||||
VIR_FREE(net->ifname);
|
VIR_FREE(net->ifname);
|
||||||
net->ifname = g_strdup(VIR_NET_GENERATED_TAP_PREFIX "%d");
|
net->ifname = g_strdup(VIR_NET_GENERATED_VNET_PREFIX "%d");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
|
@ -11081,7 +11081,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
|
|||||||
|
|
||||||
if (def->managed_tap != VIR_TRISTATE_BOOL_NO && ifname &&
|
if (def->managed_tap != VIR_TRISTATE_BOOL_NO && ifname &&
|
||||||
(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
|
(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
|
||||||
(STRPREFIX(ifname, VIR_NET_GENERATED_TAP_PREFIX) ||
|
(STRPREFIX(ifname, VIR_NET_GENERATED_VNET_PREFIX) ||
|
||||||
STRPREFIX(ifname, VIR_NET_GENERATED_MACVTAP_PREFIX) ||
|
STRPREFIX(ifname, VIR_NET_GENERATED_MACVTAP_PREFIX) ||
|
||||||
STRPREFIX(ifname, VIR_NET_GENERATED_MACVLAN_PREFIX) ||
|
STRPREFIX(ifname, VIR_NET_GENERATED_MACVLAN_PREFIX) ||
|
||||||
(prefix && STRPREFIX(ifname, prefix)))) {
|
(prefix && STRPREFIX(ifname, prefix)))) {
|
||||||
@ -25504,7 +25504,7 @@ virDomainNetDefFormat(virBufferPtr buf,
|
|||||||
if (def->ifname &&
|
if (def->ifname &&
|
||||||
(def->managed_tap == VIR_TRISTATE_BOOL_NO ||
|
(def->managed_tap == VIR_TRISTATE_BOOL_NO ||
|
||||||
!((flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE) &&
|
!((flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE) &&
|
||||||
(STRPREFIX(def->ifname, VIR_NET_GENERATED_TAP_PREFIX) ||
|
(STRPREFIX(def->ifname, VIR_NET_GENERATED_VNET_PREFIX) ||
|
||||||
STRPREFIX(def->ifname, VIR_NET_GENERATED_MACVTAP_PREFIX) ||
|
STRPREFIX(def->ifname, VIR_NET_GENERATED_MACVTAP_PREFIX) ||
|
||||||
STRPREFIX(def->ifname, VIR_NET_GENERATED_MACVLAN_PREFIX) ||
|
STRPREFIX(def->ifname, VIR_NET_GENERATED_MACVLAN_PREFIX) ||
|
||||||
(prefix && STRPREFIX(def->ifname, prefix)))))) {
|
(prefix && STRPREFIX(def->ifname, prefix)))))) {
|
||||||
|
@ -544,7 +544,7 @@ udevBridgeScanDirFilter(const struct dirent *entry)
|
|||||||
* vnet%d. Improvements to this check are welcome.
|
* vnet%d. Improvements to this check are welcome.
|
||||||
*/
|
*/
|
||||||
if (strlen(entry->d_name) >= 5) {
|
if (strlen(entry->d_name) >= 5) {
|
||||||
if (STRPREFIX(entry->d_name, VIR_NET_GENERATED_TAP_PREFIX) &&
|
if (STRPREFIX(entry->d_name, VIR_NET_GENERATED_VNET_PREFIX) &&
|
||||||
g_ascii_isdigit(entry->d_name[4]))
|
g_ascii_isdigit(entry->d_name[4]))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2554,6 +2554,7 @@ virNetDevDelMulti;
|
|||||||
virNetDevExists;
|
virNetDevExists;
|
||||||
virNetDevFeatureTypeFromString;
|
virNetDevFeatureTypeFromString;
|
||||||
virNetDevFeatureTypeToString;
|
virNetDevFeatureTypeToString;
|
||||||
|
virNetDevGenerateName;
|
||||||
virNetDevGetFeatures;
|
virNetDevGetFeatures;
|
||||||
virNetDevGetIndex;
|
virNetDevGetIndex;
|
||||||
virNetDevGetLinkInfo;
|
virNetDevGetLinkInfo;
|
||||||
@ -2577,6 +2578,7 @@ virNetDevIfStateTypeToString;
|
|||||||
virNetDevIsVirtualFunction;
|
virNetDevIsVirtualFunction;
|
||||||
virNetDevPFGetVF;
|
virNetDevPFGetVF;
|
||||||
virNetDevReadNetConfig;
|
virNetDevReadNetConfig;
|
||||||
|
virNetDevReserveName;
|
||||||
virNetDevRunEthernetScript;
|
virNetDevRunEthernetScript;
|
||||||
virNetDevRxFilterFree;
|
virNetDevRxFilterFree;
|
||||||
virNetDevRxFilterModeTypeFromString;
|
virNetDevRxFilterModeTypeFromString;
|
||||||
|
@ -456,10 +456,10 @@ qemuInterfaceEthernetConnect(virDomainDefPtr def,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!net->ifname ||
|
if (!net->ifname ||
|
||||||
STRPREFIX(net->ifname, VIR_NET_GENERATED_TAP_PREFIX) ||
|
STRPREFIX(net->ifname, VIR_NET_GENERATED_VNET_PREFIX) ||
|
||||||
strchr(net->ifname, '%')) {
|
strchr(net->ifname, '%')) {
|
||||||
VIR_FREE(net->ifname);
|
VIR_FREE(net->ifname);
|
||||||
net->ifname = g_strdup(VIR_NET_GENERATED_TAP_PREFIX "%d");
|
net->ifname = g_strdup(VIR_NET_GENERATED_VNET_PREFIX "%d");
|
||||||
/* avoid exposing vnet%d in getXMLDesc or error outputs */
|
/* avoid exposing vnet%d in getXMLDesc or error outputs */
|
||||||
template_ifname = true;
|
template_ifname = true;
|
||||||
}
|
}
|
||||||
@ -560,10 +560,10 @@ qemuInterfaceBridgeConnect(virDomainDefPtr def,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!net->ifname ||
|
if (!net->ifname ||
|
||||||
STRPREFIX(net->ifname, VIR_NET_GENERATED_TAP_PREFIX) ||
|
STRPREFIX(net->ifname, VIR_NET_GENERATED_VNET_PREFIX) ||
|
||||||
strchr(net->ifname, '%')) {
|
strchr(net->ifname, '%')) {
|
||||||
VIR_FREE(net->ifname);
|
VIR_FREE(net->ifname);
|
||||||
net->ifname = g_strdup(VIR_NET_GENERATED_TAP_PREFIX "%d");
|
net->ifname = g_strdup(VIR_NET_GENERATED_VNET_PREFIX "%d");
|
||||||
/* avoid exposing vnet%d in getXMLDesc or error outputs */
|
/* avoid exposing vnet%d in getXMLDesc or error outputs */
|
||||||
template_ifname = true;
|
template_ifname = true;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "virnetdev.h"
|
#include "virnetdev.h"
|
||||||
#include "viralloc.h"
|
#include "viralloc.h"
|
||||||
@ -95,6 +96,14 @@ VIR_LOG_INIT("util.netdev");
|
|||||||
(FEATURE_WORD(blocks, index, field) & FEATURE_FIELD_FLAG(index))
|
(FEATURE_WORD(blocks, index, field) & FEATURE_FIELD_FLAG(index))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static virNetDevGenName
|
||||||
|
virNetDevGenNames[VIR_NET_DEV_GEN_NAME_LAST] = {
|
||||||
|
{-1, VIR_NET_GENERATED_VNET_PREFIX, VIR_MUTEX_INITIALIZER},
|
||||||
|
{-1, VIR_NET_GENERATED_MACVTAP_PREFIX, VIR_MUTEX_INITIALIZER},
|
||||||
|
{-1, VIR_NET_GENERATED_MACVLAN_PREFIX, VIR_MUTEX_INITIALIZER},
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
VIR_MCAST_TYPE_INDEX_TOKEN,
|
VIR_MCAST_TYPE_INDEX_TOKEN,
|
||||||
VIR_MCAST_TYPE_NAME_TOKEN,
|
VIR_MCAST_TYPE_NAME_TOKEN,
|
||||||
@ -3516,3 +3525,116 @@ virNetDevSetRootQDisc(const char *ifname,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNetDevReserveName:
|
||||||
|
* @name: name of an existing network device
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
unsigned int id;
|
||||||
|
const char *idstr = NULL;
|
||||||
|
virNetDevGenNameType type;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (STRPREFIX(name, VIR_NET_GENERATED_VNET_PREFIX))
|
||||||
|
type = VIR_NET_DEV_GEN_NAME_VNET;
|
||||||
|
else if (STRPREFIX(name, VIR_NET_GENERATED_MACVTAP_PREFIX))
|
||||||
|
type = VIR_NET_DEV_GEN_NAME_MACVTAP;
|
||||||
|
else if (STRPREFIX(name, VIR_NET_GENERATED_MACVLAN_PREFIX))
|
||||||
|
type = VIR_NET_DEV_GEN_NAME_MACVLAN;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
VIR_INFO("marking device in use: '%s'", name);
|
||||||
|
|
||||||
|
idstr = name + strlen(virNetDevGenNames[type].prefix);
|
||||||
|
|
||||||
|
if (virStrToLong_ui(idstr, NULL, 10, &id) >= 0) {
|
||||||
|
virMutexLock(&virNetDevGenNames[type].mutex);
|
||||||
|
|
||||||
|
if (virNetDevGenNames[type].lastID < (int)id)
|
||||||
|
virNetDevGenNames[type].lastID = id;
|
||||||
|
|
||||||
|
virMutexUnlock(&virNetDevGenNames[type].mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNetDevGenerateName:
|
||||||
|
* @ifname: pointer to pointer to string which can be a template,
|
||||||
|
* NULL or user-provided name.
|
||||||
|
* @type: type of the network device
|
||||||
|
*
|
||||||
|
* generate a new (currently unused) name for a new network device based
|
||||||
|
* on @ifname. If string pointed by @ifname is a template, replace %d
|
||||||
|
* with the reserved id; if that string is NULL, just generate a new
|
||||||
|
* name. 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.
|
||||||
|
*
|
||||||
|
* Note: if string pointed by @ifname is NOT a template or NULL, leave
|
||||||
|
* it unchanged and return it directly.
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/* The @ifname is not a template, leave it unchanged. */
|
||||||
|
if (*ifname &&
|
||||||
|
(strchr(*ifname, '%') != strrchr(*ifname, '%') ||
|
||||||
|
strstr(*ifname, "%d") == NULL)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxIDd <= (double)INT_MAX)
|
||||||
|
maxID = (int)maxIDd;
|
||||||
|
|
||||||
|
do {
|
||||||
|
g_autofree char *try = NULL;
|
||||||
|
|
||||||
|
virMutexLock(&virNetDevGenNames[type].mutex);
|
||||||
|
|
||||||
|
id = ++virNetDevGenNames[type].lastID;
|
||||||
|
|
||||||
|
/* reset before overflow */
|
||||||
|
if (virNetDevGenNames[type].lastID >= maxID)
|
||||||
|
virNetDevGenNames[type].lastID = -1;
|
||||||
|
|
||||||
|
virMutexUnlock(&virNetDevGenNames[type].mutex);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
@ -38,7 +38,13 @@ typedef void virIfreq;
|
|||||||
/* Used for prefix of ifname of any tap device name generated
|
/* Used for prefix of ifname of any tap device name generated
|
||||||
* dynamically by libvirt, cannot be used for a persistent network name.
|
* dynamically by libvirt, cannot be used for a persistent network name.
|
||||||
*/
|
*/
|
||||||
#define VIR_NET_GENERATED_TAP_PREFIX "vnet"
|
#define VIR_NET_GENERATED_VNET_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 {
|
typedef enum {
|
||||||
VIR_NETDEV_RX_FILTER_MODE_NONE = 0,
|
VIR_NETDEV_RX_FILTER_MODE_NONE = 0,
|
||||||
@ -145,6 +151,21 @@ struct _virNetDevCoalesce {
|
|||||||
uint32_t rate_sample_interval;
|
uint32_t rate_sample_interval;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
VIR_NET_DEV_GEN_NAME_VNET,
|
||||||
|
VIR_NET_DEV_GEN_NAME_MACVTAP,
|
||||||
|
VIR_NET_DEV_GEN_NAME_MACVLAN,
|
||||||
|
VIR_NET_DEV_GEN_NAME_LAST
|
||||||
|
} 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,
|
int virNetDevSetupControl(const char *ifname,
|
||||||
virIfreq *ifr)
|
virIfreq *ifr)
|
||||||
@ -321,3 +342,7 @@ int virNetDevVFInterfaceStats(virPCIDeviceAddressPtr vfAddr,
|
|||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||||
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNetDevRxFilter, virNetDevRxFilterFree);
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNetDevRxFilter, virNetDevRxFilterFree);
|
||||||
|
|
||||||
|
void virNetDevReserveName(const char *name);
|
||||||
|
|
||||||
|
int virNetDevGenerateName(char **ifname, virNetDevGenNameType type);
|
||||||
|
@ -76,11 +76,11 @@ virNetDevTapReserveName(const char *name)
|
|||||||
const char *idstr = NULL;
|
const char *idstr = NULL;
|
||||||
|
|
||||||
|
|
||||||
if (STRPREFIX(name, VIR_NET_GENERATED_TAP_PREFIX)) {
|
if (STRPREFIX(name, VIR_NET_GENERATED_VNET_PREFIX)) {
|
||||||
|
|
||||||
VIR_INFO("marking device in use: '%s'", name);
|
VIR_INFO("marking device in use: '%s'", name);
|
||||||
|
|
||||||
idstr = name + strlen(VIR_NET_GENERATED_TAP_PREFIX);
|
idstr = name + strlen(VIR_NET_GENERATED_VNET_PREFIX);
|
||||||
|
|
||||||
if (virStrToLong_ui(idstr, NULL, 10, &id) >= 0) {
|
if (virStrToLong_ui(idstr, NULL, 10, &id) >= 0) {
|
||||||
virMutexLock(&virNetDevTapCreateMutex);
|
virMutexLock(&virNetDevTapCreateMutex);
|
||||||
@ -200,7 +200,7 @@ static int
|
|||||||
virNetDevTapGenerateName(char **ifname)
|
virNetDevTapGenerateName(char **ifname)
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
double maxIDd = pow(10, IFNAMSIZ - 1 - strlen(VIR_NET_GENERATED_TAP_PREFIX));
|
double maxIDd = pow(10, IFNAMSIZ - 1 - strlen(VIR_NET_GENERATED_VNET_PREFIX));
|
||||||
int maxID = INT_MAX;
|
int maxID = INT_MAX;
|
||||||
int attempts = 0;
|
int attempts = 0;
|
||||||
|
|
||||||
@ -227,7 +227,7 @@ virNetDevTapGenerateName(char **ifname)
|
|||||||
|
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
_("no unused %s names available"),
|
_("no unused %s names available"),
|
||||||
VIR_NET_GENERATED_TAP_PREFIX);
|
VIR_NET_GENERATED_VNET_PREFIX);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +270,7 @@ int virNetDevTapCreate(char **ifname,
|
|||||||
* immediately re-using names that have just been released, which
|
* immediately re-using names that have just been released, which
|
||||||
* can lead to race conditions).
|
* can lead to race conditions).
|
||||||
*/
|
*/
|
||||||
if (STREQ(*ifname, VIR_NET_GENERATED_TAP_PREFIX "%d") &&
|
if (STREQ(*ifname, VIR_NET_GENERATED_VNET_PREFIX "%d") &&
|
||||||
virNetDevTapGenerateName(ifname) < 0) {
|
virNetDevTapGenerateName(ifname) < 0) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user