DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v12] net/tap: new TUN/TAP device PMD
From: Wiles, Keith @ 2016-12-12 21:09 UTC (permalink / raw)
  To: Marc; +Cc: dev@dpdk.org
In-Reply-To: <CAExC=0R7MXQZVeCAq198P5ubRtPnPJhqCA0fUqL-dBFQksuUog@mail.gmail.com>


> On Dec 12, 2016, at 1:13 PM, Marc <marcdevel@gmail.com> wrote:
> 
> Keith,
> 
> A bit late, but two very high level questions. Do you have performance numbers compared to KNI? Did you consider using AF_PACKET PACKET_MMAP which could potentially reduce the number of syscalls to 1 for RX and TX of a burst?

Hi Marc,

I was not trying to create a high performance interface, just a Tap interface to use standard applications and calls to send/receive traffic to the DPDK application. I did not expect other then some management like interface in the application would use the Tap PMD.

> 
> Marc
> 
> On 12 December 2016 at 15:38, Keith Wiles <keith.wiles@intel.com> wrote:
> The PMD allows for DPDK and the host to communicate using a raw
> device interface on the host and in the DPDK application. The device
> created is a Tap device with a L2 packet header.
> 
> v12- Fixup minor changes for driver_name and version number
> v11- Add the tap.rst to the nic/index.rst file
> v10- Change the string name used to allow for multiple devices.
> v9 - Fix up the docs to use correct syntax
> v8 - Fix issue with tap_tx_queue_setup() not return zero on success.
> v7 - Reword the comment in common_base and fix the data->name issue
> v6 - fixed the checkpatch issues
> v5 - merge in changes from list review see related emails
>      fixed many minor edits
> v4 - merge with latest driver changes
> v3 - fix includes by removing ifdef for other type besides Linux
>      Fix the copyright notice in the Makefile
> v2 - merge all of the patches into one patch
>      Fix a typo on naming the tap device
>      Update the maintainers list
> 
> Signed-off-by: Keith Wiles <keith.wiles@intel.com>
> ---
>  MAINTAINERS                             |   5 +
>  config/common_base                      |   9 +
>  config/common_linuxapp                  |   1 +
>  doc/guides/nics/index.rst               |   1 +
>  doc/guides/nics/tap.rst                 | 136 ++++++
>  drivers/net/Makefile                    |   1 +
>  drivers/net/tap/Makefile                |  57 +++
>  drivers/net/tap/rte_eth_tap.c           | 765 ++++++++++++++++++++++++++++++++
>  drivers/net/tap/rte_pmd_tap_version.map |   4 +
>  mk/rte.app.mk                           |   1 +
>  10 files changed, 980 insertions(+)
>  create mode 100644 doc/guides/nics/tap.rst
>  create mode 100644 drivers/net/tap/Makefile
>  create mode 100644 drivers/net/tap/rte_eth_tap.c
>  create mode 100644 drivers/net/tap/rte_pmd_tap_version.map
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 26d9590..842fb6d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -398,6 +398,11 @@ F: doc/guides/nics/pcap_ring.rst
>  F: app/test/test_pmd_ring.c
>  F: app/test/test_pmd_ring_perf.c
> 
> +Tap PMD
> +M: Keith Wiles <keith.wiles@intel.com>
> +F: drivers/net/tap
> +F: doc/guides/nics/tap.rst
> +
>  Null Networking PMD
>  M: Tetsuya Mukawa <mtetsuyah@gmail.com>
>  F: drivers/net/null/
> diff --git a/config/common_base b/config/common_base
> index 652a839..eb51cdb 100644
> --- a/config/common_base
> +++ b/config/common_base
> @@ -590,3 +590,12 @@ CONFIG_RTE_APP_TEST_RESOURCE_TAR=n
>  CONFIG_RTE_TEST_PMD=y
>  CONFIG_RTE_TEST_PMD_RECORD_CORE_CYCLES=n
>  CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n
> +
> +#
> +# Compile the TAP PMD
> +#
> +# The TAP PMD is currently only built for Linux and the
> +# option is enabled by default in common_linuxapp file,
> +# set to 'n' in the common_base file.
> +#
> +CONFIG_RTE_LIBRTE_PMD_TAP=n
> diff --git a/config/common_linuxapp b/config/common_linuxapp
> index 2483dfa..782b503 100644
> --- a/config/common_linuxapp
> +++ b/config/common_linuxapp
> @@ -44,3 +44,4 @@ CONFIG_RTE_LIBRTE_PMD_VHOST=y
>  CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
>  CONFIG_RTE_LIBRTE_POWER=y
>  CONFIG_RTE_VIRTIO_USER=y
> +CONFIG_RTE_LIBRTE_PMD_TAP=y
> diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
> index 92d56a5..af92529 100644
> --- a/doc/guides/nics/index.rst
> +++ b/doc/guides/nics/index.rst
> @@ -51,6 +51,7 @@ Network Interface Controller Drivers
>      nfp
>      qede
>      szedata2
> +    tap
>      thunderx
>      virtio
>      vhost
> diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
> new file mode 100644
> index 0000000..622b9e7
> --- /dev/null
> +++ b/doc/guides/nics/tap.rst
> @@ -0,0 +1,136 @@
> +..  BSD LICENSE
> +    Copyright(c) 2016 Intel Corporation. All rights reserved.
> +    All rights reserved.
> +
> +    Redistribution and use in source and binary forms, with or without
> +    modification, are permitted provided that the following conditions
> +    are met:
> +
> +    * Redistributions of source code must retain the above copyright
> +    notice, this list of conditions and the following disclaimer.
> +    * Redistributions in binary form must reproduce the above copyright
> +    notice, this list of conditions and the following disclaimer in
> +    the documentation and/or other materials provided with the
> +    distribution.
> +    * Neither the name of Intel Corporation nor the names of its
> +    contributors may be used to endorse or promote products derived
> +    from this software without specific prior written permission.
> +
> +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> +    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> +    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> +    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> +    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> +    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> +    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> +    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> +    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> +    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> +    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> +Tun/Tap Poll Mode Driver
> +========================
> +
> +The ``rte_eth_tap.c`` PMD creates a device using TUN/TAP interfaces on the
> +local host. The PMD allows for DPDK and the host to communicate using a raw
> +device interface on the host and in the DPDK application.
> +
> +The device created is a TAP device, which sends/receives packet in a raw
> +format with a L2 header. The usage for a TAP PMD is for connectivity to the
> +local host using a TAP interface. When the TAP PMD is initialized it will
> +create a number of tap devices in the host accessed via ``ifconfig -a`` or
> +``ip`` command. The commands can be used to assign and query the virtual like
> +device.
> +
> +These TAP interfaces can be used with Wireshark or tcpdump or Pktgen-DPDK
> +along with being able to be used as a network connection to the DPDK
> +application. The method enable one or more interfaces is to use the
> +``--vdev=net_tap`` option on the DPDK application command line. Each
> +``--vdev=net_tap`` option give will create an interface named dtap0, dtap1,
> +and so on.
> +
> +The interfaced name can be changed by adding the ``iface=foo0``, for example::
> +
> +   --vdev=net_tap,iface=foo0 --vdev=net_tap,iface=foo1, ...
> +
> +Also the speed of the interface can be changed from 10G to whatever number
> +needed, but the interface does not enforce that speed, for example::
> +
> +   --vdev=net_tap,iface=foo0,speed=25000
> +
> +After the DPDK application is started you can send and receive packets on the
> +interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
> +point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
> +and others to communicate with the DPDK application. The DPDK application may
> +not understand network protocols like IPv4/6, UDP or TCP unless the
> +application has been written to understand these protocols.
> +
> +If you need the interface as a real network interface meaning running and has
> +a valid IP address then you can do this with the following commands::
> +
> +   sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
> +   sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
> +
> +Please change the IP addresses as you see fit.
> +
> +If routing is enabled on the host you can also communicate with the DPDK App
> +over the internet via a standard socket layer application as long as you
> +account for the protocol handing in the application.
> +
> +If you have a Network Stack in your DPDK application or something like it you
> +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.
> +
> +Example
> +-------
> +
> +The following is a simple example of using the TUN/TAP PMD with the Pktgen
> +packet generator. It requires that the ``socat`` utility is installed on the
> +test system.
> +
> +Build DPDK, then pull down Pktgen and build pktgen using the DPDK SDK/Target
> +used to build the dpdk you pulled down.
> +
> +Run pktgen from the pktgen directory in a terminal with a commandline like the
> +following::
> +
> +    sudo ./app/app/x86_64-native-linuxapp-gcc/app/pktgen -l 1-5 -n 4        \
> +     --proc-type auto --log-level 8 --socket-mem 512,512 --file-prefix pg   \
> +     --vdev=net_tap --vdev=net_tap -b 05:00.0 -b 05:00.1                    \
> +     -b 04:00.0 -b 04:00.1 -b 04:00.2 -b 04:00.3                            \
> +     -b 81:00.0 -b 81:00.1 -b 81:00.2 -b 81:00.3                            \
> +     -b 82:00.0 -b 83:00.0 -- -T -P -m [2:3].0 -m [4:5].1                   \
> +     -f themes/black-yellow.theme
> +
> +.. Note:
> +
> +   Change the ``-b`` options to blacklist all of your physical ports. The
> +   following command line is all one line.
> +
> +   Also, ``-f themes/black-yellow.theme`` is optional if the default colors
> +   work on your system configuration. See the Pktgen docs for more
> +   information.
> +
> +Verify with ``ifconfig -a`` command in a different xterm window, should have a
> +``dtap0`` and ``dtap1`` interfaces created.
> +
> +Next set the links for the two interfaces to up via the commands below::
> +
> +    sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
> +    sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
> +
> +Then use socat to create a loopback for the two interfaces::
> +
> +    sudo socat interface:dtap0 interface:dtap1
> +
> +Then on the Pktgen command line interface you can start sending packets using
> +the commands ``start 0`` and ``start 1`` or you can start both at the same
> +time with ``start all``. The command ``str`` is an alias for ``start all`` and
> +``stp`` is an alias for ``stop all``.
> +
> +While running you should see the 64 byte counters increasing to verify the
> +traffic is being looped back. You can use ``set all size XXX`` to change the
> +size of the packets after you stop the traffic. Use the pktgen ``help``
> +command to see a list of all commands. You can also use the ``-f`` option to
> +load commands at startup.
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index bc93230..e366a85 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -51,6 +51,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += pcap
>  DIRS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede
>  DIRS-$(CONFIG_RTE_LIBRTE_PMD_RING) += ring
>  DIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += szedata2
> +DIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += tap
>  DIRS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += thunderx
>  DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio
>  DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += vmxnet3
> diff --git a/drivers/net/tap/Makefile b/drivers/net/tap/Makefile
> new file mode 100644
> index 0000000..e18f30c
> --- /dev/null
> +++ b/drivers/net/tap/Makefile
> @@ -0,0 +1,57 @@
> +#   BSD LICENSE
> +#
> +#   Copyright(c) 2016 Intel Corporation. All rights reserved.
> +#
> +#   Redistribution and use in source and binary forms, with or without
> +#   modification, are permitted provided that the following conditions
> +#   are met:
> +#
> +#     * Redistributions of source code must retain the above copyright
> +#       notice, this list of conditions and the following disclaimer.
> +#     * Redistributions in binary form must reproduce the above copyright
> +#       notice, this list of conditions and the following disclaimer in
> +#       the documentation and/or other materials provided with the
> +#       distribution.
> +#     * Neither the name of Intel Corporation nor the names of its
> +#       contributors may be used to endorse or promote products derived
> +#       from this software without specific prior written permission.
> +#
> +#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> +#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> +#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> +#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> +#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> +#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> +#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> +#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> +#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> +#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> +#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> +include $(RTE_SDK)/mk/rte.vars.mk
> +
> +#
> +# library name
> +#
> +LIB = librte_pmd_tap.a
> +
> +EXPORT_MAP := rte_pmd_tap_version.map
> +
> +LIBABIVER := 1
> +
> +CFLAGS += -O3
> +CFLAGS += $(WERROR_FLAGS)
> +
> +#
> +# all source are stored in SRCS-y
> +#
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += rte_eth_tap.c
> +
> +# this lib depends upon:
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_eal
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_mbuf
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_mempool
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_ether
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_kvargs
> +
> +include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
> new file mode 100644
> index 0000000..976f2d9
> --- /dev/null
> +++ b/drivers/net/tap/rte_eth_tap.c
> @@ -0,0 +1,765 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2016 Intel Corporation. All rights reserved.
> + *   All rights reserved.
> + *
> + *   Redistribution and use in source and binary forms, with or without
> + *   modification, are permitted provided that the following conditions
> + *   are met:
> + *
> + *     * Redistributions of source code must retain the above copyright
> + *       notice, this list of conditions and the following disclaimer.
> + *     * Redistributions in binary form must reproduce the above copyright
> + *       notice, this list of conditions and the following disclaimer in
> + *       the documentation and/or other materials provided with the
> + *       distribution.
> + *     * Neither the name of Intel Corporation nor the names of its
> + *       contributors may be used to endorse or promote products derived
> + *       from this software without specific prior written permission.
> + *
> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +#include <rte_malloc.h>
> +#include <rte_vdev.h>
> +#include <rte_kvargs.h>
> +
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/socket.h>
> +#include <sys/ioctl.h>
> +#include <sys/mman.h>
> +#include <unistd.h>
> +#include <poll.h>
> +#include <arpa/inet.h>
> +#include <linux/if.h>
> +#include <linux/if_tun.h>
> +#include <linux/if_ether.h>
> +#include <fcntl.h>
> +
> +/* Linux based path to the TUN device */
> +#define TUN_TAP_DEV_PATH        "/dev/net/tun"
> +#define DEFAULT_TAP_NAME        "dtap"
> +
> +#define ETH_TAP_IFACE_ARG       "iface"
> +#define ETH_TAP_SPEED_ARG       "speed"
> +
> +#define RTE_PMD_TAP_MAX_QUEUES 16
> +
> +static struct rte_vdev_driver pmd_tap_drv;
> +
> +static const char *valid_arguments[] = {
> +       ETH_TAP_IFACE_ARG,
> +       ETH_TAP_SPEED_ARG,
> +       NULL
> +};
> +
> +static int tap_unit;
> +
> +static struct rte_eth_link pmd_link = {
> +       .link_speed = ETH_SPEED_NUM_10G,
> +       .link_duplex = ETH_LINK_FULL_DUPLEX,
> +       .link_status = ETH_LINK_DOWN,
> +       .link_autoneg = ETH_LINK_SPEED_AUTONEG
> +};
> +
> +struct pkt_stats {
> +       uint64_t opackets;              /* Number of output packets */
> +       uint64_t ipackets;              /* Number of input packets */
> +       uint64_t obytes;                /* Number of bytes on output */
> +       uint64_t ibytes;                /* Number of bytes on input */
> +       uint64_t errs;                  /* Number of error packets */
> +};
> +
> +struct rx_queue {
> +       struct rte_mempool *mp;         /* Mempool for RX packets */
> +       uint16_t in_port;               /* Port ID */
> +       int fd;
> +
> +       struct pkt_stats stats;         /* Stats for this RX queue */
> +};
> +
> +struct tx_queue {
> +       int fd;
> +       struct pkt_stats stats;         /* Stats for this TX queue */
> +};
> +
> +struct pmd_internals {
> +       char name[RTE_ETH_NAME_MAX_LEN];        /* Internal Tap device name */
> +       uint16_t nb_queues;             /* Number of queues supported */
> +       struct ether_addr eth_addr;     /* Mac address of the device port */
> +
> +       int if_index;                   /* IF_INDEX for the port */
> +       int fds[RTE_PMD_TAP_MAX_QUEUES]; /* List of all file descriptors */
> +
> +       struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES];    /* List of RX queues */
> +       struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES];    /* List of TX queues */
> +};
> +
> +/* Tun/Tap allocation routine
> + *
> + * name is the number of the interface to use, unless NULL to take the host
> + * supplied name.
> + */
> +static int
> +tun_alloc(char *name)
> +{
> +       struct ifreq ifr;
> +       unsigned int features;
> +       int fd;
> +
> +       memset(&ifr, 0, sizeof(struct ifreq));
> +
> +       ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
> +       if (name && name[0])
> +               strncpy(ifr.ifr_name, name, IFNAMSIZ);
> +
> +       fd = open(TUN_TAP_DEV_PATH, O_RDWR);
> +       if (fd < 0) {
> +               RTE_LOG(ERR, PMD, "Unable to create TAP interface");
> +               goto error;
> +       }
> +
> +       /* Grab the TUN features to verify we can work */
> +       if (ioctl(fd, TUNGETFEATURES, &features) < 0) {
> +               RTE_LOG(ERR, PMD, "Unable to get TUN/TAP features\n");
> +               goto error;
> +       }
> +       RTE_LOG(DEBUG, PMD, "TUN/TAP Features %08x\n", features);
> +
> +       if (!(features & IFF_MULTI_QUEUE) && (RTE_PMD_TAP_MAX_QUEUES > 1)) {
> +               RTE_LOG(DEBUG, PMD, "TUN/TAP device only one queue\n");
> +               goto error;
> +       } else if ((features & IFF_ONE_QUEUE) &&
> +                       (RTE_PMD_TAP_MAX_QUEUES == 1)) {
> +               ifr.ifr_flags |= IFF_ONE_QUEUE;
> +               RTE_LOG(DEBUG, PMD, "Single queue only support\n");
> +       } else {
> +               ifr.ifr_flags |= IFF_MULTI_QUEUE;
> +               RTE_LOG(DEBUG, PMD, "Multi-queue support for %d queues\n",
> +                       RTE_PMD_TAP_MAX_QUEUES);
> +       }
> +
> +       /* Set the TUN/TAP configuration and get the name if needed */
> +       if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) {
> +               RTE_LOG(ERR, PMD, "Unable to set TUNSETIFF for %s\n",
> +                       ifr.ifr_name);
> +               perror("TUNSETIFF");
> +               goto error;
> +       }
> +
> +       /* Always set the file descriptor to non-blocking */
> +       if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
> +               RTE_LOG(ERR, PMD, "Unable to set to nonblocking\n");
> +               perror("F_SETFL, NONBLOCK");
> +               goto error;
> +       }
> +
> +       /* If the name is different that new name as default */
> +       if (name && strcmp(name, ifr.ifr_name))
> +               snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s", ifr.ifr_name);
> +
> +       return fd;
> +
> +error:
> +       if (fd > 0)
> +               close(fd);
> +       return -1;
> +}
> +
> +/* Callback to handle the rx burst of packets to the correct interface and
> + * file descriptor(s) in a multi-queue setup.
> + */
> +static uint16_t
> +pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
> +{
> +       int len;
> +       struct rte_mbuf *mbuf;
> +       struct rx_queue *rxq = queue;
> +       uint16_t num_rx;
> +       unsigned long num_rx_bytes = 0;
> +
> +       for (num_rx = 0; num_rx < nb_pkts; ) {
> +               /* allocate the next mbuf */
> +               mbuf = rte_pktmbuf_alloc(rxq->mp);
> +               if (unlikely(!mbuf)) {
> +                       RTE_LOG(WARNING, PMD, "Unable to allocate mbuf\n");
> +                       break;
> +               }
> +
> +               len = read(rxq->fd, rte_pktmbuf_mtod(mbuf, char *),
> +                          rte_pktmbuf_tailroom(mbuf));
> +               if (len <= 0) {
> +                       rte_pktmbuf_free(mbuf);
> +                       break;
> +               }
> +
> +               mbuf->data_len = len;
> +               mbuf->pkt_len = len;
> +               mbuf->port = rxq->in_port;
> +
> +               /* account for the receive frame */
> +               bufs[num_rx++] = mbuf;
> +               num_rx_bytes += mbuf->pkt_len;
> +       }
> +       rxq->stats.ipackets += num_rx;
> +       rxq->stats.ibytes += num_rx_bytes;
> +
> +       return num_rx;
> +}
> +
> +/* Callback to handle sending packets from the tap interface
> + */
> +static uint16_t
> +pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
> +{
> +       struct rte_mbuf *mbuf;
> +       struct tx_queue *txq = queue;
> +       struct pollfd pfd;
> +       uint16_t num_tx = 0;
> +       unsigned long num_tx_bytes = 0;
> +       int i, n;
> +
> +       if (unlikely(nb_pkts == 0))
> +               return 0;
> +
> +       pfd.events = POLLOUT;
> +       pfd.fd = txq->fd;
> +       for (i = 0; i < nb_pkts; i++) {
> +               n = poll(&pfd, 1, 0);
> +
> +               if (n <= 0)
> +                       break;
> +
> +               if (pfd.revents & POLLOUT) {
> +                       /* copy the tx frame data */
> +                       mbuf = bufs[num_tx];
> +                       n = write(pfd.fd, rte_pktmbuf_mtod(mbuf, void*),
> +                                 rte_pktmbuf_pkt_len(mbuf));
> +                       if (n <= 0)
> +                               break;
> +
> +                       num_tx++;
> +                       num_tx_bytes += mbuf->pkt_len;
> +                       rte_pktmbuf_free(mbuf);
> +               }
> +       }
> +
> +       txq->stats.opackets += num_tx;
> +       txq->stats.errs += nb_pkts - num_tx;
> +       txq->stats.obytes += num_tx_bytes;
> +
> +       return num_tx;
> +}
> +
> +static int
> +tap_dev_start(struct rte_eth_dev *dev)
> +{
> +       /* Force the Link up */
> +       dev->data->dev_link.link_status = ETH_LINK_UP;
> +
> +       return 0;
> +}
> +
> +/* This function gets called when the current port gets stopped.
> + */
> +static void
> +tap_dev_stop(struct rte_eth_dev *dev)
> +{
> +       int i;
> +       struct pmd_internals *internals = dev->data->dev_private;
> +
> +       for (i = 0; i < internals->nb_queues; i++)
> +               if (internals->fds[i] != -1)
> +                       close(internals->fds[i]);
> +
> +       dev->data->dev_link.link_status = ETH_LINK_DOWN;
> +}
> +
> +static int
> +tap_dev_configure(struct rte_eth_dev *dev __rte_unused)
> +{
> +       return 0;
> +}
> +
> +static void
> +tap_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
> +{
> +       struct pmd_internals *internals = dev->data->dev_private;
> +
> +       dev_info->if_index = internals->if_index;
> +       dev_info->max_mac_addrs = 1;
> +       dev_info->max_rx_pktlen = (uint32_t)ETHER_MAX_VLAN_FRAME_LEN;
> +       dev_info->max_rx_queues = internals->nb_queues;
> +       dev_info->max_tx_queues = internals->nb_queues;
> +       dev_info->min_rx_bufsize = 0;
> +       dev_info->pci_dev = NULL;
> +}
> +
> +static void
> +tap_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *tap_stats)
> +{
> +       unsigned int i, imax;
> +       unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
> +       unsigned long rx_bytes_total = 0, tx_bytes_total = 0;
> +       const struct pmd_internals *pmd = dev->data->dev_private;
> +
> +       imax = (pmd->nb_queues < RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
> +               pmd->nb_queues : RTE_ETHDEV_QUEUE_STAT_CNTRS;
> +
> +       for (i = 0; i < imax; i++) {
> +               tap_stats->q_ipackets[i] = pmd->rxq[i].stats.ipackets;
> +               tap_stats->q_ibytes[i] = pmd->rxq[i].stats.ibytes;
> +               rx_total += tap_stats->q_ipackets[i];
> +               rx_bytes_total += tap_stats->q_ibytes[i];
> +       }
> +
> +       for (i = 0; i < imax; i++) {
> +               tap_stats->q_opackets[i] = pmd->txq[i].stats.opackets;
> +               tap_stats->q_errors[i] = pmd->txq[i].stats.errs;
> +               tap_stats->q_obytes[i] = pmd->txq[i].stats.obytes;
> +               tx_total += tap_stats->q_opackets[i];
> +               tx_err_total += tap_stats->q_errors[i];
> +               tx_bytes_total += tap_stats->q_obytes[i];
> +       }
> +
> +       tap_stats->ipackets = rx_total;
> +       tap_stats->ibytes = rx_bytes_total;
> +       tap_stats->opackets = tx_total;
> +       tap_stats->oerrors = tx_err_total;
> +       tap_stats->obytes = tx_bytes_total;
> +}
> +
> +static void
> +tap_stats_reset(struct rte_eth_dev *dev)
> +{
> +       int i;
> +       struct pmd_internals *pmd = dev->data->dev_private;
> +
> +       for (i = 0; i < pmd->nb_queues; i++) {
> +               pmd->rxq[i].stats.ipackets = 0;
> +               pmd->rxq[i].stats.ibytes = 0;
> +       }
> +
> +       for (i = 0; i < pmd->nb_queues; i++) {
> +               pmd->txq[i].stats.opackets = 0;
> +               pmd->txq[i].stats.errs = 0;
> +               pmd->txq[i].stats.obytes = 0;
> +       }
> +}
> +
> +static void
> +tap_dev_close(struct rte_eth_dev *dev __rte_unused)
> +{
> +}
> +
> +static void
> +tap_rx_queue_release(void *queue)
> +{
> +       struct rx_queue *rxq = queue;
> +
> +       if (rxq && (rxq->fd > 0)) {
> +               close(rxq->fd);
> +               rxq->fd = -1;
> +       }
> +}
> +
> +static void
> +tap_tx_queue_release(void *queue)
> +{
> +       struct tx_queue *txq = queue;
> +
> +       if (txq && (txq->fd > 0)) {
> +               close(txq->fd);
> +               txq->fd = -1;
> +       }
> +}
> +
> +static int
> +tap_link_update(struct rte_eth_dev *dev __rte_unused,
> +               int wait_to_complete __rte_unused)
> +{
> +       return 0;
> +}
> +
> +static int
> +tap_setup_queue(struct rte_eth_dev *dev,
> +               struct pmd_internals *internals,
> +               uint16_t qid)
> +{
> +       struct rx_queue *rx = &internals->rxq[qid];
> +       struct tx_queue *tx = &internals->txq[qid];
> +       int fd;
> +
> +       fd = rx->fd;
> +       if (fd < 0) {
> +               fd = tx->fd;
> +               if (fd < 0) {
> +                       RTE_LOG(INFO, PMD, "Add queue to TAP %s for qid %d\n",
> +                               dev->data->name, qid);
> +                       fd = tun_alloc(dev->data->name);
> +                       if (fd < 0) {
> +                               RTE_LOG(ERR, PMD, "tun_alloc(%s) failed\n",
> +                                       dev->data->name);
> +                               return -1;
> +                       }
> +               }
> +       }
> +       dev->data->rx_queues[qid] = rx;
> +       dev->data->tx_queues[qid] = tx;
> +
> +       rx->fd = fd;
> +       tx->fd = fd;
> +
> +       return fd;
> +}
> +
> +static int
> +tap_rx_queue_setup(struct rte_eth_dev *dev,
> +                  uint16_t rx_queue_id,
> +                  uint16_t nb_rx_desc __rte_unused,
> +                  unsigned int socket_id __rte_unused,
> +                  const struct rte_eth_rxconf *rx_conf __rte_unused,
> +                  struct rte_mempool *mp)
> +{
> +       struct pmd_internals *internals = dev->data->dev_private;
> +       uint16_t buf_size;
> +       int fd;
> +
> +       if ((rx_queue_id >= internals->nb_queues) || !mp) {
> +               RTE_LOG(ERR, PMD, "nb_queues %d mp %p\n",
> +                       internals->nb_queues, mp);
> +               return -1;
> +       }
> +
> +       internals->rxq[rx_queue_id].mp = mp;
> +       internals->rxq[rx_queue_id].in_port = dev->data->port_id;
> +
> +       /* Now get the space available for data in the mbuf */
> +       buf_size = (uint16_t)(rte_pktmbuf_data_room_size(mp) -
> +                               RTE_PKTMBUF_HEADROOM);
> +
> +       if (buf_size < ETH_FRAME_LEN) {
> +               RTE_LOG(ERR, PMD,
> +                       "%s: %d bytes will not fit in mbuf (%d bytes)\n",
> +                       dev->data->name, ETH_FRAME_LEN, buf_size);
> +               return -ENOMEM;
> +       }
> +
> +       fd = tap_setup_queue(dev, internals, rx_queue_id);
> +       if (fd == -1)
> +               return -1;
> +
> +       internals->fds[rx_queue_id] = fd;
> +       RTE_LOG(INFO, PMD, "RX TAP device name %s, qid %d on fd %d\n",
> +               dev->data->name, rx_queue_id, internals->rxq[rx_queue_id].fd);
> +
> +       return 0;
> +}
> +
> +static int
> +tap_tx_queue_setup(struct rte_eth_dev *dev,
> +                  uint16_t tx_queue_id,
> +                  uint16_t nb_tx_desc __rte_unused,
> +                  unsigned int socket_id __rte_unused,
> +                  const struct rte_eth_txconf *tx_conf __rte_unused)
> +{
> +       struct pmd_internals *internals = dev->data->dev_private;
> +       int ret;
> +
> +       if (tx_queue_id >= internals->nb_queues)
> +               return -1;
> +
> +       ret = tap_setup_queue(dev, internals, tx_queue_id);
> +       if (ret == -1)
> +               return -1;
> +
> +       RTE_LOG(INFO, PMD, "TX TAP device name %s, qid %d on fd %d\n",
> +               dev->data->name, tx_queue_id, internals->txq[tx_queue_id].fd);
> +
> +       return 0;
> +}
> +
> +static const struct eth_dev_ops ops = {
> +       .dev_start              = tap_dev_start,
> +       .dev_stop               = tap_dev_stop,
> +       .dev_close              = tap_dev_close,
> +       .dev_configure          = tap_dev_configure,
> +       .dev_infos_get          = tap_dev_info,
> +       .rx_queue_setup         = tap_rx_queue_setup,
> +       .tx_queue_setup         = tap_tx_queue_setup,
> +       .rx_queue_release       = tap_rx_queue_release,
> +       .tx_queue_release       = tap_tx_queue_release,
> +       .link_update            = tap_link_update,
> +       .stats_get              = tap_stats_get,
> +       .stats_reset            = tap_stats_reset,
> +};
> +
> +static int
> +pmd_mac_address(int fd, struct rte_eth_dev *dev, struct ether_addr *addr)
> +{
> +       struct ifreq ifr;
> +
> +       if ((fd <= 0) || !dev || !addr)
> +               return -1;
> +
> +       memset(&ifr, 0, sizeof(ifr));
> +
> +       if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) {
> +               RTE_LOG(ERR, PMD, "ioctl failed (SIOCGIFHWADDR) (%s)\n",
> +                       ifr.ifr_name);
> +               return -1;
> +       }
> +
> +       /* Set the host based MAC address to this special MAC format */
> +       ifr.ifr_hwaddr.sa_data[0] = 'T';
> +       ifr.ifr_hwaddr.sa_data[1] = 'a';
> +       ifr.ifr_hwaddr.sa_data[2] = 'p';
> +       ifr.ifr_hwaddr.sa_data[3] = '-';
> +       ifr.ifr_hwaddr.sa_data[4] = dev->data->port_id;
> +       ifr.ifr_hwaddr.sa_data[5] = dev->data->numa_node;
> +       if (ioctl(fd, SIOCSIFHWADDR, &ifr) == -1) {
> +               RTE_LOG(ERR, PMD, "%s: ioctl failed (SIOCSIFHWADDR) (%s)\n",
> +                       dev->data->name, ifr.ifr_name);
> +               return -1;
> +       }
> +
> +       /* Set the local application MAC address, needs to be different then
> +        * the host based MAC address.
> +        */
> +       ifr.ifr_hwaddr.sa_data[0] = 'd';
> +       ifr.ifr_hwaddr.sa_data[1] = 'n';
> +       ifr.ifr_hwaddr.sa_data[2] = 'e';
> +       ifr.ifr_hwaddr.sa_data[3] = 't';
> +       ifr.ifr_hwaddr.sa_data[4] = dev->data->port_id;
> +       ifr.ifr_hwaddr.sa_data[5] = dev->data->numa_node;
> +       rte_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
> +
> +       return 0;
> +}
> +
> +static int
> +eth_dev_tap_create(const char *name, char *tap_name)
> +{
> +       int numa_node = rte_socket_id();
> +       struct rte_eth_dev *dev = NULL;
> +       struct pmd_internals *pmd = NULL;
> +       struct rte_eth_dev_data *data = NULL;
> +       int i, fd = -1;
> +
> +       RTE_LOG(INFO, PMD,
> +               "%s: Create TAP Ethernet device with %d queues on numa %u\n",
> +                name, RTE_PMD_TAP_MAX_QUEUES, rte_socket_id());
> +
> +       data = rte_zmalloc_socket(tap_name, sizeof(*data), 0, numa_node);
> +       if (!data) {
> +               RTE_LOG(INFO, PMD, "Failed to allocate data\n");
> +               goto error_exit;
> +       }
> +
> +       pmd = rte_zmalloc_socket(tap_name, sizeof(*pmd), 0, numa_node);
> +       if (!pmd) {
> +               RTE_LOG(INFO, PMD, "Unable to allocate internal struct\n");
> +               goto error_exit;
> +       }
> +
> +       /* Use the name and not the tap_name */
> +       dev = rte_eth_dev_allocate(tap_name);
> +       if (!dev) {
> +               RTE_LOG(INFO, PMD, "Unable to allocate device struct\n");
> +               goto error_exit;
> +       }
> +
> +       snprintf(pmd->name, sizeof(pmd->name), "%s", tap_name);
> +
> +       pmd->nb_queues = RTE_PMD_TAP_MAX_QUEUES;
> +
> +       /* Setup some default values */
> +       data->dev_private = pmd;
> +       data->port_id = dev->data->port_id;
> +       data->dev_flags = RTE_ETH_DEV_DETACHABLE;
> +       data->kdrv = RTE_KDRV_NONE;
> +       data->drv_name = pmd_tap_drv.driver.name;
> +       data->numa_node = numa_node;
> +
> +       data->dev_link = pmd_link;
> +       data->mac_addrs = &pmd->eth_addr;
> +       data->nb_rx_queues = pmd->nb_queues;
> +       data->nb_tx_queues = pmd->nb_queues;
> +
> +       dev->data = data;
> +       dev->dev_ops = &ops;
> +       dev->driver = NULL;
> +       dev->rx_pkt_burst = pmd_rx_burst;
> +       dev->tx_pkt_burst = pmd_tx_burst;
> +       snprintf(dev->data->name, sizeof(dev->data->name), "%s", name);
> +
> +       /* Create the first Tap device */
> +       fd = tun_alloc(tap_name);
> +       if (fd < 0) {
> +               RTE_LOG(INFO, PMD, "tun_alloc() failed\n");
> +               goto error_exit;
> +       }
> +
> +       /* Presetup the fds to -1 as being not working */
> +       for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
> +               pmd->fds[i] = -1;
> +               pmd->rxq[i].fd = -1;
> +               pmd->txq[i].fd = -1;
> +       }
> +
> +       /* Take the TUN/TAP fd and place in the first location */
> +       pmd->rxq[0].fd = fd;
> +       pmd->txq[0].fd = fd;
> +       pmd->fds[0] = fd;
> +
> +       if (pmd_mac_address(fd, dev, &pmd->eth_addr) < 0) {
> +               RTE_LOG(INFO, PMD, "Unable to get MAC address\n");
> +               goto error_exit;
> +       }
> +
> +       return 0;
> +
> +error_exit:
> +       RTE_PMD_DEBUG_TRACE("Unable to initialize %s\n", name);
> +
> +       rte_free(data);
> +       rte_free(pmd);
> +
> +       rte_eth_dev_release_port(dev);
> +
> +       return -EINVAL;
> +}
> +
> +static int
> +set_interface_name(const char *key __rte_unused,
> +                  const char *value,
> +                  void *extra_args)
> +{
> +       char *name = (char *)extra_args;
> +
> +       if (value)
> +               snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s", value);
> +       else
> +               snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s%d",
> +                        DEFAULT_TAP_NAME, (tap_unit - 1));
> +
> +       return 0;
> +}
> +
> +static int
> +set_interface_speed(const char *key __rte_unused,
> +                   const char *value,
> +                   void *extra_args)
> +{
> +       *(int *)extra_args = (value) ? atoi(value) : ETH_SPEED_NUM_10G;
> +
> +       return 0;
> +}
> +
> +/* Open a TAP interface device.
> + */
> +static int
> +rte_pmd_tap_probe(const char *name, const char *params)
> +{
> +       int ret;
> +       struct rte_kvargs *kvlist = NULL;
> +       int speed;
> +       char tap_name[RTE_ETH_NAME_MAX_LEN];
> +
> +       speed = ETH_SPEED_NUM_10G;
> +       snprintf(tap_name, sizeof(tap_name), "%s%d",
> +                DEFAULT_TAP_NAME, tap_unit++);
> +
> +       RTE_LOG(INFO, PMD, "Initializing pmd_tap for %s as %s\n",
> +               name, tap_name);
> +
> +       if (params && (params[0] != '\0')) {
> +               RTE_LOG(INFO, PMD, "paramaters (%s)\n", params);
> +
> +               kvlist = rte_kvargs_parse(params, valid_arguments);
> +               if (kvlist) {
> +                       if (rte_kvargs_count(kvlist, ETH_TAP_SPEED_ARG) == 1) {
> +                               ret = rte_kvargs_process(kvlist,
> +                                                        ETH_TAP_SPEED_ARG,
> +                                                        &set_interface_speed,
> +                                                        &speed);
> +                               if (ret == -1)
> +                                       goto leave;
> +                       }
> +
> +                       if (rte_kvargs_count(kvlist, ETH_TAP_IFACE_ARG) == 1) {
> +                               ret = rte_kvargs_process(kvlist,
> +                                                        ETH_TAP_IFACE_ARG,
> +                                                        &set_interface_name,
> +                                                        tap_name);
> +                               if (ret == -1)
> +                                       goto leave;
> +                       }
> +               }
> +       }
> +       pmd_link.link_speed = speed;
> +
> +       ret = eth_dev_tap_create(name, tap_name);
> +
> +leave:
> +       if (ret == -1) {
> +               RTE_LOG(INFO, PMD, "Failed to create pmd for %s as %s\n",
> +                       name, tap_name);
> +               tap_unit--;             /* Restore the unit number */
> +       }
> +       rte_kvargs_free(kvlist);
> +
> +       return ret;
> +}
> +
> +/* detach a TAP device.
> + */
> +static int
> +rte_pmd_tap_remove(const char *name)
> +{
> +       struct rte_eth_dev *eth_dev = NULL;
> +       struct pmd_internals *internals;
> +       int i;
> +
> +       RTE_LOG(INFO, PMD, "Closing TUN/TAP Ethernet device on numa %u\n",
> +               rte_socket_id());
> +
> +       /* find the ethdev entry */
> +       eth_dev = rte_eth_dev_allocated(name);
> +       if (!eth_dev)
> +               return 0;
> +
> +       internals = eth_dev->data->dev_private;
> +       for (i = 0; i < internals->nb_queues; i++)
> +               if (internals->fds[i] != -1)
> +                       close(internals->fds[i]);
> +
> +       rte_free(eth_dev->data->dev_private);
> +       rte_free(eth_dev->data);
> +
> +       rte_eth_dev_release_port(eth_dev);
> +
> +       return 0;
> +}
> +
> +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_ALIAS(net_tap, eth_tap);
> +RTE_PMD_REGISTER_PARAM_STRING(net_tap, "iface=<string>,speed=N");
> diff --git a/drivers/net/tap/rte_pmd_tap_version.map b/drivers/net/tap/rte_pmd_tap_version.map
> new file mode 100644
> index 0000000..31eca32
> --- /dev/null
> +++ b/drivers/net/tap/rte_pmd_tap_version.map
> @@ -0,0 +1,4 @@
> +DPDK_17.02 {
> +
> +       local: *;
> +};
> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> index f75f0e2..02c32ae 100644
> --- a/mk/rte.app.mk
> +++ b/mk/rte.app.mk
> @@ -124,6 +124,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       += -lrte_pmd_pcap -lpcap
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_QEDE_PMD)       += -lrte_pmd_qede
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_RING)       += -lrte_pmd_ring
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf -lm
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD)     += -lrte_pmd_virtio
>  ifeq ($(CONFIG_RTE_LIBRTE_VHOST),y)
> --
> 2.8.0.GIT
> 
> 

