* domain to be unceremoniously killed, which would be *very*
* impolite.
*/
- if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT)
+ switch (virDomainNetGetActualType(net)) {
+ case VIR_DOMAIN_NET_TYPE_DIRECT:
virNetDevMacVLanReserveName(net->ifname);
+ break;
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ virNetDevTapReserveName(net->ifname);
+ break;
+ case VIR_DOMAIN_NET_TYPE_USER:
+ case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
+ case VIR_DOMAIN_NET_TYPE_SERVER:
+ case VIR_DOMAIN_NET_TYPE_CLIENT:
+ case VIR_DOMAIN_NET_TYPE_MCAST:
+ case VIR_DOMAIN_NET_TYPE_INTERNAL:
+ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+ case VIR_DOMAIN_NET_TYPE_UDP:
+ case VIR_DOMAIN_NET_TYPE_LAST:
+ break;
+ }
if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
if (!conn && !(conn = virGetConnectNetwork()))
#if defined(HAVE_GETIFADDRS) && defined(AF_LINK)
# include <ifaddrs.h>
#endif
+#include <math.h>
#define VIR_FROM_THIS VIR_FROM_NONE
VIR_LOG_INIT("util.netdevtap");
+virMutex virNetDevTapCreateMutex = VIR_MUTEX_INITIALIZER;
+static int virNetDevTapLastID = -1; /* not "unsigned" because callers use %d */
+
+
+/**
+ * virNetDevTapReserveName:
+ * @name: name of an existing tap device
+ *
+ * Set the value of virNetDevTapLastID to assure that any new tap
+ * device created with an autogenerated name will use a number higher
+ * than the number in the given tap device name.
+ *
+ * Returns nothing.
+ */
+void
+virNetDevTapReserveName(const char *name)
+{
+ unsigned int id;
+ const char *idstr = NULL;
+
+
+ if (STRPREFIX(name, VIR_NET_GENERATED_TAP_PREFIX)) {
+
+ VIR_INFO("marking device in use: '%s'", name);
+
+ idstr = name + strlen(VIR_NET_GENERATED_TAP_PREFIX);
+
+ if (virStrToLong_ui(idstr, NULL, 10, &id) >= 0) {
+ virMutexLock(&virNetDevTapCreateMutex);
+
+ if (virNetDevTapLastID < (int)id)
+ virNetDevTapLastID = id;
+
+ virMutexUnlock(&virNetDevTapCreateMutex);
+ }
+ }
+}
+
+
/**
* virNetDevTapGetName:
* @tapfd: a tun/tap file descriptor
#ifdef TUNSETIFF
+/**
+ * virNetDevTapGenerateName:
+ * @ifname: pointer to pointer to string containing template
+ *
+ * generate a new (currently unused) name for a new tap device based
+ * on the templace string in @ifname - replace %d with
+ * ++virNetDevTapLastID, 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.
+ */
+static int
+virNetDevTapGenerateName(char **ifname)
+{
+ int id;
+ double maxIDd = pow(10, IFNAMSIZ - 1 - strlen(VIR_NET_GENERATED_TAP_PREFIX));
+ int maxID = INT_MAX;
+ int attempts = 0;
+
+ if (maxIDd <= (double)INT_MAX)
+ maxID = (int)maxIDd;
+
+ do {
+ g_autofree char *try = NULL;
+
+ id = ++virNetDevTapLastID;
+
+ /* reset before overflow */
+ if (virNetDevTapLastID >= maxID)
+ virNetDevTapLastID = -1;
+
+ try = g_strdup_printf(*ifname, 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"),
+ VIR_NET_GENERATED_TAP_PREFIX);
+ return -1;
+}
+
+
/**
* virNetDevTapCreate:
* @ifname: the interface name
size_t tapfdSize,
unsigned int flags)
{
- size_t i;
+ size_t i = 0;
struct ifreq ifr;
int ret = -1;
- int fd;
+ int fd = 0;
+
+ virMutexLock(&virNetDevTapCreateMutex);
+
+ /* if ifname is "vnet%d", then auto-generate a name for the new
+ * device (the kernel could do this for us, but has a bad habit of
+ * immediately re-using names that have just been released, which
+ * can lead to race conditions).
+ */
+ if (STREQ(*ifname, VIR_NET_GENERATED_TAP_PREFIX "%d") &&
+ virNetDevTapGenerateName(ifname) < 0) {
+ goto cleanup;
+ }
if (!tunpath)
tunpath = "/dev/net/tun";
tapfd[i] = fd;
}
+ VIR_INFO("created device: '%s'", *ifname);
ret = 0;
cleanup:
+ virMutexUnlock(&virNetDevTapCreateMutex);
if (ret < 0) {
VIR_FORCE_CLOSE(fd);
while (i--)
goto cleanup;
}
+ VIR_INFO("delete device: '%s'", ifname);
ret = 0;
cleanup: