net/tap: let kernel choose tun device name
authorStephen Hemminger <stephen@networkplumber.org>
Fri, 11 Jan 2019 20:35:18 +0000 (12:35 -0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Mon, 14 Jan 2019 16:44:29 +0000 (17:44 +0100)
Assigning tun and tap index in DPDK tap device driver is racy
and fails if used with primary/secondary. Instead use the kernel
feature of device wildcarding where if a name with %d is used
the kernel will fill in the next available device.

Fixes: 02f96a0a82d1 ("net/tap: add TUN/TAP device PMD")
Cc: stable@dpdk.org
Reported-by: Haifeng Li <hfli@netitest.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Acked-by Keith Wiles <keith.wiles@intel.com>

drivers/net/tap/rte_eth_tap.c

index d699b4f..ed8483c 100644 (file)
@@ -79,9 +79,6 @@ static const char *valid_arguments[] = {
        NULL
 };
 
-static unsigned int tap_unit;
-static unsigned int tun_unit;
-
 static char tuntap_name[8];
 
 static volatile uint32_t tap_trigger;  /* Rx trigger */
@@ -151,8 +148,6 @@ tun_alloc(struct pmd_internals *pmd, int is_keepalive)
                IFF_TAP : IFF_TUN | IFF_POINTOPOINT;
        strlcpy(ifr.ifr_name, pmd->name, IFNAMSIZ);
 
-       TAP_LOG(DEBUG, "ifr_name '%s'", ifr.ifr_name);
-
        fd = open(TUN_TAP_DEV_PATH, O_RDWR);
        if (fd < 0) {
                TAP_LOG(ERR, "Unable to create %s interface", tuntap_name);
@@ -186,6 +181,13 @@ tun_alloc(struct pmd_internals *pmd, int is_keepalive)
                goto error;
        }
 
+       /*
+        * Name passed to kernel might be wildcard like dtun%d
+        * and need to find the resulting device.
+        */
+       TAP_LOG(DEBUG, "Device name is '%s'", ifr.ifr_name);
+       strlcpy(pmd->name, ifr.ifr_name, RTE_ETH_NAME_MAX_LEN);
+
        if (is_keepalive) {
                /*
                 * Detach the TUN/TAP keep-alive queue
@@ -1756,6 +1758,7 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, char *tap_name,
                TAP_LOG(ERR, "Unable to create %s interface", tuntap_name);
                goto error_exit;
        }
+       TAP_LOG(DEBUG, "allocated %s", pmd->name);
 
        ifr.ifr_mtu = dev->data->mtu;
        if (tap_ioctl(pmd, SIOCSIFMTU, &ifr, 1, LOCAL_AND_REMOTE) < 0)
@@ -1918,8 +1921,8 @@ set_interface_name(const char *key __rte_unused,
                }
                strlcpy(name, value, RTE_ETH_NAME_MAX_LEN);
        } else {
-               snprintf(name, RTE_ETH_NAME_MAX_LEN, "%s%d",
-                        DEFAULT_TAP_NAME, tap_unit - 1);
+               /* use tap%d which causes kernel to choose next available */
+               strlcpy(name, DEFAULT_TAP_NAME "%d", RTE_ETH_NAME_MAX_LEN);
        }
        return 0;
 }
@@ -2032,8 +2035,8 @@ rte_pmd_tun_probe(struct rte_vdev_device *dev)
                return 0;
        }
 
-       snprintf(tun_name, sizeof(tun_name), "%s%u",
-                DEFAULT_TUN_NAME, tun_unit++);
+       /* use tun%d which causes kernel to choose next available */
+       strlcpy(tun_name, DEFAULT_TUN_NAME "%d", RTE_ETH_NAME_MAX_LEN);
 
        if (params && (params[0] != '\0')) {
                TAP_LOG(DEBUG, "parameters (%s)", params);
@@ -2053,17 +2056,15 @@ rte_pmd_tun_probe(struct rte_vdev_device *dev)
        }
        pmd_link.link_speed = ETH_SPEED_NUM_10G;
 
-       TAP_LOG(DEBUG, "Initializing pmd_tun for %s as %s",
-               name, tun_name);
+       TAP_LOG(DEBUG, "Initializing pmd_tun for %s", name);
 
        ret = eth_dev_tap_create(dev, tun_name, remote_iface, 0,
-               ETH_TUNTAP_TYPE_TUN);
+                                ETH_TUNTAP_TYPE_TUN);
 
 leave:
        if (ret == -1) {
                TAP_LOG(ERR, "Failed to create pmd for %s as %s",
                        name, tun_name);
-               tun_unit--; /* Restore the unit number */
        }
        rte_kvargs_free(kvlist);
 
@@ -2219,8 +2220,9 @@ rte_pmd_tap_probe(struct rte_vdev_device *dev)
        }
 
        speed = ETH_SPEED_NUM_10G;
-       snprintf(tap_name, sizeof(tap_name), "%s%u",
-                DEFAULT_TAP_NAME, tap_unit++);
+
+       /* use tap%d which causes kernel to choose next available */
+       strlcpy(tap_name, DEFAULT_TAP_NAME "%d", RTE_ETH_NAME_MAX_LEN);
        memset(remote_iface, 0, RTE_ETH_NAME_MAX_LEN);
 
        if (params && (params[0] != '\0')) {
@@ -2283,7 +2285,6 @@ leave:
                                rte_mp_action_unregister(TAP_MP_KEY);
                        tap_devices_count--;
                }
-               tap_unit--;             /* Restore the unit number */
        }
        rte_kvargs_free(kvlist);