Regards,
Keith

^ permalink raw reply

* Re: [PATCH 7/7] net/qede: restrict maximum queues for PF/VF
From: Ferruh Yigit @ 2016-12-12 20:10 UTC (permalink / raw)
  To: Harish Patil, dev@dpdk.org; +Cc: Dept-Eng DPDK Dev
In-Reply-To: <D47438FD.C04E6%Harish.Patil@cavium.com>

On 12/12/2016 7:29 PM, Harish Patil wrote:
> 
>> On 12/3/2016 2:43 AM, Harish Patil wrote:
>>> Fix to adverstise max_rx_queues by taking into account the number
>>
>> s/adverstise/advertise
> 
> Will correct that, thanks.
> 
>>
>>> of PF connections instead of returning max_queues supported by the
>>> HW.
>>
>> Can you please describe what is the effect, what happens if this is not
>> fixed, and driver keeps reporting max_queues supported by the HW?
> 
> We have tested up to 32 Rx/Tx queues across different qede devices, so I
> would like to advertise only those many.
> Hope that is okay.

That is OK, can you please add this information to the commit log,
otherwise it is not possible to know the reasoning of the change just
with code.

Thanks.

> 
>>
>>>
>>> Fixes: 2ea6f76a ("qede: add core driver")
>>>
>>> Signed-off-by: Harish Patil <harish.patil@qlogic.com>
>>> ---
>> <...>
>>
> 
> 

^ permalink raw reply

* Re: [PATCH] net/qede: fix resource leak
From: Harish Patil @ 2016-12-12 19:32 UTC (permalink / raw)
  To: Ferruh Yigit, Yong Wang, Harish Patil; +Cc: dev@dpdk.org
In-Reply-To: <8bda30ef-8878-9032-967a-cf4a4430b493@intel.com>


>On 11/30/2016 12:32 PM, Yong Wang wrote:
>> Current code does not close 'fd' on function exit, leaking resources.
>> 
>> Signed-off-by: Yong Wang <wang.yong19@zte.com.cn>
>> ---
>
>Add new mail address of the maintainer.
>
>CC: Harish Patil <harish.patil@cavium.com>
>
><...>
>

Acked-by: Harish Patil <harish.patil@qlogic.com>


^ permalink raw reply

* Re: [PATCH 7/7] net/qede: restrict maximum queues for PF/VF
From: Harish Patil @ 2016-12-12 19:29 UTC (permalink / raw)
  To: Ferruh Yigit, dev@dpdk.org; +Cc: Dept-Eng DPDK Dev
In-Reply-To: <ef349aec-eed6-d82d-c68f-b613cab89776@intel.com>


>On 12/3/2016 2:43 AM, Harish Patil wrote:
>> Fix to adverstise max_rx_queues by taking into account the number
>
>s/adverstise/advertise

Will correct that, thanks.

>
>> of PF connections instead of returning max_queues supported by the
>> HW.
>
>Can you please describe what is the effect, what happens if this is not
>fixed, and driver keeps reporting max_queues supported by the HW?

We have tested up to 32 Rx/Tx queues across different qede devices, so I
would like to advertise only those many.
Hope that is okay.

>
>> 
>> Fixes: 2ea6f76a ("qede: add core driver")
>> 
>> Signed-off-by: Harish Patil <harish.patil@qlogic.com>
>> ---
><...>
>



^ permalink raw reply

* [PATCH] SDK: Add scripts to initialize DPDK runtime
From: Luca Boccassi @ 2016-12-12 19:24 UTC (permalink / raw)
  To: dev; +Cc: Christian Ehrhardt, Luca Boccassi

From: Christian Ehrhardt <christian.ehrhardt@canonical.com>

A tools/init directory is added with dpdk-init, a script that can be
used to initialize a DPDK runtime environment. 2 config files with
default options, dpdk.conf and interfaces, are provided as well
together with a SysV init script and a systemd service unit.

Signed-off-by: Luca Boccassi <lboccass@brocade.com>
Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
---
 mk/rte.sdkinstall.mk       |  21 ++++
 tools/init/dpdk-init.in    | 256 +++++++++++++++++++++++++++++++++++++++++++++
 tools/init/dpdk.conf       |  60 +++++++++++
 tools/init/dpdk.init.in    |  57 ++++++++++
 tools/init/dpdk.service.in |  12 +++
 tools/init/interfaces      |  16 +++
 6 files changed, 422 insertions(+)
 create mode 100755 tools/init/dpdk-init.in
 create mode 100644 tools/init/dpdk.conf
 create mode 100755 tools/init/dpdk.init.in
 create mode 100644 tools/init/dpdk.service.in
 create mode 100644 tools/init/interfaces

diff --git a/mk/rte.sdkinstall.mk b/mk/rte.sdkinstall.mk
index 7b0d8b5..a3a5a9a 100644
--- a/mk/rte.sdkinstall.mk
+++ b/mk/rte.sdkinstall.mk
@@ -69,6 +69,14 @@ datadir     ?=       $(datarootdir)/dpdk
 mandir      ?=       $(datarootdir)/man
 sdkdir      ?=                $(datadir)
 targetdir   ?=                $(datadir)/$(RTE_TARGET)
+# If pkgconfig or systemd.pc are not available fall back to most likely default
+ifeq ($(shell pkg-config systemd; echo $$?), 0)
+systemduserunitdir ?= $(shell pkg-config --variable=systemdsystemunitdir systemd)
+else
+systemduserunitdir ?= /lib/systemd/system
+endif
+initdir     ?= /etc/init.d
+configdir   ?= /etc/dpdk
 
 # The install directories may be staged in DESTDIR
 
@@ -162,6 +170,19 @@ install-sdk:
 	$(Q)cp -a               $O/app/dpdk-pmdinfogen   $(DESTDIR)$(targetdir)/app
 	$(Q)$(call rte_symlink, $(DESTDIR)$(includedir), $(DESTDIR)$(targetdir)/include)
 	$(Q)$(call rte_symlink, $(DESTDIR)$(libdir),     $(DESTDIR)$(targetdir)/lib)
+	$(Q)$(call rte_mkdir,                            $(DESTDIR)$(initdir))
+	$(Q)sed -e "s|@@configdir@@|$(configdir)|g" -e "s|@@sbindir@@|$(sbindir)|g" \
+		$(RTE_SDK)/tools/init/dpdk.init.in > $(DESTDIR)$(initdir)/dpdk
+	$(Q)chmod +x                                     $(DESTDIR)$(initdir)/dpdk
+	$(Q)$(call rte_mkdir,                            $(DESTDIR)$(systemduserunitdir))
+	$(Q)sed "s|@@sbindir@@|$(sbindir)|g" $(RTE_SDK)/tools/init/dpdk.service.in > \
+		$(DESTDIR)$(systemduserunitdir)/dpdk.service
+	$(Q)$(call rte_mkdir,                            $(DESTDIR)$(configdir))
+	$(Q)cp -a               $(RTE_SDK)/tools/init/dpdk.conf  $(DESTDIR)$(configdir)
+	$(Q)cp -a               $(RTE_SDK)/tools/init/interfaces $(DESTDIR)$(configdir)
+	$(Q)sed -e "s|@@configdir@@|$(configdir)|g" -e "s|@@sbindir@@|$(sbindir)|g" \
+		$(RTE_SDK)/tools/init/dpdk-init.in > $(DESTDIR)$(sbindir)/dpdk-init
+	$(Q)chmod +x                                     $(DESTDIR)$(sbindir)/dpdk-init
 
 install-doc:
 ifneq ($(wildcard $O/doc/html),)
