}
if (!net->ifname ||
- STRPREFIX(net->ifname, VIR_NET_GENERATED_TAP_PREFIX) ||
+ STRPREFIX(net->ifname, VIR_NET_GENERATED_VNET_PREFIX) ||
strchr(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 (def->managed_tap != VIR_TRISTATE_BOOL_NO && ifname &&
(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_MACVLAN_PREFIX) ||
(prefix && STRPREFIX(ifname, prefix)))) {
if (def->ifname &&
(def->managed_tap == VIR_TRISTATE_BOOL_NO ||
!((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_MACVLAN_PREFIX) ||
(prefix && STRPREFIX(def->ifname, prefix)))))) {
* vnet%d. Improvements to this check are welcome.
*/
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]))
return 0;
}
virNetDevExists;
virNetDevFeatureTypeFromString;
virNetDevFeatureTypeToString;
+virNetDevGenerateName;
virNetDevGetFeatures;
virNetDevGetIndex;
virNetDevGetLinkInfo;
virNetDevIsVirtualFunction;
virNetDevPFGetVF;
virNetDevReadNetConfig;
+virNetDevReserveName;
virNetDevRunEthernetScript;
virNetDevRxFilterFree;
virNetDevRxFilterModeTypeFromString;
}
} else {
if (!net->ifname ||
- STRPREFIX(net->ifname, VIR_NET_GENERATED_TAP_PREFIX) ||
+ STRPREFIX(net->ifname, VIR_NET_GENERATED_VNET_PREFIX) ||
strchr(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 */
template_ifname = true;
}
}
if (!net->ifname ||
- STRPREFIX(net->ifname, VIR_NET_GENERATED_TAP_PREFIX) ||
+ STRPREFIX(net->ifname, VIR_NET_GENERATED_VNET_PREFIX) ||
strchr(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 */
template_ifname = true;
}
*/
#include <config.h>
+#include <math.h>
#include "virnetdev.h"
#include "viralloc.h"
(FEATURE_WORD(blocks, index, field) & FEATURE_FIELD_FLAG(index))
#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 {
VIR_MCAST_TYPE_INDEX_TOKEN,
VIR_MCAST_TYPE_NAME_TOKEN,
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;
+}
/* Used for prefix of ifname of any tap device name generated
* 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 {
VIR_NETDEV_RX_FILTER_MODE_NONE = 0,
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,
virIfreq *ifr)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNetDevRxFilter, virNetDevRxFilterFree);
+
+void virNetDevReserveName(const char *name);
+
+int virNetDevGenerateName(char **ifname, virNetDevGenNameType type);
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);
- idstr = name + strlen(VIR_NET_GENERATED_TAP_PREFIX);
+ idstr = name + strlen(VIR_NET_GENERATED_VNET_PREFIX);
if (virStrToLong_ui(idstr, NULL, 10, &id) >= 0) {
virMutexLock(&virNetDevTapCreateMutex);
virNetDevTapGenerateName(char **ifname)
{
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 attempts = 0;
virReportError(VIR_ERR_INTERNAL_ERROR,
_("no unused %s names available"),
- VIR_NET_GENERATED_TAP_PREFIX);
+ VIR_NET_GENERATED_VNET_PREFIX);
return -1;
}
* immediately re-using names that have just been released, which
* 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) {
goto cleanup;
}