The change adds TUN PMD logic to the existing TAP PMD. TUN PMD can
be initialized with 'net_tunX' where 'X' represents unique id. PMD
supports argument interface, while MAC address and remote are not
supported.

Signed-off-by: Vipin Varghese <vipin.vargh...@intel.com>
---

Changes in V2:
 - updated the documentation word error - Pascal
---
 doc/guides/nics/tap.rst       |  15 ++++-
 drivers/net/tap/rte_eth_tap.c | 132 +++++++++++++++++++++++++++++++++---------
 2 files changed, 118 insertions(+), 29 deletions(-)

diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
index ea61be3..0fbbbba 100644
--- a/doc/guides/nics/tap.rst
+++ b/doc/guides/nics/tap.rst
@@ -1,8 +1,8 @@
 ..  SPDX-License-Identifier: BSD-3-Clause
     Copyright(c) 2016 Intel Corporation.
 
-Tap Poll Mode Driver
-====================
+Tun|Tap Poll Mode Driver
+========================
 
 The ``rte_eth_tap.c`` PMD creates a device using TAP interfaces on the
 local host. The PMD allows for DPDK and the host to communicate using a raw
@@ -77,6 +77,17 @@ can utilize that stack to handle the network protocols. Plus 
you would be able
 to address the interface using an IP address assigned to the internal
 interface.
 
+The TUN PMD allows user to create a TUN device on host. The PMD allows user
+to transmit and receive packets via DPDK API calls with L3 header and payload.
+The devices in host can be accessed via ``ifconfig`` or ``ip`` command. TUN
+interfaces are passed to DPDK ``rte_eal_init`` arguments as 
``--vdev=net_tunX``,
+where X stands for unique id, example::
+
+   --vdev=net_tun0 --vdev=net_tun1,iface=foo1, ...
+
+Unlike TAP PMD, TUN PMD does not support user arguments as ``MAC`` or 
``remote`` user
+options. Default interface name is ``dtunX``, where X stands for unique id.
+
 Flow API support
 ----------------
 
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index f09db0e..42c9db4 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -42,6 +42,7 @@
 /* Linux based path to the TUN device */
 #define TUN_TAP_DEV_PATH        "/dev/net/tun"
 #define DEFAULT_TAP_NAME        "dtap"
+#define DEFAULT_TUN_NAME        "dtun"
 
 #define ETH_TAP_IFACE_ARG       "iface"
 #define ETH_TAP_REMOTE_ARG      "remote"
@@ -49,6 +50,7 @@
 #define ETH_TAP_MAC_FIXED       "fixed"
 
 static struct rte_vdev_driver pmd_tap_drv;
+static struct rte_vdev_driver pmd_tun_drv;
 
 static const char *valid_arguments[] = {
        ETH_TAP_IFACE_ARG,
@@ -58,6 +60,10 @@
 };
 
 static int tap_unit;
+static int tun_unit;
+
+static int tap_type;
+static char tuntap_name[8];
 
 static volatile uint32_t tap_trigger;  /* Rx trigger */
 