diff --git a/tools/init/dpdk-init.in b/tools/init/dpdk-init.in
new file mode 100755
index 0000000..89e0399
--- /dev/null
+++ b/tools/init/dpdk-init.in
@@ -0,0 +1,256 @@
+#!/bin/sh
+#
+# dpdk-init: startup script to initialize a dpdk runtime environment
+#
+# Copyright 2015-2016 Canonical Ltd.
+# Autor: Stefan Bader <stefan.bader@canonical.com>
+# Autor: Christian Ehrhardt <christian.ehrhardt@canonical.com>
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License version 3,
+#    as published by the Free Software Foundation.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+set -e
+
+DPDK_BIND="@@sbindir@@/dpdk-devbind"
+DPDK_INTERF="@@configdir@@/interfaces"
+DPDK_CONF="@@configdir@@/dpdk.conf"
+
+
+# pagesize supports [G|g]/[M|m]/[K|k]
+get_kbytes() {
+    local unit
+    local num
+    unit=$(echo "${1}" | sed 's/[0-9]*//g')
+    num=$(echo "${1}" | sed 's/[^0-9]*//g')
+    case ${unit} in
+    *g | *G)
+        echo $((num*1024*1024))
+        ;;
+    *m | *M)
+        echo $((num*1024))
+        ;;
+    *k | *K)
+        echo $((num))
+        ;;
+    *)
+        echo $((num/1024))
+        ;;
+    esac
+}
+
+get_default_hpgsz() {
+    default_hpgsz=$(grep "Hugepagesize:" /proc/meminfo \
+        | sed 's/^Hugepagesize:\s*//g' | sed 's/\s*kB$//g')
+    echo "${default_hpgsz}"
+}
+
+get_hugetlbfs_mountpoint() {
+    local requested_hpgsz
+    local mp_hpgsz
+    requested_hpgsz=$(get_kbytes "${1}")
+
+    grep hugetlbfs /proc/mounts | while read \
+        mntfrom mntpoint mntfstype mntopt mntdump mntfsck; do
+
+        # check if the current muntpoint is of the requested huge page size
+        case ${mntopt} in
+        *pagesize=*)
+            mp_hpgsz=$(echo "${mntopt}" | sed 's/.*pagesize=//g' | sed 's/,.*//g')
+            mp_hpgsz=$(get_kbytes "${mp_hpgsz}")
+            ;;
+        *)
+            mp_hpgsz=$(get_default_hpgsz)
+            ;;
+        esac
+        if [ "${requested_hpgsz}" -eq "${mp_hpgsz}" ]; then
+            echo "${mntpoint}"
+            return
+        fi
+    done
+}
+
+_mount_hugetlbfs() {
+    local MNT="/dev/hugepages"
+    local MNTOPTS=""
+    local requested_hpgsz
+    local default_hpgsz
+    requested_hpgsz=$(get_kbytes "${1}")
+    default_hpgsz=$(get_default_hpgsz)
+
+    # kernel might not support the requested size
+    if [ ! -d "/sys/kernel/mm/hugepages/hugepages-${requested_hpgsz}kB" ]; then
+        echo "WARNING: requested page size of ${requested_hpgsz}kB " \
+             "not supported by the kernel"
+        return 0
+    fi
+
+    # special case if this is not the default huge page size
+    if [ "${requested_hpgsz}" -ne "${default_hpgsz}" ]; then
+        MNT="${MNT}-${requested_hpgsz}"
+        MNTOPTS="pagesize=${requested_hpgsz}K"
+    fi
+
+    if [ ! -e "${MNT}" ]; then
+        mkdir "${MNT}"
+        if [ $? -ne 0 ]; then
+            echo "Could not create directory ${MNT}!" >&2
+            return 1
+        fi
+    fi
+    mount -thugetlbfs hugetlbfs "${MNT}" -o "${MNTOPTS}"
+    return $?
+}
+
+#
+# The DPDK library will use the first mounted instance it finds for a given
+# page size. so if there is already one for a given size there is no need to
+# create another for the same huge page size.
+#
+mount_hugetlbfs() {
+    if [ ! -r "$DPDK_CONF" ]; then
+        return 1
+    fi
+    . "$DPDK_CONF"
+
+    # if a page size is requested, there has to be a mountpoint for that size
+    if [ -n "${NR_2M_PAGES}" -a -z "$(get_hugetlbfs_mountpoint '2M')" ]; then
+        _mount_hugetlbfs 2M
+    fi
+    if [ -n "${NR_16M_PAGES}" -a -z "$(get_hugetlbfs_mountpoint '16M')" ]; then
+        _mount_hugetlbfs 16M
+    fi
+    if [ -n "${NR_1G_PAGES}" -a -z "$(get_hugetlbfs_mountpoint '1G')" ]; then
+        _mount_hugetlbfs 1G
+    fi
+}
+
+_setup_hugepages() {
+    MMDIR="/sys/kernel/mm/hugepages/${1}"
+    PAGES=${2}
+
+    if [ "$PAGES" != "" ]; then
+        if [ "$PAGES" -gt 0 ]; then
+            if [ -d "$MMDIR" -a -w "$MMDIR/nr_hugepages" ]; then
+                # increases the chance to allocate enough huge pages
+                # configurable, since it comes at a perf penality
+                if [ "$DROPCACHE_BEFORE_HP_ALLOC" = "1" ]; then
+                    echo 3 > /proc/sys/vm/drop_caches
+                fi
+
+                echo "$PAGES" > "$MMDIR/nr_hugepages"
+
+                GOTPAGES=$(cat "$MMDIR/nr_hugepages")
+                if [ "$GOTPAGES" -lt "$PAGES" ]; then
+                    echo "WARNING: could not allocate $PAGES at " \
+                         "$MMDIR/nr_hugepages (only got $GOTPAGES)."
+                fi
+            else
+                echo "WARNING: $MMDIR/nr_hugepages not found/writable"
+            fi
+        fi
+    fi
+}
+
+#
+# Reserve a certain amount of hugepages (defined in /etc/dpdk.conf)
+#
+setup_hugepages() {
+    if [ ! -r "$DPDK_CONF" ]; then
+        return 1
+    fi
+    . "$DPDK_CONF"
+
+    _setup_hugepages "hugepages-2048kB" "$NR_2M_PAGES"
+    _setup_hugepages "hugepages-16384kB" "$NR_16M_PAGES"
+    _setup_hugepages "hugepages-1048576kB" "$NR_1G_PAGES"
+
+    # dpdk uses 2*#hugepages mappings, increase for huge systems LP #1507921
+    if [ -d /sys/kernel/mm/hugepages ]; then
+        max_map_count=$(awk -v pad=65530 '{tot+=$1}END{print tot*2+pad}' \
+            /sys/kernel/mm/hugepages/hugepages-*/nr_hugepages)
+        sysctl -q vm.max_map_count="${max_map_count:-65530}"
+    fi
+
+    return 0
+}
+
+#
+# Allow NICs to be automatically bound to DPDK compatible drivers on boot.
+#
+bind_interfaces() {
+    if [ ! -r "$DPDK_INTERF" ]; then
+        return 0
+    fi
+    grep -v '^[ \t]*#' "$DPDK_INTERF" | while read BUS ID MOD; do
+        if [ "$BUS" = "" -o "$ID" = "" -o "$MOD" = "" ]; then
+            echo "WARNING: incomplete spec in $DPDK_INTERF" \
+                " - BUS '$BUS' ID '$ID' MOD '$MOD'"
+            continue
+        fi
+        if [ "$BUS" != "pci" ]; then
+            echo "WARNING: incompatible bus '$BUS' in $DPDK_INTERF"
+            continue
+        fi
+
+        SYSFSPATH="/sys/bus/$BUS/devices/$ID"
+        if [ ! -e "$SYSFSPATH" ]; then
+            echo "WARNING: invalid pci ID '$ID' in $DPDK_INTERF" \
+                " - '$SYSFSPATH' does not exist"
+            continue
+        fi
+        if [ -L "$SYSFSPATH/driver" ]; then
+            CUR=$(readlink "$SYSFSPATH/driver")
+            CUR=$(basename "$CUR")
+        else
+            # device existing, but currently unregistered
+            CUR=""
+        fi
+        if [ "$MOD" != "$CUR" ]; then
+            modprobe -q "$MOD" || true
+            # cloud img have no linux-image-extra initially (uip_pci_generic)
+            # so check if the module is available (loadable/built in)
+            if [ -e "/sys/bus/pci/drivers/${MOD}" ]; then
+                echo "Reassigning pci:$ID to $MOD"
+                $DPDK_BIND -b "$MOD" "$ID"
+            else
+                echo "Warning: failed assigning pci:$ID," \
+                     " module $MOD not available"
+            fi
+        else
+            echo "pci:$ID already assigned to $MOD"
+        fi
+    done
+}
+
+
+
+case "$1" in
+start)
+    mount_hugetlbfs
+    setup_hugepages
+    bind_interfaces
+    ;;
+stop)
+    ;;
+reload|force-reload)
+    setup_hugepages
+    bind_interfaces
+    ;;
+status)
+    $DPDK_BIND --status
+    ;;
+*)
+    echo "Usage: $0 {start|stop|reload|force-reload|status}"
+    exit 1
+    ;;
+esac
+
diff --git a/tools/init/dpdk.conf b/tools/init/dpdk.conf
new file mode 100644
index 0000000..a5aea86
--- /dev/null
+++ b/tools/init/dpdk.conf
@@ -0,0 +1,60 @@
+#
+# The number of 2M hugepages to reserve on system boot
+#
+# Default is 0
+# To e.g. let it reserve 128M via 64x 2M Hugepages set:
+# NR_2M_PAGES=64
+
+#
+# The number of 1G hugepages to reserve on system boot
+#
+# Default is 0
+# To e.g. let it reserve 2G via 2x 1G Hugepages set:
+# NR_1G_PAGES=2
+
+# The number of 16M hugepages to reserve, supported e.g. on ppc64el
+#
+# Default is 0
+# To e.g. let it reserve 512M via 32x 16M Hugepages set:
+# NR_16M_PAGES=32
+
+#
+# Dropping slab and pagecache can help to successfully allocate hugepages,
+# especially later in the lifecycle of a system.
+# This comes at the cost of loosing all slab and pagecache on (re)start
+# of the dpdk service - therefore the default is off.
+#
+# Default is 0
+# Set to 1 to enable it
+#DROPCACHE_BEFORE_HP_ALLOC=0
+
+# The DPDK library will use the first mounted hugetlbfs.
+# The init scripts try to ensure there is at least one default hugetlbfs
+# mountpoint on start.
+# If you have multiple hugetlbfs mountpoints for a complex (e.g. specific numa
+# policies) setup it should be controlled by the admin instead of this init
+# script. In that case specific mountpoints can be provided as parameters to
+# the DPDK library.
+
+# Hardware may support other granularities of hugepages (like 4M). But the
+# larger the hugepages the earlier those should be allocated.
+# Note: the dpdk init scripts will report warnings, but not fail if they could
+# not allocate the requested amount of hugepages.
+# The more or the larger the hugepages to be allocated are, the more it is
+# recommended to do the reservation as kernel commandline arguments.
+# To do so edit /etc/default/grub: GRUB_CMDLINE_LINUX_DEFAULT
+# and add [hugepagesz=xx] hugepages=yy ...
+#
+# Kernel commandline config:
+# hugepagesz sets the size for the next hugepages reservation (default 2M)
+# hugepages  reserves the given number of hugepages of the size set before
+#
+# After modifying /etc/default/grub, the command "update-grub" has to be
+# run in order to re-generate the grub config files. The new values will
+# be used after next reboot.
+#
+# example:
+# GRUB_CMDLINE_LINUX_DEFAULT="... hugepages=16 hugepagesz=1G hugepages=2"
+#
+# If the system supports it, this will reserve 16x 2M pages and 2x 1G pages.
+#
diff --git a/tools/init/dpdk.init.in b/tools/init/dpdk.init.in
new file mode 100755
index 0000000..1e26450
--- /dev/null
+++ b/tools/init/dpdk.init.in
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+### BEGIN INIT INFO
+# Provides:          dpdk
+# Required-Start:    $remote_fs $local_fs
+# Required-Stop:     $remote_fs $local_fs
+# Default-Start:     S
+# Default-Stop:      0 1 6
+# Short-Description: start dpdk runtime environment
+### END INIT INFO
+
+set -e
+
+PATH="/sbin:/bin:/usr/bin"
+
+[ -d @@configdir@@ ] || exit 0
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
+# and status_of_proc is working.
+. /lib/lsb/init-functions
+
+error=0
+case "$1" in
+start)
+    log_action_begin_msg "Starting DPDK environment" "dpdk"
+    output=$(@@sbindir@@/dpdk-init start 2>&1) || error="$?"
+    if [ ! -z "$output" ]; then
+        echo "$output" | while read line; do
+            log_action_cont_msg "$line"
+        done
+    fi
+    log_action_end_msg $error
+    exit $error
+    ;;
+stop)
+    ;;
+restart|force-reload)
+    ;;
+status)
+    output=$(@@sbindir@@/dpdk-init --status 2>&1) || error="$?"
+    if [ ! -z "$output" ]; then
+        echo "$output" | while read line; do
+            log_action_cont_msg "$line"
+        done
+    fi
+    log_action_end_msg $error
+    exit $error
+    ;;
+*)
+    echo "Usage: $0 {start|stop|restart|force-reload|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
+
diff --git a/tools/init/dpdk.service.in b/tools/init/dpdk.service.in
new file mode 100644
index 0000000..1968081
--- /dev/null
+++ b/tools/init/dpdk.service.in
@@ -0,0 +1,12 @@
+[Unit]
+Description=DPDK runtime environment
+DefaultDependencies=false
+After=network-pre.target local-fs.target
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=@@sbindir@@/dpdk-init start
+
+[Install]
+WantedBy=multi-user.target
diff --git a/tools/init/interfaces b/tools/init/interfaces
new file mode 100644
index 0000000..73c3fca
--- /dev/null
+++ b/tools/init/interfaces
@@ -0,0 +1,16 @@
+#
+# <bus>		Currently only "pci" is supported
+# <id>		Device ID on the specified bus
+# <driver>	Driver to bind against (vfio-pci, uio_pci_generic, igb_uio or
+#               rte_kni)
+#
+# Be aware that the two dpdk compatible drivers uio_pci_generic and vfio-pci are
+# part of linux-image-extra-<VERSION> package on Debian-based distributions.
+# This package is not always installed by default - for example in cloud-images.
+# So please install it in case you run into missing module issues.
+#
+# <bus>	<id>		<driver>
+# pci	0000:04:00.0	vfio-pci
+# pci	0000:04:00.1	uio_pci_generic
+# pci	0000:05:00.0	igb_uio
+# pci	0000:06:00.0	rte_kni
-- 
2.1.4

^ permalink raw reply related

* Re: [PATCH v12] net/tap: new TUN/TAP device PMD
From: Marc @ 2016-12-12 19:13 UTC (permalink / raw)
  To: Keith Wiles; +Cc: dev
In-Reply-To: <20161212143838.37269-1-keith.wiles@intel.com>

Keith,

A bit late, but two very high level questions. Do you have performance
numbers compared to KNI? Did you consider using AF_PACKET PACKET_MMAP which
could potentially reduce the number of syscalls to 1 for RX and TX of a
burst?

Marc

On 12 December 2016 at 15:38, Keith Wiles <keith.wiles@intel.com> wrote:

