[dpdk-dev] [PATCH v3] ntnic: add PMD driver

Neil Horman nhorman at tuxdriver.com
Fri Sep 9 15:51:08 CEST 2016


On Fri, Sep 09, 2016 at 12:48:38PM +0000, Finn Christensen wrote:
> This is the Napatech NTNIC Poll Mode Driver (PMD) for DPDK.
> 
> This patch adds support for Napatech NICs to DPDK. This is the
> initial implementation.
> 
> Signed-off-by: Finn Christensen <fc at napatech.com>
> ---
> v3:
>   * Removed the need for binary libraries on build
> v2:
>   * Added information how to build the PMD without NIC
>     Board Support Package
>   * Fixed some formatting issues
So, this is a step in the right direction, but I think its solving the wrong
problem.  If you have a dependency on an external library, thats ok, and
accessing it via dlopen makes it possible to build the library without having
that library present, but it not really in keeping with the spirit of what I
meant.  This driver is still effectively dependent on a binary blob that we have
no visibility into.  The better solution is releasing the source for the ntnic
and ntos libraries.  The license file in the referenced git tree indicates its
BSD licensed, so I don't think there should be a problem in doing that.

Neil

> ---
>  MAINTAINERS                                 |    5 +
>  config/common_base                          |    6 +
>  doc/guides/nics/features/ntnic.ini          |   14 +
>  doc/guides/nics/index.rst                   |    1 +
>  doc/guides/nics/ntnic.rst                   |  145 ++++
>  drivers/net/Makefile                        |    1 +
>  drivers/net/ntnic/Makefile                  |   66 ++
>  drivers/net/ntnic/rte_eth_ntnic.c           | 1150 +++++++++++++++++++++++++++
>  drivers/net/ntnic/rte_pmd_ntnic_version.map |    4 +
>  mk/rte.app.mk                               |    3 +
>  10 files changed, 1395 insertions(+)
>  create mode 100644 doc/guides/nics/features/ntnic.ini
>  create mode 100644 doc/guides/nics/ntnic.rst
>  create mode 100644 drivers/net/ntnic/Makefile
>  create mode 100644 drivers/net/ntnic/rte_eth_ntnic.c
>  create mode 100644 drivers/net/ntnic/rte_pmd_ntnic_version.map
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index bc9aa02..d3e5f56 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -356,6 +356,11 @@ M: Sony Chacko <sony.chacko at qlogic.com>
>  F: drivers/net/qede/
>  F: doc/guides/nics/qede.rst
> 
> +Napatech ntnic
> +M: Finn Christensen <fc at napatech.com>
> +F: drivers/net/ntnic/
> +F: doc/guides/nics/ntnic.rst
> +
>  RedHat virtio
>  M: Huawei Xie <huawei.xie at intel.com>
>  M: Yuanhan Liu <yuanhan.liu at linux.intel.com>
> diff --git a/config/common_base b/config/common_base
> index 7830535..4a3b2b8 100644
> --- a/config/common_base
> +++ b/config/common_base
> @@ -309,6 +309,12 @@ CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16
>  CONFIG_RTE_LIBRTE_PMD_PCAP=n
> 
>  #
> +# Compile software PMD backed by NTNIC files
> +#
> +CONFIG_RTE_LIBRTE_PMD_NTNIC=n
> +
> +
> +#
>  # Compile link bonding PMD library
>  #
>  CONFIG_RTE_LIBRTE_PMD_BOND=y
> diff --git a/doc/guides/nics/features/ntnic.ini b/doc/guides/nics/features/ntnic.ini
> new file mode 100644
> index 0000000..4237e6e
> --- /dev/null
> +++ b/doc/guides/nics/features/ntnic.ini
> @@ -0,0 +1,14 @@
> +;
> +; Supported features of the 'ntnic' network poll mode driver.
> +;
> +; Refer to default.ini for the full list of available PMD features.
> +;
> +[Features]
> +Link status          = Y
> +Queue start/stop     = Y
> +Promiscuous mode     = Y
> +Jumbo frame          = Y
> +Basic stats          = Y
> +Multiprocess aware   = Y
> +x86-64               = Y
> +Usage doc            = Y
> diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
> index 92d56a5..5c4205c 100644
> --- a/doc/guides/nics/index.rst
> +++ b/doc/guides/nics/index.rst
> @@ -52,6 +52,7 @@ Network Interface Controller Drivers
>      qede
>      szedata2
>      thunderx
> +    ntnic
>      virtio
>      vhost
>      vmxnet3
> diff --git a/doc/guides/nics/ntnic.rst b/doc/guides/nics/ntnic.rst
> new file mode 100644
> index 0000000..f9398db
> --- /dev/null
> +++ b/doc/guides/nics/ntnic.rst
> @@ -0,0 +1,145 @@
> +..  BSD LICENSE
> +    Copyright (c) 2016 Napatech A/S
> +    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 Napatech 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.
> +
> +NTNIC Poll Mode Driver
> +======================
> +
> +The NTNIC poll mode driver library (**librte_pmd_ntnic**) implements support
> +for **Napatech NIC** 40/50 Gbps adapters.
> +This PMD is implemented as a pure software virtual device and must be created
> +by using the EAL --vdev=parameter (parameters are explained i detail later).
> +It runs on top of the Napatech NFV NIC Board Support Package that must be
> +installed and started.
> +If no Napatech NIC is available, you can download the Napatech NTAPI includes
> +to build with.
> +
> +Supported Features
> +------------------
> +
> +- RSS (Receive Side Scaling)
> +- TSS (Transmit Side Scaling)
> +- Promiscuous mode
> +- Basic statistics
> +
> +
> +Prerequisites
> +-------------
> +
> +Requires Napatech NIC and Napatech NIC Board Support Package installed and
> +running in version **0.3.0** or higher.
> +This includes external libraries and kernel driver for resources
> +allocations and initialization.
> +If build only is required, download the Napatech NTAPI to build against.
> +
> +Pre-Installation Configuration
> +------------------------------
> +
> +Environment variables
> +~~~~~~~~~~~~~~~~~~~~~
> +
> +In order to compile the Napatech NIC PMD, user must:
> +
> +* Export the environment variable NAPATECH3_PATH with the path where
> +  the Napatech Board Support Package was installed (default location is
> +  /opt/napatech3).
> +  Or if no Napatech NIC available:
> +  Download the Napatech NTAPI include files from Github:
> +  `Napatech NTAPI <https://github.com/napa-tech/ntapi>`_.
> +
> +
> +Config File Options
> +~~~~~~~~~~~~~~~~~~~
> +
> +- ``CONFIG_RTE_LIBRTE_PMD_NTNIC`` (default **n**)
> +
> +Using the NTNIC PMD from a DPDK application using EAL vdev parameter
> +--------------------------------------------------------------------
> +
> +Napatech NIC PMD VDEV parameters
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +The Napatech NIC PMD vdev has the following command line parameters to enable
> +its features.
> +
> +* port
> +  Configures which NT port the vdev should use.
> +
> +      --vdev eth_ntnic0,port=4,rxqs=1,txqs=1
> +
> +  This will create a DPDK port0 using NT port 4
> +
> +* rxqs
> +  Control how many receive queues a vdev should have. The traffic from a vdev
> +  will be load balanced to this amount of queues and each queue can be handled
> +  by its own lcore.
> +  Note: The ntservice.ini HostBuffersRx must be configured to the sum of all
> +  receive queues across all vdevs.
> +
> +      --vdev eth_ntnic0,port=0,rxqs=8,txqs=1
> +
> +  Traffic from NT port 0 will be split across
> +  8 queues meaning that 8 lcores can be
> +  opened on DPDK port 0 and each will be
> +  their individual traffic.
> +
> +* hash
> +  Control which load balancing scheme should be used when running with multiple
> +  receive queues.
> +  The possible values are:
> +    1 = HashRoundRobin
> +    2 = Hash2TupleSorted
> +    3 = Hash5TupleSorted
> +
> +      --vdev eth_ntnic0,port=0,rxqs=4,hash=3,txqs=1
> +
> +  Create 4 queues from NT port 0 and
> +  load balance the traffic using the
> +  5-tuple sorted algorithm. Each of the
> +  4 queues can be opened via DPDK port 0
> +
> +* txqs
> +  Control how many transmit queues a vdev should have. Each queue can be used
> +  by a lcore and each queue is independent for other queues.
> +  Note: The ntservice.ini HostBuffersTx must be configured to the sum of all
> +  transmit queues across all vdevs.
> +
> +      --vdev eth_ntnic0,port=0,txqs=32,rxqs=1
> +
> +  Enable 32 transmit queues on NT port 0
> +
> +
> +Changes to Napatech driver configuration file ntservice.ini
> +-----------------------------------------------------------
> +Depending on the number of queues that is created, more hostbuffers may be
> +needed pre-allocated by the Napatech NIC Driver. This is controlled in the
> +ntservice.ini file (default locations is /opt/napatech3/config).
> +The Napatech NIC Driver must be re-started when this configuration file is
> +changed.
> +
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index bc93230..aff29e9 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -55,6 +55,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += thunderx
>  DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio
>  DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += vmxnet3
>  DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += xenvirt
> +DIRS-$(CONFIG_RTE_LIBRTE_PMD_NTNIC) += ntnic
> 
>  ifeq ($(CONFIG_RTE_LIBRTE_VHOST),y)
>  DIRS-$(CONFIG_RTE_LIBRTE_PMD_VHOST) += vhost
> diff --git a/drivers/net/ntnic/Makefile b/drivers/net/ntnic/Makefile
> new file mode 100644
> index 0000000..d816c56
> --- /dev/null
> +++ b/drivers/net/ntnic/Makefile
> @@ -0,0 +1,66 @@
> +#   BSD LICENSE
> +#
> +#   Copyright(c) 2016 Napatech A/S. 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 Napatech 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_ntnic.a
> +
> +CFLAGS += -O3 -g
> +CFLAGS += $(WERROR_FLAGS)
> +CFLAGS += -I$(NAPATECH3_PATH)/include
> +CFLAGS += -DNAPATECH3_LIB_PATH=\"$(NAPATECH3_PATH)/lib\"
> +LDLIBS += -ldl
> +
> +EXPORT_MAP := rte_pmd_ntnic_version.map
> +
> +LIBABIVER := 1
> +
> +#
> +# all source are stored in SRCS-y
> +#
> +SRCS-$(CONFIG_RTE_LIBRTE_PMD_NTNIC) += rte_eth_ntnic.c
> +
> +#
> +# Export include files
> +#
> +SYMLINK-y-include +=
> +
> +# this lib depends upon:
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NTNIC) += lib/librte_eal
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NTNIC) += lib/librte_mbuf
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NTNIC) += lib/librte_mempool
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NTNIC) += lib/librte_ether
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_NTNIC) += lib/librte_kvargs
> +
> +include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/drivers/net/ntnic/rte_eth_ntnic.c b/drivers/net/ntnic/rte_eth_ntnic.c
> new file mode 100644
> index 0000000..f83e94d
> --- /dev/null
> +++ b/drivers/net/ntnic/rte_eth_ntnic.c
> @@ -0,0 +1,1150 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2016 Napatech A/S. 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 Napatech 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 <time.h>
> +#include <dlfcn.h>
> +#include <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +#include <rte_malloc.h>
> +#include <rte_memcpy.h>
> +#include <rte_string_fns.h>
> +#include <rte_cycles.h>
> +#include <rte_kvargs.h>
> +#include <rte_dev.h>
> +#include <net/if.h>
> +#include <nt.h>
> +
> +#define ETH_NTNIC_PORT_ARG            "port"
> +#define ETH_NTNIC_PORTEND_ARG         "portend"
> +#define ETH_NTNIC_RXQUEUES_ARG        "rxqs"
> +#define ETH_NTNIC_TXQUEUES_ARG        "txqs"
> +#define ETH_NTNIC_STREAMID_ARG        "streamid"
> +#define ETH_NTNIC_HASH_ARG            "hash"
> +
> +#define HW_MAX_PKT_LEN  10000
> +#define HW_MTU    (HW_MAX_PKT_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN)
> +
> +#define MAX_RX_QUEUES 64
> +#define MAX_TX_QUEUES 64
> +#define MAX_NTNIC_PORTS 32
> +
> +static void *_libnt;
> +
> +/* NTAPI library functions */
> +int (*_NT_Init)(uint32_t);
> +int (*_NT_NetRxOpen)(NtNetStreamRx_t *,
> +               const char *, enum NtNetInterface_e, uint32_t, int);
> +int (*_NT_NetRxGet)(NtNetStreamRx_t, NtNetBuf_t *, int);
> +int (*_NT_NetRxRelease)(NtNetStreamRx_t, NtNetBuf_t);
> +int (*_NT_NetRxClose)(NtNetStreamRx_t);
> +char *(*_NT_ExplainError)(int, char *, uint32_t);
> +int (*_NT_NetTxOpen)(NtNetStreamTx_t *,
> +               const char *, uint64_t, uint32_t, uint32_t);
> +int (*_NT_NetTxRingbufferInit)(NtNetStreamTx_t, uint32_t);
> +int (*_NT_NetTxRingbufferTransmitPacket)(NtNetStreamTx_t,
> +               uint8_t *, uint16_t);
> +int (*_NT_NetTxRingbufferFlush)(NtNetStreamTx_t);
> +void (*_NT_NetTxRingbufferDone)(NtNetStreamTx_t);
> +int (*_NT_NetTxClose)(NtNetStreamTx_t);
> +int (*_NT_InfoOpen)(NtInfoStream_t *, const char *);
> +int (*_NT_InfoRead)(NtInfoStream_t, NtInfo_t *);
> +int (*_NT_InfoClose)(NtInfoStream_t);
> +int (*_NT_ConfigOpen)(NtConfigStream_t *, const char *);
> +int (*_NT_ConfigClose)(NtConfigStream_t);
> +int (*_NT_NTPL)(NtConfigStream_t, const char *,
> +               NtNtplInfo_t *, uint32_t);
> +
> +static char ebuf[1024];
> +
> +struct array_s {
> +       uint32_t value[MAX_RX_QUEUES];
> +       int count;
> +};
> +
> +static volatile uint16_t port_locks[MAX_NTNIC_PORTS];
> +
> +struct ntnic_rx_queue {
> +       NtNetStreamRx_t        net_rx[MAX_RX_QUEUES]; /* NT Rx streams */
> +       int                    rx_idx; /* Current Rx stream index */
> +       struct rte_mempool     *mb_pool; /* mbuf memory pool */
> +       uint16_t               buf_size; /* Size of data area in mbuf */
> +       NtNetBuf_t             seg; /* The current NT data segment */
> +       struct NtNetBuf_s      pkt; /* The current packet */
> +       volatile unsigned long rx_pkts; /* Rx packet statistics */
> +       volatile unsigned long err_pkts; /* Rx error packet statistics */
> +       struct array_s         astreamids; /* NT streams to read from */
> +       int                    enabled; /* Enabling/disabling of this queue */
> +};
> +
> +struct ntnic_tx_queue {
> +       NtNetStreamTx_t        net_tx; /* NT Tx stream */
> +       volatile unsigned long tx_pkts; /* Tx packet statistics */
> +       volatile unsigned long err_pkts; /* Tx error packet stat */
> +       volatile uint16_t     *plock; /* Per port transmit atomic lock */
> +       uint32_t               port; /* Tx port for this queue */
> +       int                    enabled; /* Enabling/disabling of this queue */
> +       int                    fcs_add; /* If needs added room for FCS */
> +};
> +
> +struct pmd_internals {
> +       struct ntnic_rx_queue rxq[MAX_RX_QUEUES]; /* Array of Rx queues */
> +       struct ntnic_tx_queue txq[MAX_TX_QUEUES]; /* Array of Tx queues */
> +       int                 if_index; /* Itf index always 0 - no bonding */
> +       unsigned int        nb_rx_queues; /* Number of Rx queues configured */
> +       unsigned int        nb_tx_queues; /* Number of Tx queues configured */
> +       int                 MAC_50G; /*  True if 50G ports */
> +};
> +
> +static const char *valid_arguments[] = {
> +       ETH_NTNIC_PORT_ARG,
> +       ETH_NTNIC_PORTEND_ARG,
> +       ETH_NTNIC_RXQUEUES_ARG,
> +       ETH_NTNIC_TXQUEUES_ARG,
> +       ETH_NTNIC_STREAMID_ARG,
> +       ETH_NTNIC_HASH_ARG,
> +       NULL
> +};
> +
> +static struct ether_addr eth_addr[MAX_NTNIC_PORTS];
> +static const char *drivername = "NTNIC PMD";
> +
> +static int
> +eth_ntnic_rx_jumbo(struct rte_mempool *mb_pool,
> +       struct rte_mbuf *mbuf,
> +       const u_char *data,
> +       uint16_t data_len)
> +{
> +       struct rte_mbuf *m = mbuf;
> +
> +       /* Copy the first segment. */
> +       uint16_t len = rte_pktmbuf_tailroom(mbuf);
> +
> +       rte_memcpy(rte_pktmbuf_append(mbuf, len), data, len);
> +       data_len -= len;
> +       data += len;
> +
> +       while (data_len > 0) {
> +               /* Allocate next mbuf and point to that. */
> +               m->next = rte_pktmbuf_alloc(mb_pool);
> +
> +               if (unlikely(!m->next))
> +                       return -1;
> +
> +               m = m->next;
> +
> +               /* Headroom is not needed in chained mbufs. */
> +               rte_pktmbuf_prepend(m, rte_pktmbuf_headroom(m));
> +               m->pkt_len = 0;
> +               m->data_len = 0;
> +
> +               /* Copy next segment. */
> +               len = RTE_MIN(rte_pktmbuf_tailroom(m), data_len);
> +               rte_memcpy(rte_pktmbuf_append(m, len), data, len);
> +
> +               mbuf->nb_segs++;
> +               data_len -= len;
> +               data += len;
> +       }
> +
> +       return mbuf->nb_segs;
> +}
> +
> +
> +
> +static uint16_t
> +eth_ntnic_rx(void *queue,
> +       struct rte_mbuf **bufs,
> +       uint16_t nb_pkts)
> +{
> +       unsigned int i;
> +       struct rte_mbuf *mbuf;
> +       struct ntnic_rx_queue *rx_q = queue;
> +       uint16_t num_rx = 0;
> +       uint16_t data_len;
> +
> +       if (unlikely(rx_q->net_rx[rx_q->rx_idx] == NULL || nb_pkts == 0))
> +               return 0;
> +
> +       /* Do we have any data segment */
> +       if (rx_q->seg == NULL) {
> +               /* Next stream - if multiple streams are combined */
> +               rx_q->rx_idx =
> +                       (rx_q->rx_idx <
> +                       (rx_q->astreamids.count - 1)) ? rx_q->rx_idx + 1
> +                                       : 0;
> +
> +               if ((*_NT_NetRxGet)(rx_q->net_rx[rx_q->rx_idx],
> +                               &rx_q->seg, 0) != NT_SUCCESS) {
> +                       if (rx_q->seg != NULL) {
> +                               (*_NT_NetRxRelease)(rx_q->net_rx[rx_q->rx_idx],
> +                                               rx_q->seg);
> +                               rx_q->seg = NULL;
> +                       }
> +                       return 0;
> +               }
> +               if (NT_NET_GET_SEGMENT_LENGTH(rx_q->seg)) {
> +                       /* Build a packet structure */
> +                       _nt_net_build_pkt_netbuf(rx_q->seg, &rx_q->pkt);
> +               } else {
> +                       (*_NT_NetRxRelease)(rx_q->net_rx[rx_q->rx_idx],
> +                                       rx_q->seg);
> +                       rx_q->seg = NULL;
> +                       return 0;
> +               }
> +       }
> +
> +       if (rte_mempool_get_bulk(rx_q->mb_pool, (void **)bufs, nb_pkts) != 0)
> +               return 0;
> +
> +       for (i = 0; i < nb_pkts; i++) {
> +               mbuf = bufs[i];
> +               rte_mbuf_refcnt_set(mbuf, 1);
> +               rte_pktmbuf_reset(mbuf);
> +
> +               /* HW slicing not supported */
> +               data_len = (uint16_t)NT_NET_GET_PKT_WIRE_LENGTH((&rx_q->pkt))
> +                               - 4;
> +               if (data_len <= rx_q->buf_size) {
> +                       /* Packet will fit in the mbuf, go ahead and copy */
> +                       mbuf->pkt_len = mbuf->data_len;
> +                       data_len = mbuf->data_len;
> +                       rte_memcpy((u_char *)mbuf->buf_addr +
> +                                       RTE_PKTMBUF_HEADROOM,
> +                                       NT_NET_GET_PKT_L2_PTR((&rx_q->pkt)),
> +                                       mbuf->data_len);
> +               } else {
> +                       /* Try read jumbo frame into multi mbufs. */
> +                       if (unlikely(eth_ntnic_rx_jumbo(rx_q->mb_pool,
> +                                       mbuf,
> +                                       NT_NET_GET_PKT_L2_PTR((&rx_q->pkt)),
> +                                       data_len) == -1))
> +                               break;
> +               }
> +
> +               mbuf->port = NT_NET_GET_PKT_RXPORT((&rx_q->pkt));
> +               num_rx++;
> +
> +               /* Get the next packet if any */
> +               if (_nt_net_get_next_packet(rx_q->seg,
> +                               NT_NET_GET_SEGMENT_LENGTH(rx_q->seg),
> +                               &rx_q->pkt) == 0) {
> +                       (*_NT_NetRxRelease)(rx_q->net_rx[rx_q->rx_idx],
> +                                       rx_q->seg);
> +                       rx_q->seg = NULL;
> +                       break;
> +               }
> +
> +               rx_q->rx_pkts++;
> +       }
> +
> +       if (num_rx < nb_pkts) {
> +               rte_mempool_put_bulk(rx_q->mb_pool,
> +                               (void * const *)(bufs + num_rx),
> +                               nb_pkts - num_rx);
> +       }
> +       return num_rx;
> +}
> +
> +
> +
> +
> +
> +/* Callback to handle sending packets through a NT NIC. */
> +static uint16_t
> +eth_ntnic_tx_ringbuffer(void *queue,
> +       struct rte_mbuf **bufs,
> +       uint16_t nb_pkts)
> +{
> +       unsigned int i;
> +       struct ntnic_tx_queue *tx_q = queue;
> +       int retval;
> +       uint16_t old;
> +       uint16_t new_flag = 0;
> +
> +
> +       if (unlikely(tx_q == NULL || tx_q->net_tx == NULL || nb_pkts == 0))
> +               return 0;
> +
> +
> +       do {
> +               old = 0;
> +               new_flag = 1;
> +               retval = rte_atomic16_cmpset(tx_q->plock, old, new_flag);
> +       } while (unlikely(retval == 0));
> +
> +       for (i = 0; i < nb_pkts; i++) {
> +               /* Not allowed to TX less than 64 byte packets */
> +               if (bufs[i]->pkt_len < 60)
> +                       bufs[i]->pkt_len = 60;
> +
> +               /* transmit a single packet */
> +               (*_NT_NetTxRingbufferTransmitPacket)(tx_q->net_tx,
> +                               rte_pktmbuf_mtod(bufs[i], uint8_t *),
> +                               bufs[i]->pkt_len + 4 - tx_q->fcs_add);
> +               rte_pktmbuf_free(bufs[i]);
> +       }
> +       tx_q->tx_pkts += nb_pkts;
> +
> +       *tx_q->plock = 0;
> +       return nb_pkts;
> +}
> +
> +
> +
> +static int
> +eth_dev_start(struct rte_eth_dev *dev)
> +{
> +       struct pmd_internals *internals = dev->data->dev_private;
> +       struct ntnic_rx_queue *rx_q = internals->rxq;
> +       struct ntnic_tx_queue *tx_q = internals->txq;
> +       uint queue;
> +       int status, idx;
> +
> +       RTE_LOG(INFO, PMD, "NTNIC: %s\n", __func__);
> +
> +       if ((internals->nb_tx_queues | internals->nb_rx_queues) == 0)
> +               return -1;
> +
> +       for (queue = 0; queue < internals->nb_rx_queues; queue++) {
> +               if (rx_q[queue].enabled) {
> +                       char str[128], val[10];
> +                       str[0] = 0;
> +                       /* build list of streamids to log */
> +                       for (idx = 0; idx <
> +                               rx_q[queue].astreamids.count; idx++) {
> +                               if (idx)
> +                                       sprintf(val, ",%d",
> +                                       rx_q[queue].astreamids.value[idx]);
> +                               else
> +                                       sprintf(val, "%i",
> +                                       rx_q[queue].astreamids.value[idx]);
> +                               strcat(str, val);
> +                       }
> +
> +                       for (idx = 0; idx < rx_q[queue].astreamids.count;
> +                                       idx++) {
> +                               status =
> +                               (*_NT_NetRxOpen)(&rx_q[queue].net_rx[idx],
> +                                       "DPDK",
> +                                       NT_NET_INTERFACE_SEGMENT,
> +                                       rx_q[queue].astreamids.value[idx], -1);
> +                               if (status != NT_SUCCESS) {
> +                                       /* try packet interface instead */
> +                                       (*_NT_ExplainError)(status,
> +                                                       ebuf,
> +                                                       sizeof(ebuf));
> +                                       RTE_LOG(ERR, PMD,
> +                                               "NT_NetRxOpen() failed: %s\n",
> +                                               ebuf);
> +                                       return -1;
> +                               }
> +                       }
> +               }
> +       }
> +
> +       for (queue = 0; queue < internals->nb_tx_queues; queue++) {
> +               if (tx_q[queue].enabled) {
> +                       RTE_LOG(INFO, PMD, "NTNIC: NT_NetTxOpen(%d)\n",
> +                                       tx_q[queue].port);
> +                       status = (*_NT_NetTxOpen)(&tx_q[queue].net_tx, "DPDK",
> +                                       1 << tx_q[queue].port,
> +                                       dev->pci_dev->numa_node, 0);
> +                       if (status != NT_SUCCESS) {
> +                               (*_NT_ExplainError)(status, ebuf,
> +                                               sizeof(ebuf));
> +                               RTE_LOG(INFO, PMD,
> +                               "NT_NetTxOpen(0x%X, %d, 0) failed: %s\n",
> +                               1 << tx_q[queue].port,
> +                               dev->pci_dev->numa_node, ebuf);
> +                               return -1;
> +                       }
> +
> +                       /* Init and associate RTD Tx Ring buf to Tx handler */
> +                       status = (*_NT_NetTxRingbufferInit)(
> +                                               tx_q[queue].net_tx,
> +                                               tx_q[queue].port);
> +                       if (status != NT_SUCCESS) {
> +                               (*_NT_ExplainError)(status, ebuf,
> +                                               sizeof(ebuf));
> +                               RTE_LOG(ERR, PMD,
> +                               "NT_NetRxOpen() failed: %s\n",
> +                               ebuf);
> +                               return -1;
> +                       }
> +               }
> +               tx_q[queue].plock = &port_locks[tx_q[queue].port];
> +               tx_q[queue].fcs_add = (internals->MAC_50G) ? 4 : 0;
> +       }
> +
> +       dev->data->dev_link.link_status = 1;
> +       return 0;
> +}
> +
> +
> +static void
> +eth_dev_stop(struct rte_eth_dev *dev)
> +{
> +       struct pmd_internals *internals = dev->data->dev_private;
> +       struct ntnic_rx_queue *rx_q = internals->rxq;
> +       struct ntnic_tx_queue *tx_q = internals->txq;
> +       uint q;
> +       int idx;
> +       RTE_LOG(INFO, PMD, "NTNIC: %s\n", __func__);
> +
> +       for (q = 0; q < internals->nb_rx_queues; q++) {
> +               if (rx_q[q].seg) {
> +                       (*_NT_NetRxRelease)(rx_q[q].net_rx[rx_q->rx_idx],
> +                               rx_q[q].seg);
> +                       rx_q[q].seg = NULL;
> +               }
> +               for (idx = 0; idx < rx_q[q].astreamids.count; idx++) {
> +                       if (rx_q[q].net_rx[idx])
> +                       (void)(*_NT_NetRxClose)(rx_q[q].net_rx[idx]);
> +               }
> +       }
> +       for (q = 0; q < internals->nb_tx_queues; q++) {
> +               if (tx_q[q].net_tx) {
> +                       (*_NT_NetTxRingbufferDone)(tx_q[q].net_tx);
> +                       (void)(*_NT_NetTxClose)(tx_q[q].net_tx);
> +               }
> +       }
> +       dev->data->dev_link.link_status = 0;
> +}
> +
> +static int
> +eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
> +{
> +       RTE_LOG(INFO, PMD, "NTNIC: %s\n", __func__);
> +       return 0;
> +}
> +
> +static void
> +eth_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->driver_name = drivername;
> +       dev_info->max_mac_addrs = 1;
> +       dev_info->max_rx_pktlen = HW_MTU;
> +       dev_info->max_rx_queues = (uint16_t)internals->nb_rx_queues;
> +       dev_info->max_tx_queues = (uint16_t)internals->nb_tx_queues;
> +       dev_info->min_rx_bufsize = 0;
> +       dev_info->pci_dev = NULL;
> +}
> +
> +static void
> +eth_stats_get(struct rte_eth_dev *dev,
> +       struct rte_eth_stats *igb_stats)
> +{
> +       unsigned int i;
> +       unsigned long rx_total = 0;
> +       unsigned long tx_total = 0;
> +       unsigned long tx_err_total = 0;
> +       const struct pmd_internals *internal = dev->data->dev_private;
> +
> +       memset(igb_stats, 0, sizeof(*igb_stats));
> +       for (i = 0;
> +               i < RTE_ETHDEV_QUEUE_STAT_CNTRS && i < internal->nb_rx_queues;
> +               i++) {
> +               igb_stats->q_ipackets[i] = internal->rxq[i].rx_pkts;
> +               rx_total += igb_stats->q_ipackets[i];
> +       }
> +       for (i = 0;
> +               i < RTE_ETHDEV_QUEUE_STAT_CNTRS && i < internal->nb_tx_queues;
> +               i++) {
> +               igb_stats->q_opackets[i] = internal->txq[i].tx_pkts;
> +               igb_stats->q_errors[i] = internal->txq[i].err_pkts;
> +               tx_total += igb_stats->q_opackets[i];
> +               tx_err_total += igb_stats->q_errors[i];
> +       }
> +
> +       igb_stats->ipackets = rx_total;
> +       igb_stats->opackets = tx_total;
> +       igb_stats->oerrors = tx_err_total;
> +}
> +
> +static void
> +eth_stats_reset(struct rte_eth_dev *dev)
> +{
> +       unsigned int i;
> +       struct pmd_internals *internal = dev->data->dev_private;
> +
> +       for (i = 0; i < internal->nb_rx_queues; i++)
> +               internal->rxq[i].rx_pkts = 0;
> +       for (i = 0; i < internal->nb_tx_queues; i++) {
> +               internal->txq[i].tx_pkts = 0;
> +               internal->txq[i].err_pkts = 0;
> +       }
> +}
> +
> +static void
> +eth_dev_close(struct rte_eth_dev *dev __rte_unused)
> +{
> +       RTE_LOG(INFO, PMD, "NTNIC: %s\n", __func__);
> +}
> +
> +static void
> +eth_queue_release(void *q __rte_unused)
> +{
> +       RTE_LOG(INFO, PMD, "NTNIC: %s\n", __func__);
> +}
> +
> +static int
> +eth_link_update(struct rte_eth_dev *dev __rte_unused,
> +       int wait_to_complete __rte_unused)
> +{
> +       return 0;
> +}
> +
> +static int
> +eth_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 *mb_pool)
> +{
> +       struct rte_pktmbuf_pool_private *mbp_priv;
> +       struct pmd_internals *internals = dev->data->dev_private;
> +       struct ntnic_rx_queue *rx_q = &internals->rxq[rx_queue_id];
> +
> +       RTE_LOG(INFO, PMD, "NTNIC RX queue setup\n");
> +       rx_q->mb_pool = mb_pool;
> +       dev->data->rx_queues[rx_queue_id] = rx_q;
> +
> +       mbp_priv =  rte_mempool_get_priv(rx_q->mb_pool);
> +       rx_q->buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
> +                                       RTE_PKTMBUF_HEADROOM);
> +       rx_q->enabled = 1;
> +       return 0;
> +}
> +
> +static int
> +eth_tx_queue_setup(struct rte_eth_dev *dev __rte_unused,
> +       uint16_t tx_queue_id __rte_unused,
> +       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;
> +       RTE_LOG(INFO, PMD, "NTNIC TX queue setup\n");
> +       dev->data->tx_queues[tx_queue_id] = &internals->txq[tx_queue_id];
> +       internals->txq[tx_queue_id].enabled = 1;
> +       return 0;
> +}
> +
> +static int _dev_set_mtu(struct rte_eth_dev *dev __rte_unused, uint16_t mtu)
> +{
> +       if (mtu < 46 || mtu > HW_MTU)
> +               return -EINVAL;
> +
> +       return 0;
> +}
> +
> +static struct eth_dev_ops ops = {
> +               .dev_start = eth_dev_start,
> +               .dev_stop = eth_dev_stop,
> +               .dev_close = eth_dev_close,
> +               .mtu_set = _dev_set_mtu,
> +               .dev_configure = eth_dev_configure,
> +               .dev_infos_get = eth_dev_info,
> +               .rx_queue_setup = eth_rx_queue_setup,
> +               .tx_queue_setup = eth_tx_queue_setup,
> +               .rx_queue_release = eth_queue_release,
> +               .tx_queue_release = eth_queue_release,
> +               .link_update = eth_link_update,
> +               .stats_get = eth_stats_get,
> +               .stats_reset = eth_stats_reset,
> +};
> +
> +static int
> +rte_pmd_init_internals(const char *name,
> +               const unsigned int nb_rx_queues,
> +               const unsigned int nb_tx_queues,
> +               const unsigned int numa_node,
> +               struct array_s *pastreamids,
> +               const uint32_t port,
> +               struct rte_eth_dev **eth_dev)
> +{
> +       struct pmd_internals *internals = NULL;
> +       struct rte_eth_dev_data *data = NULL;
> +       struct rte_pci_device *pci_dev = NULL;
> +       uint i, status;
> +       char err_buf[NT_ERRBUF_SIZE];
> +       NtInfoStream_t info;
> +       NtInfo_t info_port;
> +       struct rte_eth_link pmd_link;
> +       assert(nb_rx_queues < MAX_RX_QUEUES);
> +       assert(nb_tx_queues < MAX_TX_QUEUES);
> +       assert(port < MAX_NTNIC_PORTS);
> +
> +       RTE_LOG(INFO, PMD,
> +                       "Creating ntnic-backend ethdev on numa socket %u\n",
> +                       numa_node);
> +
> +       /* now do all data allocation - for eth_dev structure, dummy pci driver
> +        * and internal (private) data
> +        */
> +       data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
> +       if (data == NULL)
> +               goto error;
> +
> +       pci_dev = rte_zmalloc_socket(name, sizeof(*pci_dev), 0, numa_node);
> +       if (pci_dev == NULL)
> +               goto error;
> +
> +       internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
> +       if (internals == NULL)
> +               goto error;
> +
> +       /* reserve an ethdev entry */
> +       *eth_dev = rte_eth_dev_allocate(name, RTE_ETH_DEV_VIRTUAL);
> +       if (*eth_dev == NULL)
> +               goto error;
> +
> +       /* Open the information stream */
> +       status = (*_NT_InfoOpen)(&info, "DPDK Info stream");
> +       if (status != NT_SUCCESS) {
> +               (*_NT_ExplainError)(status, err_buf, sizeof(err_buf));
> +               RTE_LOG(ERR, PMD,
> +                       ">>> Error: NT_InfoOpen failed. Code 0x%x = %s\n",
> +                       status, err_buf);
> +               return status;
> +       }
> +
> +       /* Find local port offset */
> +       info_port.cmd = NT_INFO_CMD_READ_PORT_V7;
> +       info_port.u.port_v7.portNo = (uint8_t)(port);
> +       status = (*_NT_InfoRead)(info, &info_port);
> +       if (status != 0) {
> +               (*_NT_ExplainError)(status, err_buf, sizeof(err_buf));
> +               RTE_LOG(ERR, PMD,
> +                       "ERROR: NT_InfoRead failed. Code 0x%x = %s\n",
> +                       status, err_buf);
> +               return status;
> +       }
> +
> +       /* check for 50G MAC */
> +       if (info_port.u.port_v7.data.adapterInfo.fpgaid.s.product == 9506 ||
> +               info_port.u.port_v7.data.adapterInfo.fpgaid.s.product == 9509) {
> +               internals->MAC_50G = 1;
> +       } else {
> +               internals->MAC_50G = 0;
> +               /* Check for valid FPGAs (NFV NICs) */
> +               if (info_port.u.port_v7.data.adapterInfo.fpgaid.s.product !=
> +                       9507 &&
> +                       info_port.u.port_v7.data.adapterInfo.fpgaid.s.product !=
> +                       9510) {
> +                       RTE_LOG(ERR, PMD,
> +                       "ERROR: NTNIC PMD does not support the NT adapter"
> +                       "- port %i\n",
> +                       port);
> +                       return -1;
> +               }
> +       }
> +
> +       internals->nb_rx_queues = nb_rx_queues;
> +       internals->nb_tx_queues = nb_tx_queues;
> +       for (i = 0; i < nb_rx_queues; i++) {
> +               int idx;
> +               for (idx = 0; idx < pastreamids->count; idx++) {
> +                       internals->rxq[i].astreamids.value[idx] =
> +                                       pastreamids->value[idx] + i;
> +               }
> +
> +               internals->rxq[i].astreamids.count = pastreamids->count;
> +
> +               internals->rxq[i].seg = NULL;
> +               internals->rxq[i].enabled = 0;
> +       }
> +
> +       for (i = 0; i < nb_tx_queues; i++) {
> +       if (port < info_port.u.port_v7.data.adapterInfo.portOffset) {
> +               RTE_LOG(ERR, PMD, "Error wrong port specified\n");
> +               return -1;
> +       }
> +               internals->txq[i].port = port;
> +               internals->txq[i].enabled = 0;
> +       }
> +
> +       switch (info_port.u.port_v7.data.speed) {
> +       case NT_LINK_SPEED_UNKNOWN:
> +               pmd_link.link_speed = ETH_SPEED_NUM_1G;
> +               break;
> +       case NT_LINK_SPEED_10M:
> +               pmd_link.link_speed = ETH_SPEED_NUM_10M;
> +               break;
> +       case NT_LINK_SPEED_100M:
> +               pmd_link.link_speed = ETH_SPEED_NUM_100M;
> +               break;
> +       case NT_LINK_SPEED_1G:
> +               pmd_link.link_speed = ETH_SPEED_NUM_1G;
> +               break;
> +       case NT_LINK_SPEED_10G:
> +               pmd_link.link_speed = ETH_SPEED_NUM_10G;
> +               break;
> +       case NT_LINK_SPEED_40G:
> +               pmd_link.link_speed = ETH_SPEED_NUM_40G;
> +               break;
> +       case NT_LINK_SPEED_50G:
> +               pmd_link.link_speed = ETH_SPEED_NUM_50G;
> +               break;
> +       case NT_LINK_SPEED_100G:
> +               pmd_link.link_speed = ETH_SPEED_NUM_100G;
> +               break;
> +       }
> +
> +       memcpy(&eth_addr[port].addr_bytes, &info_port.u.port_v7.data.macAddress,
> +                       sizeof(eth_addr[port].addr_bytes));
> +       status = (*_NT_InfoClose)(info);
> +       if (status != NT_SUCCESS) {
> +               (*_NT_ExplainError)(status, err_buf, sizeof(err_buf));
> +               RTE_LOG(ERR, PMD,
> +                       ">>> Error: NT_InfoOpen failed. Code 0x%x = %s\n",
> +                       status, err_buf);
> +               return status;
> +       }
> +
> +       pmd_link.link_duplex = ETH_LINK_FULL_DUPLEX;
> +       pmd_link.link_status = 0;
> +
> +       internals->if_index = 0;
> +
> +       pci_dev->numa_node = numa_node;
> +
> +       data->dev_private = internals;
> +       data->port_id = (*eth_dev)->data->port_id;
> +       data->nb_rx_queues = (uint16_t)nb_rx_queues;
> +       data->nb_tx_queues = (uint16_t)nb_tx_queues;
> +       data->dev_link = pmd_link;
> +       data->mac_addrs = &eth_addr[port];
> +       data->numa_node = numa_node;
> +       data->drv_name = drivername;
> +
> +       (*eth_dev)->data = data;
> +       (*eth_dev)->dev_ops = &ops;
> +       (*eth_dev)->pci_dev = pci_dev;
> +
> +       return 0;
> +
> +error:
> +       if (data)
> +               rte_free(data);
> +       if (pci_dev)
> +               rte_free(pci_dev);
> +       if (internals)
> +               rte_free(internals);
> +       return -1;
> +}
> +
> +/*
> + * convert ascii to int
> + */
> +static inline int
> +ascii_to_u32(const char *key __rte_unused,
> +               const char *value, void *extra_args __rte_unused)
> +{
> +       *(uint32_t *)extra_args = atoi(value);
> +       return 0;
> +}
> +
> +static inline int
> +ascii_to_u32_array(const char *key __rte_unused,
> +               const char *value, void *extra_args)
> +{
> +       struct array_s *pastreams = (struct array_s *)extra_args;
> +       int sval, eval;
> +       if (sscanf(value, "%d..%d", &sval, &eval) == 2) {
> +               int cnt;
> +               for (cnt = sval; cnt <= eval; cnt++)
> +                       pastreams->value[pastreams->count++] = cnt;
> +       } else {
> +               pastreams->value[pastreams->count++] = atoi(value);
> +       }
> +       return 0;
> +}
> +
> +
> +static int DoNtpl(const char *ntplStr)
> +{
> +       NtConfigStream_t hCfgStream;
> +       NtNtplInfo_t ntplInfo;
> +       int status;
> +
> +       status = (*_NT_ConfigOpen)(&hCfgStream, "capture");
> +       if (status != NT_SUCCESS) {
> +               /* Get the status code as text */
> +               (*_NT_ExplainError)(status, ebuf, sizeof(ebuf) - 1);
> +               fprintf(stderr, "NT_ConfigOpen() failed: %s\n", ebuf);
> +               return -1;
> +       }
> +
> +       RTE_LOG(INFO, PMD, "NTPL : %s\n", ntplStr);
> +       status = (*_NT_NTPL)(hCfgStream, ntplStr, &ntplInfo,
> +                               NT_NTPL_PARSER_VALIDATE_NORMAL);
> +       if (status != NT_SUCCESS) {
> +               /* Get the status code as text */
> +               (*_NT_ExplainError)(status, ebuf, sizeof(ebuf) - 1);
> +               fprintf(stderr, "NT_NTPL() failed: %s\n", ebuf);
> +               fprintf(stderr, ">>> NTPL errorcode: %X\n",
> +                               ntplInfo.u.errorData.errCode);
> +               fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[0]);
> +               fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[1]);
> +               fprintf(stderr, ">>> %s\n", ntplInfo.u.errorData.errBuffer[2]);
> +               (*_NT_ConfigClose)(hCfgStream);
> +               return -1;
> +       }
> +       (*_NT_ConfigClose)(hCfgStream);
> +       return 0;
> +}
> +
> +
> +static int
> +_nt_lib_open(void)
> +{
> +       char path[128];
> +       strcpy(path, NAPATECH3_LIB_PATH);
> +       strcat(path, "/libntapi.so");
> +
> +       /* Load the library */
> +       _libnt = dlopen(path, RTLD_NOW);
> +       if (_libnt == NULL) {
> +               /* Library does not exist. */
> +               fprintf(stderr, "Failed to find needed library : %s\n", path);
> +               return -1;
> +       }
> +       _NT_Init = dlsym(_libnt, "NT_Init");
> +       if (_NT_Init == NULL) {
> +               fprintf(stderr, "Failed to find \"NT_Init\" in %s\n", path);
> +               return -1;
> +       }
> +
> +       _NT_ConfigOpen = dlsym(_libnt, "NT_ConfigOpen");
> +       if (_NT_ConfigOpen == NULL) {
> +               fprintf(stderr, "Failed to find \"NT_ConfigOpen\" in %s\n",
> +                               path);
> +               return -1;
> +       }
> +       _NT_ConfigClose = dlsym(_libnt, "NT_ConfigClose");
> +       if (_NT_ConfigClose == NULL) {
> +               fprintf(stderr, "Failed to find \"NT_ConfigClose\" in %s\n",
> +                               path);
> +               return -1;
> +       }
> +       _NT_NTPL = dlsym(_libnt, "NT_NTPL");
> +       if (_NT_NTPL == NULL) {
> +               fprintf(stderr, "Failed to find \"NT_NTPL\" in %s\n",
> +                               path);
> +               return -1;
> +       }
> +
> +       _NT_InfoOpen = dlsym(_libnt, "NT_InfoOpen");
> +       if (_NT_InfoOpen == NULL) {
> +               fprintf(stderr, "Failed to find \"NT_InfoOpen\" in %s\n",
> +                               path);
> +               return -1;
> +       }
> +       _NT_InfoRead = dlsym(_libnt, "NT_InfoRead");
> +       if (_NT_InfoRead == NULL) {
> +               fprintf(stderr, "Failed to find \"NT_InfoRead\" in %s\n",
> +                               path);
> +               return -1;
> +       }
> +       _NT_InfoClose = dlsym(_libnt, "NT_InfoClose");
> +       if (_NT_InfoClose == NULL) {
> +               fprintf(stderr, "Failed to find \"NT_InfoClose\" in %s\n",
> +                               path);
> +               return -1;
> +       }
> +
> +       _NT_ExplainError = dlsym(_libnt, "NT_ExplainError");
> +       if (_NT_ExplainError == NULL) {
> +               fprintf(stderr, "Failed to find \"NT_ExplainError\" in %s\n",
> +                               path);
> +               return -1;
> +       }
> +       _NT_NetTxOpen = dlsym(_libnt, "NT_NetTxOpen");
> +       if (_NT_NetTxOpen == NULL) {
> +               fprintf(stderr, "Failed to find \"NT_NetTxOpen\" in %s\n",
> +                               path);
> +               return -1;
> +       }
> +       _NT_NetTxRingbufferInit = dlsym(_libnt, "NT_NetTxRingbufferInit");
> +       if (_NT_NetTxRingbufferInit == NULL) {
> +               fprintf(stderr,
> +                       "Failed to find \"NT_NetTxRingbufferInit\" in %s\n",
> +                       path);
> +               return -1;
> +       }
> +       _NT_NetTxRingbufferFlush = dlsym(_libnt, "NT_NetTxRingbufferFlush");
> +       if (_NT_NetTxRingbufferFlush == NULL) {
> +               fprintf(stderr,
> +                       "Failed to find \"NT_NetTxRingbufferFlush\" in %s\n",
> +                       path);
> +               return -1;
> +       }
> +       _NT_NetTxRingbufferTransmitPacket =
> +                       dlsym(_libnt, "NT_NetTxRingbufferTransmitPacket");
> +       if (_NT_NetTxRingbufferTransmitPacket == NULL) {
> +               fprintf(stderr,
> +                       "Failed to find \"NT_NetTxRingbufferTransmitPacket\""
> +                       " in %s\n", path);
> +               return -1;
> +       }
> +       _NT_NetTxRingbufferDone = dlsym(_libnt, "NT_NetTxRingbufferDone");
> +       if (_NT_NetTxRingbufferDone == NULL) {
> +               fprintf(stderr,
> +                       "Failed to find \"NT_NetTxRingbufferDone\" in %s\n",
> +                       path);
> +               return -1;
> +       }
> +       _NT_NetTxClose = dlsym(_libnt, "NT_NetTxClose");
> +       if (_NT_NetTxClose == NULL) {
> +               fprintf(stderr, "Failed to find \"NT_NetTxClose\" in %s\n",
> +                               path);
> +               return -1;
> +       }
> +
> +       _NT_NetRxOpen = dlsym(_libnt, "NT_NetRxOpen");
> +       if (_NT_NetRxOpen == NULL) {
> +               fprintf(stderr, "Failed to find \"NT_NetRxOpen\" in %s\n",
> +                               path);
> +               return -1;
> +       }
> +       _NT_NetRxGet = dlsym(_libnt, "NT_NetRxGet");
> +       if (_NT_NetRxGet == NULL) {
> +               fprintf(stderr, "Failed to find \"NT_NetRxGet\" in %s\n",
> +                               path);
> +               return -1;
> +       }
> +       _NT_NetRxRelease = dlsym(_libnt, "NT_NetRxRelease");
> +       if (_NT_NetRxRelease == NULL) {
> +               fprintf(stderr, "Failed to find \"NT_NetRxRelease\" in %s\n",
> +                               path);
> +               return -1;
> +       }
> +       _NT_NetRxClose = dlsym(_libnt, "NT_NetRxClose");
> +       if (_NT_NetRxClose == NULL) {
> +               fprintf(stderr, "Failed to find \"NT_NetRxClose\" in %s\n",
> +                               path);
> +               return -1;
> +       }
> +
> +       return 0;
> +}
> +
> +
> +
> +static int
> +rte_pmd_ntnic_devinit(const char *name, const char *params)
> +{
> +       unsigned int numa_node;
> +       int ret = 0;
> +       struct rte_kvargs *kvlist;
> +       struct rte_eth_dev *eth_dev;
> +       unsigned int i;
> +       uint32_t rxqueues = 0;
> +       uint32_t txqueues = 0;
> +       uint32_t port = 0;
> +       uint32_t portend = (uint32_t)-1;
> +       uint32_t hash = (uint32_t)-1;
> +       struct array_s astreamids;
> +
> +       static int first = 1;
> +       static int stream_id;
> +       char ntplStr[512];
> +
> +       astreamids.count = 0;
> +
> +       RTE_LOG(INFO, PMD, "Initializing pmd_ntnic for %s\n", name);
> +
> +       numa_node = rte_socket_id();
> +
> +       kvlist = rte_kvargs_parse(params, valid_arguments);
> +       if (kvlist == NULL)
> +               return -1;
> +
> +       /* Get port to use for Rx/Tx */
> +       i = rte_kvargs_count(kvlist, ETH_NTNIC_PORT_ARG);
> +       if (i) {
> +               assert(i == 1);
> +               ret = rte_kvargs_process(kvlist, ETH_NTNIC_PORT_ARG,
> +                                               &ascii_to_u32, &port);
> +       }
> +       /* If Rx port merge is need, her the portend is specified */
> +       i = rte_kvargs_count(kvlist, ETH_NTNIC_PORTEND_ARG);
> +       if (i) {
> +               assert(i == 1);
> +               ret = rte_kvargs_process(kvlist, ETH_NTNIC_PORTEND_ARG,
> +                                               &ascii_to_u32, &portend);
> +       }
> +
> +       /* Get # RX queues */
> +       i = rte_kvargs_count(kvlist, ETH_NTNIC_RXQUEUES_ARG);
> +       if (i) {
> +               assert(i == 1);
> +               ret = rte_kvargs_process(kvlist, ETH_NTNIC_RXQUEUES_ARG,
> +                                               &ascii_to_u32, &rxqueues);
> +       }
> +       /* Get # TX queues */
> +       i = rte_kvargs_count(kvlist, ETH_NTNIC_TXQUEUES_ARG);
> +       if (i) {
> +               assert(i == 1);
> +               ret = rte_kvargs_process(kvlist, ETH_NTNIC_TXQUEUES_ARG,
> +                                               &ascii_to_u32, &txqueues);
> +       }
> +
> +       /* Get list of streamIds - if used */
> +       i = rte_kvargs_count(kvlist, ETH_NTNIC_STREAMID_ARG);
> +       if (i) {
> +               ret = rte_kvargs_process(kvlist, ETH_NTNIC_STREAMID_ARG,
> +                                       &ascii_to_u32_array, &astreamids);
> +       }
> +
> +       /* Get an alternative hash algorithm */
> +       i = rte_kvargs_count(kvlist, ETH_NTNIC_HASH_ARG);
> +       if (i) {
> +               assert(i == 1);
> +               ret = rte_kvargs_process(kvlist, ETH_NTNIC_HASH_ARG,
> +                                               &ascii_to_u32, &hash);
> +       }
> +
> +       /* check portend and streamids */
> +       if (portend != (uint32_t)-1 && astreamids.count) {
> +               RTE_LOG(ERR, PMD, "Cannot specify portend when one or more"
> +                       " streamid's are specified\n");
> +               return -1;
> +       }
> +       rte_kvargs_free(kvlist);
> +
> +       if (ret < 0)
> +               return -1;
> +
> +       ret = _nt_lib_open();
> +       if (ret < 0)
> +               return -1;
> +
> +       if (first)
> +               (*_NT_Init)(NTAPI_VERSION);
> +
> +       if (astreamids.count) {
> +               first = 0;
> +               /*
> +                * if a specific streamid specified then use that otherwise,
> +                * port defaults to Tx port only
> +                */
> +               if (rte_pmd_init_internals(name, rxqueues, txqueues, numa_node,
> +                               &astreamids, port, &eth_dev) < 0)
> +                       return -1;
> +       } else {
> +               struct array_s astrids;
> +               if (first) {
> +                       /* Delete all NTPL */
> +                       sprintf(ntplStr, "Delete=All");
> +                       if (DoNtpl(ntplStr) != 0)
> +                               return -1;
> +                       first = 0;
> +               }
> +               astrids.count = 1;
> +               astrids.value[0] = stream_id;
> +               if (rte_pmd_init_internals(name, rxqueues, txqueues, numa_node,
> +                               &astrids, port, &eth_dev) < 0)
> +                       return -1;
> +
> +               /* Assign the traffic */
> +               if (portend != (uint32_t)-1) {
> +                       sprintf(ntplStr,
> +                               "Assign[streamid=(%d..%d);Descriptor=NT]"
> +                               "=port==(%d..%d)",
> +                               stream_id,
> +                               (stream_id + rxqueues - 1), port, portend);
> +
> +               } else {
> +                       sprintf(ntplStr,
> +                               "Assign[streamid=(%d..%d);Descriptor=NT]"
> +                               "=port==%d",
> +                               stream_id,
> +                               (stream_id + rxqueues - 1), port);
> +               }
> +               if (DoNtpl(ntplStr) != 0)
> +                       return -1;
> +
> +               if (hash != (uint32_t)-1) {
> +                       switch (hash) {
> +                       default:
> +                       case 1:
> +                               DoNtpl("HashMode=HashRoundRobin");
> +                               break;
> +                       case 2:
> +                               DoNtpl("HashMode=Hash2TupleSorted");
> +                               break;
> +                       case 3:
> +                               DoNtpl("HashMode=Hash5TupleSorted");
> +                               break;
> +                       }
> +               }
> +
> +               stream_id += rxqueues;
> +       }
> +
> +       eth_dev->rx_pkt_burst = eth_ntnic_rx;
> +       eth_dev->tx_pkt_burst = eth_ntnic_tx_ringbuffer;
> +
> +       return 0;
> +}
> +
> +static int
> +rte_pmd_ntnic_devuninit(const char *name)
> +{
> +       (void)name;
> +       if (_libnt != NULL)
> +               dlclose(_libnt);
> +       return 0;
> +}
> +
> +
> +static struct rte_driver pmd_ntnic_drv = {
> +       .type = PMD_VDEV,
> +       .init = rte_pmd_ntnic_devinit,
> +       .uninit = rte_pmd_ntnic_devuninit,
> +};
> +
> +PMD_REGISTER_DRIVER(pmd_ntnic_drv, eth_ntnic);
> +DRIVER_REGISTER_PARAM_STRING(eth_ntnic,
> +       "port=<int> "
> +       "rxqs=<int>"
> +       "txqs=<int>"
> +       "hash=<int>"
> +       "streamids=<int..int>");
> +
> diff --git a/drivers/net/ntnic/rte_pmd_ntnic_version.map b/drivers/net/ntnic/rte_pmd_ntnic_version.map
> new file mode 100644
> index 0000000..ef35398
> --- /dev/null
> +++ b/drivers/net/ntnic/rte_pmd_ntnic_version.map
> @@ -0,0 +1,4 @@
> +DPDK_2.0 {
> +
> +       local: *;
> +};
> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> index 1a0095b..9ef357f 100644
> --- a/mk/rte.app.mk
> +++ b/mk/rte.app.mk
> @@ -120,6 +120,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MPIPE_PMD)      += -lrte_pmd_mpipe -lgxio
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD)        += -lrte_pmd_nfp -lm
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL)       += -lrte_pmd_null
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP)       += -lrte_pmd_pcap -lpcap
> +
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_QEDE_PMD)       += -lrte_pmd_qede -lz
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_RING)       += -lrte_pmd_ring
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2)   += -lrte_pmd_szedata2 -lsze2
> @@ -143,6 +144,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_KASUMI)     += -lrte_pmd_kasumi
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_KASUMI)     += -L$(LIBSSO_KASUMI_PATH)/build -lsso_kasumi
>  endif # CONFIG_RTE_LIBRTE_CRYPTODEV
> 
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NTNIC)      += -lrte_pmd_ntnic
>  endif # !CONFIG_RTE_BUILD_SHARED_LIBS
> 
>  _LDLIBS-y += --no-whole-archive
> @@ -163,6 +165,7 @@ endif
>  _LDLIBS-$(CONFIG_RTE_PORT_PCAP)             += -lpcap
>  endif # !CONFIG_RTE_BUILD_SHARED_LIBS
> 
> +
>  _LDLIBS-y += $(EXECENV_LDLIBS)
> 
>  LDLIBS += $(_LDLIBS-y) $(CPU_LDLIBS) $(EXTRA_LDLIBS)
> --
> 2.9.0
> 
> Disclaimer: This email and any files transmitted with it may contain confidential information intended for the addressee(s) only. The information is not to be surrendered or copied to unauthorized persons. If you have received this communication in error, please notify the sender immediately and delete this e-mail from your system.
> 


More information about the dev mailing list