@@ -104,24 +110,26 @@ enum ioctl_mode {
         * Do not set IFF_NO_PI as packet information header will be needed
         * to check if a received packet has been truncated.
         */
-       ifr.ifr_flags = IFF_TAP;
+       ifr.ifr_flags = (tap_type) ? IFF_TAP : IFF_TUN;
        snprintf(ifr.ifr_name, IFNAMSIZ, "%s", pmd->name);
 
        RTE_LOG(DEBUG, PMD, "ifr_name '%s'\n", ifr.ifr_name);
 
        fd = open(TUN_TAP_DEV_PATH, O_RDWR);
        if (fd < 0) {
-               RTE_LOG(ERR, PMD, "Unable to create TAP interface\n");
+               RTE_LOG(ERR, PMD, "Unable to create %s interface\n",
+                       tuntap_name);
                goto error;
        }
 
 #ifdef IFF_MULTI_QUEUE
        /* Grab the TUN features to verify we can work multi-queue */
        if (ioctl(fd, TUNGETFEATURES, &features) < 0) {
-               RTE_LOG(ERR, PMD, "TAP unable to get TUN/TAP features\n");
+               RTE_LOG(ERR, PMD, "%s unable to get TUN/TAP features\n",
+                       tuntap_name);
                goto error;
        }
-       RTE_LOG(DEBUG, PMD, "  TAP Features %08x\n", features);
+       RTE_LOG(DEBUG, PMD, " %s Features %08x\n", tuntap_name, features);
 
        if (features & IFF_MULTI_QUEUE) {
                RTE_LOG(DEBUG, PMD, "  Multi-queue support for %d queues\n",
@@ -1108,7 +1116,7 @@ enum ioctl_mode {
                tmp = &(*tmp)->next;
        }
 
-       RTE_LOG(DEBUG, PMD, "  RX TAP device name %s, qid %d on fd %d\n",
+       RTE_LOG(DEBUG, PMD, "  RX TUNTAP device name %s, qid %d on fd %d\n",
                internals->name, rx_queue_id, internals->rxq[rx_queue_id].fd);
 
        return 0;
@@ -1163,7 +1171,7 @@ enum ioctl_mode {
        if (ret == -1)
                return -1;
        RTE_LOG(DEBUG, PMD,
-               "  TX TAP device name %s, qid %d on fd %d csum %s\n",
+               "  TX TUNTAP device name %s, qid %d on fd %d csum %s\n",
                internals->name, tx_queue_id, internals->txq[tx_queue_id].fd,
                txq->csum ? "on" : "off");
 
@@ -1346,17 +1354,19 @@ enum ioctl_mode {
        struct ifreq ifr;
        int i;
 
-       RTE_LOG(DEBUG, PMD, "  TAP device on numa %u\n", rte_socket_id());
+       RTE_LOG(DEBUG, PMD, "  %s device on numa %u\n",
+               tuntap_name, rte_socket_id());
 
        data = rte_zmalloc_socket(tap_name, sizeof(*data), 0, numa_node);
        if (!data) {
-               RTE_LOG(ERR, PMD, "TAP Failed to allocate data\n");
+               RTE_LOG(ERR, PMD, "%s Failed to allocate data\n", tuntap_name);
                goto error_exit_nodev;
        }
 
        dev = rte_eth_vdev_allocate(vdev, sizeof(*pmd));
        if (!dev) {
-               RTE_LOG(ERR, PMD, "TAP Unable to allocate device struct\n");
+               RTE_LOG(ERR, PMD, "%s Unable to allocate device struct\n",
+                       tuntap_name);
                goto error_exit_nodev;
        }
 
@@ -1367,8 +1377,8 @@ enum ioctl_mode {
        pmd->ioctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
        if (pmd->ioctl_sock == -1) {
                RTE_LOG(ERR, PMD,
-                       "TAP Unable to get a socket for management: %s\n",
-                       strerror(errno));
+                       "%s Unable to get a socket for management: %s\n",
+                       tuntap_name, strerror(errno));
                goto error_exit;
        }
 
@@ -1399,15 +1409,17 @@ enum ioctl_mode {
                pmd->txq[i].fd = -1;
        }
 
-       if (fixed_mac_type) {
-               /* fixed mac = 00:64:74:61:70:<iface_idx> */
-               static int iface_idx;
-               char mac[ETHER_ADDR_LEN] = "\0dtap";
+       if (tap_type) {
+               if (fixed_mac_type) {
+                       /* fixed mac = 00:64:74:61:70:<iface_idx> */
+                       static int iface_idx;
+                       char mac[ETHER_ADDR_LEN] = "\0dtap";
 
-               mac[ETHER_ADDR_LEN - 1] = iface_idx++;
-               rte_memcpy(&pmd->eth_addr, mac, ETHER_ADDR_LEN);
-       } else {
-               eth_random_addr((uint8_t *)&pmd->eth_addr);
+                       mac[ETHER_ADDR_LEN - 1] = iface_idx++;
+                       rte_memcpy(&pmd->eth_addr, mac, ETHER_ADDR_LEN);
+               } else {
+                       eth_random_addr((uint8_t *)&pmd->eth_addr);
+               }
        }
 
        /* Immediately create the netdevice (this will create the 1st queue). */
@@ -1422,11 +1434,13 @@ enum ioctl_mode {
        if (tap_ioctl(pmd, SIOCSIFMTU, &ifr, 1, LOCAL_AND_REMOTE) < 0)
                goto error_exit;
 
-       memset(&ifr, 0, sizeof(struct ifreq));
-       ifr.ifr_hwaddr.sa_family = AF_LOCAL;
-       rte_memcpy(ifr.ifr_hwaddr.sa_data, &pmd->eth_addr, ETHER_ADDR_LEN);
-       if (tap_ioctl(pmd, SIOCSIFHWADDR, &ifr, 0, LOCAL_ONLY) < 0)
-               goto error_exit;
+       if (tap_type) {
+               memset(&ifr, 0, sizeof(struct ifreq));
+               ifr.ifr_hwaddr.sa_family = AF_LOCAL;
+               rte_memcpy(ifr.ifr_hwaddr.sa_data, &pmd->eth_addr, 
ETHER_ADDR_LEN);
+               if (tap_ioctl(pmd, SIOCSIFHWADDR, &ifr, 0, LOCAL_ONLY) < 0)
+                       goto error_exit;
+       }
 
        /*
         * Set up everything related to rte_flow:
@@ -1533,8 +1547,8 @@ enum ioctl_mode {
        rte_eth_dev_release_port(dev);
 
 error_exit_nodev:
-       RTE_LOG(ERR, PMD, "TAP Unable to initialize %s\n",
-               rte_vdev_device_name(vdev));
+       RTE_LOG(ERR, PMD, "%s Unable to initialize %s\n",
+               tuntap_name, rte_vdev_device_name(vdev));
 
        rte_free(data);
        return -EINVAL;
@@ -1580,6 +1594,61 @@ enum ioctl_mode {
        return 0;
 }
 
+/* Open a TUN interface device.
+ */
+static int
+rte_pmd_tun_probe(struct rte_vdev_device *dev)
+{
+       const char *name, *params;
+       int ret;
+       struct rte_kvargs *kvlist = NULL;
+       char tun_name[RTE_ETH_NAME_MAX_LEN];
+       char remote_iface[RTE_ETH_NAME_MAX_LEN];
+
+       tap_type = 0;
+       strcpy(tuntap_name, "TUN");
+
+       name = rte_vdev_device_name(dev);
+       params = rte_vdev_device_args(dev);
+
+       memset(remote_iface, 0, RTE_ETH_NAME_MAX_LEN);
+       snprintf(tun_name, sizeof(tun_name), "%s%d",
+               DEFAULT_TUN_NAME, tun_unit++);
+
+       if (params && (params[0] != '\0')) {
+               RTE_LOG(DEBUG, PMD, "parameters (%s)\n", params);
+
+               kvlist = rte_kvargs_parse(params, valid_arguments);
+               if (kvlist) {
+                       if (rte_kvargs_count(kvlist, ETH_TAP_IFACE_ARG) == 1) {
+                               ret = rte_kvargs_process(kvlist,
+                                       ETH_TAP_IFACE_ARG,
+                                       &set_interface_name,
+                                       tun_name);
+
+                               if (ret == -1)
+                                       goto leave;
+                       }
+               }
+       }
+       pmd_link.link_speed = ETH_SPEED_NUM_10G;
+
+       RTE_LOG(NOTICE, PMD, "Initializing pmd_tun for %s as %s\n",
+               name, tun_name);
+
+       ret = eth_dev_tap_create(dev, tun_name, remote_iface, 0);
+
+leave:
+       if (ret == -1) {
+               RTE_LOG(ERR, PMD, "Failed to create pmd for %s as %s\n",
+                       name, tun_name);
+               tun_unit--; /* Restore the unit number */
+       }
+       rte_kvargs_free(kvlist);
+
+       return ret;
+}
+
 /* Open a TAP interface device.
  */
 static int
@@ -1593,6 +1662,9 @@ enum ioctl_mode {
        char remote_iface[RTE_ETH_NAME_MAX_LEN];
        int fixed_mac_type = 0;
 
+       tap_type = 1;
+       strcpy(tuntap_name, "TAP");
+
        name = rte_vdev_device_name(dev);
        params = rte_vdev_device_args(dev);
 
@@ -1652,7 +1724,7 @@ enum ioctl_mode {
        return ret;
 }
 
-/* detach a TAP device.
+/* detach a TUNTAP device.
  */
 static int
 rte_pmd_tap_remove(struct rte_vdev_device *dev)
@@ -1695,11 +1767,17 @@ enum ioctl_mode {
        return 0;
 }
 
+static struct rte_vdev_driver pmd_tun_drv = {
+       .probe = rte_pmd_tun_probe,
+       .remove = rte_pmd_tap_remove,
+};
+
 static struct rte_vdev_driver pmd_tap_drv = {
        .probe = rte_pmd_tap_probe,
        .remove = rte_pmd_tap_remove,
 };
 RTE_PMD_REGISTER_VDEV(net_tap, pmd_tap_drv);
+RTE_PMD_REGISTER_VDEV(net_tun, pmd_tun_drv);
 RTE_PMD_REGISTER_ALIAS(net_tap, eth_tap);
 RTE_PMD_REGISTER_PARAM_STRING(net_tap,
                              ETH_TAP_IFACE_ARG "=<string> "
-- 
1.9.1

Reply via email to