> The PMD allows for DPDK and the host to communicate using a raw
> device interface on the host and in the DPDK application. The device
> created is a Tap device with a L2 packet header.
>
> v12- Fixup minor changes for driver_name and version number
> v11- Add the tap.rst to the nic/index.rst file
> v10- Change the string name used to allow for multiple devices.
> v9 - Fix up the docs to use correct syntax
> v8 - Fix issue with tap_tx_queue_setup() not return zero on success.
> v7 - Reword the comment in common_base and fix the data->name issue
> v6 - fixed the checkpatch issues
> v5 - merge in changes from list review see related emails
>      fixed many minor edits
> v4 - merge with latest driver changes
> v3 - fix includes by removing ifdef for other type besides Linux
>      Fix the copyright notice in the Makefile
> v2 - merge all of the patches into one patch
>      Fix a typo on naming the tap device
>      Update the maintainers list
>
> Signed-off-by: Keith Wiles <keith.wiles@intel.com>
> ---
>  MAINTAINERS                             |   5 +
>  config/common_base                      |   9 +
>  config/common_linuxapp                  |   1 +
>  doc/guides/nics/index.rst               |   1 +
>  doc/guides/nics/tap.rst                 | 136 ++++++
>  drivers/net/Makefile                    |   1 +
>  drivers/net/tap/Makefile                |  57 +++
>  drivers/net/tap/rte_eth_tap.c           | 765
> ++++++++++++++++++++++++++++++++
>  drivers/net/tap/rte_pmd_tap_version.map |   4 +
>  mk/rte.app.mk                           |   1 +
>  10 files changed, 980 insertions(+)
>  create mode 100644 doc/guides/nics/tap.rst
>  create mode 100644 drivers/net/tap/Makefile
>  create mode 100644 drivers/net/tap/rte_eth_tap.c
>  create mode 100644 drivers/net/tap/rte_pmd_tap_version.map
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 26d9590..842fb6d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -398,6 +398,11 @@ F: doc/guides/nics/pcap_ring.rst
>  F: app/test/test_pmd_ring.c
>  F: app/test/test_pmd_ring_perf.c
>
> +Tap PMD
> +M: Keith Wiles <keith.wiles@intel.com>
> +F: drivers/net/tap
> +F: doc/guides/nics/tap.rst
> +
>  Null Networking PMD
>  M: Tetsuya Mukawa <mtetsuyah@gmail.com>
>  F: drivers/net/null/
> diff --git a/config/common_base b/config/common_base
> index 652a839..eb51cdb 100644
> --- a/config/common_base
> +++ b/config/common_base
> @@ -590,3 +590,12 @@ CONFIG_RTE_APP_TEST_RESOURCE_TAR=n
>  CONFIG_RTE_TEST_PMD=y
>  CONFIG_RTE_TEST_PMD_RECORD_CORE_CYCLES=n
>  CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n
> +
> +#
> +# Compile the TAP PMD
> +#
> +# The TAP PMD is currently only built for Linux and the
> +# option is enabled by default in common_linuxapp file,
> +# set to 'n' in the common_base file.
> +#
> +CONFIG_RTE_LIBRTE_PMD_TAP=n
> diff --git a/config/common_linuxapp b/config/common_linuxapp
> index 2483dfa..782b503 100644
> --- a/config/common_linuxapp
> +++ b/config/common_linuxapp
> @@ -44,3 +44,4 @@ CONFIG_RTE_LIBRTE_PMD_VHOST=y
>  CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
>  CONFIG_RTE_LIBRTE_POWER=y
>  CONFIG_RTE_VIRTIO_USER=y
> +CONFIG_RTE_LIBRTE_PMD_TAP=y
> diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
> index 92d56a5..af92529 100644
> --- a/doc/guides/nics/index.rst
> +++ b/doc/guides/nics/index.rst
> @@ -51,6 +51,7 @@ Network Interface Controller Drivers
>      nfp
>      qede
>      szedata2
> +    tap
>      thunderx
>      virtio
>      vhost
> diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
> new file mode 100644
> index 0000000..622b9e7
> --- /dev/null
> +++ b/doc/guides/nics/tap.rst
> @@ -0,0 +1,136 @@
> +..  BSD LICENSE
> +    Copyright(c) 2016 Intel Corporation. All rights reserved.
> +    All rights reserved.
> +
> +    Redistribution and use in source and binary forms, with or without
> +    modification, are permitted provided that the following conditions
> +    are met:
> +
> +    * Redistributions of source code must retain the above copyright
> +    notice, this list of conditions and the following disclaimer.
> +    * Redistributions in binary form must reproduce the above copyright
> +    notice, this list of conditions and the following disclaimer in
> +    the documentation and/or other materials provided with the
> +    distribution.
> +    * Neither the name of Intel Corporation nor the names of its
> +    contributors may be used to endorse or promote products derived
> +    from this software without specific prior written permission.
> +
> +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> +    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> +    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> +    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> +    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> +    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> +    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> +    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> +    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> +    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> +    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> +Tun/Tap Poll Mode Driver
> +========================
> +
> +The ``rte_eth_tap.c`` PMD creates a device using TUN/TAP interfaces on the
> +local host. The PMD allows for DPDK and the host to communicate using a
> raw
> +device interface on the host and in the DPDK application.
> +
> +The device created is a TAP device, which sends/receives packet in a raw
> +format with a L2 header. The usage for a TAP PMD is for connectivity to
> the
> +local host using a TAP interface. When the TAP PMD is initialized it will
> +create a number of tap devices in the host accessed via ``ifconfig -a`` or
> +``ip`` command. The commands can be used to assign and query the virtual
> like
> +device.
> +
> +These TAP interfaces can be used with Wireshark or tcpdump or Pktgen-DPDK
> +along with being able to be used as a network connection to the DPDK
> +application. The method enable one or more interfaces is to use the
> +``--vdev=net_tap`` option on the DPDK application command line. Each
> +``--vdev=net_tap`` option give will create an interface named dtap0,
> dtap1,
> +and so on.
> +
> +The interfaced name can be changed by adding the ``iface=foo0``, for
> example::
> +
> +   --vdev=net_tap,iface=foo0 --vdev=net_tap,iface=foo1, ...
> +
> +Also the speed of the interface can be changed from 10G to whatever number
> +needed, but the interface does not enforce that speed, for example::
> +
> +   --vdev=net_tap,iface=foo0,speed=25000
> +
> +After the DPDK application is started you can send and receive packets on
> the
> +interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
> +point of view you can use any host tool like tcpdump, Wireshark, ping,
> Pktgen
> +and others to communicate with the DPDK application. The DPDK application
> may
> +not understand network protocols like IPv4/6, UDP or TCP unless the
> +application has been written to understand these protocols.
> +
> +If you need the interface as a real network interface meaning running and
> has
> +a valid IP address then you can do this with the following commands::
> +
> +   sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
> +   sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
> +
> +Please change the IP addresses as you see fit.
> +
> +If routing is enabled on the host you can also communicate with the DPDK
> App
> +over the internet via a standard socket layer application as long as you
> +account for the protocol handing in the application.
> +
> +If you have a Network Stack in your DPDK application or something like it
> you
> +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.
> +
> +Example
> +-------
> +
> +The following is a simple example of using the TUN/TAP PMD with the Pktgen
> +packet generator. It requires that the ``socat`` utility is installed on
> the
> +test system.
> +
> +Build DPDK, then pull down Pktgen and build pktgen using the DPDK
> SDK/Target
> +used to build the dpdk you pulled down.
> +
> +Run pktgen from the pktgen directory in a terminal with a commandline
> like the
> +following::
> +
> +    sudo ./app/app/x86_64-native-linuxapp-gcc/app/pktgen -l 1-5 -n 4
>     \
> +     --proc-type auto --log-level 8 --socket-mem 512,512 --file-prefix
> pg   \
> +     --vdev=net_tap --vdev=net_tap -b 05:00.0 -b 05:00.1
>   \
> +     -b 04:00.0 -b 04:00.1 -b 04:00.2 -b 04:00.3
>   \
> +     -b 81:00.0 -b 81:00.1 -b 81:00.2 -b 81:00.3
>   \
> +     -b 82:00.0 -b 83:00.0 -- -T -P -m [2:3].0 -m [4:5].1
>    \
> +     -f themes/black-yellow.theme
> +
> +.. Note:
> +
> +   Change the ``-b`` options to blacklist all of your physical ports. The
> +   following command line is all one line.
> +
> +   Also, ``-f themes/black-yellow.theme`` is optional if the default
> colors
> +   work on your system configuration. See the Pktgen docs for more
> +   information.
> +
> +Verify with ``ifconfig -a`` command in a different xterm window, should
> have a
> +``dtap0`` and ``dtap1`` interfaces created.
> +
> +Next set the links for the two interfaces to up via the commands below::
> +
> +    sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev
> dtap0
> +    sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev
> dtap1
> +
> +Then use socat to create a loopback for the two interfaces::
> +
> +    sudo socat interface:dtap0 interface:dtap1
> +
> +Then on the Pktgen command line interface you can start sending packets
> using
> +the commands ``start 0`` and ``start 1`` or you can start both at the same
> +time with ``start all``. The command ``str`` is an alias for ``start
> all`` and
> +``stp`` is an alias for ``stop all``.
> +
> +While running you should see the 64 byte counters increasing to verify the
> +traffic is being looped back. You can use ``set all size XXX`` to change
> the
> +size of the packets after you stop the traffic. Use the pktgen ``help``
> +command to see a list of all commands. You can also use the ``-f`` option
> to
> +load commands at startup.
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index bc93230..e366a85 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -51,6 +51,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += pcap
>  DIRS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede
>  DIRS-$(CONFIG_RTE_LIBRTE_PMD_RING) += ring
>  DIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += szedata2
> +DIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += tap
>  DIRS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += thunderx
>  DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio
>  DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += vmxnet3
> diff --git a/drivers/net/tap/Makefile b/drivers/net/tap/Makefile
> new file mode 100644
> index 0000000..e18f30c
> --- /dev/null
> +++ b/drivers/net/tap/Makefile
> @@ -0,0 +1,57 @@
> +#   BSD LICENSE
> +#
> +#   Copyright(c) 2016 Intel Corporation. All rights reserved.
> +#
> +#   Redistribution and use in source and binary forms, with or without
> +#   modification, are permitted provided that the following conditions
> +#   are met:
> +#
> +#     * Redistributions of source code must retain the above copyright
> +#       notice, this list of conditions and the following disclaimer.
> +#     * Redistributions in binary form must reproduce the above copyright
> +#       notice, this list of conditions and the following disclaimer in
> +#       the documentation and/or other materials provided with the
> +#       distribution.
> +#     * Neither the name of Intel Corporation nor the names of its
> +#       contributors may be used to endorse or promote products derived
> +#       from this software without specific prior written permission.
> +#
> +#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> +#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> +#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> +#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> +#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> +#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> +#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> +#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> +#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> +#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> +#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> +include $(RTE_SDK)/mk/rte.vars.mk
> +
> +#
> +# library name
> +#
> +LIB = librte_pmd_tap.a
> +
> +EXPORT_MAP := rte_pmd_tap_version.map
> +
> +LIBABIVER := 1
> +
> +CFLAGS += -O3
> +CFLAGS += $(WERROR_FLAGS)
> +
> +#
> +# all source are stored in SRCS-y
> +#
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += rte_eth_tap.c
> +
> +# this lib depends upon:
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_eal
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_mbuf
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_mempool
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_ether
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_kvargs
> +
> +include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
> new file mode 100644
> index 0000000..976f2d9
> --- /dev/null
> +++ b/drivers/net/tap/rte_eth_tap.c
> @@ -0,0 +1,765 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2016 Intel Corporation. All rights reserved.
> + *   All rights reserved.
> + *
> + *   Redistribution and use in source and binary forms, with or without
> + *   modification, are permitted provided that the following conditions
> + *   are met:
> + *
> + *     * Redistributions of source code must retain the above copyright
> + *       notice, this list of conditions and the following disclaimer.
> + *     * Redistributions in binary form must reproduce the above copyright
> + *       notice, this list of conditions and the following disclaimer in
> + *       the documentation and/or other materials provided with the
> + *       distribution.
> + *     * Neither the name of Intel Corporation nor the names of its
> + *       contributors may be used to endorse or promote products derived
> + *       from this software without specific prior written permission.
> + *
> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +#include <rte_malloc.h>
> +#include <rte_vdev.h>
> +#include <rte_kvargs.h>
> +
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/socket.h>
> +#include <sys/ioctl.h>
> +#include <sys/mman.h>
> +#include <unistd.h>
> +#include <poll.h>
> +#include <arpa/inet.h>
> +#include <linux/if.h>
> +#include <linux/if_tun.h>
> +#include <linux/if_ether.h>
> +#include <fcntl.h>
> +
> +/* Linux based path to the TUN device */
> +#define TUN_TAP_DEV_PATH        "/dev/net/tun"
> +#define DEFAULT_TAP_NAME        "dtap"
> +
> +#define ETH_TAP_IFACE_ARG       "iface"
> +#define ETH_TAP_SPEED_ARG       "speed"
> +
> +#define RTE_PMD_TAP_MAX_QUEUES 16
> +
> +static struct rte_vdev_driver pmd_tap_drv;
> +
> +static const char *valid_arguments[] = {
> +       ETH_TAP_IFACE_ARG,
> +       ETH_TAP_SPEED_ARG,
> +       NULL
> +};
> +
> +static int tap_unit;
> +
> +static struct rte_eth_link pmd_link = {
> +       .link_speed = ETH_SPEED_NUM_10G,
> +       .link_duplex = ETH_LINK_FULL_DUPLEX,
> +       .link_status = ETH_LINK_DOWN,
> +       .link_autoneg = ETH_LINK_SPEED_AUTONEG
> +};
> +
> +struct pkt_stats {
> +       uint64_t opackets;              /* Number of output packets */
> +       uint64_t ipackets;              /* Number of input packets */
> +       uint64_t obytes;                /* Number of bytes on output */
> +       uint64_t ibytes;                /* Number of bytes on input */
> +       uint64_t errs;                  /* Number of error packets */
> +};
> +
> +struct rx_queue {
> +       struct rte_mempool *mp;         /* Mempool for RX packets */
> +       uint16_t in_port;               /* Port ID */
> +       int fd;
> +
> +       struct pkt_stats stats;         /* Stats for this RX queue */
> +};
> +
> +struct tx_queue {
> +       int fd;
> +       struct pkt_stats stats;         /* Stats for this TX queue */
> +};
> +
> +struct pmd_internals {
> +       char name[RTE_ETH_NAME_MAX_LEN];        /* Internal Tap device
> name */
> +       uint16_t nb_queues;             /* Number of queues supported */
> +       struct ether_addr eth_addr;     /* Mac address of the device port
> */
> +
> +       int if_index;                   /* IF_INDEX for the port */
> +       int fds[RTE_PMD_TAP_MAX_QUEUES]; /* List of all file descriptors */
> +
> +       struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES];    /* List of RX
> queues */
> +       struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES];    /* List of TX
> queues */
> +};
> +
> +/* Tun/Tap allocation routine
> + *
> + * name is the number of the interface to use, unless NULL to take the
> host
> + * supplied name.
> + */
> +static int
> +tun_alloc(char *name)
> +{
> +       struct ifreq ifr;
> +       unsigned int features;
> +       int fd;
> +
> +       memset(&ifr, 0, sizeof(struct ifreq));
> +
> +       ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
> +       if (name && name[0])
> +               strncpy(ifr.ifr_name, name, IFNAMSIZ);
> +
> +       fd = open(TUN_TAP_DEV_PATH, O_RDWR);
> +       if (fd < 0) {
> +               RTE_LOG(ERR, PMD, "Unable to create TAP interface");
> +               goto error;
> +       }
> +
> +       /* Grab the TUN features to verify we can work */
> +       if (ioctl(fd, TUNGETFEATURES, &features) < 0) {
> +               RTE_LOG(ERR, PMD, "Unable to get TUN/TAP features\n");
> +               goto error;
> +       }
> +       RTE_LOG(DEBUG, PMD, "TUN/TAP Features %08x\n", features);
> +
> +       if (!(features & IFF_MULTI_QUEUE) && (RTE_PMD_TAP_MAX_QUEUES > 1))
> {
> +               RTE_LOG(DEBUG, PMD, "TUN/TAP device only one queue\n");
> +               goto error;
> +       } else if ((features & IFF_ONE_QUEUE) &&
> +                       (RTE_PMD_TAP_MAX_QUEUES == 1)) {
> +               ifr.ifr_flags |= IFF_ONE_QUEUE;
> +               RTE_LOG(DEBUG, PMD, "Single queue only support\n");
> +       } else {
> +               ifr.ifr_flags |= IFF_MULTI_QUEUE;
> +               RTE_LOG(DEBUG, PMD, "Multi-queue support for %d queues\n",
> +                       RTE_PMD_TAP_MAX_QUEUES);
> +       }
> +
> +       /* Set the TUN/TAP configuration and get the name if needed */
> +       if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) {
> +               RTE_LOG(ERR, PMD, "Unable to set TUNSETIFF for %s\n",
> +                       ifr.ifr_name);
> +               perror("TUNSETIFF");
> +               goto error;
> +       }
> +
> +       /* Always set the file descriptor to non-blocking */
> +       if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
> +               RTE_LOG(ERR, PMD, "Unable to set to nonblocking\n");
> +               perror("F_SETFL, NONBLOCK");
> +               goto error;
> +       }
> +
> +       /* If the name is different that new name as default */
> +       if (name && strcmp(name, ifr.ifr_name))
> +               snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s",
> ifr.ifr_name);
> +
> +       return fd;
> +
> +error:
> +       if (fd > 0)
> +               close(fd);
> +       return -1;
> +}
> +
> +/* Callback to handle the rx burst of packets to the correct interface and
> + * file descriptor(s) in a multi-queue setup.
> + */
> +static uint16_t
> +pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
> +{
> +       int len;
> +       struct rte_mbuf *mbuf;
> +       struct rx_queue *rxq = queue;
> +       uint16_t num_rx;
> +       unsigned long num_rx_bytes = 0;
> +
> +       for (num_rx = 0; num_rx < nb_pkts; ) {
> +               /* allocate the next mbuf */
> +               mbuf = rte_pktmbuf_alloc(rxq->mp);
> +               if (unlikely(!mbuf)) {
> +                       RTE_LOG(WARNING, PMD, "Unable to allocate mbuf\n");
> +                       break;
> +               }
> +
> +               len = read(rxq->fd, rte_pktmbuf_mtod(mbuf, char *),
> +                          rte_pktmbuf_tailroom(mbuf));
> +               if (len <= 0) {
> +                       rte_pktmbuf_free(mbuf);
> +                       break;
> +               }
> +
> +               mbuf->data_len = len;
> +               mbuf->pkt_len = len;
> +               mbuf->port = rxq->in_port;
> +
> +               /* account for the receive frame */
> +               bufs[num_rx++] = mbuf;
> +               num_rx_bytes += mbuf->pkt_len;
> +       }
> +       rxq->stats.ipackets += num_rx;
> +       rxq->stats.ibytes += num_rx_bytes;
> +
> +       return num_rx;
> +}
> +
> +/* Callback to handle sending packets from the tap interface
> + */
> +static uint16_t
> +pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
> +{
> +       struct rte_mbuf *mbuf;
> +       struct tx_queue *txq = queue;
> +       struct pollfd pfd;
> +       uint16_t num_tx = 0;
> +       unsigned long num_tx_bytes = 0;
> +       int i, n;
> +
> +       if (unlikely(nb_pkts == 0))
> +               return 0;
> +
> +       pfd.events = POLLOUT;
> +       pfd.fd = txq->fd;
> +       for (i = 0; i < nb_pkts; i++) {
> +               n = poll(&pfd, 1, 0);
> +
> +               if (n <= 0)
> +                       break;
> +
> +               if (pfd.revents & POLLOUT) {
> +                       /* copy the tx frame data */
> +                       mbuf = bufs[num_tx];
> +                       n = write(pfd.fd, rte_pktmbuf_mtod(mbuf, void*),
> +                                 rte_pktmbuf_pkt_len(mbuf));
> +                       if (n <= 0)
> +                               break;
> +
> +                       num_tx++;
> +                       num_tx_bytes += mbuf->pkt_len;
> +                       rte_pktmbuf_free(mbuf);
> +               }
> +       }
> +
> +       txq->stats.opackets += num_tx;
> +       txq->stats.errs += nb_pkts - num_tx;
> +       txq->stats.obytes += num_tx_bytes;
> +
> +       return num_tx;
> +}
> +
> +static int
> +tap_dev_start(struct rte_eth_dev *dev)
> +{
> +       /* Force the Link up */
> +       dev->data->dev_link.link_status = ETH_LINK_UP;
> +
> +       return 0;
> +}
> +
> +/* This function gets called when the current port gets stopped.
> + */
> +static void
> +tap_dev_stop(struct rte_eth_dev *dev)
> +{
> +       int i;
> +       struct pmd_internals *internals = dev->data->dev_private;
> +
> +       for (i = 0; i < internals->nb_queues; i++)
> +               if (internals->fds[i] != -1)
> +                       close(internals->fds[i]);
> +
> +       dev->data->dev_link.link_status = ETH_LINK_DOWN;
> +}
> +
> +static int
> +tap_dev_configure(struct rte_eth_dev *dev __rte_unused)
> +{
> +       return 0;
> +}
> +
> +static void
> +tap_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
> +{
> +       struct pmd_internals *internals = dev->data->dev_private;
> +
> +       dev_info->if_index = internals->if_index;
> +       dev_info->max_mac_addrs = 1;
> +       dev_info->max_rx_pktlen = (uint32_t)ETHER_MAX_VLAN_FRAME_LEN;
> +       dev_info->max_rx_queues = internals->nb_queues;
> +       dev_info->max_tx_queues = internals->nb_queues;
> +       dev_info->min_rx_bufsize = 0;
> +       dev_info->pci_dev = NULL;
> +}
> +
> +static void
> +tap_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *tap_stats)
> +{
> +       unsigned int i, imax;
> +       unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
> +       unsigned long rx_bytes_total = 0, tx_bytes_total = 0;
> +       const struct pmd_internals *pmd = dev->data->dev_private;
> +
> +       imax = (pmd->nb_queues < RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
> +               pmd->nb_queues : RTE_ETHDEV_QUEUE_STAT_CNTRS;
> +
> +       for (i = 0; i < imax; i++) {
> +               tap_stats->q_ipackets[i] = pmd->rxq[i].stats.ipackets;
> +               tap_stats->q_ibytes[i] = pmd->rxq[i].stats.ibytes;
> +               rx_total += tap_stats->q_ipackets[i];
> +               rx_bytes_total += tap_stats->q_ibytes[i];
> +       }
> +
> +       for (i = 0; i < imax; i++) {
> +               tap_stats->q_opackets[i] = pmd->txq[i].stats.opackets;
> +               tap_stats->q_errors[i] = pmd->txq[i].stats.errs;
> +               tap_stats->q_obytes[i] = pmd->txq[i].stats.obytes;
> +               tx_total += tap_stats->q_opackets[i];
> +               tx_err_total += tap_stats->q_errors[i];
> +               tx_bytes_total += tap_stats->q_obytes[i];
> +       }
> +
> +       tap_stats->ipackets = rx_total;
> +       tap_stats->ibytes = rx_bytes_total;
> +       tap_stats->opackets = tx_total;
> +       tap_stats->oerrors = tx_err_total;
> +       tap_stats->obytes = tx_bytes_total;
> +}
> +
> +static void
> +tap_stats_reset(struct rte_eth_dev *dev)
> +{
> +       int i;
> +       struct pmd_internals *pmd = dev->data->dev_private;
> +
> +       for (i = 0; i < pmd->nb_queues; i++) {
> +               pmd->rxq[i].stats.ipackets = 0;
> +               pmd->rxq[i].stats.ibytes = 0;
> +       }
> +
> +       for (i = 0; i < pmd->nb_queues; i++) {
> +               pmd->txq[i].stats.opackets = 0;
> +               pmd->txq[i].stats.errs = 0;
> +               pmd->txq[i].stats.obytes = 0;
> +       }
> +}
> +
> +static void
> +tap_dev_close(struct rte_eth_dev *dev __rte_unused)
> +{
> +}
> +
> +static void
> +tap_rx_queue_release(void *queue)
> +{
> +       struct rx_queue *rxq = queue;
> +
> +       if (rxq && (rxq->fd > 0)) {
> +               close(rxq->fd);
> +               rxq->fd = -1;
> +       }
> +}
> +
> +static void
> +tap_tx_queue_release(void *queue)
> +{
> +       struct tx_queue *txq = queue;
> +
> +       if (txq && (txq->fd > 0)) {
> +               close(txq->fd);
> +               txq->fd = -1;
> +       }
> +}
> +
> +static int
> +tap_link_update(struct rte_eth_dev *dev __rte_unused,
> +               int wait_to_complete __rte_unused)
> +{
> +       return 0;
> +}
> +
> +static int
> +tap_setup_queue(struct rte_eth_dev *dev,
> +               struct pmd_internals *internals,
> +               uint16_t qid)
> +{
> +       struct rx_queue *rx = &internals->rxq[qid];
> +       struct tx_queue *tx = &internals->txq[qid];
> +       int fd;
> +
> +       fd = rx->fd;
> +       if (fd < 0) {
> +               fd = tx->fd;
> +               if (fd < 0) {
> +                       RTE_LOG(INFO, PMD, "Add queue to TAP %s for qid
> %d\n",
> +                               dev->data->name, qid);
> +                       fd = tun_alloc(dev->data->name);
> +                       if (fd < 0) {
> +                               RTE_LOG(ERR, PMD, "tun_alloc(%s) failed\n",
> +                                       dev->data->name);
> +                               return -1;
> +                       }
> +               }
> +       }
> +       dev->data->rx_queues[qid] = rx;
> +       dev->data->tx_queues[qid] = tx;
> +
> +       rx->fd = fd;
> +       tx->fd = fd;
> +
> +       return fd;
> +}
> +
> +static int
> +tap_rx_queue_setup(struct rte_eth_dev *dev,
> +                  uint16_t rx_queue_id,
> +                  uint16_t nb_rx_desc __rte_unused,
> +                  unsigned int socket_id __rte_unused,
> +                  const struct rte_eth_rxconf *rx_conf __rte_unused,
> +                  struct rte_mempool *mp)
> +{
> +       struct pmd_internals *internals = dev->data->dev_private;
> +       uint16_t buf_size;
> +       int fd;
> +
> +       if ((rx_queue_id >= internals->nb_queues) || !mp) {
> +               RTE_LOG(ERR, PMD, "nb_queues %d mp %p\n",
> +                       internals->nb_queues, mp);
> +               return -1;
> +       }
> +
> +       internals->rxq[rx_queue_id].mp = mp;
> +       internals->rxq[rx_queue_id].in_port = dev->data->port_id;
> +
> +       /* Now get the space available for data in the mbuf */
> +       buf_size = (uint16_t)(rte_pktmbuf_data_room_size(mp) -
> +                               RTE_PKTMBUF_HEADROOM);
> +
> +       if (buf_size < ETH_FRAME_LEN) {
> +               RTE_LOG(ERR, PMD,
> +                       "%s: %d bytes will not fit in mbuf (%d bytes)\n",
> +                       dev->data->name, ETH_FRAME_LEN, buf_size);
> +               return -ENOMEM;
> +       }
> +
> +       fd = tap_setup_queue(dev, internals, rx_queue_id);
> +       if (fd == -1)
> +               return -1;
> +
> +       internals->fds[rx_queue_id] = fd;
> +       RTE_LOG(INFO, PMD, "RX TAP device name %s, qid %d on fd %d\n",
> +               dev->data->name, rx_queue_id, internals->rxq[rx_queue_id].
> fd);
> +
> +       return 0;
> +}
> +
> +static int
> +tap_tx_queue_setup(struct rte_eth_dev *dev,
> +                  uint16_t tx_queue_id,
> +                  uint16_t nb_tx_desc __rte_unused,
> +                  unsigned int socket_id __rte_unused,
> +                  const struct rte_eth_txconf *tx_conf __rte_unused)
> +{
> +       struct pmd_internals *internals = dev->data->dev_private;
> +       int ret;
> +
> +       if (tx_queue_id >= internals->nb_queues)
> +               return -1;
> +
> +       ret = tap_setup_queue(dev, internals, tx_queue_id);
> +       if (ret == -1)
> +               return -1;
> +
> +       RTE_LOG(INFO, PMD, "TX TAP device name %s, qid %d on fd %d\n",
> +               dev->data->name, tx_queue_id, internals->txq[tx_queue_id].
> fd);
> +
> +       return 0;
> +}
> +
> +static const struct eth_dev_ops ops = {
> +       .dev_start              = tap_dev_start,
> +       .dev_stop               = tap_dev_stop,
> +       .dev_close              = tap_dev_close,
> +       .dev_configure          = tap_dev_configure,
> +       .dev_infos_get          = tap_dev_info,
> +       .rx_queue_setup         = tap_rx_queue_setup,
> +       .tx_queue_setup         = tap_tx_queue_setup,
> +       .rx_queue_release       = tap_rx_queue_release,
> +       .tx_queue_release       = tap_tx_queue_release,
> +       .link_update            = tap_link_update,
> +       .stats_get              = tap_stats_get,
> +       .stats_reset            = tap_stats_reset,
> +};
> +
> +static int
> +pmd_mac_address(int fd, struct rte_eth_dev *dev, struct ether_addr *addr)
> +{
> +       struct ifreq ifr;
> +
> +       if ((fd <= 0) || !dev || !addr)
> +               return -1;
> +
> +       memset(&ifr, 0, sizeof(ifr));
> +
> +       if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) {
> +               RTE_LOG(ERR, PMD, "ioctl failed (SIOCGIFHWADDR) (%s)\n",
> +                       ifr.ifr_name);
> +               return -1;
> +       }
> +
> +       /* Set the host based MAC address to this special MAC format */
> +       ifr.ifr_hwaddr.sa_data[0] = 'T';
> +       ifr.ifr_hwaddr.sa_data[1] = 'a';
> +       ifr.ifr_hwaddr.sa_data[2] = 'p';
> +       ifr.ifr_hwaddr.sa_data[3] = '-';
> +       ifr.ifr_hwaddr.sa_data[4] = dev->data->port_id;
> +       ifr.ifr_hwaddr.sa_data[5] = dev->data->numa_node;
> +       if (ioctl(fd, SIOCSIFHWADDR, &ifr) == -1) {
> +               RTE_LOG(ERR, PMD, "%s: ioctl failed (SIOCSIFHWADDR)
> (%s)\n",
> +                       dev->data->name, ifr.ifr_name);
> +               return -1;
> +       }
> +
> +       /* Set the local application MAC address, needs to be different
> then
> +        * the host based MAC address.
> +        */
> +       ifr.ifr_hwaddr.sa_data[0] = 'd';
> +       ifr.ifr_hwaddr.sa_data[1] = 'n';
> +       ifr.ifr_hwaddr.sa_data[2] = 'e';
> +       ifr.ifr_hwaddr.sa_data[3] = 't';
> +       ifr.ifr_hwaddr.sa_data[4] = dev->data->port_id;
> +       ifr.ifr_hwaddr.sa_data[5] = dev->data->numa_node;
> +       rte_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
> +
> +       return 0;
> +}
> +
> +static int
> +eth_dev_tap_create(const char *name, char *tap_name)
> +{
> +       int numa_node = rte_socket_id();
> +       struct rte_eth_dev *dev = NULL;
> +       struct pmd_internals *pmd = NULL;
> +       struct rte_eth_dev_data *data = NULL;
> +       int i, fd = -1;
> +
> +       RTE_LOG(INFO, PMD,
> +               "%s: Create TAP Ethernet device with %d queues on numa
> %u\n",
> +                name, RTE_PMD_TAP_MAX_QUEUES, rte_socket_id());
> +
> +       data = rte_zmalloc_socket(tap_name, sizeof(*data), 0, numa_node);
> +       if (!data) {
> +               RTE_LOG(INFO, PMD, "Failed to allocate data\n");
> +               goto error_exit;
> +       }
> +
> +       pmd = rte_zmalloc_socket(tap_name, sizeof(*pmd), 0, numa_node);
> +       if (!pmd) {
> +               RTE_LOG(INFO, PMD, "Unable to allocate internal struct\n");
> +               goto error_exit;
> +       }
> +
> +       /* Use the name and not the tap_name */
> +       dev = rte_eth_dev_allocate(tap_name);
> +       if (!dev) {
> +               RTE_LOG(INFO, PMD, "Unable to allocate device struct\n");
> +               goto error_exit;
> +       }
> +
> +       snprintf(pmd->name, sizeof(pmd->name), "%s", tap_name);
> +
> +       pmd->nb_queues = RTE_PMD_TAP_MAX_QUEUES;
> +
> +       /* Setup some default values */
> +       data->dev_private = pmd;
> +       data->port_id = dev->data->port_id;
> +       data->dev_flags = RTE_ETH_DEV_DETACHABLE;
> +       data->kdrv = RTE_KDRV_NONE;
> +       data->drv_name = pmd_tap_drv.driver.name;
> +       data->numa_node = numa_node;
> +
> +       data->dev_link = pmd_link;
> +       data->mac_addrs = &pmd->eth_addr;
> +       data->nb_rx_queues = pmd->nb_queues;
> +       data->nb_tx_queues = pmd->nb_queues;
> +
> +       dev->data = data;
> +       dev->dev_ops = &ops;
> +       dev->driver = NULL;
> +       dev->rx_pkt_burst = pmd_rx_burst;
> +       dev->tx_pkt_burst = pmd_tx_burst;
> +       snprintf(dev->data->name, sizeof(dev->data->name), "%s", name);
> +
> +       /* Create the first Tap device */
> +       fd = tun_alloc(tap_name);
> +       if (fd < 0) {
> +               RTE_LOG(INFO, PMD, "tun_alloc() failed\n");
> +               goto error_exit;
> +       }
> +
> +       /* Presetup the fds to -1 as being not working */
> +       for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
> +               pmd->fds[i] = -1;
> +               pmd->rxq[i].fd = -1;
> +               pmd->txq[i].fd = -1;
> +       }
> +
> +       /* Take the TUN/TAP fd and place in the first location */
> +       pmd->rxq[0].fd = fd;
> +       pmd->txq[0].fd = fd;
> +       pmd->fds[0] = fd;
> +
> +       if (pmd_mac_address(fd, dev, &pmd->eth_addr) < 0) {
> +               RTE_LOG(INFO, PMD, "Unable to get MAC address\n");
> +               goto error_exit;
> +       }
> +
> +       return 0;
> +
> +error_exit:
> +       RTE_PMD_DEBUG_TRACE("Unable to initialize %s\n", name);
> +
> +       rte_free(data);
> +       rte_free(pmd);
> +
> +       rte_eth_dev_release_port(dev);
> +
> +       return -EINVAL;
> +}
> +
> +static int
> +set_interface_name(const char *key __rte_unused,
> +                  const char *value,
> +                  void *extra_args)
> +{
> +       char *name = (char *)extra_args;
> +
> +       if (value)
> +               snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s", value);
> +       else
> +               snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s%d",
> +                        DEFAULT_TAP_NAME, (tap_unit - 1));
> +
> +       return 0;
> +}
> +
> +static int
> +set_interface_speed(const char *key __rte_unused,
> +                   const char *value,
> +                   void *extra_args)
> +{
> +       *(int *)extra_args = (value) ? atoi(value) : ETH_SPEED_NUM_10G;
> +
> +       return 0;
> +}
> +
> +/* Open a TAP interface device.
> + */
> +static int
> +rte_pmd_tap_probe(const char *name, const char *params)
> +{
> +       int ret;
> +       struct rte_kvargs *kvlist = NULL;
> +       int speed;
> +       char tap_name[RTE_ETH_NAME_MAX_LEN];
> +
> +       speed = ETH_SPEED_NUM_10G;
> +       snprintf(tap_name, sizeof(tap_name), "%s%d",
> +                DEFAULT_TAP_NAME, tap_unit++);
> +
> +       RTE_LOG(INFO, PMD, "Initializing pmd_tap for %s as %s\n",
> +               name, tap_name);
> +
> +       if (params && (params[0] != '\0')) {
> +               RTE_LOG(INFO, PMD, "paramaters (%s)\n", params);
> +
> +               kvlist = rte_kvargs_parse(params, valid_arguments);
> +               if (kvlist) {
> +                       if (rte_kvargs_count(kvlist, ETH_TAP_SPEED_ARG) ==
> 1) {
> +                               ret = rte_kvargs_process(kvlist,
> +                                                        ETH_TAP_SPEED_ARG,
> +
> &set_interface_speed,
> +                                                        &speed);
> +                               if (ret == -1)
> +                                       goto leave;
> +                       }
> +
> +                       if (rte_kvargs_count(kvlist, ETH_TAP_IFACE_ARG) ==
> 1) {
> +                               ret = rte_kvargs_process(kvlist,
> +                                                        ETH_TAP_IFACE_ARG,
> +
> &set_interface_name,
> +                                                        tap_name);
> +                               if (ret == -1)
> +                                       goto leave;
> +                       }
> +               }
> +       }
> +       pmd_link.link_speed = speed;
> +
> +       ret = eth_dev_tap_create(name, tap_name);
> +
> +leave:
> +       if (ret == -1) {
> +               RTE_LOG(INFO, PMD, "Failed to create pmd for %s as %s\n",
> +                       name, tap_name);
> +               tap_unit--;             /* Restore the unit number */
> +       }
> +       rte_kvargs_free(kvlist);
> +
> +       return ret;
> +}
> +
> +/* detach a TAP device.
> + */
> +static int
> +rte_pmd_tap_remove(const char *name)
> +{
> +       struct rte_eth_dev *eth_dev = NULL;
> +       struct pmd_internals *internals;
> +       int i;
> +
> +       RTE_LOG(INFO, PMD, "Closing TUN/TAP Ethernet device on numa %u\n",
> +               rte_socket_id());
> +
> +       /* find the ethdev entry */
> +       eth_dev = rte_eth_dev_allocated(name);
> +       if (!eth_dev)
> +               return 0;
> +
> +       internals = eth_dev->data->dev_private;
> +       for (i = 0; i < internals->nb_queues; i++)
> +               if (internals->fds[i] != -1)
> +                       close(internals->fds[i]);
> +
> +       rte_free(eth_dev->data->dev_private);
> +       rte_free(eth_dev->data);
> +
> +       rte_eth_dev_release_port(eth_dev);
> +
> +       return 0;
> +}
> +
> +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_ALIAS(net_tap, eth_tap);
> +RTE_PMD_REGISTER_PARAM_STRING(net_tap, "iface=<string>,speed=N");
> diff --git a/drivers/net/tap/rte_pmd_tap_version.map
> b/drivers/net/tap/rte_pmd_tap_version.map
> new file mode 100644
> index 0000000..31eca32
> --- /dev/null
> +++ b/drivers/net/tap/rte_pmd_tap_version.map
> @@ -0,0 +1,4 @@
> +DPDK_17.02 {
> +
> +       local: *;
> +};
> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> index f75f0e2..02c32ae 100644
> --- a/mk/rte.app.mk
> +++ b/mk/rte.app.mk
> @@ -124,6 +124,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       +=
> -lrte_pmd_pcap -lpcap
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_QEDE_PMD)       += -lrte_pmd_qede
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_RING)       += -lrte_pmd_ring
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) +=
> -lrte_pmd_thunderx_nicvf -lm
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD)     += -lrte_pmd_virtio
>  ifeq ($(CONFIG_RTE_LIBRTE_VHOST),y)
> --
> 2.8.0.GIT
>
>

^ permalink raw reply

* Re: [PATCH] vmxnet3: fix Rx deadlock
From: Yong Wang @ 2016-12-12 18:17 UTC (permalink / raw)
  To: Stefan Puiu; +Cc: dev@dpdk.org, mac_leehk@yahoo.com.hk
In-Reply-To: <CACKs7VAJDu6aMY6tLJXcM4doS8diZkAOidVCRZwR6u1RTuRaDQ@mail.gmail.com>

> -----Original Message-----
> From: Stefan Puiu [mailto:stefan.puiu@gmail.com]
> Sent: Monday, December 12, 2016 12:27 AM
> To: Yong Wang <yongwang@vmware.com>
> Cc: dev@dpdk.org; mac_leehk@yahoo.com.hk
> Subject: Re: [PATCH] vmxnet3: fix Rx deadlock
> 
> Hello and thanks for reviewing the patch.
> 
> On Wed, Nov 30, 2016 at 6:59 AM, Yong Wang <yongwang@vmware.com>
> wrote:
> [...]
> > I think a more accurate description is that the particular descriptor's
> generation bit never got flipped properly when an mbuf failed to be refilled
> which caused the rx stuck, rather than vmxnet3_post_rx_bufs() not being
> called afterwards.
> >
> 
> Not sure if this kind of level of detail is useful, but if you can
> think of a better explanation to put in the changelist, I can add it.
> I see the generation bit not flipping as a symptom, while the core
> problem is the hardware can't write to the descriptor. I felt the
> explanation was going into too much detail anyway, so I've reworded it
> a bit for v2. Let me know what you think.

This is one of the cases that I prefer accuracy and I think the level of details is needed for whoever will work on this part of the code (datapath tx and rx routines).

The v2 description looks good to me expect the following description:

"nobody retries this later, so the driver gets stuck in this state."

The driver definitely retries vmxnet3_post_rx_bufs() after it was in the problematic state but due to the descriptor's gen bit not flipped, the driver won't refill an mbuf.  How about "the driver won't refill the mbuf after this so it gets stuck in this state."?

> Thanks,
> Stefan.

^ permalink raw reply

* Re: [PATCH 6/7] net/qede: fix maximum VF count to 0
From: Ferruh Yigit @ 2016-12-12 18:13 UTC (permalink / raw)
  To: Harish Patil, dev@dpdk.org; +Cc: Dept-Eng DPDK Dev, Thomas Monjalon
In-Reply-To: <D47420A6.C0178%Harish.Patil@cavium.com>

On 12/12/2016 5:47 PM, Harish Patil wrote:
> 
>> On 12/3/2016 2:43 AM, Harish Patil wrote:
>>> Set max_vfs to 0 since it is relevant only to SR-IOV PF
>>> which is not supported yet.
>>>
>>> Fixes: 2ea6f76a ("qede: add core driver")
>>>
>>> Signed-off-by: Harish Patil <harish.patil@qlogic.com>
>>
>> Can you please update patch title to indicate what has been fixed
>> instead of what has been done in the patch.
> 
> Can you please clarify? The change in the patch is to set max_vfs=0.
> So that’s why the title - "fix maximum VF count to 0"

Let me try, if I can :)

I can see what patch does, and I got the reasoning behind.

Previously driver was reporting as it was supporting SR-IOV with DPDK
PF, right? But it was wrong and you are fixing it.

How you fix is by setting max_vfs=0, but that is the technical detail of
the fix.

What you are trying to fix is not setting a variable to a specific
value, what you are trying to fix is SR-IOV support.

I hope I can make it more clear.

> 
>>
>>
>> btw, while checking feature list, I have seen qede_vf supports SR-IOV,
>> is that correct?
> 
> Yes. The supported combination for SR-IOV is VF driver (qede PMD) with PF
> driver (qede linux driver).

So you are using SR-IOV feature set in VF driver, as meaning VF driver
support exists. I don't know what SR-IOV feature mean for VF drivers.
Some other VF drivers not has this feature flag set.

CC'ed Thomas for help, if this is the intention of the feature flag, it
is OK.

> We don’t have support for SR-IOV PF driver yet. When SR-IOV PF driver is
> supported then max_vfs shall return the actual max VFs, but for now it
> should return max_vfs=0. Hope it is clear.
> 
>>
>>> ---
>>>  drivers/net/qede/qede_ethdev.c | 5 +----
>>>  1 file changed, 1 insertion(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/net/qede/qede_ethdev.c
>>> b/drivers/net/qede/qede_ethdev.c
>>> index ee8fb43..10abb8b 100644
>>> --- a/drivers/net/qede/qede_ethdev.c
>>> +++ b/drivers/net/qede/qede_ethdev.c
>>> @@ -976,10 +976,7 @@ static int qede_dev_configure(struct rte_eth_dev
>>> *eth_dev)
>>>  	dev_info->max_rx_queues = (uint16_t)QEDE_MAX_RSS_CNT(qdev);
>>>  	dev_info->max_tx_queues = dev_info->max_rx_queues;
>>>  	dev_info->max_mac_addrs = qdev->dev_info.num_mac_addrs;
>>> -	if (IS_VF(edev))
>>> -		dev_info->max_vfs = 0;
>>> -	else
>>> -		dev_info->max_vfs = (uint16_t)NUM_OF_VFS(&qdev->edev);
>>> +	dev_info->max_vfs = 0;
>>>  	dev_info->reta_size = ECORE_RSS_IND_TABLE_SIZE;
>>>  	dev_info->hash_key_size = ECORE_RSS_KEY_SIZE * sizeof(uint32_t);
>>>  	dev_info->flow_type_rss_offloads = (uint64_t)QEDE_RSS_OFFLOAD_ALL;
>>>
>>
>>
> 
> 

^ permalink raw reply

* Re: [RFC PATCH] eventdev: add buffered enqueue and flush APIs
From: Eads, Gage @ 2016-12-12 17:56 UTC (permalink / raw)
  To: Jerin Jacob
  Cc: dev@dpdk.org, Richardson, Bruce, Van Haaren, Harry,
	hemant.agrawal@nxp.com
In-Reply-To: <20161208044139.GA24793@svelivela-lt.caveonetworks.com>



>  -----Original Message-----
>  From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
>  Sent: Wednesday, December 7, 2016 10:42 PM
>  To: Eads, Gage <gage.eads@intel.com>
>  Cc: dev@dpdk.org; Richardson, Bruce <bruce.richardson@intel.com>; Van
>  Haaren, Harry <harry.van.haaren@intel.com>; hemant.agrawal@nxp.com
>  Subject: Re: [RFC PATCH] eventdev: add buffered enqueue and flush APIs
>  
>  On Mon, Dec 05, 2016 at 11:30:46PM +0000, Eads, Gage wrote:
>  >
>  > > On Dec 3, 2016, at 5:18 AM, Jerin Jacob
>  <jerin.jacob@caviumnetworks.com> wrote:
>  > >
>  > >> On Fri, Dec 02, 2016 at 01:45:56PM -0600, Gage Eads wrote:
>  > >> This commit adds buffered enqueue functionality to the eventdev API.
>  > >> It is conceptually similar to the ethdev API's tx buffering,
>  > >> however with a smaller API surface and no dropping of events.
>  > >
>  > > Hello Gage,
>  > > Different implementation may have different strategies to hold the buffers.
>  >
>  > A benefit of inlining the buffering logic in the header is that we avoid the
>  overhead of entering the PMD for what is a fairly simple operation (common
>  case: add event to an array, increment counter). If we make this
>  implementation-defined (i.e. use PMD callbacks), we lose that benefit.
>  In general, I agree from the system perspective. But, few general issues with
>  eventdev integration part,
>  
>  1) What if the burst has ATOMIC flows and if we are NOT en-queuing to the
>  implementation then other event ports won't get the packets from the same
>  ATOMIC tag ? BAD. Right?

I'm not sure what scenario you're describing here. The buffered (as implemented in my patch) and non-buffered enqueue operations are functionally the same (as long as the buffer is flushed), the difference lies in when the events are moved from the application level to the PMD.

>  2) At least, In our HW implementation, The event buffer strategy is more like, if
>  you enqueue to HW then ONLY you get the events from dequeue provided if op
>  == RTE_EVENT_OP_FORWARD.So it will create deadlock.i.e application cannot
>  hold the events with RTE_EVENT_OP_FORWARD

If I'm reading this correctly, you're concerned that buffered events can result in deadlock if they're not flushed. Whether the buffering is done in the app itself, inline in the API, or in the PMDs, not flushing the buffer is an application bug. E.g. the app could be fixed by flushing its enqueue buffer after processing every burst dequeued event set, or only if dequeue returns 0 events.

>  3) So considering the above case there is nothing like flush for us
>  4) In real high throughput benchmark case, we will get the packets at the rate
>  of max burst and then we always needs to memcpy before we flush.
>  Otherwise there will be ordering issue as burst can get us the packet from
>  different flows(unlike polling mode)

I take it you're referring to the memcpy in the patch, and not an additional memcpy? At any rate, I'm hoping that SIMD instructions can optimize the 16B event copy.

>  
>  >
>  > > and some does not need to hold the buffers if it is DDR backed.
>  >
>  > Though DDR-backed hardware doesn't need to buffer in software, doing so
>  would reduce the software overhead of enqueueing. Compared to N individual
>  calls to enqueue, buffering N events then calling enqueue burst once can
>  benefit from amortized (or parallelized) PMD-specific bookkeeping and error-
>  checking across the set of events, and will definitely benefit from the amortized
>  function call overhead and better I-cache behavior. (Essentially this is VPP from
>  the fd.io project.) This should result in higher overall event throughout
>  (agnostic of the underlying device).
>  
>  See above. I am not against burst processing in "application".
>  The flush does not make sense for us in HW perspective and it is costly for us if
>  we trying generalize it.
>  

Besides the data copy that buffering requires, are there additional costs from your perspective?

>  >
>  > I'm skeptical that other buffering strategies would emerge, but I can only
>  speculate on Cavium/NXP/etc. NPU software.
>  i>
>  > > IHMO, This may not be the candidate for common code. I guess you can
>  > > move this to driver side and abstract under SW driver's enqueue_burst.
>  > >
>  >
>  > I don't think that will work without adding a flush API, otherwise we could
>  have indefinitely buffered events. I see three ways forward:
>  
>  I agree. More portable way is to move the "flush" to the implementation and
>  "flush"
>  whenever it makes sense to PMD.
>  
>  >
>  > - The proposed approach
>  > - Add the proposed functions but make them implementation-specific.
>  > - Require the application to write its own buffering logic (i.e. no
>  > API change)
>  
>  I think, If the additional function call overhead cost is too much for SW
>  implementation then we can think of implementation-specific API or custom
>  application flow based on SW driver.
>  
>  But I am not fan of that(but tempted do now a days), If we take that route, we
>  have truckload of custom implementation specific API and now we try to hide
>  all black magic under enqueue/dequeue to make it portable at some expense.

Agreed, it's not worth special-casing the API with this relatively minor addition.

Thanks,
Gage

^ permalink raw reply

* [PATCH] vhost: Introduce vhost-user's REPLY_ACK feature
From: Maxime Coquelin @ 2016-12-12 17:54 UTC (permalink / raw)
  To: yuanhan.liu, dev; +Cc: Maxime Coquelin

REPLY_ACK features provide a generic way for QEMU to ensure both
completion and success of a request.

As described in vhost-user spec in QEMU repository, QEMU sets
VHOST_USER_NEED_REPLY flag (bit 3) when expecting a reply_ack from
the backend. Backend must reply with 0 for success or non-zero
otherwise when flag is set.

Currently, only VHOST_USER_SET_MEM_TABLE request implements reply_ack,
in order to synchronize mapping updates.

This patch enables REPLY_ACK feature generally, but only checks error
code for VHOST_USER_SET_MEM_TABLE.

Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
---
Hi,

The intend of this patch is not to fix a known issue, but it is
nice to have this feature, and it will be used by upcoming MTU
feature if it remains in its current form.

Thanks,
Maxime

 lib/librte_vhost/vhost_user.c | 11 ++++++++++-
 lib/librte_vhost/vhost_user.h |  5 ++++-
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/lib/librte_vhost/vhost_user.c b/lib/librte_vhost/vhost_user.c
index 6b83c15..9ce80cb 100644
--- a/lib/librte_vhost/vhost_user.c
+++ b/lib/librte_vhost/vhost_user.c
@@ -903,6 +903,7 @@ send_vhost_message(int sockfd, struct VhostUserMsg *msg)
 		return 0;
 
 	msg->flags &= ~VHOST_USER_VERSION_MASK;
+	msg->flags &= ~VHOST_USER_NEED_REPLY;
 	msg->flags |= VHOST_USER_VERSION;
 	msg->flags |= VHOST_USER_REPLY_MASK;
 
@@ -938,6 +939,7 @@ vhost_user_msg_handler(int vid, int fd)
 		return -1;
 	}
 
+	ret = 0;
 	RTE_LOG(INFO, VHOST_CONFIG, "read message %s\n",
 		vhost_message_str[msg.request]);
 	switch (msg.request) {
@@ -967,7 +969,7 @@ vhost_user_msg_handler(int vid, int fd)
 		break;
 
 	case VHOST_USER_SET_MEM_TABLE:
-		vhost_user_set_mem_table(dev, &msg);
+		ret = vhost_user_set_mem_table(dev, &msg);
 		break;
 
 	case VHOST_USER_SET_LOG_BASE:
@@ -1025,9 +1027,16 @@ vhost_user_msg_handler(int vid, int fd)
 		break;
 
 	default:
+		ret = -1;
 		break;
 
 	}
 
+	if (msg.flags & VHOST_USER_NEED_REPLY) {
+		msg.payload.u64 = !!ret;
+		msg.size = sizeof(msg.payload.u64);
+		send_vhost_message(fd, &msg);
+	}
+
 	return 0;
 }
diff --git a/lib/librte_vhost/vhost_user.h b/lib/librte_vhost/vhost_user.h
index ba78d32..179e441 100644
--- a/lib/librte_vhost/vhost_user.h
+++ b/lib/librte_vhost/vhost_user.h
@@ -46,10 +46,12 @@
 #define VHOST_USER_PROTOCOL_F_MQ	0
 #define VHOST_USER_PROTOCOL_F_LOG_SHMFD	1
 #define VHOST_USER_PROTOCOL_F_RARP	2
+#define VHOST_USER_PROTOCOL_F_REPLY_ACK	3
 
 #define VHOST_USER_PROTOCOL_FEATURES	((1ULL << VHOST_USER_PROTOCOL_F_MQ) | \
 					 (1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD) |\
-					 (1ULL << VHOST_USER_PROTOCOL_F_RARP))
+					 (1ULL << VHOST_USER_PROTOCOL_F_RARP) | \
+					 (1ULL << VHOST_USER_PROTOCOL_F_REPLY_ACK))
 
 typedef enum VhostUserRequest {
 	VHOST_USER_NONE = 0,
@@ -98,6 +100,7 @@ typedef struct VhostUserMsg {
 
 #define VHOST_USER_VERSION_MASK     0x3
 #define VHOST_USER_REPLY_MASK       (0x1 << 2)
+#define VHOST_USER_NEED_REPLY		(0x1 << 3)
 	uint32_t flags;
 	uint32_t size; /* the following payload size */
 	union {
-- 
2.9.3

^ permalink raw reply related

* Re: [PATCH 2/7] net/qede: refactor filtering code
From: Ferruh Yigit @ 2016-12-12 17:53 UTC (permalink / raw)
  To: Harish Patil, dev@dpdk.org; +Cc: Dept-Eng DPDK Dev
In-Reply-To: <D4741EDB.C012D%Harish.Patil@cavium.com>

On 12/12/2016 5:36 PM, Harish Patil wrote:
> 
>> On 12/3/2016 2:43 AM, Harish Patil wrote:
>>> The filter_config in qed_eth_ops_pass is a wrapper call driving all the
>>> filtering configuration. This requires defining multiple structures and
>>> passing different function arguments for each filter type which is
>>> unnecessary. So as part of this refactoring we remove filter_config from
>>> qed_eth_ops_pass and invoke base apis directly. Another change is to
>>> use a singly list for unicast/multicast macs and thereby prevent
>>> duplicate
>>
>> singly linked list?
> 
> Yes. Two lists to track unicast and multicast mac entries:
> +       SLIST_HEAD(mc_list_head, qede_mcast_entry) mc_list_head;
> 
> +       SLIST_HEAD(uc_list_head, qede_ucast_entry) uc_list_head;
> 
> 
> 
>>
>>> entries.
>>>
>>> This change is primarily intended to support future tunneling support
>>> which makes use of existing L2 filtering/classifications.
>>>
>>> Fixes: 2ea6f76a ("qede: add core driver")
>>
>> What is fixed in this patch, isn't it a refactor?
> 
> The fix part is to make use of the newly added lists and prevent duplicate
> mac filters.
> Before that there were no checks. Other than that its refactoring to
> mainly invoke direct base APIs.

So this is not fixing any defect in driver, so I believe Fixes tag can
be removed. This tag is mainly useful to pick commits for stable trees.

> 
>>
>> btw, all Fixes formats are wrong in the patchset, can you please use the
>> git alias provided:
>> http://dpdk.org/doc/guides/contributing/patches.html#commit-messages-body
>>
>>>
>>> Signed-off-by: Harish Patil <harish.patil@qlogic.com>
>>> ---
>> <...>
>>
> 
> 

^ permalink raw reply

* Re: [PATCH 1/7] net/qede: reduce noise in debug logs
From: Ferruh Yigit @ 2016-12-12 17:50 UTC (permalink / raw)
  To: Harish Patil, dev@dpdk.org; +Cc: Dept-Eng DPDK Dev, Mody, Rasesh
In-Reply-To: <D474163F.BFFD0%Harish.Patil@cavium.com>

On 12/12/2016 5:15 PM, Harish Patil wrote:
> Hi Ferruh,
> 
>> On 12/3/2016 2:43 AM, Harish Patil wrote:
>>> From: Rasesh Mody <Rasesh.Mody@cavium.com>
>>>
>>> Replace CONFIG_RTE_LIBRTE_QEDE_DEBUG_DRIVER with
>>> CONFIG_RTE_LIBRTE_QEDE_DEBUG_VAL which is a 32-bit bitmapped value
>>> where each bit represent a particular submodule to debug. Also move
>>> notice messages under CONFIG_RTE_LIBRTE_QEDE_DEBUG_INFO.
>>>
>>> Signed-off-by: Harish Patil <harish.patil@qlogic.com>
>>> Signed-off-by: Rasesh Mody <Rasesh.Mody@cavium.com>
>>> ---
>>>  config/common_base             |  2 +-
>>>  doc/guides/nics/qede.rst       |  4 ++--
>>>  drivers/net/qede/qede_ethdev.c |  4 ++--
>>>  drivers/net/qede/qede_logs.h   | 21 +++++----------------
>>>  4 files changed, 10 insertions(+), 21 deletions(-)
>>>
>>> diff --git a/config/common_base b/config/common_base
>>> index 4bff83a..2ffd557 100644
>>> --- a/config/common_base
>>> +++ b/config/common_base
>>> @@ -320,7 +320,7 @@ CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1=n
>>>  CONFIG_RTE_LIBRTE_QEDE_PMD=y
>>>  CONFIG_RTE_LIBRTE_QEDE_DEBUG_INIT=n
>>>  CONFIG_RTE_LIBRTE_QEDE_DEBUG_INFO=n
>>> -CONFIG_RTE_LIBRTE_QEDE_DEBUG_DRIVER=n
>>> +CONFIG_RTE_LIBRTE_QEDE_DEBUG_VAL=0
>>>  CONFIG_RTE_LIBRTE_QEDE_DEBUG_TX=n
>>>  CONFIG_RTE_LIBRTE_QEDE_DEBUG_RX=n
>>>  #Provides abs path/name of the firmware file.
>>> diff --git a/doc/guides/nics/qede.rst b/doc/guides/nics/qede.rst
>>> index d22ecdd..ddf4248 100644
>>> --- a/doc/guides/nics/qede.rst
>>> +++ b/doc/guides/nics/qede.rst
>>> @@ -103,9 +103,9 @@ enabling debugging options may affect system
>>> performance.
>>>  
>>>    Toggle display of generic debugging messages.
>>>  
>>> -- ``CONFIG_RTE_LIBRTE_QEDE_DEBUG_DRIVER`` (default **n**)
>>> +- ``CONFIG_RTE_LIBRTE_QEDE_DEBUG_VAL`` (default **0**)
>>
>> Does it make sense to document how DEBUG_VAL used?
>>
>> Also commit log says bitmapped value to enable/disable a particular
>> submodule, you may want to document here which value enable/disable
>> which submodule.
>>
>>>  
>>> -  Toggle display of ecore related messages.
>>> +  Control driver debug verbosity using 32-bit bitmap flags.
>>>  
>>>  - ``CONFIG_RTE_LIBRTE_QEDE_DEBUG_TX`` (default **n**)
>>>  
> 
> Not really, I think that would be too much. But if you think it really
> helps then perhaps yes we can document.
> Otherwise it is just for internal debugging.

As a user of your driver, how can I know how to enable / disable a
module log?
I know VAL enables / disables them, but I don't know what modules exists
and what values are required.

If this is just for internal debugging and user not need to configure
this one, does it needs to be a config option in configuration file?

> 
> 
>>
>> <...>
>>
>>> diff --git a/drivers/net/qede/qede_logs.h b/drivers/net/qede/qede_logs.h
>>> index 45c4af0..08fdf04 100644
>>> --- a/drivers/net/qede/qede_logs.h
>>> +++ b/drivers/net/qede/qede_logs.h
>>> @@ -16,15 +16,18 @@
>>>  		(p_dev)->name ? (p_dev)->name : "", \
>>>  		##__VA_ARGS__)
>>>  
>>> +#ifdef RTE_LIBRTE_QEDE_DEBUG_INFO
>>
>> Is "_INFO" carries any meaning in this config option, why not just
>> RTE_LIBRTE_QEDE_DEBUG?
> 
> INFO is used to mean just informational type of messages.
> If you think it doesn’t make sense then I can rename it.

I don't have a strong opinion, I think that _INFO is not adding value
unless you have different config options per each level like _VERBOSE,
_INFO, _NOTICE. But if you believe your users will benefit from it, it
is your call.

> 
>>
>>>  #define DP_NOTICE(p_dev, is_assert, fmt, ...) \
>>>  	rte_log(RTE_LOG_NOTICE, RTE_LOGTYPE_PMD,\
>>>  		"[QEDE PMD: (%s)]%s:" fmt, \
>>>  		(p_dev)->name ? (p_dev)->name : "", \
>>>  		 __func__, \
>>>  		##__VA_ARGS__)
>>> +#else
>>> +#define DP_NOTICE(p_dev, fmt, ...) do { } while (0)
>>> +#endif
>>>  
>>>  #ifdef RTE_LIBRTE_QEDE_DEBUG_INFO
>>> -
>>>  #define DP_INFO(p_dev, fmt, ...) \
>>>  	rte_log(RTE_LOG_INFO, RTE_LOGTYPE_PMD, \
>>>  		"[%s:%d(%s)]" fmt, \
>>> @@ -33,10 +36,8 @@
>>>  		##__VA_ARGS__)
>>>  #else
>>>  #define DP_INFO(p_dev, fmt, ...) do { } while (0)
>>> -
>>>  #endif
>>>  
>>> -#ifdef RTE_LIBRTE_QEDE_DEBUG_DRIVER
>>
>> Are you sure you want to enable DP_VERBOSE, I guess most verbose log
>> macro, by default? Perhaps may want to control it via
>> RTE_LIBRTE_QEDE_DEBUG_INFO?
> 
> DP_VERBOSE is enabled but it has a check:
>  if ((p_dev)->dp_module & module)
> which controls what to print.
> Here dp_module is controlled by CONFIG_RTE_LIBRTE_QEDE_DEBUG_VAL flag.
> Hope it is clear.

Clear thanks,

I guess right now:
DEBUG_VAL: enables verbose debug for selected module(s)
DEBUG_INFO: Enables NOTICE and INFO level for ? (all modules?)
ERR level is always enabled

Again it is your call, but I think CONFIG_RTE_LIBRTE_QEDE_DEBUG can be
used to enable/disable all debugs, and when enabled QEDE_DEBUG_VAL can
select which modules to enable verbose debug ...

>>
>>>  #define DP_VERBOSE(p_dev, module, fmt, ...) \
>>>  do { \
>>>  	if ((p_dev)->dp_module & module) \
>>> @@ -46,9 +47,7 @@
>>>  		      (p_dev)->name ? (p_dev)->name : "", \
>>>  		      ##__VA_ARGS__); \
>>>  } while (0)
>>> -#else
>>> -#define DP_VERBOSE(p_dev, fmt, ...) do { } while (0)
>>> -#endif
>>> +
>>>  
>> <...>
>>
>>
> 

^ permalink raw reply

* Re: [PATCH 6/7] net/qede: fix maximum VF count to 0
From: Harish Patil @ 2016-12-12 17:47 UTC (permalink / raw)
  To: Ferruh Yigit, Harish Patil, dev@dpdk.org; +Cc: Dept-Eng DPDK Dev
In-Reply-To: <f7ccf786-4f58-5e1e-3cd2-28725bb4e8b5@intel.com>


>On 12/3/2016 2:43 AM, Harish Patil wrote:
>> Set max_vfs to 0 since it is relevant only to SR-IOV PF
>> which is not supported yet.
>> 
>> Fixes: 2ea6f76a ("qede: add core driver")
>> 
>> Signed-off-by: Harish Patil <harish.patil@qlogic.com>
>
>Can you please update patch title to indicate what has been fixed
>instead of what has been done in the patch.

Can you please clarify? The change in the patch is to set max_vfs=0.
So that’s why the title - "fix maximum VF count to 0"

>
>
>btw, while checking feature list, I have seen qede_vf supports SR-IOV,
>is that correct?

Yes. The supported combination for SR-IOV is VF driver (qede PMD) with PF
driver (qede linux driver).
We don’t have support for SR-IOV PF driver yet. When SR-IOV PF driver is
supported then max_vfs shall return the actual max VFs, but for now it
should return max_vfs=0. Hope it is clear.

>
>> ---
>>  drivers/net/qede/qede_ethdev.c | 5 +----
>>  1 file changed, 1 insertion(+), 4 deletions(-)
>> 
>> diff --git a/drivers/net/qede/qede_ethdev.c
>>b/drivers/net/qede/qede_ethdev.c
>> index ee8fb43..10abb8b 100644
>> --- a/drivers/net/qede/qede_ethdev.c
>> +++ b/drivers/net/qede/qede_ethdev.c
>> @@ -976,10 +976,7 @@ static int qede_dev_configure(struct rte_eth_dev
>>*eth_dev)
>>  	dev_info->max_rx_queues = (uint16_t)QEDE_MAX_RSS_CNT(qdev);
>>  	dev_info->max_tx_queues = dev_info->max_rx_queues;
>>  	dev_info->max_mac_addrs = qdev->dev_info.num_mac_addrs;
>> -	if (IS_VF(edev))
>> -		dev_info->max_vfs = 0;
>> -	else
>> -		dev_info->max_vfs = (uint16_t)NUM_OF_VFS(&qdev->edev);
>> +	dev_info->max_vfs = 0;
>>  	dev_info->reta_size = ECORE_RSS_IND_TABLE_SIZE;
>>  	dev_info->hash_key_size = ECORE_RSS_KEY_SIZE * sizeof(uint32_t);
>>  	dev_info->flow_type_rss_offloads = (uint64_t)QEDE_RSS_OFFLOAD_ALL;
>> 
>
>



^ permalink raw reply

* Re: [PATCH 2/7] net/qede: refactor filtering code
From: Harish Patil @ 2016-12-12 17:36 UTC (permalink / raw)
  To: Ferruh Yigit, Harish Patil, dev@dpdk.org; +Cc: Dept-Eng DPDK Dev
In-Reply-To: <f114b64c-0a63-736a-98a6-b8cae747f21a@intel.com>


>On 12/3/2016 2:43 AM, Harish Patil wrote:
>> The filter_config in qed_eth_ops_pass is a wrapper call driving all the
>> filtering configuration. This requires defining multiple structures and
>> passing different function arguments for each filter type which is
>> unnecessary. So as part of this refactoring we remove filter_config from
>> qed_eth_ops_pass and invoke base apis directly. Another change is to
>> use a singly list for unicast/multicast macs and thereby prevent
>>duplicate
>
>singly linked list?

Yes. Two lists to track unicast and multicast mac entries:
+       SLIST_HEAD(mc_list_head, qede_mcast_entry) mc_list_head;

+       SLIST_HEAD(uc_list_head, qede_ucast_entry) uc_list_head;



>
>> entries.
>> 
>> This change is primarily intended to support future tunneling support
>> which makes use of existing L2 filtering/classifications.
>> 
>> Fixes: 2ea6f76a ("qede: add core driver")
>
>What is fixed in this patch, isn't it a refactor?

The fix part is to make use of the newly added lists and prevent duplicate
mac filters.
Before that there were no checks. Other than that its refactoring to
mainly invoke direct base APIs.

>
>btw, all Fixes formats are wrong in the patchset, can you please use the
>git alias provided:
>http://dpdk.org/doc/guides/contributing/patches.html#commit-messages-body
>
>> 
>> Signed-off-by: Harish Patil <harish.patil@qlogic.com>
>> ---
><...>
>



^ permalink raw reply

* Re: [PATCH v12 0/6] add Tx preparation
From: Ananyev, Konstantin @ 2016-12-12 17:29 UTC (permalink / raw)
  To: Yong Wang, Yigit, Ferruh, Thomas Monjalon
  Cc: Harish Patil, dev@dpdk.org, Rahul Lakkireddy, Stephen Hurd,
	Jan Medala, Jakub Palider, John Daley, Adrien Mazarguil,
	Alejandro Lucero, Rasesh Mody, Jacob, Jerin, Yuanhan Liu,
	Kulasek, TomaszX, olivier.matz@6wind.com
In-Reply-To: <BY2PR05MB2359405F47AFEB13EE708D91AF840@BY2PR05MB2359.namprd05.prod.outlook.com>



> > > This means vmxnet3 PMD also should be updated, right?
> >
> > Yes, that's right.
> >
> > >Should that update
> > > be part of tx_prep patchset? Or separate patch?
> >
> > Another question I suppose is who will do the actual patch for vmxnet3.
> > Yong, are you ok to do the patch for vmxnet3, or prefer us to do that?
> > Please note, that in both cases will need your help in testing/reviewing it.
> > Konstantin
> 
> It will be great if you can put together a patch as part of the entire patchset on tx_prep() for vmxnet3 and I will definitely help review
> it.

Ok. 

> 
> Regarding testing, I can definitely help but I don't have a testing harness to cover the entire matrix (different ESX version, different
> vmxnet3 device version, VM-VM, VM-physical over different uplinks, etc.) so it will be limited.  Related to this, I have the impression
> that Intel has some existing coverage for vmxnet3 as well as other NICs.  Do we know if that will cover this use case as well?

I'll ask our validation team, but I don't know off-hand what coverage for vmxnet3 we have.
Konstantin


> 
> > >
> > > >>>
> > > >>
> > > >>>>> This is for any TX offload for which the upper layer SW would have
> > > >>
> > > >>>>> to modify the contents of the packet.
> > > >>
> > > >>>>> Though as I can see for qede neither PKT_TX_IP_CKSUM or
> > > >>
> > > >>>> PKT_TX_TCP_CKSUM
> > > >>
> > > >>>>> exhibits any extra requirements for the user.
> > > >>
> > > >>>>> Is that correct?
> > > >>
> > > >>
> > > >


^ permalink raw reply

* Re: [PATCH 1/7] net/qede: reduce noise in debug logs
From: Harish Patil @ 2016-12-12 17:15 UTC (permalink / raw)
  To: Ferruh Yigit, Harish Patil, dev@dpdk.org; +Cc: Dept-Eng DPDK Dev, Mody, Rasesh
In-Reply-To: <91ac9846-530c-2dd3-4bd6-2c3b9143405b@intel.com>

Hi Ferruh,

>On 12/3/2016 2:43 AM, Harish Patil wrote:
>> From: Rasesh Mody <Rasesh.Mody@cavium.com>
>> 
>> Replace CONFIG_RTE_LIBRTE_QEDE_DEBUG_DRIVER with
>> CONFIG_RTE_LIBRTE_QEDE_DEBUG_VAL which is a 32-bit bitmapped value
>> where each bit represent a particular submodule to debug. Also move
>> notice messages under CONFIG_RTE_LIBRTE_QEDE_DEBUG_INFO.
>> 
>> Signed-off-by: Harish Patil <harish.patil@qlogic.com>
>> Signed-off-by: Rasesh Mody <Rasesh.Mody@cavium.com>
>> ---
>>  config/common_base             |  2 +-
>>  doc/guides/nics/qede.rst       |  4 ++--
>>  drivers/net/qede/qede_ethdev.c |  4 ++--
>>  drivers/net/qede/qede_logs.h   | 21 +++++----------------
>>  4 files changed, 10 insertions(+), 21 deletions(-)
>> 
>> diff --git a/config/common_base b/config/common_base
>> index 4bff83a..2ffd557 100644
>> --- a/config/common_base
>> +++ b/config/common_base
>> @@ -320,7 +320,7 @@ CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1=n
>>  CONFIG_RTE_LIBRTE_QEDE_PMD=y
>>  CONFIG_RTE_LIBRTE_QEDE_DEBUG_INIT=n
>>  CONFIG_RTE_LIBRTE_QEDE_DEBUG_INFO=n
>> -CONFIG_RTE_LIBRTE_QEDE_DEBUG_DRIVER=n
>> +CONFIG_RTE_LIBRTE_QEDE_DEBUG_VAL=0
>>  CONFIG_RTE_LIBRTE_QEDE_DEBUG_TX=n
>>  CONFIG_RTE_LIBRTE_QEDE_DEBUG_RX=n
>>  #Provides abs path/name of the firmware file.
>> diff --git a/doc/guides/nics/qede.rst b/doc/guides/nics/qede.rst
>> index d22ecdd..ddf4248 100644
>> --- a/doc/guides/nics/qede.rst
>> +++ b/doc/guides/nics/qede.rst
>> @@ -103,9 +103,9 @@ enabling debugging options may affect system
>>performance.
>>  
>>    Toggle display of generic debugging messages.
>>  
>> -- ``CONFIG_RTE_LIBRTE_QEDE_DEBUG_DRIVER`` (default **n**)
>> +- ``CONFIG_RTE_LIBRTE_QEDE_DEBUG_VAL`` (default **0**)
>
>Does it make sense to document how DEBUG_VAL used?
>
>Also commit log says bitmapped value to enable/disable a particular
>submodule, you may want to document here which value enable/disable
>which submodule.
>
>>  
>> -  Toggle display of ecore related messages.
>> +  Control driver debug verbosity using 32-bit bitmap flags.
>>  
>>  - ``CONFIG_RTE_LIBRTE_QEDE_DEBUG_TX`` (default **n**)
>>  

Not really, I think that would be too much. But if you think it really
helps then perhaps yes we can document.
Otherwise it is just for internal debugging.


>
><...>
>
>> diff --git a/drivers/net/qede/qede_logs.h b/drivers/net/qede/qede_logs.h
>> index 45c4af0..08fdf04 100644
>> --- a/drivers/net/qede/qede_logs.h
>> +++ b/drivers/net/qede/qede_logs.h
>> @@ -16,15 +16,18 @@
>>  		(p_dev)->name ? (p_dev)->name : "", \
>>  		##__VA_ARGS__)
>>  
>> +#ifdef RTE_LIBRTE_QEDE_DEBUG_INFO
>
>Is "_INFO" carries any meaning in this config option, why not just
>RTE_LIBRTE_QEDE_DEBUG?

INFO is used to mean just informational type of messages.
If you think it doesn’t make sense then I can rename it.

>
>>  #define DP_NOTICE(p_dev, is_assert, fmt, ...) \
>>  	rte_log(RTE_LOG_NOTICE, RTE_LOGTYPE_PMD,\
>>  		"[QEDE PMD: (%s)]%s:" fmt, \
>>  		(p_dev)->name ? (p_dev)->name : "", \
>>  		 __func__, \
>>  		##__VA_ARGS__)
>> +#else
>> +#define DP_NOTICE(p_dev, fmt, ...) do { } while (0)
>> +#endif
>>  
>>  #ifdef RTE_LIBRTE_QEDE_DEBUG_INFO
>> -
>>  #define DP_INFO(p_dev, fmt, ...) \
>>  	rte_log(RTE_LOG_INFO, RTE_LOGTYPE_PMD, \
>>  		"[%s:%d(%s)]" fmt, \
>> @@ -33,10 +36,8 @@
>>  		##__VA_ARGS__)
>>  #else
>>  #define DP_INFO(p_dev, fmt, ...) do { } while (0)
>> -
>>  #endif
>>  
>> -#ifdef RTE_LIBRTE_QEDE_DEBUG_DRIVER
>
>Are you sure you want to enable DP_VERBOSE, I guess most verbose log
>macro, by default? Perhaps may want to control it via
>RTE_LIBRTE_QEDE_DEBUG_INFO?

DP_VERBOSE is enabled but it has a check:
 if ((p_dev)->dp_module & module)
which controls what to print.
Here dp_module is controlled by CONFIG_RTE_LIBRTE_QEDE_DEBUG_VAL flag.
Hope it is clear.
>
>>  #define DP_VERBOSE(p_dev, module, fmt, ...) \
>>  do { \
>>  	if ((p_dev)->dp_module & module) \
>> @@ -46,9 +47,7 @@
>>  		      (p_dev)->name ? (p_dev)->name : "", \
>>  		      ##__VA_ARGS__); \
>>  } while (0)
>> -#else
>> -#define DP_VERBOSE(p_dev, fmt, ...) do { } while (0)
>> -#endif
>> +
>>  
><...>
>
>


^ permalink raw reply

* Re: [PATCH] vhost: allow for many vhost user ports
From: Jan Wickbom @ 2016-12-12 16:55 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev@dpdk.org, Patrik Andersson R
In-Reply-To: <20161208055041.GO31182@yliu-dev.sh.intel.com>



> -----Original Message-----
> From: Yuanhan Liu [mailto:yuanhan.liu@linux.intel.com]
> Sent: den 8 december 2016 06:51
> To: Jan Wickbom <jan.wickbom@ericsson.com>
> Cc: dev@dpdk.org; Patrik Andersson R <patrik.r.andersson@ericsson.com>
> Subject: Re: [PATCH] vhost: allow for many vhost user ports
> 
> On Wed, Dec 07, 2016 at 01:23:48PM +0000, Jan Wickbom wrote:
> > > On Thu, Dec 01, 2016 at 04:26:50PM +0100, Jan Wickbom wrote:
> > > >  static int
> > > > -fdset_fill(fd_set *rfset, fd_set *wfset, struct fdset *pfdset)
> > > > +fdset_fill(struct pollfd *rwfds, struct fdset *pfdset)
> ...
> > > > +		rwfds[i].fd = pfdentry->fd;
> > > > +		rwfds[i].events = pfdentry->rcb ? POLLIN : 0;
> > > > +		rwfds[i].events |= pfdentry->wcb ? POLLOUT :
> > > 0;
> > >
> > > Another thing is we don't have to re-init this rwfds array again
> > > and again. Instead, we could
> > >
> > > - set it up correctly when fdset_add is invoked: set the fd and
> > >   events.
> > >
> > > - reset revents when it's been handled at fdset_event_dispatch().
> > >
> > > - swap with the last one and shrink the array on fd delete
> > >
> > > Could you make a follow up patch for that?
> >
> > I don't see how that could easily be done. The loop index, i, is a direct
> reference between
> > an entry in the rwfds array and an entry in the pfdset array. It should stay
> like that while we are
> > hanging in the poll(). If  an entry in the pfdset array is removed while we
> are hanging in the poll()
> > and we then immediately replaces it with the last entry in the array we will
> end up in trouble if the
> > revent gets set for the "replaced" index. The direct reference is gone.
> > Or am I missing something?
> 
> Yes, we should not shrink the rwfds during the poll, but we could later, at
> the end of the while() loop.

Did something in v3, please have a look.

> 
> Talking about that, you should not invoke fdset_shrink() inside fdset_del(),
> since it could be in the poll stage.

Thanks! Forgot this! Will send a v4

> 
> 	--yliu

^ permalink raw reply

* [PATCH v3] vhost: allow for many vhost user ports
From: Jan Wickbom @ 2016-12-12 16:50 UTC (permalink / raw)
  To: yuanhan.liu; +Cc: dev, patrik.r.andersson, Jan Wickbom
In-Reply-To: <1480606010-6132-1-git-send-email-jan.wickbom@ericsson.com>

Currently select() is used to monitor file descriptors for vhostuser
ports. This limits the number of ports possible to create since the
fd number is used as index in the fd_set and we have seen fds > 1023.
This patch changes select() to poll(). This way we can keep an
packed (pollfd) array for the fds, e.g. as many fds as the size of
the array.

Also see:
http://dpdk.org/ml/archives/dev/2016-April/037024.html

Signed-off-by: Jan Wickbom <jan.wickbom@ericsson.com>
Reported-by: Patrik Andersson <patrik.r.andersson@ericsson.com>
---

v3:
* removed unnecessary include
* removed fdset_fill, made it functionally part of poll loop

v2:
* removed unnecessary casts
* static array replacing allocated memory

 lib/librte_vhost/fd_man.c | 194 +++++++++++++++++++++++++---------------------
 lib/librte_vhost/fd_man.h |   2 +-
 2 files changed, 105 insertions(+), 91 deletions(-)

diff --git a/lib/librte_vhost/fd_man.c b/lib/librte_vhost/fd_man.c
index 2d3eeb7..c360d07 100644
--- a/lib/librte_vhost/fd_man.c
+++ b/lib/librte_vhost/fd_man.c
@@ -35,16 +35,40 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/socket.h>
-#include <sys/select.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <poll.h>
 #include <unistd.h>
+#include <string.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
 
 #include "fd_man.h"
 
+#define FDPOLLERR (POLLERR | POLLHUP | POLLNVAL)
+
+
+static struct pollfd rwfds[MAX_FDS];
+
+/**
+ * Adjusts the highest index populated in the array of fds
+ * @return
+ *   The new size of fdset.
+ */
+static void
+fdset_shrink(struct fdset *pfdset)
+{
+	int idx;
+
+	for (idx = pfdset->num - 1;
+	     idx >= 0 && pfdset->fd[idx].fd == -1;
+	     idx--)
+		;
+
+	pfdset->num = idx + 1;
+}
+
 /**
  * Returns the index in the fdset for a given fd.
  * If fd is -1, it means to search for a free entry.
@@ -56,72 +80,32 @@
 {
 	int i;
 
-	if (pfdset == NULL)
-		return -1;
-
-	for (i = 0; i < MAX_FDS && pfdset->fd[i].fd != fd; i++)
+	for (i = 0; i < pfdset->num && pfdset->fd[i].fd != fd; i++)
 		;
 
-	return i ==  MAX_FDS ? -1 : i;
+	return i == pfdset->num ? -1 : i;
 }
 
 static int
 fdset_find_free_slot(struct fdset *pfdset)
 {
-	return fdset_find_fd(pfdset, -1);
+	if (pfdset->num < MAX_FDS)
+		return pfdset->num;
+	else
+		return fdset_find_fd(pfdset, -1);
 }
 
-static int
-fdset_add_fd(struct fdset  *pfdset, int idx, int fd,
+static void
+fdset_add_fd(struct fdset *pfdset, int idx, int fd,
 	fd_cb rcb, fd_cb wcb, void *dat)
 {
 	struct fdentry *pfdentry;
 
-	if (pfdset == NULL || idx >= MAX_FDS || fd >= FD_SETSIZE)
-		return -1;
-
 	pfdentry = &pfdset->fd[idx];
 	pfdentry->fd = fd;
 	pfdentry->rcb = rcb;
 	pfdentry->wcb = wcb;
 	pfdentry->dat = dat;
-
-	return 0;
-}
-
-/**
- * Fill the read/write fd_set with the fds in the fdset.
- * @return
- *  the maximum fds filled in the read/write fd_set.
- */
-static int
-fdset_fill(fd_set *rfset, fd_set *wfset, struct fdset *pfdset)
-{
-	struct fdentry *pfdentry;
-	int i, maxfds = -1;
-	int num = MAX_FDS;
-
-	if (pfdset == NULL)
-		return -1;
-
-	for (i = 0; i < num; i++) {
-		pfdentry = &pfdset->fd[i];
-		if (pfdentry->fd != -1) {
-			int added = 0;
-			if (pfdentry->rcb && rfset) {
-				FD_SET(pfdentry->fd, rfset);
-				added = 1;
-			}
-			if (pfdentry->wcb && wfset) {
-				FD_SET(pfdentry->fd, wfset);
-				added = 1;
-			}
-			if (added)
-				maxfds = pfdentry->fd < maxfds ?
-					maxfds : pfdentry->fd;
-		}
-	}
-	return maxfds;
 }
 
 void
@@ -132,6 +116,8 @@
 	if (pfdset == NULL)
 		return;
 
+	pthread_mutex_init(&pfdset->fd_mutex, NULL);
+
 	for (i = 0; i < MAX_FDS; i++) {
 		pfdset->fd[i].fd = -1;
 		pfdset->fd[i].dat = NULL;
@@ -152,14 +138,15 @@
 
 	pthread_mutex_lock(&pfdset->fd_mutex);
 
-	/* Find a free slot in the list. */
 	i = fdset_find_free_slot(pfdset);
-	if (i == -1 || fdset_add_fd(pfdset, i, fd, rcb, wcb, dat) < 0) {
+	if (i == -1) {
 		pthread_mutex_unlock(&pfdset->fd_mutex);
 		return -2;
 	}
 
-	pfdset->num++;
+	fdset_add_fd(pfdset, i, fd, rcb, wcb, dat);
+	if (i == pfdset->num)
+		pfdset->num++;
 
 	pthread_mutex_unlock(&pfdset->fd_mutex);
 
@@ -189,7 +176,7 @@
 			pfdset->fd[i].fd = -1;
 			pfdset->fd[i].rcb = pfdset->fd[i].wcb = NULL;
 			pfdset->fd[i].dat = NULL;
-			pfdset->num--;
+			fdset_shrink(pfdset);
 			i = -1;
 		}
 		pthread_mutex_unlock(&pfdset->fd_mutex);
@@ -198,25 +185,26 @@
 	return dat;
 }
 
+
 /**
- *  Unregister the fd at the specified slot from the fdset.
+ *  Moves the fd from last slot to specified slot, including
+ *  corresponding pollfd
  */
 static void
-fdset_del_slot(struct fdset *pfdset, int index)
+fdset_move_last(struct fdset *pfdset, int idx)
 {
-	if (pfdset == NULL || index < 0 || index >= MAX_FDS)
-		return;
-
-	pthread_mutex_lock(&pfdset->fd_mutex);
+	int last_idx = pfdset->num - 1;
 
-	pfdset->fd[index].fd = -1;
-	pfdset->fd[index].rcb = pfdset->fd[index].wcb = NULL;
-	pfdset->fd[index].dat = NULL;
-	pfdset->num--;
+	if (idx < last_idx) {
+		pfdset->fd[idx] = pfdset->fd[last_idx];
+		pfdset->fd[last_idx].fd = -1;
 
-	pthread_mutex_unlock(&pfdset->fd_mutex);
+		rwfds[idx] = rwfds[last_idx];
+		rwfds[last_idx].revents = 0;
+	}
 }
 
+
 /**
  * This functions runs in infinite blocking loop until there is no fd in
  * pfdset. It calls corresponding r/w handler if there is event on the fd.
@@ -229,55 +217,71 @@
 void
 fdset_event_dispatch(struct fdset *pfdset)
 {
-	fd_set rfds, wfds;
-	int i, maxfds;
+	int i;
 	struct fdentry *pfdentry;
-	int num = MAX_FDS;
 	fd_cb rcb, wcb;
 	void *dat;
 	int fd;
 	int remove1, remove2;
-	int ret;
 
 	if (pfdset == NULL)
 		return;
 
-	while (1) {
-		struct timeval tv;
-		tv.tv_sec = 1;
-		tv.tv_usec = 0;
-		FD_ZERO(&rfds);
-		FD_ZERO(&wfds);
-		pthread_mutex_lock(&pfdset->fd_mutex);
-
-		maxfds = fdset_fill(&rfds, &wfds, pfdset);
-
-		pthread_mutex_unlock(&pfdset->fd_mutex);
+	memset(rwfds, 0, sizeof(rwfds));
 
+	while (1) {
 		/*
-		 * When select is blocked, other threads might unregister
+		 * When poll is blocked, other threads might unregister
 		 * listenfds from and register new listenfds into fdset.
-		 * When select returns, the entries for listenfds in the fdset
+		 * When poll returns, the entries for listenfds in the fdset
 		 * might have been updated. It is ok if there is unwanted call
 		 * for new listenfds.
 		 */
-		ret = select(maxfds + 1, &rfds, &wfds, NULL, &tv);
-		if (ret <= 0)
-			continue;
+		poll(rwfds, pfdset->num, 1000 /* millisecs */);
 
-		for (i = 0; i < num; i++) {
-			remove1 = remove2 = 0;
+		for (i = 0; i < pfdset->num; ) {
 			pthread_mutex_lock(&pfdset->fd_mutex);
+
 			pfdentry = &pfdset->fd[i];
 			fd = pfdentry->fd;
+
+			if (fd < 0) {
+				/* Removed during poll */
+
+				fdset_move_last(pfdset, i);
+				fdset_shrink(pfdset);
+
+				pthread_mutex_unlock(&pfdset->fd_mutex);
+
+				continue;
+			}
+
+			if (!rwfds[i].revents) {
+				/* No revents, maybe added during poll */
+
+				rwfds[i].fd = fd;
+				rwfds[i].events = pfdentry->rcb ? POLLIN : 0;
+				rwfds[i].events |= pfdentry->wcb ? POLLOUT : 0;
+				pthread_mutex_unlock(&pfdset->fd_mutex);
+
+				i++;
+				continue;
+			}
+
+			/* Valid fd, and at least one revent ... */
+
+			remove1 = remove2 = 0;
+
 			rcb = pfdentry->rcb;
 			wcb = pfdentry->wcb;
 			dat = pfdentry->dat;
 			pfdentry->busy = 1;
+
 			pthread_mutex_unlock(&pfdset->fd_mutex);
-			if (fd >= 0 && FD_ISSET(fd, &rfds) && rcb)
+
+			if (rcb && rwfds[i].revents & (POLLIN | FDPOLLERR))
 				rcb(fd, dat, &remove1);
-			if (fd >= 0 && FD_ISSET(fd, &wfds) && wcb)
+			if (wcb && rwfds[i].revents & (POLLOUT | FDPOLLERR))
 				wcb(fd, dat, &remove2);
 			pfdentry->busy = 0;
 			/*
@@ -292,8 +296,18 @@
 			 * listen fd in another thread, we couldn't call
 			 * fd_set_del.
 			 */
-			if (remove1 || remove2)
-				fdset_del_slot(pfdset, i);
+			if (remove1 || remove2) {
+				pthread_mutex_lock(&pfdset->fd_mutex);
+
+				fdset_move_last(pfdset, i);
+				fdset_shrink(pfdset);
+
+				pthread_mutex_unlock(&pfdset->fd_mutex);
+
+				continue;
+			}
+
+			i++;
 		}
 	}
 }
diff --git a/lib/librte_vhost/fd_man.h b/lib/librte_vhost/fd_man.h
index bd66ed1..b5ba688 100644
--- a/lib/librte_vhost/fd_man.h
+++ b/lib/librte_vhost/fd_man.h
@@ -51,7 +51,7 @@ struct fdentry {
 struct fdset {
 	struct fdentry fd[MAX_FDS];
 	pthread_mutex_t fd_mutex;
-	int num;	/* current fd number of this fdset */
+	int num;	/* highest index occupied in fd array + 1 */
 };
 
 
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH v3 6/9] examples/ethtool: use ixgbe public function
From: Ferruh Yigit @ 2016-12-12 16:25 UTC (permalink / raw)
  To: Bernard Iremonger, thomas.monjalon, dev
In-Reply-To: <1481550626-14539-7-git-send-email-bernard.iremonger@intel.com>

On 12/12/2016 1:50 PM, Bernard Iremonger wrote:
> Replace rte_eth_dev_set_vf_rxmode with rte_pmd_ixgbe_set_vf_rx_mode.
> 
> Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
> ---
>  examples/ethtool/lib/rte_ethtool.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/examples/ethtool/lib/rte_ethtool.c b/examples/ethtool/lib/rte_ethtool.c
> index a1f91d4..0e539f7 100644
> --- a/examples/ethtool/lib/rte_ethtool.c
> +++ b/examples/ethtool/lib/rte_ethtool.c
> @@ -1,7 +1,7 @@
>  /*-
>   *   BSD LICENSE
>   *
> - *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
> + *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
>   *   All rights reserved.
>   *
>   *   Redistribution and use in source and binary forms, with or without
> @@ -36,6 +36,7 @@
>  #include <rte_version.h>
>  #include <rte_ethdev.h>
>  #include <rte_ether.h>
> +#include <rte_pmd_ixgbe.h>
>  #include "rte_ethtool.h"
>  
>  #define PKTPOOL_SIZE 512
> @@ -354,7 +355,7 @@ rte_ethtool_net_set_rx_mode(uint8_t port_id)
>  
>  	/* Set VF vf_rx_mode, VF unsupport status is discard */
>  	for (vf = 0; vf < num_vfs; vf++)
> -		rte_eth_dev_set_vf_rxmode(port_id, vf,
> +		rte_pmd_ixgbe_set_vf_rxmode(port_id, vf,

Will these cause a build error if IXGBE_PMD is not enabled?

>  			ETH_VMDQ_ACCEPT_UNTAG, 0);
>  
>  	/* Enable Rx vlan filter, VF unspport status is discard */
> 

^ permalink raw reply

* Re: [PATCH v3 9/9] doc: update release notes
From: Ferruh Yigit @ 2016-12-12 16:07 UTC (permalink / raw)
  To: Iremonger, Bernard, thomas.monjalon@6wind.com, dev@dpdk.org
In-Reply-To: <8CEF83825BEC744B83065625E567D7C224D06914@IRSMSX108.ger.corp.intel.com>

On 12/12/2016 3:55 PM, Iremonger, Bernard wrote:
> Hi Ferruh,
> 
> 
>> -----Original Message-----
>> From: Yigit, Ferruh
>> Sent: Monday, December 12, 2016 3:52 PM
>> To: Iremonger, Bernard <bernard.iremonger@intel.com>;
>> thomas.monjalon@6wind.com; dev@dpdk.org
>> Subject: Re: [dpdk-dev] [PATCH v3 9/9] doc: update release notes
>>
>> Hi Bernard,
>>
>> On 12/12/2016 1:50 PM, Bernard Iremonger wrote:
>>> Add release note for removing set VF API's from the ethdev, renaming
>>> the API's and moving them to the ixgbe PMD.
>>
>> Sorry, my bad, I wasn't clear enough.
>>
>> I was thinking about updating "Shared Library Versions" section of the
>> release notes, and increasing the librte_ethdev.so version (from 5 to 6) I
>> believe new feature section does not require an update.
>>
>> If you don't mind I can update library version with previous patch, and you
>> don't need to send a new version of the patch. Please let me know.
> 
> Yes, that's fine with me.

It seems already increased for this release, by another patch, so no
change required there.

I will move your release notes changes to "API Changes" section.

> 
>  
>>>
>>> Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
>>> ---
>>>  doc/guides/rel_notes/release_17_02.rst | 20 ++++++++++++++++++++
>>>  1 file changed, 20 insertions(+)
>>>
>>> diff --git a/doc/guides/rel_notes/release_17_02.rst
>>> b/doc/guides/rel_notes/release_17_02.rst
>>> index 3b65038..d30b258 100644
>>> --- a/doc/guides/rel_notes/release_17_02.rst
>>> +++ b/doc/guides/rel_notes/release_17_02.rst
>>> @@ -38,6 +38,26 @@ New Features
>>>       Also, make sure to start the actual text at the margin.
>>>
>> =========================================================
>>>
>>> +* **Moved five APIs for VF management from the ethdev to the ixgbe
>>> +PMD.**
>>> +
>>> +  The following five APIs for VF management from the PF have been
>>> + removed from the ethdev,  renamed and added to the ixgbe PMD::
>>> +
>>> +    rte_eth_dev_set_vf_rate_limit
>>> +    rte_eth_dev_set_vf_rx
>>> +    rte_eth_dev_set_vf_rxmode
>>> +    rte_eth_dev_set_vf_tx
>>> +    rte_eth_dev_set_vf_vlan_filter
>>> +
>>> +  The API's have been renamed to the following::
>>> +
>>> +    rte_pmd_ixgbe_set_vf_rate_limit
>>> +    rte_pmd_ixgbe_set_vf_rx
>>> +    rte_pmd_ixgbe_set_vf_rxmode
>>> +    rte_pmd_ixgbe_set_vf_tx
>>> +    rte_pmd_ixgbe_set_vf_vlan_filter
>>> +
>>> +  The declarations for the API’s can be found in ``rte_pmd_ixgbe.h``.
>>>
>>>  Resolved Issues
>>>  ---------------
>>>
> Regards,
> 
> Bernard.
> 

^ permalink raw reply

* Re: [PATCH v3 9/9] doc: update release notes
From: Iremonger, Bernard @ 2016-12-12 15:55 UTC (permalink / raw)
  To: Yigit, Ferruh, thomas.monjalon@6wind.com, dev@dpdk.org
In-Reply-To: <9eab7091-fc0a-cc12-3588-64df429cd3b0@intel.com>

Hi Ferruh,


> -----Original Message-----
> From: Yigit, Ferruh
> Sent: Monday, December 12, 2016 3:52 PM
> To: Iremonger, Bernard <bernard.iremonger@intel.com>;
> thomas.monjalon@6wind.com; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v3 9/9] doc: update release notes
> 
> Hi Bernard,
> 
> On 12/12/2016 1:50 PM, Bernard Iremonger wrote:
> > Add release note for removing set VF API's from the ethdev, renaming
> > the API's and moving them to the ixgbe PMD.
> 
> Sorry, my bad, I wasn't clear enough.
> 
> I was thinking about updating "Shared Library Versions" section of the
> release notes, and increasing the librte_ethdev.so version (from 5 to 6) I
> believe new feature section does not require an update.
> 
> If you don't mind I can update library version with previous patch, and you
> don't need to send a new version of the patch. Please let me know.

Yes, that's fine with me.

 
> >
> > Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
> > ---
> >  doc/guides/rel_notes/release_17_02.rst | 20 ++++++++++++++++++++
> >  1 file changed, 20 insertions(+)
> >
> > diff --git a/doc/guides/rel_notes/release_17_02.rst
> > b/doc/guides/rel_notes/release_17_02.rst
> > index 3b65038..d30b258 100644
> > --- a/doc/guides/rel_notes/release_17_02.rst
> > +++ b/doc/guides/rel_notes/release_17_02.rst
> > @@ -38,6 +38,26 @@ New Features
> >       Also, make sure to start the actual text at the margin.
> >
> =========================================================
> >
> > +* **Moved five APIs for VF management from the ethdev to the ixgbe
> > +PMD.**
> > +
> > +  The following five APIs for VF management from the PF have been
> > + removed from the ethdev,  renamed and added to the ixgbe PMD::
> > +
> > +    rte_eth_dev_set_vf_rate_limit
> > +    rte_eth_dev_set_vf_rx
> > +    rte_eth_dev_set_vf_rxmode
> > +    rte_eth_dev_set_vf_tx
> > +    rte_eth_dev_set_vf_vlan_filter
> > +
> > +  The API's have been renamed to the following::
> > +
> > +    rte_pmd_ixgbe_set_vf_rate_limit
> > +    rte_pmd_ixgbe_set_vf_rx
> > +    rte_pmd_ixgbe_set_vf_rxmode
> > +    rte_pmd_ixgbe_set_vf_tx
> > +    rte_pmd_ixgbe_set_vf_vlan_filter
> > +
> > +  The declarations for the API’s can be found in ``rte_pmd_ixgbe.h``.
> >
> >  Resolved Issues
> >  ---------------
> >
Regards,

Bernard.


^ permalink raw reply

* Re: [PATCH v3 9/9] doc: update release notes
From: Ferruh Yigit @ 2016-12-12 15:51 UTC (permalink / raw)
  To: Bernard Iremonger, thomas.monjalon, dev
In-Reply-To: <1481550626-14539-10-git-send-email-bernard.iremonger@intel.com>

Hi Bernard,

On 12/12/2016 1:50 PM, Bernard Iremonger wrote:
> Add release note for removing set VF API's from the ethdev,
> renaming the API's and moving them to the ixgbe PMD.

Sorry, my bad, I wasn't clear enough.

I was thinking about updating "Shared Library Versions" section of the
release notes, and increasing the librte_ethdev.so version (from 5 to 6)
I believe new feature section does not require an update.

If you don't mind I can update library version with previous patch, and
you don't need to send a new version of the patch. Please let me know.

> 
> Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
> ---
>  doc/guides/rel_notes/release_17_02.rst | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
> 
> diff --git a/doc/guides/rel_notes/release_17_02.rst b/doc/guides/rel_notes/release_17_02.rst
> index 3b65038..d30b258 100644
> --- a/doc/guides/rel_notes/release_17_02.rst
> +++ b/doc/guides/rel_notes/release_17_02.rst
> @@ -38,6 +38,26 @@ New Features
>       Also, make sure to start the actual text at the margin.
>       =========================================================
>  
> +* **Moved five APIs for VF management from the ethdev to the ixgbe PMD.**
> +
> +  The following five APIs for VF management from the PF have been removed from the ethdev,
> +  renamed and added to the ixgbe PMD::
> +
> +    rte_eth_dev_set_vf_rate_limit
> +    rte_eth_dev_set_vf_rx
> +    rte_eth_dev_set_vf_rxmode
> +    rte_eth_dev_set_vf_tx
> +    rte_eth_dev_set_vf_vlan_filter
> +
> +  The API's have been renamed to the following::
> +
> +    rte_pmd_ixgbe_set_vf_rate_limit
> +    rte_pmd_ixgbe_set_vf_rx
> +    rte_pmd_ixgbe_set_vf_rxmode
> +    rte_pmd_ixgbe_set_vf_tx
> +    rte_pmd_ixgbe_set_vf_vlan_filter
> +
> +  The declarations for the API’s can be found in ``rte_pmd_ixgbe.h``.
>  
>  Resolved Issues
>  ---------------
> 

^ permalink raw reply

* Re: [PATCH v12 0/6] add Tx preparation
From: Ananyev, Konstantin @ 2016-12-12 15:02 UTC (permalink / raw)
  To: Jan Medala, Yigit, Ferruh
  Cc: Thomas Monjalon, Harish Patil, dev@dpdk.org, Rahul Lakkireddy,
	Stephen Hurd, Jakub Palider, John Daley, Adrien Mazarguil,
	Alejandro Lucero, Rasesh Mody, Jacob, Jerin, Yuanhan Liu,
	Kulasek, TomaszX, olivier.matz@6wind.com, Yong Wang
In-Reply-To: <CANw_3ZdK2HUZC3K6LLB2QtD3AmKvjtObRDPwjZS0g5rHTEpcBQ@mail.gmail.com>

Hi Jan,

>Hello,

>Sorry for late response.

>From ENA perspective, we need to dig deeper about the requirements and use cases, but I'm pretty confident (95%) that ena will need to implement tx_prep() API. There is at least one >scenario, when HW relay on partial checksum.

Could you let us know as soon as you'll figure it out.
Hopefully will still be able to hit into 17.02 integration deadline.
Thanks
Konstantin

^ permalink raw reply

* Re: [dpdk-dev, 1/8] drivers/common/dpaa2: Run time assembler for Descriptor formation
From: Neil Horman @ 2016-12-12 14:59 UTC (permalink / raw)
  To: Akhil Goyal
  Cc: dev, thomas.monjalon, eclan.doherty, pablo.de.lara.guarch,
	hemant.agrawal, Horia Geanta Neag
In-Reply-To: <20161205125540.6419-2-akhil.goyal@nxp.com>

On Mon, Dec 05, 2016 at 06:25:33PM +0530, Akhil Goyal wrote:
> FLib is a library which helps in making the descriptors which
> is understood by NXP's SEC hardware.
> This patch provides header files for command words which can be used
> for descritptor formation.
> 
> Signed-off-by: Horia Geanta Neag <horia.geanta@nxp.com>
> Acked-by: Akhil Goyal <akhil.goyal@nxp.com>
> ---
>  drivers/common/dpaa2/flib/README                   |  43 +
>  drivers/common/dpaa2/flib/compat.h                 | 186 +++++
>  drivers/common/dpaa2/flib/rta.h                    | 918 +++++++++++++++++++++
>  .../common/dpaa2/flib/rta/fifo_load_store_cmd.h    | 308 +++++++
>  drivers/common/dpaa2/flib/rta/header_cmd.h         | 213 +++++
>  drivers/common/dpaa2/flib/rta/jump_cmd.h           | 172 ++++
>  drivers/common/dpaa2/flib/rta/key_cmd.h            | 187 +++++
>  drivers/common/dpaa2/flib/rta/load_cmd.h           | 301 +++++++
>  drivers/common/dpaa2/flib/rta/math_cmd.h           | 366 ++++++++
>  drivers/common/dpaa2/flib/rta/move_cmd.h           | 405 +++++++++
>  drivers/common/dpaa2/flib/rta/nfifo_cmd.h          | 161 ++++
>  drivers/common/dpaa2/flib/rta/operation_cmd.h      | 549 ++++++++++++
>  drivers/common/dpaa2/flib/rta/protocol_cmd.h       | 680 +++++++++++++++
>  drivers/common/dpaa2/flib/rta/sec_run_time_asm.h   | 767 +++++++++++++++++
>  drivers/common/dpaa2/flib/rta/seq_in_out_ptr_cmd.h | 172 ++++
>  drivers/common/dpaa2/flib/rta/signature_cmd.h      |  40 +
>  drivers/common/dpaa2/flib/rta/store_cmd.h          | 149 ++++
>  17 files changed, 5617 insertions(+)
>  create mode 100644 drivers/common/dpaa2/flib/README
>  create mode 100644 drivers/common/dpaa2/flib/compat.h
>  create mode 100644 drivers/common/dpaa2/flib/rta.h
>  create mode 100644 drivers/common/dpaa2/flib/rta/fifo_load_store_cmd.h
>  create mode 100644 drivers/common/dpaa2/flib/rta/header_cmd.h
>  create mode 100644 drivers/common/dpaa2/flib/rta/jump_cmd.h
>  create mode 100644 drivers/common/dpaa2/flib/rta/key_cmd.h
>  create mode 100644 drivers/common/dpaa2/flib/rta/load_cmd.h
>  create mode 100644 drivers/common/dpaa2/flib/rta/math_cmd.h
>  create mode 100644 drivers/common/dpaa2/flib/rta/move_cmd.h
>  create mode 100644 drivers/common/dpaa2/flib/rta/nfifo_cmd.h
>  create mode 100644 drivers/common/dpaa2/flib/rta/operation_cmd.h
>  create mode 100644 drivers/common/dpaa2/flib/rta/protocol_cmd.h
>  create mode 100644 drivers/common/dpaa2/flib/rta/sec_run_time_asm.h
>  create mode 100644 drivers/common/dpaa2/flib/rta/seq_in_out_ptr_cmd.h
>  create mode 100644 drivers/common/dpaa2/flib/rta/signature_cmd.h
>  create mode 100644 drivers/common/dpaa2/flib/rta/store_cmd.h
> 
> diff --git a/drivers/common/dpaa2/flib/README b/drivers/common/dpaa2/flib/README
> new file mode 100644
> index 0000000..a8b3358
> --- /dev/null
> +++ b/drivers/common/dpaa2/flib/README
> @@ -0,0 +1,43 @@
> +Copyright 2008-2013 Freescale Semiconductor, Inc.
> +
> +Runtime Assembler provides an easy and flexible runtime method for writing
> +SEC descriptors.
> +
> +1. What's supported
> +===================
> +1.1 Initialization/verification code for descriptor buffer.
> +1.2 Configuration/verification code for SEC commands:
> +       FIFOLOAD and SEQFIFOLOAD;
> +       FIFOSTORE and SEQFIFOSTORE;
> +       SHARED HEADER and JOB HEADER;
> +       JUMP;
> +       KEY;
> +       LOAD and SEQLOAD;
> +       MATH;
> +       MOVE and MOVELEN;
> +       NFIFO - pseudo command (shortcut for writing FIFO entries using LOAD command);
> +       PKA OPERATION and ALGORITHM OPERATION;
> +       PROTOCOL;
> +       SEQ IN PTR and SEQ OUT PTR;
> +       SIGNATURE;
> +       STORE and SEQSTORE.
> +1.3 Support for referential code:
> +	patching routines for LOAD, MOVE, JUMP and HEADER commands.
> +	raw patching (i.e. patch any 4-byte word from descriptor)
> +1.4 Support for extended (32/36/40-bit) pointer size.
> +1.5 SEC Eras 1-6
> +	Below is a non-exhaustive list of platforms:
> +	Era 1 - P4080R1
> +	Era 2 - P4080R2
> +	Era 3 - P1010, P1023, P3041, P5020
> +	Era 4 - BSC9131, BSC9132, P4080R3
> +	Era 5 - P5040, B4860, T4240R1
> +	Era 6 - C290, T4240R2, T1040, T2080
> +
> +2. What's not supported
> +=======================
> +2.1 SEC Eras 7 and 8.
> +
> +3. Integration
> +==============
> +To integrate this tool into your project, rta.h file must be included.
> diff --git a/drivers/common/dpaa2/flib/compat.h b/drivers/common/dpaa2/flib/compat.h
> new file mode 100644
> index 0000000..bd946e1
> --- /dev/null
> +++ b/drivers/common/dpaa2/flib/compat.h
> @@ -0,0 +1,186 @@
> +/*
> + * Copyright 2013 Freescale Semiconductor, Inc.
> + *
> + * SPDX-License-Identifier: BSD-3-Clause or GPL-2.0+
> + */
> +
> +#ifndef __RTA_COMPAT_H__
> +#define __RTA_COMPAT_H__
> +
> +#include <stdint.h>
> +#include <errno.h>
> +
> +#ifdef __GLIBC__
> +#include <string.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <stdbool.h>
> +#include <byteswap.h>
> +
> +#ifndef __BYTE_ORDER__
> +#error "Undefined endianness"
> +#endif
> +
> +/* FSL's Embedded Warrior C Library; assume AIOP or MC environment */
> +#elif defined(__EWL__) && (defined(AIOP) || defined(MC))
> +#include "common/fsl_string.h"
> +#include "common/fsl_stdlib.h"
> +#include "common/fsl_stdio.h"
> +#if defined(AIOP)
> +#include "dplib/fsl_cdma.h"
> +#endif
> +#include "fsl_dbg.h"
> +#include "fsl_endian.h"
> +#if _EWL_C99
> +#include <stdbool.h>
> +#else
> +#if !__option(c99)
> +typedef unsigned char			_Bool;
> +#endif
> +#define bool				_Bool
> +#define true				1
> +#define false				0
> +#define __bool_true_false_are_defined	1
> +#endif /* _EWL_C99 */
> +#else
> +#error Environment not supported!
> +#endif
> +
> +#ifndef __always_inline
> +#define __always_inline inline __attribute__((always_inline))
> +#endif
> +
> +#ifndef __always_unused
> +#define __always_unused __attribute__((unused))
> +#endif
> +
> +#ifndef __maybe_unused
> +#define __maybe_unused __attribute__((unused))
> +#endif
> +
> +#if defined(__GLIBC__) && (defined(SUPPRESS_PRINTS) || \
> +			   (!defined(pr_debug) && !defined(RTA_DEBUG)))
> +#ifndef __printf
> +#define __printf(a, b)	__attribute__((format(printf, 1, 2)))
> +#endif
> +static inline __printf(1, 2) int no_printf(const char *fmt __always_unused, ...)
> +{
> +	return 0;
> +}
> +#endif
> +
> +#if defined(__GLIBC__) && !defined(pr_debug)
> +#if !defined(SUPPRESS_PRINTS) && defined(RTA_DEBUG)
> +#define pr_debug(fmt, ...)    printf(fmt, ##__VA_ARGS__)
> +#else
> +#define pr_debug(fmt, ...)    no_printf(fmt, ##__VA_ARGS__)
> +#endif
> +#endif /* pr_debug */
> +
> +#if defined(__GLIBC__) && !defined(pr_err)
> +#if !defined(SUPPRESS_PRINTS)
> +#define pr_err(fmt, ...)    printf(fmt, ##__VA_ARGS__)
> +#else
> +#define pr_err(fmt, ...)    no_printf(fmt, ##__VA_ARGS__)
> +#endif
> +#endif /* pr_err */
> +
> +#if defined(__GLIBC__) && !defined(pr_warning)
> +#if !defined(SUPPRESS_PRINTS)
> +#define pr_warning(fmt, ...)    printf(fmt, ##__VA_ARGS__)
> +#else
> +#define pr_warning(fmt, ...)    no_printf(fmt, ##__VA_ARGS__)
> +#endif
> +#endif /* pr_warning */
> +
> +#if defined(__GLIBC__) && !defined(pr_warn)
> +#define pr_warn	pr_warning
> +#endif /* pr_warn */
Seems like logging should be folded into the rte logging facility, not
controlled independently, and manipulated via redefinitions of printf

> +
> +/**
> + * ARRAY_SIZE - returns the number of elements in an array
> + * @x: array
> + */
> +#ifndef ARRAY_SIZE
> +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
> +#endif
> +
> +#ifndef ALIGN
> +#define ALIGN(x, a) (((x) + ((__typeof__(x))(a) - 1)) & \
> +			~((__typeof__(x))(a) - 1))
> +#endif
> +
> +#ifndef BIT
> +#define BIT(nr)		(1UL << (nr))
> +#endif
> +
> +#ifndef upper_32_bits
> +/**
> + * upper_32_bits - return bits 32-63 of a number
> + * @n: the number we're accessing
> + */
> +#define upper_32_bits(n) ((uint32_t)(((n) >> 16) >> 16))
> +#endif
> +
> +#ifndef lower_32_bits
> +/**
> + * lower_32_bits - return bits 0-31 of a number
> + * @n: the number we're accessing
> + */
> +#define lower_32_bits(n) ((uint32_t)(n))
> +#endif
> +
> +/* Use Linux naming convention */
> +#ifdef __GLIBC__
> +	#define swab16(x) bswap_16(x)
> +	#define swab32(x) bswap_32(x)
> +	#define swab64(x) bswap_64(x)
> +	/* Define cpu_to_be32 macro if not defined in the build environment */
> +	#if !defined(cpu_to_be32)
> +		#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
> +			#define cpu_to_be32(x)	(x)
> +		#else
> +			#define cpu_to_be32(x)	swab32(x)
> +		#endif
> +	#endif
> +	/* Define cpu_to_le32 macro if not defined in the build environment */
> +	#if !defined(cpu_to_le32)
> +		#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
> +			#define cpu_to_le32(x)	swab32(x)
> +		#else
> +			#define cpu_to_le32(x)	(x)
> +		#endif
Definately shouldn't be redefining your own byte swapping routines here.

^ permalink raw reply

* [PATCH v12] net/tap: new TUN/TAP device PMD
From: Keith Wiles @ 2016-12-12 14:38 UTC (permalink / raw)
  To: dev; +Cc: pmatilai, yuanhan.liu, ferruh.yigit, john.mcnamara
In-Reply-To: <1476396234-44694-1-git-send-email-keith.wiles@intel.com>

The PMD allows for DPDK and the host to communicate using a raw
device interface on the host and in the DPDK application. The device
created is a Tap device with a L2 packet header.

v12- Fixup minor changes for driver_name and version number
v11- Add the tap.rst to the nic/index.rst file
v10- Change the string name used to allow for multiple devices.
v9 - Fix up the docs to use correct syntax
v8 - Fix issue with tap_tx_queue_setup() not return zero on success.
v7 - Reword the comment in common_base and fix the data->name issue
v6 - fixed the checkpatch issues
v5 - merge in changes from list review see related emails
     fixed many minor edits
v4 - merge with latest driver changes
v3 - fix includes by removing ifdef for other type besides Linux
     Fix the copyright notice in the Makefile
v2 - merge all of the patches into one patch
     Fix a typo on naming the tap device
     Update the maintainers list

Signed-off-by: Keith Wiles <keith.wiles@intel.com>
---
 MAINTAINERS                             |   5 +
 config/common_base                      |   9 +
 config/common_linuxapp                  |   1 +
 doc/guides/nics/index.rst               |   1 +
 doc/guides/nics/tap.rst                 | 136 ++++++
 drivers/net/Makefile                    |   1 +
 drivers/net/tap/Makefile                |  57 +++
 drivers/net/tap/rte_eth_tap.c           | 765 ++++++++++++++++++++++++++++++++
 drivers/net/tap/rte_pmd_tap_version.map |   4 +
 mk/rte.app.mk                           |   1 +
 10 files changed, 980 insertions(+)
 create mode 100644 doc/guides/nics/tap.rst
 create mode 100644 drivers/net/tap/Makefile
 create mode 100644 drivers/net/tap/rte_eth_tap.c
 create mode 100644 drivers/net/tap/rte_pmd_tap_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index 26d9590..842fb6d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -398,6 +398,11 @@ F: doc/guides/nics/pcap_ring.rst
 F: app/test/test_pmd_ring.c
 F: app/test/test_pmd_ring_perf.c
 
+Tap PMD
+M: Keith Wiles <keith.wiles@intel.com>
+F: drivers/net/tap
+F: doc/guides/nics/tap.rst
+
 Null Networking PMD
 M: Tetsuya Mukawa <mtetsuyah@gmail.com>
 F: drivers/net/null/
diff --git a/config/common_base b/config/common_base
index 652a839..eb51cdb 100644
--- a/config/common_base
+++ b/config/common_base
@@ -590,3 +590,12 @@ CONFIG_RTE_APP_TEST_RESOURCE_TAR=n
 CONFIG_RTE_TEST_PMD=y
 CONFIG_RTE_TEST_PMD_RECORD_CORE_CYCLES=n
 CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n
+
+#
+# Compile the TAP PMD
+#
+# The TAP PMD is currently only built for Linux and the
+# option is enabled by default in common_linuxapp file,
+# set to 'n' in the common_base file.
+#
+CONFIG_RTE_LIBRTE_PMD_TAP=n
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 2483dfa..782b503 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -44,3 +44,4 @@ CONFIG_RTE_LIBRTE_PMD_VHOST=y
 CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
 CONFIG_RTE_LIBRTE_POWER=y
 CONFIG_RTE_VIRTIO_USER=y
+CONFIG_RTE_LIBRTE_PMD_TAP=y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 92d56a5..af92529 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -51,6 +51,7 @@ Network Interface Controller Drivers
     nfp
     qede
     szedata2
+    tap
     thunderx
     virtio
     vhost
diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
new file mode 100644
index 0000000..622b9e7
--- /dev/null
+++ b/doc/guides/nics/tap.rst
@@ -0,0 +1,136 @@
+..  BSD LICENSE
+    Copyright(c) 2016 Intel Corporation. All rights reserved.
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+    * Neither the name of Intel Corporation nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Tun/Tap Poll Mode Driver
+========================
+
+The ``rte_eth_tap.c`` PMD creates a device using TUN/TAP interfaces on the
+local host. The PMD allows for DPDK and the host to communicate using a raw
+device interface on the host and in the DPDK application.
+
+The device created is a TAP device, which sends/receives packet in a raw
+format with a L2 header. The usage for a TAP PMD is for connectivity to the
+local host using a TAP interface. When the TAP PMD is initialized it will
+create a number of tap devices in the host accessed via ``ifconfig -a`` or
+``ip`` command. The commands can be used to assign and query the virtual like
+device.
+
+These TAP interfaces can be used with Wireshark or tcpdump or Pktgen-DPDK
+along with being able to be used as a network connection to the DPDK
+application. The method enable one or more interfaces is to use the
+``--vdev=net_tap`` option on the DPDK application command line. Each
+``--vdev=net_tap`` option give will create an interface named dtap0, dtap1,
+and so on.
+
+The interfaced name can be changed by adding the ``iface=foo0``, for example::
+
+   --vdev=net_tap,iface=foo0 --vdev=net_tap,iface=foo1, ...
+
+Also the speed of the interface can be changed from 10G to whatever number
+needed, but the interface does not enforce that speed, for example::
+
+   --vdev=net_tap,iface=foo0,speed=25000
+
+After the DPDK application is started you can send and receive packets on the
+interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
+point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
+and others to communicate with the DPDK application. The DPDK application may
+not understand network protocols like IPv4/6, UDP or TCP unless the
+application has been written to understand these protocols.
+
+If you need the interface as a real network interface meaning running and has
+a valid IP address then you can do this with the following commands::
+
+   sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
+   sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
+
+Please change the IP addresses as you see fit.
+
+If routing is enabled on the host you can also communicate with the DPDK App
+over the internet via a standard socket layer application as long as you
+account for the protocol handing in the application.
+
+If you have a Network Stack in your DPDK application or something like it you
+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.
+
+Example
+-------
+
+The following is a simple example of using the TUN/TAP PMD with the Pktgen
+packet generator. It requires that the ``socat`` utility is installed on the
+test system.
+
+Build DPDK, then pull down Pktgen and build pktgen using the DPDK SDK/Target
+used to build the dpdk you pulled down.
+
+Run pktgen from the pktgen directory in a terminal with a commandline like the
+following::
+
+    sudo ./app/app/x86_64-native-linuxapp-gcc/app/pktgen -l 1-5 -n 4        \
+     --proc-type auto --log-level 8 --socket-mem 512,512 --file-prefix pg   \
+     --vdev=net_tap --vdev=net_tap -b 05:00.0 -b 05:00.1                    \
+     -b 04:00.0 -b 04:00.1 -b 04:00.2 -b 04:00.3                            \
+     -b 81:00.0 -b 81:00.1 -b 81:00.2 -b 81:00.3                            \
+     -b 82:00.0 -b 83:00.0 -- -T -P -m [2:3].0 -m [4:5].1                   \
+     -f themes/black-yellow.theme
+
+.. Note:
+
+   Change the ``-b`` options to blacklist all of your physical ports. The
+   following command line is all one line.
+
+   Also, ``-f themes/black-yellow.theme`` is optional if the default colors
+   work on your system configuration. See the Pktgen docs for more
+   information.
+
+Verify with ``ifconfig -a`` command in a different xterm window, should have a
+``dtap0`` and ``dtap1`` interfaces created.
+
+Next set the links for the two interfaces to up via the commands below::
+
+    sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
+    sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
+
+Then use socat to create a loopback for the two interfaces::
+
+    sudo socat interface:dtap0 interface:dtap1
+
+Then on the Pktgen command line interface you can start sending packets using
+the commands ``start 0`` and ``start 1`` or you can start both at the same
+time with ``start all``. The command ``str`` is an alias for ``start all`` and
+``stp`` is an alias for ``stop all``.
+
+While running you should see the 64 byte counters increasing to verify the
+traffic is being looped back. You can use ``set all size XXX`` to change the
+size of the packets after you stop the traffic. Use the pktgen ``help``
+command to see a list of all commands. You can also use the ``-f`` option to
+load commands at startup.
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index bc93230..e366a85 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -51,6 +51,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += pcap
 DIRS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_RING) += ring
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += szedata2
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += tap
 DIRS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += thunderx
 DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += vmxnet3
diff --git a/drivers/net/tap/Makefile b/drivers/net/tap/Makefile
new file mode 100644
index 0000000..e18f30c
--- /dev/null
+++ b/drivers/net/tap/Makefile
@@ -0,0 +1,57 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 Intel Corporation. All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_tap.a
+
+EXPORT_MAP := rte_pmd_tap_version.map
+
+LIBABIVER := 1
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += rte_eth_tap.c
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_mempool
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
new file mode 100644
index 0000000..976f2d9
--- /dev/null
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -0,0 +1,765 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_vdev.h>
+#include <rte_kvargs.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <poll.h>
+#include <arpa/inet.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <linux/if_ether.h>
+#include <fcntl.h>
+
+/* Linux based path to the TUN device */
+#define TUN_TAP_DEV_PATH        "/dev/net/tun"
+#define DEFAULT_TAP_NAME        "dtap"
+
+#define ETH_TAP_IFACE_ARG       "iface"
+#define ETH_TAP_SPEED_ARG       "speed"
+
+#define RTE_PMD_TAP_MAX_QUEUES	16
+
+static struct rte_vdev_driver pmd_tap_drv;
+
+static const char *valid_arguments[] = {
+	ETH_TAP_IFACE_ARG,
+	ETH_TAP_SPEED_ARG,
+	NULL
+};
+
+static int tap_unit;
+
+static struct rte_eth_link pmd_link = {
+	.link_speed = ETH_SPEED_NUM_10G,
+	.link_duplex = ETH_LINK_FULL_DUPLEX,
+	.link_status = ETH_LINK_DOWN,
+	.link_autoneg = ETH_LINK_SPEED_AUTONEG
+};
+
+struct pkt_stats {
+	uint64_t opackets;		/* Number of output packets */
+	uint64_t ipackets;		/* Number of input packets */
+	uint64_t obytes;		/* Number of bytes on output */
+	uint64_t ibytes;		/* Number of bytes on input */
+	uint64_t errs;			/* Number of error packets */
+};
+
+struct rx_queue {
+	struct rte_mempool *mp;		/* Mempool for RX packets */
+	uint16_t in_port;		/* Port ID */
+	int fd;
+
+	struct pkt_stats stats;		/* Stats for this RX queue */
+};
+
+struct tx_queue {
+	int fd;
+	struct pkt_stats stats;		/* Stats for this TX queue */
+};
+
+struct pmd_internals {
+	char name[RTE_ETH_NAME_MAX_LEN];	/* Internal Tap device name */
+	uint16_t nb_queues;		/* Number of queues supported */
+	struct ether_addr eth_addr;	/* Mac address of the device port */
+
+	int if_index;			/* IF_INDEX for the port */
+	int fds[RTE_PMD_TAP_MAX_QUEUES]; /* List of all file descriptors */
+
+	struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES];	/* List of RX queues */
+	struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES];	/* List of TX queues */
+};
+
+/* Tun/Tap allocation routine
+ *
+ * name is the number of the interface to use, unless NULL to take the host
+ * supplied name.
+ */
+static int
+tun_alloc(char *name)
+{
+	struct ifreq ifr;
+	unsigned int features;
+	int fd;
+
+	memset(&ifr, 0, sizeof(struct ifreq));
+
+	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+	if (name && name[0])
+		strncpy(ifr.ifr_name, name, IFNAMSIZ);
+
+	fd = open(TUN_TAP_DEV_PATH, O_RDWR);
+	if (fd < 0) {
+		RTE_LOG(ERR, PMD, "Unable to create TAP interface");
+		goto error;
+	}
+
+	/* Grab the TUN features to verify we can work */
+	if (ioctl(fd, TUNGETFEATURES, &features) < 0) {
+		RTE_LOG(ERR, PMD, "Unable to get TUN/TAP features\n");
+		goto error;
+	}
+	RTE_LOG(DEBUG, PMD, "TUN/TAP Features %08x\n", features);
+
+	if (!(features & IFF_MULTI_QUEUE) && (RTE_PMD_TAP_MAX_QUEUES > 1)) {
+		RTE_LOG(DEBUG, PMD, "TUN/TAP device only one queue\n");
+		goto error;
+	} else if ((features & IFF_ONE_QUEUE) &&
+			(RTE_PMD_TAP_MAX_QUEUES == 1)) {
+		ifr.ifr_flags |= IFF_ONE_QUEUE;
+		RTE_LOG(DEBUG, PMD, "Single queue only support\n");
+	} else {
+		ifr.ifr_flags |= IFF_MULTI_QUEUE;
+		RTE_LOG(DEBUG, PMD, "Multi-queue support for %d queues\n",
+			RTE_PMD_TAP_MAX_QUEUES);
+	}
+
+	/* Set the TUN/TAP configuration and get the name if needed */
+	if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) {
+		RTE_LOG(ERR, PMD, "Unable to set TUNSETIFF for %s\n",
+			ifr.ifr_name);
+		perror("TUNSETIFF");
+		goto error;
+	}
+
+	/* Always set the file descriptor to non-blocking */
+	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+		RTE_LOG(ERR, PMD, "Unable to set to nonblocking\n");
+		perror("F_SETFL, NONBLOCK");
+		goto error;
+	}
+
+	/* If the name is different that new name as default */
+	if (name && strcmp(name, ifr.ifr_name))
+		snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s", ifr.ifr_name);
+
+	return fd;
+
+error:
+	if (fd > 0)
+		close(fd);
+	return -1;
+}
+
+/* Callback to handle the rx burst of packets to the correct interface and
+ * file descriptor(s) in a multi-queue setup.
+ */
+static uint16_t
+pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	int len;
+	struct rte_mbuf *mbuf;
+	struct rx_queue *rxq = queue;
+	uint16_t num_rx;
+	unsigned long num_rx_bytes = 0;
+
+	for (num_rx = 0; num_rx < nb_pkts; ) {
+		/* allocate the next mbuf */
+		mbuf = rte_pktmbuf_alloc(rxq->mp);
+		if (unlikely(!mbuf)) {
+			RTE_LOG(WARNING, PMD, "Unable to allocate mbuf\n");
+			break;
+		}
+
+		len = read(rxq->fd, rte_pktmbuf_mtod(mbuf, char *),
+			   rte_pktmbuf_tailroom(mbuf));
+		if (len <= 0) {
+			rte_pktmbuf_free(mbuf);
+			break;
+		}
+
+		mbuf->data_len = len;
+		mbuf->pkt_len = len;
+		mbuf->port = rxq->in_port;
+
+		/* account for the receive frame */
+		bufs[num_rx++] = mbuf;
+		num_rx_bytes += mbuf->pkt_len;
+	}
+	rxq->stats.ipackets += num_rx;
+	rxq->stats.ibytes += num_rx_bytes;
+
+	return num_rx;
+}
+
+/* Callback to handle sending packets from the tap interface
+ */
+static uint16_t
+pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	struct rte_mbuf *mbuf;
+	struct tx_queue *txq = queue;
+	struct pollfd pfd;
+	uint16_t num_tx = 0;
+	unsigned long num_tx_bytes = 0;
+	int i, n;
+
+	if (unlikely(nb_pkts == 0))
+		return 0;
+
+	pfd.events = POLLOUT;
+	pfd.fd = txq->fd;
+	for (i = 0; i < nb_pkts; i++) {
+		n = poll(&pfd, 1, 0);
+
+		if (n <= 0)
+			break;
+
+		if (pfd.revents & POLLOUT) {
+			/* copy the tx frame data */
+			mbuf = bufs[num_tx];
+			n = write(pfd.fd, rte_pktmbuf_mtod(mbuf, void*),
+				  rte_pktmbuf_pkt_len(mbuf));
+			if (n <= 0)
+				break;
+
+			num_tx++;
+			num_tx_bytes += mbuf->pkt_len;
+			rte_pktmbuf_free(mbuf);
+		}
+	}
+
+	txq->stats.opackets += num_tx;
+	txq->stats.errs += nb_pkts - num_tx;
+	txq->stats.obytes += num_tx_bytes;
+
+	return num_tx;
+}
+
+static int
+tap_dev_start(struct rte_eth_dev *dev)
+{
+	/* Force the Link up */
+	dev->data->dev_link.link_status = ETH_LINK_UP;
+
+	return 0;
+}
+
+/* This function gets called when the current port gets stopped.
+ */
+static void
+tap_dev_stop(struct rte_eth_dev *dev)
+{
+	int i;
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	for (i = 0; i < internals->nb_queues; i++)
+		if (internals->fds[i] != -1)
+			close(internals->fds[i]);
+
+	dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+tap_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+static void
+tap_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+
+	dev_info->if_index = internals->if_index;
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = (uint32_t)ETHER_MAX_VLAN_FRAME_LEN;
+	dev_info->max_rx_queues = internals->nb_queues;
+	dev_info->max_tx_queues = internals->nb_queues;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static void
+tap_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *tap_stats)
+{
+	unsigned int i, imax;
+	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
+	unsigned long rx_bytes_total = 0, tx_bytes_total = 0;
+	const struct pmd_internals *pmd = dev->data->dev_private;
+
+	imax = (pmd->nb_queues < RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
+		pmd->nb_queues : RTE_ETHDEV_QUEUE_STAT_CNTRS;
+
+	for (i = 0; i < imax; i++) {
+		tap_stats->q_ipackets[i] = pmd->rxq[i].stats.ipackets;
+		tap_stats->q_ibytes[i] = pmd->rxq[i].stats.ibytes;
+		rx_total += tap_stats->q_ipackets[i];
+		rx_bytes_total += tap_stats->q_ibytes[i];
+	}
+
+	for (i = 0; i < imax; i++) {
+		tap_stats->q_opackets[i] = pmd->txq[i].stats.opackets;
+		tap_stats->q_errors[i] = pmd->txq[i].stats.errs;
+		tap_stats->q_obytes[i] = pmd->txq[i].stats.obytes;
+		tx_total += tap_stats->q_opackets[i];
+		tx_err_total += tap_stats->q_errors[i];
+		tx_bytes_total += tap_stats->q_obytes[i];
+	}
+
+	tap_stats->ipackets = rx_total;
+	tap_stats->ibytes = rx_bytes_total;
+	tap_stats->opackets = tx_total;
+	tap_stats->oerrors = tx_err_total;
+	tap_stats->obytes = tx_bytes_total;
+}
+
+static void
+tap_stats_reset(struct rte_eth_dev *dev)
+{
+	int i;
+	struct pmd_internals *pmd = dev->data->dev_private;
+
+	for (i = 0; i < pmd->nb_queues; i++) {
+		pmd->rxq[i].stats.ipackets = 0;
+		pmd->rxq[i].stats.ibytes = 0;
+	}
+
+	for (i = 0; i < pmd->nb_queues; i++) {
+		pmd->txq[i].stats.opackets = 0;
+		pmd->txq[i].stats.errs = 0;
+		pmd->txq[i].stats.obytes = 0;
+	}
+}
+
+static void
+tap_dev_close(struct rte_eth_dev *dev __rte_unused)
+{
+}
+
+static void
+tap_rx_queue_release(void *queue)
+{
+	struct rx_queue *rxq = queue;
+
+	if (rxq && (rxq->fd > 0)) {
+		close(rxq->fd);
+		rxq->fd = -1;
+	}
+}
+
+static void
+tap_tx_queue_release(void *queue)
+{
+	struct tx_queue *txq = queue;
+
+	if (txq && (txq->fd > 0)) {
+		close(txq->fd);
+		txq->fd = -1;
+	}
+}
+
+static int
+tap_link_update(struct rte_eth_dev *dev __rte_unused,
+		int wait_to_complete __rte_unused)
+{
+	return 0;
+}
+
+static int
+tap_setup_queue(struct rte_eth_dev *dev,
+		struct pmd_internals *internals,
+		uint16_t qid)
+{
+	struct rx_queue *rx = &internals->rxq[qid];
+	struct tx_queue *tx = &internals->txq[qid];
+	int fd;
+
+	fd = rx->fd;
+	if (fd < 0) {
+		fd = tx->fd;
+		if (fd < 0) {
+			RTE_LOG(INFO, PMD, "Add queue to TAP %s for qid %d\n",
+				dev->data->name, qid);
+			fd = tun_alloc(dev->data->name);
+			if (fd < 0) {
+				RTE_LOG(ERR, PMD, "tun_alloc(%s) failed\n",
+					dev->data->name);
+				return -1;
+			}
+		}
+	}
+	dev->data->rx_queues[qid] = rx;
+	dev->data->tx_queues[qid] = tx;
+
+	rx->fd = fd;
+	tx->fd = fd;
+
+	return fd;
+}
+
+static int
+tap_rx_queue_setup(struct rte_eth_dev *dev,
+		   uint16_t rx_queue_id,
+		   uint16_t nb_rx_desc __rte_unused,
+		   unsigned int socket_id __rte_unused,
+		   const struct rte_eth_rxconf *rx_conf __rte_unused,
+		   struct rte_mempool *mp)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	uint16_t buf_size;
+	int fd;
+
+	if ((rx_queue_id >= internals->nb_queues) || !mp) {
+		RTE_LOG(ERR, PMD, "nb_queues %d mp %p\n",
+			internals->nb_queues, mp);
+		return -1;
+	}
+
+	internals->rxq[rx_queue_id].mp = mp;
+	internals->rxq[rx_queue_id].in_port = dev->data->port_id;
+
+	/* Now get the space available for data in the mbuf */
+	buf_size = (uint16_t)(rte_pktmbuf_data_room_size(mp) -
+				RTE_PKTMBUF_HEADROOM);
+
+	if (buf_size < ETH_FRAME_LEN) {
+		RTE_LOG(ERR, PMD,
+			"%s: %d bytes will not fit in mbuf (%d bytes)\n",
+			dev->data->name, ETH_FRAME_LEN, buf_size);
+		return -ENOMEM;
+	}
+
+	fd = tap_setup_queue(dev, internals, rx_queue_id);
+	if (fd == -1)
+		return -1;
+
+	internals->fds[rx_queue_id] = fd;
+	RTE_LOG(INFO, PMD, "RX TAP device name %s, qid %d on fd %d\n",
+		dev->data->name, rx_queue_id, internals->rxq[rx_queue_id].fd);
+
+	return 0;
+}
+
+static int
+tap_tx_queue_setup(struct rte_eth_dev *dev,
+		   uint16_t tx_queue_id,
+		   uint16_t nb_tx_desc __rte_unused,
+		   unsigned int socket_id __rte_unused,
+		   const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+
+	if (tx_queue_id >= internals->nb_queues)
+		return -1;
+
+	ret = tap_setup_queue(dev, internals, tx_queue_id);
+	if (ret == -1)
+		return -1;
+
+	RTE_LOG(INFO, PMD, "TX TAP device name %s, qid %d on fd %d\n",
+		dev->data->name, tx_queue_id, internals->txq[tx_queue_id].fd);
+
+	return 0;
+}
+
+static const struct eth_dev_ops ops = {
+	.dev_start              = tap_dev_start,
+	.dev_stop               = tap_dev_stop,
+	.dev_close              = tap_dev_close,
+	.dev_configure          = tap_dev_configure,
+	.dev_infos_get          = tap_dev_info,
+	.rx_queue_setup         = tap_rx_queue_setup,
+	.tx_queue_setup         = tap_tx_queue_setup,
+	.rx_queue_release       = tap_rx_queue_release,
+	.tx_queue_release       = tap_tx_queue_release,
+	.link_update            = tap_link_update,
+	.stats_get              = tap_stats_get,
+	.stats_reset            = tap_stats_reset,
+};
+
+static int
+pmd_mac_address(int fd, struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct ifreq ifr;
+
+	if ((fd <= 0) || !dev || !addr)
+		return -1;
+
+	memset(&ifr, 0, sizeof(ifr));
+
+	if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) {
+		RTE_LOG(ERR, PMD, "ioctl failed (SIOCGIFHWADDR) (%s)\n",
+			ifr.ifr_name);
+		return -1;
+	}
+
+	/* Set the host based MAC address to this special MAC format */
+	ifr.ifr_hwaddr.sa_data[0] = 'T';
+	ifr.ifr_hwaddr.sa_data[1] = 'a';
+	ifr.ifr_hwaddr.sa_data[2] = 'p';
+	ifr.ifr_hwaddr.sa_data[3] = '-';
+	ifr.ifr_hwaddr.sa_data[4] = dev->data->port_id;
+	ifr.ifr_hwaddr.sa_data[5] = dev->data->numa_node;
+	if (ioctl(fd, SIOCSIFHWADDR, &ifr) == -1) {
+		RTE_LOG(ERR, PMD, "%s: ioctl failed (SIOCSIFHWADDR) (%s)\n",
+			dev->data->name, ifr.ifr_name);
+		return -1;
+	}
+
+	/* Set the local application MAC address, needs to be different then
+	 * the host based MAC address.
+	 */
+	ifr.ifr_hwaddr.sa_data[0] = 'd';
+	ifr.ifr_hwaddr.sa_data[1] = 'n';
+	ifr.ifr_hwaddr.sa_data[2] = 'e';
+	ifr.ifr_hwaddr.sa_data[3] = 't';
+	ifr.ifr_hwaddr.sa_data[4] = dev->data->port_id;
+	ifr.ifr_hwaddr.sa_data[5] = dev->data->numa_node;
+	rte_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+	return 0;
+}
+
+static int
+eth_dev_tap_create(const char *name, char *tap_name)
+{
+	int numa_node = rte_socket_id();
+	struct rte_eth_dev *dev = NULL;
+	struct pmd_internals *pmd = NULL;
+	struct rte_eth_dev_data *data = NULL;
+	int i, fd = -1;
+
+	RTE_LOG(INFO, PMD,
+		"%s: Create TAP Ethernet device with %d queues on numa %u\n",
+		 name, RTE_PMD_TAP_MAX_QUEUES, rte_socket_id());
+
+	data = rte_zmalloc_socket(tap_name, sizeof(*data), 0, numa_node);
+	if (!data) {
+		RTE_LOG(INFO, PMD, "Failed to allocate data\n");
+		goto error_exit;
+	}
+
+	pmd = rte_zmalloc_socket(tap_name, sizeof(*pmd), 0, numa_node);
+	if (!pmd) {
+		RTE_LOG(INFO, PMD, "Unable to allocate internal struct\n");
+		goto error_exit;
+	}
+
+	/* Use the name and not the tap_name */
+	dev = rte_eth_dev_allocate(tap_name);
+	if (!dev) {
+		RTE_LOG(INFO, PMD, "Unable to allocate device struct\n");
+		goto error_exit;
+	}
+
+	snprintf(pmd->name, sizeof(pmd->name), "%s", tap_name);
+
+	pmd->nb_queues = RTE_PMD_TAP_MAX_QUEUES;
+
+	/* Setup some default values */
+	data->dev_private = pmd;
+	data->port_id = dev->data->port_id;
+	data->dev_flags = RTE_ETH_DEV_DETACHABLE;
+	data->kdrv = RTE_KDRV_NONE;
+	data->drv_name = pmd_tap_drv.driver.name;
+	data->numa_node = numa_node;
+
+	data->dev_link = pmd_link;
+	data->mac_addrs = &pmd->eth_addr;
+	data->nb_rx_queues = pmd->nb_queues;
+	data->nb_tx_queues = pmd->nb_queues;
+
+	dev->data = data;
+	dev->dev_ops = &ops;
+	dev->driver = NULL;
+	dev->rx_pkt_burst = pmd_rx_burst;
+	dev->tx_pkt_burst = pmd_tx_burst;
+	snprintf(dev->data->name, sizeof(dev->data->name), "%s", name);
+
+	/* Create the first Tap device */
+	fd = tun_alloc(tap_name);
+	if (fd < 0) {
+		RTE_LOG(INFO, PMD, "tun_alloc() failed\n");
+		goto error_exit;
+	}
+
+	/* Presetup the fds to -1 as being not working */
+	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
+		pmd->fds[i] = -1;
+		pmd->rxq[i].fd = -1;
+		pmd->txq[i].fd = -1;
+	}
+
+	/* Take the TUN/TAP fd and place in the first location */
+	pmd->rxq[0].fd = fd;
+	pmd->txq[0].fd = fd;
+	pmd->fds[0] = fd;
+
+	if (pmd_mac_address(fd, dev, &pmd->eth_addr) < 0) {
+		RTE_LOG(INFO, PMD, "Unable to get MAC address\n");
+		goto error_exit;
+	}
+
+	return 0;
+
+error_exit:
+	RTE_PMD_DEBUG_TRACE("Unable to initialize %s\n", name);
+
+	rte_free(data);
+	rte_free(pmd);
+
+	rte_eth_dev_release_port(dev);
+
+	return -EINVAL;
+}
+
+static int
+set_interface_name(const char *key __rte_unused,
+		   const char *value,
+		   void *extra_args)
+{
+	char *name = (char *)extra_args;
+
+	if (value)
+		snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s", value);
+	else
+		snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s%d",
+			 DEFAULT_TAP_NAME, (tap_unit - 1));
+
+	return 0;
+}
+
+static int
+set_interface_speed(const char *key __rte_unused,
+		    const char *value,
+		    void *extra_args)
+{
+	*(int *)extra_args = (value) ? atoi(value) : ETH_SPEED_NUM_10G;
+
+	return 0;
+}
+
+/* Open a TAP interface device.
+ */
+static int
+rte_pmd_tap_probe(const char *name, const char *params)
+{
+	int ret;
+	struct rte_kvargs *kvlist = NULL;
+	int speed;
+	char tap_name[RTE_ETH_NAME_MAX_LEN];
+
+	speed = ETH_SPEED_NUM_10G;
+	snprintf(tap_name, sizeof(tap_name), "%s%d",
+		 DEFAULT_TAP_NAME, tap_unit++);
+
+	RTE_LOG(INFO, PMD, "Initializing pmd_tap for %s as %s\n",
+		name, tap_name);
+
+	if (params && (params[0] != '\0')) {
+		RTE_LOG(INFO, PMD, "paramaters (%s)\n", params);
+
+		kvlist = rte_kvargs_parse(params, valid_arguments);
+		if (kvlist) {
+			if (rte_kvargs_count(kvlist, ETH_TAP_SPEED_ARG) == 1) {
+				ret = rte_kvargs_process(kvlist,
+							 ETH_TAP_SPEED_ARG,
+							 &set_interface_speed,
+							 &speed);
+				if (ret == -1)
+					goto leave;
+			}
+
+			if (rte_kvargs_count(kvlist, ETH_TAP_IFACE_ARG) == 1) {
+				ret = rte_kvargs_process(kvlist,
+							 ETH_TAP_IFACE_ARG,
+							 &set_interface_name,
+							 tap_name);
+				if (ret == -1)
+					goto leave;
+			}
+		}
+	}
+	pmd_link.link_speed = speed;
+
+	ret = eth_dev_tap_create(name, tap_name);
+
+leave:
+	if (ret == -1) {
+		RTE_LOG(INFO, PMD, "Failed to create pmd for %s as %s\n",
+			name, tap_name);
+		tap_unit--;		/* Restore the unit number */
+	}
+	rte_kvargs_free(kvlist);
+
+	return ret;
+}
+
+/* detach a TAP device.
+ */
+static int
+rte_pmd_tap_remove(const char *name)
+{
+	struct rte_eth_dev *eth_dev = NULL;
+	struct pmd_internals *internals;
+	int i;
+
+	RTE_LOG(INFO, PMD, "Closing TUN/TAP Ethernet device on numa %u\n",
+		rte_socket_id());
+
+	/* find the ethdev entry */
+	eth_dev = rte_eth_dev_allocated(name);
+	if (!eth_dev)
+		return 0;
+
+	internals = eth_dev->data->dev_private;
+	for (i = 0; i < internals->nb_queues; i++)
+		if (internals->fds[i] != -1)
+			close(internals->fds[i]);
+
+	rte_free(eth_dev->data->dev_private);
+	rte_free(eth_dev->data);
+
+	rte_eth_dev_release_port(eth_dev);
+
+	return 0;
+}
+
+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_ALIAS(net_tap, eth_tap);
+RTE_PMD_REGISTER_PARAM_STRING(net_tap, "iface=<string>,speed=N");
diff --git a/drivers/net/tap/rte_pmd_tap_version.map b/drivers/net/tap/rte_pmd_tap_version.map
new file mode 100644
index 0000000..31eca32
--- /dev/null
+++ b/drivers/net/tap/rte_pmd_tap_version.map
@@ -0,0 +1,4 @@
+DPDK_17.02 {
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index f75f0e2..02c32ae 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -124,6 +124,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       += -lrte_pmd_pcap -lpcap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_QEDE_PMD)       += -lrte_pmd_qede
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_RING)       += -lrte_pmd_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP)        += -lrte_pmd_tap
 _LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf -lm
 _LDLIBS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD)     += -lrte_pmd_virtio
 ifeq ($(CONFIG_RTE_LIBRTE_VHOST),y)
-- 
2.8.0.GIT

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox