From patchwork Thu Oct 3 13:19:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bruce Richardson X-Patchwork-Id: 60495 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id CC48C1C127; Thu, 3 Oct 2019 15:19:56 +0200 (CEST) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by dpdk.org (Postfix) with ESMTP id 39EEF1C11A; Thu, 3 Oct 2019 15:19:54 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Oct 2019 06:19:53 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.67,252,1566889200"; d="scan'208";a="185910570" Received: from silpixa00399126.ir.intel.com (HELO silpixa00399126.ger.corp.intel.com) ([10.237.223.2]) by orsmga008.jf.intel.com with ESMTP; 03 Oct 2019 06:19:51 -0700 From: Bruce Richardson To: dev@dpdk.org Cc: techboard@dpdk.org, Ciara Power Date: Thu, 3 Oct 2019 14:19:16 +0100 Message-Id: <20191003131918.30970-5-bruce.richardson@intel.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191003131918.30970-1-bruce.richardson@intel.com> References: <20191003131918.30970-1-bruce.richardson@intel.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH 4/6] examples/netmap-compat: remove example from DPDK X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Ciara Power Rather than providing a shim layer on top of netmap, we should instead encourage users to create apps using the DPDK APIs directly. Signed-off-by: Ciara Power --- MAINTAINERS | 3 - doc/guides/sample_app_ug/index.rst | 1 - doc/guides/sample_app_ug/intro.rst | 2 +- .../sample_app_ug/netmap_compatibility.rst | 130 --- examples/Makefile | 1 - examples/meson.build | 2 +- examples/netmap_compat/Makefile | 22 - examples/netmap_compat/bridge/Makefile | 35 - examples/netmap_compat/bridge/bridge.c | 343 ------- examples/netmap_compat/lib/compat_netmap.c | 899 ------------------ examples/netmap_compat/lib/compat_netmap.h | 51 - examples/netmap_compat/meson.build | 10 - examples/netmap_compat/netmap/netmap.h | 289 ------ examples/netmap_compat/netmap/netmap_user.h | 95 -- 14 files changed, 2 insertions(+), 1881 deletions(-) delete mode 100644 doc/guides/sample_app_ug/netmap_compatibility.rst delete mode 100644 examples/netmap_compat/Makefile delete mode 100644 examples/netmap_compat/bridge/Makefile delete mode 100644 examples/netmap_compat/bridge/bridge.c delete mode 100644 examples/netmap_compat/lib/compat_netmap.c delete mode 100644 examples/netmap_compat/lib/compat_netmap.h delete mode 100644 examples/netmap_compat/meson.build delete mode 100644 examples/netmap_compat/netmap/netmap.h delete mode 100644 examples/netmap_compat/netmap/netmap_user.h diff --git a/MAINTAINERS b/MAINTAINERS index 7be363327..6b9fa4dc2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1464,9 +1464,6 @@ F: doc/guides/sample_app_ug/link_status_intr.rst F: examples/load_balancer/ F: doc/guides/sample_app_ug/load_balancer.rst -F: examples/netmap_compat/ -F: doc/guides/sample_app_ug/netmap_compatibility.rst - L-threads - EXPERIMENTAL M: John McNamara F: examples/performance-thread/ diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst index dafe8553f..5f4924df6 100644 --- a/doc/guides/sample_app_ug/index.rst +++ b/doc/guides/sample_app_ug/index.rst @@ -43,7 +43,6 @@ Sample Applications User Guides vhost_scsi vhost_crypto vdpa - netmap_compatibility ip_pipeline test_pipeline eventdev_pipeline diff --git a/doc/guides/sample_app_ug/intro.rst b/doc/guides/sample_app_ug/intro.rst index 6e0af6301..39af887da 100644 --- a/doc/guides/sample_app_ug/intro.rst +++ b/doc/guides/sample_app_ug/intro.rst @@ -31,7 +31,7 @@ applications that are available in the examples directory of DPDK: .. table:: **Some of the DPDK Sample applications** +---------------------------------------+--------------------------------------+ - | Bonding | Netmap Compatibility | + | Bonding | | +---------------------------------------+--------------------------------------+ | Command Line | Packet Ordering | +---------------------------------------+--------------------------------------+ diff --git a/doc/guides/sample_app_ug/netmap_compatibility.rst b/doc/guides/sample_app_ug/netmap_compatibility.rst deleted file mode 100644 index 219613e2a..000000000 --- a/doc/guides/sample_app_ug/netmap_compatibility.rst +++ /dev/null @@ -1,130 +0,0 @@ -.. SPDX-License-Identifier: BSD-3-Clause - Copyright(c) 2010-2014 Intel Corporation. - -Netmap Compatibility Sample Application -======================================= - -Introduction ------------- - -The Netmap compatibility library provides a minimal set of APIs to give programs written against the Netmap APIs -the ability to be run, with minimal changes to their source code, using the DPDK to perform the actual packet I/O. - -Since Netmap applications use regular system calls, like ``open()``, ``ioctl()`` and -``mmap()`` to communicate with the Netmap kernel module performing the packet I/O, -the ``compat_netmap`` library provides a set of similar APIs to use in place of those system calls, -effectively turning a Netmap application into a DPDK application. - -The provided library is currently minimal and doesn't support all the features that Netmap supports, -but is enough to run simple applications, such as the bridge example detailed below. - -Knowledge of Netmap is required to understand the rest of this section. -Please refer to the Netmap distribution for details about Netmap. - -Available APIs --------------- - -The library provides the following drop-in replacements for system calls usually used in Netmap applications: - -* ``rte_netmap_close()`` - -* ``rte_netmap_ioctl()`` - -* ``rte_netmap_open()`` - -* ``rte_netmap_mmap()`` - -* ``rte_netmap_poll()`` - -They use the same signature as their libc counterparts, and can be used as drop-in replacements in most cases. - -Caveats -------- - -Given the difference between the way Netmap and the DPDK approach packet I/O, -there are caveats and limitations to be aware of when trying to use the ``compat_netmap`` library, the most important of these are listed below. -These may change as the library is updated: - -* Any system call that can potentially affect file descriptors cannot be used with a descriptor returned by the ``rte_netmap_open()`` function. - -Note that: - -* The ``rte_netmap_mmap()`` function merely returns the address of a DPDK memzone. - The address, length, flags, offset, and other arguments are ignored. - -* The ``rte_netmap_poll()`` function only supports infinite (negative) or zero time outs. - It effectively turns calls to the ``poll()`` system call made in a Netmap application into polling of the DPDK ports, - changing the semantics of the usual POSIX defined poll. - -* Not all of Netmap's features are supported: host rings, - slot flags and so on are not supported or are simply not relevant in the DPDK model. - -* The Netmap manual page states that "*a device obtained through /dev/netmap also supports the ioctl supported by network devices*". - This is not the case with this compatibility layer. - -* The Netmap kernel module exposes a sysfs interface to change some internal parameters, such as the size of the shared memory region. - This interface is not available when using this compatibility layer. - -Porting Netmap Applications ---------------------------- - -Porting Netmap applications typically involves two major steps: - -* Changing the system calls to use their ``compat_netmap`` library counterparts. - -* Adding further DPDK initialization code. - -Since the ``compat_netmap`` functions have the same signature as the usual libc calls, the change is trivial in most cases. - -The usual DPDK initialization code involving ``rte_eal_init()`` and ``rte_pci_probe()`` -has to be added to the Netmap application in the same way it is used in all other DPDK sample applications. -Please refer to the *DPDK Programmer's Guide* and example source code for details about initialization. - -In addition of the regular DPDK initialization code, -the ported application needs to call initialization functions for the ``compat_netmap`` library, -namely ``rte_netmap_init()`` and ``rte_netmap_init_port()``. - -These two initialization functions take ``compat_netmap`` specific data structures as parameters: -``struct rte_netmap_conf`` and ``struct rte_netmap_port_conf``. -The structures' fields are Netmap related and are self-explanatory for developers familiar with Netmap. -They are defined in ``$RTE_SDK/examples/netmap_compat/lib/compat_netmap.h``. - -The bridge application is an example largely based on the bridge example shipped with the Netmap distribution. -It shows how a minimal Netmap application with minimal and straightforward source code changes can be run on top of the DPDK. -Please refer to ``$RTE_SDK/examples/netmap_compat/bridge/bridge.c`` for an example of a ported application. - -Compiling the Application -------------------------- - -To compile the sample application see :doc:`compiling`. - -The application is located in the ``netmap_compat`` sub-directory. - -Running the "bridge" Sample Application ---------------------------------------- - -The application requires a single command line option: - -.. code-block:: console - - ./build/bridge [EAL options] -- -i INTERFACE_A [-i INTERFACE_B] - -where, - -* ``-i INTERFACE``: Interface (DPDK port number) to use. - - If a single ``-i`` parameter is given, the interface will send back all the traffic it receives. - If two ``-i`` parameters are given, the two interfaces form a bridge, - where traffic received on one interface is replicated and sent to the other interface. - -For example, to run the application in a linux environment using port 0 and 2: - -.. code-block:: console - - ./build/bridge [EAL options] -- -i 0 -i 2 - -Refer to the *DPDK Getting Started Guide for Linux* for general information on running applications and -the Environment Abstraction Layer (EAL) options. - -Note that unlike a traditional bridge or the ``l2fwd`` sample application, no MAC address changes are done on the frames. -Do not forget to take this into account when configuring a traffic generators and testing this sample application. diff --git a/examples/Makefile b/examples/Makefile index 02ff86534..6bba09ce9 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -50,7 +50,6 @@ endif DIRS-y += link_status_interrupt DIRS-$(CONFIG_RTE_LIBRTE_LPM) += load_balancer DIRS-y += multi_process -DIRS-y += netmap_compat/bridge DIRS-y += ntb DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += packet_ordering ifeq ($(CONFIG_RTE_ARCH_X86_64),y) diff --git a/examples/meson.build b/examples/meson.build index 6c26fffb4..f0356f2a1 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -30,7 +30,7 @@ all_examples = [ 'multi_process/hotplug_mp', 'multi_process/simple_mp', 'multi_process/symmetric_mp', - 'netmap_compat', 'ntb', 'packet_ordering', + 'ntb', 'packet_ordering', 'performance-thread', 'ptpclient', 'qos_meter', 'qos_sched', 'rxtx_callbacks', diff --git a/examples/netmap_compat/Makefile b/examples/netmap_compat/Makefile deleted file mode 100644 index b9f78d173..000000000 --- a/examples/netmap_compat/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2010-2014 Intel Corporation - -ifeq ($(RTE_SDK),) -$(error "Please define RTE_SDK environment variable") -endif - -# Default target, detect a build directory, by looking for a path with a .config -RTE_TARGET ?= $(notdir $(abspath $(dir $(firstword $(wildcard $(RTE_SDK)/*/.config))))) - -include $(RTE_SDK)/mk/rte.vars.mk -unexport RTE_SRCDIR RTE_OUTPUT RTE_EXTMK - -DIRS-y += bridge - -.PHONY: all clean $(DIRS-y) - -all: $(DIRS-y) -clean: $(DIRS-y) - -$(DIRS-y): - $(MAKE) -C $@ $(MAKECMDGOALS) O=$(RTE_OUTPUT) diff --git a/examples/netmap_compat/bridge/Makefile b/examples/netmap_compat/bridge/Makefile deleted file mode 100644 index 7ed30e57b..000000000 --- a/examples/netmap_compat/bridge/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2010-2014 Intel Corporation - -ifeq ($(RTE_SDK),) -$(error "Please define the RTE_SDK environment variable") -endif - -# Default target, detect a build directory, by looking for a path with a .config -RTE_TARGET ?= $(notdir $(abspath $(dir $(firstword $(wildcard $(RTE_SDK)/*/.config))))) - -include $(RTE_SDK)/mk/rte.vars.mk - -ifneq ($(CONFIG_RTE_EXEC_ENV_LINUX),y) -$(info This application can only operate in a linux environment, \ -please change the definition of the RTE_TARGET environment variable) -all: -clean: -else - -# binary name -APP = bridge - -# for compat_netmap.c -VPATH := $(SRCDIR)/../lib - -# all source are stored in SRCS-y -SRCS-y := bridge.c -SRCS-y += compat_netmap.c - -CFLAGS += -O3 -I$(SRCDIR)/../lib -I$(SRCDIR)/../netmap -CFLAGS += $(WERROR_FLAGS) - -include $(RTE_SDK)/mk/rte.extapp.mk - -endif diff --git a/examples/netmap_compat/bridge/bridge.c b/examples/netmap_compat/bridge/bridge.c deleted file mode 100644 index d40e163b0..000000000 --- a/examples/netmap_compat/bridge/bridge.c +++ /dev/null @@ -1,343 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "compat_netmap.h" - - -#define BUF_SIZE RTE_MBUF_DEFAULT_DATAROOM -#define MBUF_DATA_SIZE (BUF_SIZE + RTE_PKTMBUF_HEADROOM) - -#define MBUF_PER_POOL 8192 - -struct rte_eth_conf eth_conf = { - .rxmode = { - .split_hdr_size = 0, - }, - .txmode = { - .mq_mode = ETH_MQ_TX_NONE, - }, -}; - -#define MAX_QUEUE_NUM 1 -#define RX_QUEUE_NUM 1 -#define TX_QUEUE_NUM 1 - -#define MAX_DESC_NUM 0x400 -#define RX_DESC_NUM 0x100 -#define TX_DESC_NUM 0x200 - -#define RX_SYNC_NUM 0x20 -#define TX_SYNC_NUM 0x20 - -struct rte_netmap_port_conf port_conf = { - .eth_conf = ð_conf, - .socket_id = SOCKET_ID_ANY, - .nr_tx_rings = TX_QUEUE_NUM, - .nr_rx_rings = RX_QUEUE_NUM, - .nr_tx_slots = TX_DESC_NUM, - .nr_rx_slots = RX_DESC_NUM, - .tx_burst = TX_SYNC_NUM, - .rx_burst = RX_SYNC_NUM, -}; - -struct rte_netmap_conf netmap_conf = { - .socket_id = SOCKET_ID_ANY, - .max_bufsz = BUF_SIZE, - .max_rings = MAX_QUEUE_NUM, - .max_slots = MAX_DESC_NUM, -}; - -static int stop = 0; - -#define MAX_PORT_NUM 2 - -struct netmap_port { - int fd; - struct netmap_if *nmif; - struct netmap_ring *rx_ring; - struct netmap_ring *tx_ring; - const char *str; - uint8_t id; -}; - -static struct { - uint32_t num; - struct netmap_port p[MAX_PORT_NUM]; - void *mem; -} ports; - -static void -usage(const char *prgname) -{ - fprintf(stderr, "Usage: %s [EAL args] -- [OPTION]...\n" - "-h, --help \t Show this help message and exit\n" - "-i INTERFACE_A \t Interface (DPDK port number) to use\n" - "[ -i INTERFACE_B \t Interface (DPDK port number) to use ]\n", - prgname); -} - -static uint8_t -parse_portid(const char *portid_str) -{ - char *end; - unsigned id; - - id = strtoul(portid_str, &end, 10); - - if (end == portid_str || *end != '\0' || id > RTE_MAX_ETHPORTS) - rte_exit(EXIT_FAILURE, "Invalid port number\n"); - - return (uint8_t) id; -} - -static int -parse_args(int argc, char **argv) -{ - int opt; - - while ((opt = getopt(argc, argv, "hi:")) != -1) { - switch (opt) { - case 'h': - usage(argv[0]); - rte_exit(EXIT_SUCCESS, "exiting..."); - break; - case 'i': - if (ports.num >= RTE_DIM(ports.p)) { - usage(argv[0]); - rte_exit(EXIT_FAILURE, "configs with %u " - "ports are not supported\n", - ports.num + 1); - - } - - ports.p[ports.num].str = optarg; - ports.p[ports.num].id = parse_portid(optarg); - ports.num++; - break; - default: - usage(argv[0]); - rte_exit(EXIT_FAILURE, "invalid option: %c\n", opt); - } - } - - return 0; -} - -static void sigint_handler(__rte_unused int sig) -{ - stop = 1; - signal(SIGINT, SIG_DFL); -} - -static void move(int n, struct netmap_ring *rx, struct netmap_ring *tx) -{ - uint32_t tmp; - - while (n-- > 0) { - tmp = tx->slot[tx->cur].buf_idx; - - tx->slot[tx->cur].buf_idx = rx->slot[rx->cur].buf_idx; - tx->slot[tx->cur].len = rx->slot[rx->cur].len; - tx->slot[tx->cur].flags |= NS_BUF_CHANGED; - tx->cur = NETMAP_RING_NEXT(tx, tx->cur); - tx->avail--; - - rx->slot[rx->cur].buf_idx = tmp; - rx->slot[rx->cur].flags |= NS_BUF_CHANGED; - rx->cur = NETMAP_RING_NEXT(rx, rx->cur); - rx->avail--; - } -} - -static int -netmap_port_open(uint32_t idx) -{ - int err; - struct netmap_port *port; - struct nmreq req; - - port = ports.p + idx; - - port->fd = rte_netmap_open("/dev/netmap", O_RDWR); - - strlcpy(req.nr_name, port->str, sizeof(req.nr_name)); - req.nr_version = NETMAP_API; - req.nr_ringid = 0; - - err = rte_netmap_ioctl(port->fd, NIOCGINFO, &req); - if (err) { - printf("[E] NIOCGINFO ioctl failed (error %d)\n", err); - return err; - } - - strlcpy(req.nr_name, port->str, sizeof(req.nr_name)); - req.nr_version = NETMAP_API; - req.nr_ringid = 0; - - err = rte_netmap_ioctl(port->fd, NIOCREGIF, &req); - if (err) { - printf("[E] NIOCREGIF ioctl failed (error %d)\n", err); - return err; - } - - /* mmap only once. */ - if (ports.mem == NULL) - ports.mem = rte_netmap_mmap(NULL, req.nr_memsize, - PROT_WRITE | PROT_READ, MAP_PRIVATE, port->fd, 0); - - if (ports.mem == MAP_FAILED) { - printf("[E] NETMAP mmap failed for fd: %d)\n", port->fd); - return -ENOMEM; - } - - port->nmif = NETMAP_IF(ports.mem, req.nr_offset); - - port->tx_ring = NETMAP_TXRING(port->nmif, 0); - port->rx_ring = NETMAP_RXRING(port->nmif, 0); - - return 0; -} - - -int main(int argc, char *argv[]) -{ - int err, ret; - uint32_t i, pmsk; - struct nmreq req; - struct pollfd pollfd[MAX_PORT_NUM]; - struct rte_mempool *pool; - struct netmap_ring *rx_ring, *tx_ring; - - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot initialize EAL\n"); - - argc -= ret; - argv += ret; - - parse_args(argc, argv); - - if (ports.num == 0) - rte_exit(EXIT_FAILURE, "no ports specified\n"); - - if (rte_eth_dev_count_avail() < 1) - rte_exit(EXIT_FAILURE, "Not enough ethernet ports available\n"); - - pool = rte_pktmbuf_pool_create("mbuf_pool", MBUF_PER_POOL, 32, 0, - MBUF_DATA_SIZE, rte_socket_id()); - if (pool == NULL) - rte_exit(EXIT_FAILURE, "Couldn't create mempool\n"); - - netmap_conf.socket_id = rte_socket_id(); - err = rte_netmap_init(&netmap_conf); - - if (err < 0) - rte_exit(EXIT_FAILURE, - "Couldn't initialize librte_compat_netmap\n"); - else - printf("librte_compat_netmap initialized\n"); - - port_conf.pool = pool; - port_conf.socket_id = rte_socket_id(); - - for (i = 0; i != ports.num; i++) { - - err = rte_netmap_init_port(ports.p[i].id, &port_conf); - if (err < 0) - rte_exit(EXIT_FAILURE, "Couldn't setup port %hhu\n", - ports.p[i].id); - - rte_eth_promiscuous_enable(ports.p[i].id); - } - - for (i = 0; i != ports.num; i++) { - - err = netmap_port_open(i); - if (err) { - rte_exit(EXIT_FAILURE, "Couldn't set port %hhu " - "under NETMAP control\n", - ports.p[i].id); - } - else - printf("Port %hhu now in Netmap mode\n", ports.p[i].id); - } - - memset(pollfd, 0, sizeof(pollfd)); - - for (i = 0; i != ports.num; i++) { - pollfd[i].fd = ports.p[i].fd; - pollfd[i].events = POLLIN | POLLOUT; - } - - signal(SIGINT, sigint_handler); - - pmsk = ports.num - 1; - - printf("Bridge up and running!\n"); - - while (!stop) { - uint32_t n_pkts; - - pollfd[0].revents = 0; - pollfd[1].revents = 0; - - ret = rte_netmap_poll(pollfd, ports.num, 0); - if (ret < 0) { - stop = 1; - printf("[E] poll returned with error %d\n", ret); - } - - if (((pollfd[0].revents | pollfd[1].revents) & POLLERR) != 0) { - printf("POLLERR!\n"); - } - - if ((pollfd[0].revents & POLLIN) != 0 && - (pollfd[pmsk].revents & POLLOUT) != 0) { - - rx_ring = ports.p[0].rx_ring; - tx_ring = ports.p[pmsk].tx_ring; - - n_pkts = RTE_MIN(rx_ring->avail, tx_ring->avail); - move(n_pkts, rx_ring, tx_ring); - } - - if (pmsk != 0 && (pollfd[pmsk].revents & POLLIN) != 0 && - (pollfd[0].revents & POLLOUT) != 0) { - - rx_ring = ports.p[pmsk].rx_ring; - tx_ring = ports.p[0].tx_ring; - - n_pkts = RTE_MIN(rx_ring->avail, tx_ring->avail); - move(n_pkts, rx_ring, tx_ring); - } - } - - printf("Bridge stopped!\n"); - - for (i = 0; i != ports.num; i++) { - err = rte_netmap_ioctl(ports.p[i].fd, NIOCUNREGIF, &req); - if (err) { - printf("[E] NIOCUNREGIF ioctl failed (error %d)\n", - err); - } - else - printf("Port %hhu unregistered from Netmap mode\n", ports.p[i].id); - - rte_netmap_close(ports.p[i].fd); - } - return 0; -} diff --git a/examples/netmap_compat/lib/compat_netmap.c b/examples/netmap_compat/lib/compat_netmap.c deleted file mode 100644 index 10a437943..000000000 --- a/examples/netmap_compat/lib/compat_netmap.c +++ /dev/null @@ -1,899 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "compat_netmap.h" - -struct netmap_port { - struct rte_mempool *pool; - struct netmap_if *nmif; - struct rte_eth_conf eth_conf; - struct rte_eth_txconf tx_conf; - struct rte_eth_rxconf rx_conf; - int32_t socket_id; - uint16_t nr_tx_rings; - uint16_t nr_rx_rings; - uint32_t nr_tx_slots; - uint32_t nr_rx_slots; - uint16_t tx_burst; - uint16_t rx_burst; - uint32_t fd; -}; - -struct fd_port { - uint32_t port; -}; - -#ifndef POLLRDNORM -#define POLLRDNORM 0x0040 -#endif - -#ifndef POLLWRNORM -#define POLLWRNORM 0x0100 -#endif - -#define FD_PORT_FREE UINT32_MAX -#define FD_PORT_RSRV (FD_PORT_FREE - 1) - -struct netmap_state { - struct rte_netmap_conf conf; - uintptr_t buf_start; - void *mem; - uint32_t mem_sz; - uint32_t netif_memsz; -}; - - -#define COMPAT_NETMAP_MAX_NOFILE (2 * RTE_MAX_ETHPORTS) -#define COMPAT_NETMAP_MAX_BURST 64 -#define COMPAT_NETMAP_MAX_PKT_PER_SYNC (2 * COMPAT_NETMAP_MAX_BURST) - -static struct netmap_port ports[RTE_MAX_ETHPORTS]; -static struct netmap_state netmap; - -static struct fd_port fd_port[COMPAT_NETMAP_MAX_NOFILE]; -static const int next_fd_start = RLIMIT_NOFILE + 1; -static rte_spinlock_t netmap_lock; - -#define IDX_TO_FD(x) ((x) + next_fd_start) -#define FD_TO_IDX(x) ((x) - next_fd_start) -#define FD_VALID(x) ((x) >= next_fd_start && \ - (x) < (typeof (x))(RTE_DIM(fd_port) + next_fd_start)) - -#define PORT_NUM_RINGS (2 * netmap.conf.max_rings) -#define PORT_NUM_SLOTS (PORT_NUM_RINGS * netmap.conf.max_slots) - -#define BUF_IDX(port, ring, slot) \ - (((port) * PORT_NUM_RINGS + (ring)) * netmap.conf.max_slots + \ - (slot)) - -#define NETMAP_IF_RING_OFS(rid, rings, slots) ({\ - struct netmap_if *_if; \ - struct netmap_ring *_rg; \ - sizeof(*_if) + \ - (rings) * sizeof(_if->ring_ofs[0]) + \ - (rid) * sizeof(*_rg) + \ - (slots) * sizeof(_rg->slot[0]); \ - }) - -static void netmap_unregif(uint32_t idx, uint32_t port); - - -static int32_t -ifname_to_portid(const char *ifname, uint16_t *port) -{ - char *endptr; - uint64_t portid; - - errno = 0; - portid = strtoul(ifname, &endptr, 10); - if (endptr == ifname || *endptr != '\0' || - portid >= RTE_DIM(ports) || errno != 0) - return -EINVAL; - - *port = portid; - return 0; -} - -/** - * Given a dpdk mbuf, fill in the Netmap slot in ring r and its associated - * buffer with the data held by the mbuf. - * Note that mbuf chains are not supported. - */ -static void -mbuf_to_slot(struct rte_mbuf *mbuf, struct netmap_ring *r, uint32_t index) -{ - char *data; - uint16_t length; - - data = rte_pktmbuf_mtod(mbuf, char *); - length = rte_pktmbuf_data_len(mbuf); - - if (length > r->nr_buf_size) - length = 0; - - r->slot[index].len = length; - rte_memcpy(NETMAP_BUF(r, r->slot[index].buf_idx), data, length); -} - -/** - * Given a Netmap ring and a slot index for that ring, construct a dpdk mbuf - * from the data held in the buffer associated with the slot. - * Allocation/deallocation of the dpdk mbuf are the responsibility of the - * caller. - * Note that mbuf chains are not supported. - */ -static void -slot_to_mbuf(struct netmap_ring *r, uint32_t index, struct rte_mbuf *mbuf) -{ - char *data; - uint16_t length; - - rte_pktmbuf_reset(mbuf); - length = r->slot[index].len; - data = rte_pktmbuf_append(mbuf, length); - - if (data != NULL) - rte_memcpy(data, NETMAP_BUF(r, r->slot[index].buf_idx), length); -} - -static int32_t -fd_reserve(void) -{ - uint32_t i; - - for (i = 0; i != RTE_DIM(fd_port) && fd_port[i].port != FD_PORT_FREE; - i++) - ; - - if (i == RTE_DIM(fd_port)) - return -ENOMEM; - - fd_port[i].port = FD_PORT_RSRV; - return IDX_TO_FD(i); -} - -static int32_t -fd_release(int32_t fd) -{ - uint32_t idx, port; - - idx = FD_TO_IDX(fd); - - if (!FD_VALID(fd) || (port = fd_port[idx].port) == FD_PORT_FREE) - return -EINVAL; - - /* if we still have a valid port attached, release the port */ - if (port < RTE_DIM(ports) && ports[port].fd == idx) { - netmap_unregif(idx, port); - } - - fd_port[idx].port = FD_PORT_FREE; - return 0; -} - -static int -check_nmreq(struct nmreq *req, uint16_t *port) -{ - int32_t rc; - uint16_t portid; - - if (req == NULL) - return -EINVAL; - - if (req->nr_version != NETMAP_API) { - req->nr_version = NETMAP_API; - return -EINVAL; - } - - if ((rc = ifname_to_portid(req->nr_name, &portid)) != 0) { - RTE_LOG(ERR, USER1, "Invalid interface name:\"%s\" " - "in NIOCGINFO call\n", req->nr_name); - return rc; - } - - if (ports[portid].pool == NULL) { - RTE_LOG(ERR, USER1, "Misconfigured portid %u\n", portid); - return -EINVAL; - } - - *port = portid; - return 0; -} - -/** - * Simulate a Netmap NIOCGINFO ioctl: given a struct nmreq holding an interface - * name (a port number in our case), fill the struct nmreq in with advisory - * information about the interface: number of rings and their size, total memory - * required in the map, ... - * Those are preconfigured using rte_eth_{,tx,rx}conf and - * rte_netmap_port_conf structures - * and calls to rte_netmap_init_port() in the Netmap application. - */ -static int -ioctl_niocginfo(__rte_unused int fd, void * param) -{ - uint16_t portid; - struct nmreq *req; - int32_t rc; - - req = (struct nmreq *)param; - if ((rc = check_nmreq(req, &portid)) != 0) - return rc; - - req->nr_tx_rings = (uint16_t)(ports[portid].nr_tx_rings - 1); - req->nr_rx_rings = (uint16_t)(ports[portid].nr_rx_rings - 1); - req->nr_tx_slots = ports[portid].nr_tx_slots; - req->nr_rx_slots = ports[portid].nr_rx_slots; - - /* in current implementation we have all NETIFs shared aone region. */ - req->nr_memsize = netmap.mem_sz; - req->nr_offset = 0; - - return 0; -} - -static void -netmap_ring_setup(struct netmap_ring *ring, uint16_t port, uint32_t ringid, - uint32_t num_slots) -{ - uint32_t j; - - ring->buf_ofs = netmap.buf_start - (uintptr_t)ring; - ring->num_slots = num_slots; - ring->cur = 0; - ring->reserved = 0; - ring->nr_buf_size = netmap.conf.max_bufsz; - ring->flags = 0; - ring->ts.tv_sec = 0; - ring->ts.tv_usec = 0; - - for (j = 0; j < ring->num_slots; j++) { - ring->slot[j].buf_idx = BUF_IDX(port, ringid, j); - ring->slot[j].len = 0; - ring->flags = 0; - } -} - -static int -netmap_regif(struct nmreq *req, uint32_t idx, uint16_t port) -{ - struct netmap_if *nmif; - struct netmap_ring *ring; - uint32_t i, slots, start_ring; - int32_t rc; - - if (ports[port].fd < RTE_DIM(fd_port)) { - RTE_LOG(ERR, USER1, "port %u already in use by fd: %u\n", - port, IDX_TO_FD(ports[port].fd)); - return -EBUSY; - } - if (fd_port[idx].port != FD_PORT_RSRV) { - RTE_LOG(ERR, USER1, "fd: %u is misconfigured\n", - IDX_TO_FD(idx)); - return -EBUSY; - } - - nmif = ports[port].nmif; - - /* setup netmap_if fields. */ - memset(nmif, 0, netmap.netif_memsz); - - /* only ALL rings supported right now. */ - if (req->nr_ringid != 0) - return -EINVAL; - - strlcpy(nmif->ni_name, req->nr_name, sizeof(nmif->ni_name)); - nmif->ni_version = req->nr_version; - - /* Netmap uses ni_(r|t)x_rings + 1 */ - nmif->ni_rx_rings = ports[port].nr_rx_rings - 1; - nmif->ni_tx_rings = ports[port].nr_tx_rings - 1; - - /* - * Setup TX rings and slots. - * Refer to the comments in netmap.h for details - */ - - slots = 0; - for (i = 0; i < nmif->ni_tx_rings + 1; i++) { - - nmif->ring_ofs[i] = NETMAP_IF_RING_OFS(i, - PORT_NUM_RINGS, slots); - - ring = NETMAP_TXRING(nmif, i); - netmap_ring_setup(ring, port, i, ports[port].nr_tx_slots); - ring->avail = ring->num_slots; - - slots += ports[port].nr_tx_slots; - } - - /* - * Setup RX rings and slots. - * Refer to the comments in netmap.h for details - */ - - start_ring = i; - - for (; i < nmif->ni_rx_rings + 1 + start_ring; i++) { - - nmif->ring_ofs[i] = NETMAP_IF_RING_OFS(i, - PORT_NUM_RINGS, slots); - - ring = NETMAP_RXRING(nmif, (i - start_ring)); - netmap_ring_setup(ring, port, i, ports[port].nr_rx_slots); - ring->avail = 0; - - slots += ports[port].nr_rx_slots; - } - - if ((rc = rte_eth_dev_start(port)) < 0) { - RTE_LOG(ERR, USER1, - "Couldn't start ethernet device %s (error %d)\n", - req->nr_name, rc); - return rc; - } - - /* setup fdi <--> port relationtip. */ - ports[port].fd = idx; - fd_port[idx].port = port; - - req->nr_memsize = netmap.mem_sz; - req->nr_offset = (uintptr_t)nmif - (uintptr_t)netmap.mem; - - return 0; -} - -/** - * Simulate a Netmap NIOCREGIF ioctl: - */ -static int -ioctl_niocregif(int32_t fd, void * param) -{ - uint16_t portid; - int32_t rc; - uint32_t idx; - struct nmreq *req; - - req = (struct nmreq *)param; - if ((rc = check_nmreq(req, &portid)) != 0) - return rc; - - idx = FD_TO_IDX(fd); - - rte_spinlock_lock(&netmap_lock); - rc = netmap_regif(req, idx, portid); - rte_spinlock_unlock(&netmap_lock); - - return rc; -} - -static void -netmap_unregif(uint32_t idx, uint32_t port) -{ - fd_port[idx].port = FD_PORT_RSRV; - ports[port].fd = UINT32_MAX; - rte_eth_dev_stop(port); -} - -/** - * Simulate a Netmap NIOCUNREGIF ioctl: put an interface running in Netmap - * mode back in "normal" mode. In our case, we just stop the port associated - * with this file descriptor. - */ -static int -ioctl_niocunregif(int fd) -{ - uint32_t idx, port; - int32_t rc; - - idx = FD_TO_IDX(fd); - - rte_spinlock_lock(&netmap_lock); - - port = fd_port[idx].port; - if (port < RTE_DIM(ports) && ports[port].fd == idx) { - netmap_unregif(idx, port); - rc = 0; - } else { - RTE_LOG(ERR, USER1, - "%s: %d is not associated with valid port\n", - __func__, fd); - rc = -EINVAL; - } - - rte_spinlock_unlock(&netmap_lock); - return rc; -} - -/** - * A call to rx_sync_ring will try to fill a Netmap RX ring with as many - * packets as it can hold coming from its dpdk port. - */ -static inline int -rx_sync_ring(struct netmap_ring *ring, uint16_t port, uint16_t ring_number, - uint16_t max_burst) -{ - int32_t i, n_rx; - uint16_t burst_size; - uint32_t cur_slot, n_free_slots; - struct rte_mbuf *rx_mbufs[COMPAT_NETMAP_MAX_BURST]; - - n_free_slots = ring->num_slots - (ring->avail + ring->reserved); - n_free_slots = RTE_MIN(n_free_slots, max_burst); - cur_slot = (ring->cur + ring->avail) & (ring->num_slots - 1); - - while (n_free_slots) { - burst_size = (uint16_t)RTE_MIN(n_free_slots, RTE_DIM(rx_mbufs)); - - /* receive up to burst_size packets from the NIC's queue */ - n_rx = rte_eth_rx_burst(port, ring_number, rx_mbufs, - burst_size); - - if (n_rx == 0) - return 0; - if (unlikely(n_rx < 0)) - return -1; - - /* Put those n_rx packets in the Netmap structures */ - for (i = 0; i < n_rx ; i++) { - mbuf_to_slot(rx_mbufs[i], ring, cur_slot); - rte_pktmbuf_free(rx_mbufs[i]); - cur_slot = NETMAP_RING_NEXT(ring, cur_slot); - } - - /* Update the Netmap ring structure to reflect the change */ - ring->avail += n_rx; - n_free_slots -= n_rx; - } - - return 0; -} - -static inline int -rx_sync_if(uint32_t port) -{ - uint16_t burst; - uint32_t i, rc; - struct netmap_if *nifp; - struct netmap_ring *r; - - nifp = ports[port].nmif; - burst = ports[port].rx_burst; - rc = 0; - - for (i = 0; i < nifp->ni_rx_rings + 1; i++) { - r = NETMAP_RXRING(nifp, i); - rx_sync_ring(r, port, (uint16_t)i, burst); - rc += r->avail; - } - - return rc; -} - -/** - * Simulate a Netmap NIOCRXSYNC ioctl: - */ -static int -ioctl_niocrxsync(int fd) -{ - uint32_t idx, port; - - idx = FD_TO_IDX(fd); - if ((port = fd_port[idx].port) < RTE_DIM(ports) && - ports[port].fd == idx) { - return rx_sync_if(fd_port[idx].port); - } else { - return -EINVAL; - } -} - -/** - * A call to tx_sync_ring will try to empty a Netmap TX ring by converting its - * buffers into rte_mbufs and sending them out on the rings's dpdk port. - */ -static int -tx_sync_ring(struct netmap_ring *ring, uint16_t port, uint16_t ring_number, - struct rte_mempool *pool, uint16_t max_burst) -{ - uint32_t i, n_tx; - uint16_t burst_size; - uint32_t cur_slot, n_used_slots; - struct rte_mbuf *tx_mbufs[COMPAT_NETMAP_MAX_BURST]; - - n_used_slots = ring->num_slots - ring->avail; - n_used_slots = RTE_MIN(n_used_slots, max_burst); - cur_slot = (ring->cur + ring->avail) & (ring->num_slots - 1); - - while (n_used_slots) { - burst_size = (uint16_t)RTE_MIN(n_used_slots, RTE_DIM(tx_mbufs)); - - for (i = 0; i < burst_size; i++) { - tx_mbufs[i] = rte_pktmbuf_alloc(pool); - if (tx_mbufs[i] == NULL) - goto err; - - slot_to_mbuf(ring, cur_slot, tx_mbufs[i]); - cur_slot = NETMAP_RING_NEXT(ring, cur_slot); - } - - n_tx = rte_eth_tx_burst(port, ring_number, tx_mbufs, - burst_size); - - /* Update the Netmap ring structure to reflect the change */ - ring->avail += n_tx; - n_used_slots -= n_tx; - - /* Return the mbufs that failed to transmit to their pool */ - if (unlikely(n_tx != burst_size)) { - for (i = n_tx; i < burst_size; i++) - rte_pktmbuf_free(tx_mbufs[i]); - break; - } - } - - return 0; - -err: - for (; i == 0; --i) - rte_pktmbuf_free(tx_mbufs[i]); - - RTE_LOG(ERR, USER1, - "Couldn't get mbuf from mempool is the mempool too small?\n"); - return -1; -} - -static int -tx_sync_if(uint32_t port) -{ - uint16_t burst; - uint32_t i, rc; - struct netmap_if *nifp; - struct netmap_ring *r; - struct rte_mempool *mp; - - nifp = ports[port].nmif; - mp = ports[port].pool; - burst = ports[port].tx_burst; - rc = 0; - - for (i = 0; i < nifp->ni_tx_rings + 1; i++) { - r = NETMAP_TXRING(nifp, i); - tx_sync_ring(r, port, (uint16_t)i, mp, burst); - rc += r->avail; - } - - return rc; -} - -/** - * Simulate a Netmap NIOCTXSYNC ioctl: - */ -static inline int -ioctl_nioctxsync(int fd) -{ - uint32_t idx, port; - - idx = FD_TO_IDX(fd); - if ((port = fd_port[idx].port) < RTE_DIM(ports) && - ports[port].fd == idx) { - return tx_sync_if(fd_port[idx].port); - } else { - return -EINVAL; - } -} - -/** - * Give the library a mempool of rte_mbufs with which it can do the - * rte_mbuf <--> netmap slot conversions. - */ -int -rte_netmap_init(const struct rte_netmap_conf *conf) -{ - size_t buf_ofs, nmif_sz, sz; - size_t port_rings, port_slots, port_bufs; - uint32_t i, port_num; - - port_num = RTE_MAX_ETHPORTS; - port_rings = 2 * conf->max_rings; - port_slots = port_rings * conf->max_slots; - port_bufs = port_slots; - - nmif_sz = NETMAP_IF_RING_OFS(port_rings, port_rings, port_slots); - sz = nmif_sz * port_num; - - buf_ofs = RTE_ALIGN_CEIL(sz, RTE_CACHE_LINE_SIZE); - sz = buf_ofs + port_bufs * conf->max_bufsz * port_num; - - if (sz > UINT32_MAX || - (netmap.mem = rte_zmalloc_socket(__func__, sz, - RTE_CACHE_LINE_SIZE, conf->socket_id)) == NULL) { - RTE_LOG(ERR, USER1, "%s: failed to allocate %zu bytes\n", - __func__, sz); - return -ENOMEM; - } - - netmap.mem_sz = sz; - netmap.netif_memsz = nmif_sz; - netmap.buf_start = (uintptr_t)netmap.mem + buf_ofs; - netmap.conf = *conf; - - rte_spinlock_init(&netmap_lock); - - /* Mark all ports as unused and set NETIF pointer. */ - for (i = 0; i != RTE_DIM(ports); i++) { - ports[i].fd = UINT32_MAX; - ports[i].nmif = (struct netmap_if *) - ((uintptr_t)netmap.mem + nmif_sz * i); - } - - /* Mark all fd_ports as unused. */ - for (i = 0; i != RTE_DIM(fd_port); i++) { - fd_port[i].port = FD_PORT_FREE; - } - - return 0; -} - - -int -rte_netmap_init_port(uint16_t portid, const struct rte_netmap_port_conf *conf) -{ - int32_t ret; - uint16_t i; - uint16_t rx_slots, tx_slots; - struct rte_eth_rxconf rxq_conf; - struct rte_eth_txconf txq_conf; - struct rte_eth_dev_info dev_info; - - if (conf == NULL || - portid >= RTE_DIM(ports) || - conf->nr_tx_rings > netmap.conf.max_rings || - conf->nr_rx_rings > netmap.conf.max_rings) { - RTE_LOG(ERR, USER1, "%s(%u): invalid parameters\n", - __func__, portid); - return -EINVAL; - } - - rx_slots = (uint16_t)rte_align32pow2(conf->nr_rx_slots); - tx_slots = (uint16_t)rte_align32pow2(conf->nr_tx_slots); - - if (tx_slots > netmap.conf.max_slots || - rx_slots > netmap.conf.max_slots) { - RTE_LOG(ERR, USER1, "%s(%u): invalid parameters\n", - __func__, portid); - return -EINVAL; - } - - rte_eth_dev_info_get(portid, &dev_info); - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - conf->eth_conf->txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - ret = rte_eth_dev_configure(portid, conf->nr_rx_rings, - conf->nr_tx_rings, conf->eth_conf); - - if (ret < 0) { - RTE_LOG(ERR, USER1, "Couldn't configure port %u\n", portid); - return ret; - } - - ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &rx_slots, &tx_slots); - - if (ret < 0) { - RTE_LOG(ERR, USER1, - "Couldn't ot adjust number of descriptors for port %u\n", - portid); - return ret; - } - - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = conf->eth_conf->rxmode.offloads; - txq_conf = dev_info.default_txconf; - txq_conf.offloads = conf->eth_conf->txmode.offloads; - for (i = 0; i < conf->nr_tx_rings; i++) { - ret = rte_eth_tx_queue_setup(portid, i, tx_slots, - conf->socket_id, &txq_conf); - - if (ret < 0) { - RTE_LOG(ERR, USER1, - "fail to configure TX queue %u of port %u\n", - i, portid); - return ret; - } - - ret = rte_eth_rx_queue_setup(portid, i, rx_slots, - conf->socket_id, &rxq_conf, conf->pool); - - if (ret < 0) { - RTE_LOG(ERR, USER1, - "fail to configure RX queue %u of port %u\n", - i, portid); - return ret; - } - } - - /* copy config to the private storage. */ - ports[portid].eth_conf = conf->eth_conf[0]; - ports[portid].pool = conf->pool; - ports[portid].socket_id = conf->socket_id; - ports[portid].nr_tx_rings = conf->nr_tx_rings; - ports[portid].nr_rx_rings = conf->nr_rx_rings; - ports[portid].nr_tx_slots = tx_slots; - ports[portid].nr_rx_slots = rx_slots; - ports[portid].tx_burst = conf->tx_burst; - ports[portid].rx_burst = conf->rx_burst; - - return 0; -} - -int -rte_netmap_close(__rte_unused int fd) -{ - int32_t rc; - - rte_spinlock_lock(&netmap_lock); - rc = fd_release(fd); - rte_spinlock_unlock(&netmap_lock); - - if (rc < 0) { - errno =-rc; - rc = -1; - } - return rc; -} - -int rte_netmap_ioctl(int fd, uint32_t op, void *param) -{ - int ret; - - if (!FD_VALID(fd)) { - errno = EBADF; - return -1; - } - - switch (op) { - - case NIOCGINFO: - ret = ioctl_niocginfo(fd, param); - break; - - case NIOCREGIF: - ret = ioctl_niocregif(fd, param); - break; - - case NIOCUNREGIF: - ret = ioctl_niocunregif(fd); - break; - - case NIOCRXSYNC: - ret = ioctl_niocrxsync(fd); - break; - - case NIOCTXSYNC: - ret = ioctl_nioctxsync(fd); - break; - - default: - ret = -ENOTTY; - } - - if (ret < 0) { - errno = -ret; - ret = -1; - } else { - ret = 0; - } - - return ret; -} - -void * -rte_netmap_mmap(void *addr, size_t length, - int prot, int flags, int fd, off_t offset) -{ - static const int cprot = PROT_WRITE | PROT_READ; - - if (!FD_VALID(fd) || length + offset > netmap.mem_sz || - (prot & cprot) != cprot || - ((flags & MAP_FIXED) != 0 && addr != NULL)) { - - errno = EINVAL; - return MAP_FAILED; - } - - return (void *)((uintptr_t)netmap.mem + (uintptr_t)offset); -} - -/** - * Return a "fake" file descriptor with a value above RLIMIT_NOFILE so that - * any attempt to use that file descriptor with the usual API will fail. - */ -int -rte_netmap_open(__rte_unused const char *pathname, __rte_unused int flags) -{ - int fd; - - rte_spinlock_lock(&netmap_lock); - fd = fd_reserve(); - rte_spinlock_unlock(&netmap_lock); - - if (fd < 0) { - errno = -fd; - fd = -1; - } - return fd; -} - -/** - * Doesn't support timeout other than 0 or infinite (negative) timeout - */ -int -rte_netmap_poll(struct pollfd *fds, nfds_t nfds, int timeout) -{ - int32_t count_it, ret; - uint32_t i, idx, port; - uint32_t want_rx, want_tx; - - if (timeout > 0) - return -1; - - ret = 0; - do { - for (i = 0; i < nfds; i++) { - - count_it = 0; - - if (!FD_VALID(fds[i].fd) || fds[i].events == 0) { - fds[i].revents = 0; - continue; - } - - idx = FD_TO_IDX(fds[i].fd); - if ((port = fd_port[idx].port) >= RTE_DIM(ports) || - ports[port].fd != idx) { - - fds[i].revents |= POLLERR; - ret++; - continue; - } - - want_rx = fds[i].events & (POLLIN | POLLRDNORM); - want_tx = fds[i].events & (POLLOUT | POLLWRNORM); - - if (want_rx && rx_sync_if(port) > 0) { - fds[i].revents = (uint16_t) - (fds[i].revents | want_rx); - count_it = 1; - } - if (want_tx && tx_sync_if(port) > 0) { - fds[i].revents = (uint16_t) - (fds[i].revents | want_tx); - count_it = 1; - } - - ret += count_it; - } - } - while ((ret == 0 && timeout < 0) || timeout); - - return ret; -} diff --git a/examples/netmap_compat/lib/compat_netmap.h b/examples/netmap_compat/lib/compat_netmap.h deleted file mode 100644 index 12b618b68..000000000 --- a/examples/netmap_compat/lib/compat_netmap.h +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _RTE_COMPAT_NETMAP_H_ - -#include -#include -#include - -#include -#include - -#include "netmap.h" -#include "netmap_user.h" - -/** - * One can overwrite Netmap macros here as needed - */ - -struct rte_netmap_conf { - int32_t socket_id; - uint32_t max_rings; /* number of rings(queues) per netmap_if(port) */ - uint32_t max_slots; /* number of slots(descriptors) per netmap ring. */ - uint16_t max_bufsz; /* size of each netmap buffer. */ -}; - -struct rte_netmap_port_conf { - struct rte_eth_conf *eth_conf; - struct rte_mempool *pool; - int32_t socket_id; - uint16_t nr_tx_rings; - uint16_t nr_rx_rings; - uint32_t nr_tx_slots; - uint32_t nr_rx_slots; - uint16_t tx_burst; - uint16_t rx_burst; -}; - -int rte_netmap_init(const struct rte_netmap_conf *conf); -int rte_netmap_init_port(uint16_t portid, - const struct rte_netmap_port_conf *conf); - -int rte_netmap_close(int fd); -int rte_netmap_ioctl(int fd, uint32_t op, void *param); -int rte_netmap_open(const char *pathname, int flags); -int rte_netmap_poll(struct pollfd *fds, nfds_t nfds, int timeout); -void *rte_netmap_mmap(void *addr, size_t length, int prot, int flags, int fd, - off_t offset); - -#endif /* _RTE_COMPAT_NETMAP_H_ */ diff --git a/examples/netmap_compat/meson.build b/examples/netmap_compat/meson.build deleted file mode 100644 index c370d7476..000000000 --- a/examples/netmap_compat/meson.build +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2018 Intel Corporation - -# meson file, for building this example as part of a main DPDK build. -# -# To build this example as a standalone application with an already-installed -# DPDK instance, use 'make' - -# Example app currently unsupported by meson build -build = false diff --git a/examples/netmap_compat/netmap/netmap.h b/examples/netmap_compat/netmap/netmap.h deleted file mode 100644 index 677c8a9fb..000000000 --- a/examples/netmap_compat/netmap/netmap.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (C) 2011 Matteo Landi, Luigi Rizzo. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. Neither the name of the authors nor the names of their contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY MATTEO LANDI 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 MATTEO LANDI 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. - */ - -/* - * $FreeBSD: head/sys/net/netmap.h 231198 2012-02-08 11:43:29Z luigi $ - * $Id: netmap.h 10879 2012-04-12 22:48:59Z luigi $ - * - * Definitions of constants and the structures used by the netmap - * framework, for the part visible to both kernel and userspace. - * Detailed info on netmap is available with "man netmap" or at - * - * http://info.iet.unipi.it/~luigi/netmap/ - */ - -#ifndef _NET_NETMAP_H_ -#define _NET_NETMAP_H_ - -/* - * --- Netmap data structures --- - * - * The data structures used by netmap are shown below. Those in - * capital letters are in an mmapp()ed area shared with userspace, - * while others are private to the kernel. - * Shared structures do not contain pointers but only memory - * offsets, so that addressing is portable between kernel and userspace. - - - softc -+----------------+ -| standard fields| -| if_pspare[0] ----------+ -+----------------+ | - | -+----------------+<------+ -|(netmap_adapter)| -| | netmap_kring -| tx_rings *--------------------------------->+---------------+ -| | netmap_kring | ring *---------. -| rx_rings *--------->+---------------+ | nr_hwcur | | -+----------------+ | ring *--------. | nr_hwavail | V - | nr_hwcur | | | selinfo | | - | nr_hwavail | | +---------------+ . - | selinfo | | | ... | . - +---------------+ | |(ntx+1 entries)| - | .... | | | | - |(nrx+1 entries)| | +---------------+ - | | | - KERNEL +---------------+ | - | - ==================================================================== - | - USERSPACE | NETMAP_RING - +---->+-------------+ - / | cur | - NETMAP_IF (nifp, one per file desc.) / | avail | - +---------------+ / | buf_ofs | - | ni_tx_rings | / +=============+ - | ni_rx_rings | / | buf_idx | slot[0] - | | / | len, flags | - | | / +-------------+ - +===============+ / | buf_idx | slot[1] - | txring_ofs[0] | (rel.to nifp)--' | len, flags | - | txring_ofs[1] | +-------------+ - (num_rings+1 entries) (nr_num_slots entries) - | txring_ofs[n] | | buf_idx | slot[n-1] - +---------------+ | len, flags | - | rxring_ofs[0] | +-------------+ - | rxring_ofs[1] | - (num_rings+1 entries) - | txring_ofs[n] | - +---------------+ - - * The private descriptor ('softc' or 'adapter') of each interface - * is extended with a "struct netmap_adapter" containing netmap-related - * info (see description in dev/netmap/netmap_kernel.h. - * Among other things, tx_rings and rx_rings point to the arrays of - * "struct netmap_kring" which in turn reache the various - * "struct netmap_ring", shared with userspace. - - * The NETMAP_RING is the userspace-visible replica of the NIC ring. - * Each slot has the index of a buffer, its length and some flags. - * In user space, the buffer address is computed as - * (char *)ring + buf_ofs + index*NETMAP_BUF_SIZE - * In the kernel, buffers do not necessarily need to be contiguous, - * and the virtual and physical addresses are derived through - * a lookup table. - * To associate a different buffer to a slot, applications must - * write the new index in buf_idx, and set NS_BUF_CHANGED flag to - * make sure that the kernel updates the hardware ring as needed. - * - * Normally the driver is not requested to report the result of - * transmissions (this can dramatically speed up operation). - * However the user may request to report completion by setting - * NS_REPORT. - */ -struct netmap_slot { - uint32_t buf_idx; /* buffer index */ - uint16_t len; /* packet length, to be copied to/from the hw ring */ - uint16_t flags; /* buf changed, etc. */ -#define NS_BUF_CHANGED 0x0001 /* must resync the map, buffer changed */ -#define NS_REPORT 0x0002 /* ask the hardware to report results - * e.g. by generating an interrupt - */ -}; - -/* - * Netmap representation of a TX or RX ring (also known as "queue"). - * This is a queue implemented as a fixed-size circular array. - * At the software level, two fields are important: avail and cur. - * - * In TX rings: - * avail indicates the number of slots available for transmission. - * It is updated by the kernel after every netmap system call. - * It MUST BE decremented by the application when it appends a - * packet. - * cur indicates the slot to use for the next packet - * to send (i.e. the "tail" of the queue). - * It MUST BE incremented by the application before - * netmap system calls to reflect the number of newly - * sent packets. - * It is checked by the kernel on netmap system calls - * (normally unmodified by the kernel unless invalid). - * - * The kernel side of netmap uses two additional fields in its own - * private ring structure, netmap_kring: - * nr_hwcur is a copy of nr_cur on an NIOCTXSYNC. - * nr_hwavail is the number of slots known as available by the - * hardware. It is updated on an INTR (inc by the - * number of packets sent) and on a NIOCTXSYNC - * (decrease by nr_cur - nr_hwcur) - * A special case, nr_hwavail is -1 if the transmit - * side is idle (no pending transmits). - * - * In RX rings: - * avail is the number of packets available (possibly 0). - * It MUST BE decremented by the application when it consumes - * a packet, and it is updated to nr_hwavail on a NIOCRXSYNC - * cur indicates the first slot that contains a packet not - * processed yet (the "head" of the queue). - * It MUST BE incremented by the software when it consumes - * a packet. - * reserved indicates the number of buffers before 'cur' - * that the application has still in use. Normally 0, - * it MUST BE incremented by the application when it - * does not return the buffer immediately, and decremented - * when the buffer is finally freed. - * - * The kernel side of netmap uses two additional fields in the kring: - * nr_hwcur is a copy of nr_cur on an NIOCRXSYNC - * nr_hwavail is the number of packets available. It is updated - * on INTR (inc by the number of new packets arrived) - * and on NIOCRXSYNC (decreased by nr_cur - nr_hwcur). - * - * DATA OWNERSHIP/LOCKING: - * The netmap_ring is owned by the user program and it is only - * accessed or modified in the upper half of the kernel during - * a system call. - * - * The netmap_kring is only modified by the upper half of the kernel. - */ -struct netmap_ring { - /* - * nr_buf_base_ofs is meant to be used through macros. - * It contains the offset of the buffer region from this - * descriptor. - */ - ssize_t buf_ofs; - uint32_t num_slots; /* number of slots in the ring. */ - uint32_t avail; /* number of usable slots */ - uint32_t cur; /* 'current' r/w position */ - uint32_t reserved; /* not refilled before current */ - - uint16_t nr_buf_size; - uint16_t flags; -#define NR_TIMESTAMP 0x0002 /* set timestamp on *sync() */ - - struct timeval ts; /* time of last *sync() */ - - /* the slots follow. This struct has variable size */ - struct netmap_slot slot[0]; /* array of slots. */ -}; - - -/* - * Netmap representation of an interface and its queue(s). - * There is one netmap_if for each file descriptor on which we want - * to select/poll. We assume that on each interface has the same number - * of receive and transmit queues. - * select/poll operates on one or all pairs depending on the value of - * nmr_queueid passed on the ioctl. - */ -struct netmap_if { - char ni_name[IFNAMSIZ]; /* name of the interface. */ - u_int ni_version; /* API version, currently unused */ - u_int ni_rx_rings; /* number of rx rings */ - u_int ni_tx_rings; /* if zero, same as ni_rx_rings */ - /* - * The following array contains the offset of each netmap ring - * from this structure. The first ni_tx_queues+1 entries refer - * to the tx rings, the next ni_rx_queues+1 refer to the rx rings - * (the last entry in each block refers to the host stack rings). - * The area is filled up by the kernel on NIOCREG, - * and then only read by userspace code. - */ - ssize_t ring_ofs[0]; -}; - -#ifndef NIOCREGIF -/* - * ioctl names and related fields - * - * NIOCGINFO takes a struct ifreq, the interface name is the input, - * the outputs are number of queues and number of descriptor - * for each queue (useful to set number of threads etc.). - * - * NIOCREGIF takes an interface name within a struct ifreq, - * and activates netmap mode on the interface (if possible). - * - * NIOCUNREGIF unregisters the interface associated to the fd. - * - * NIOCTXSYNC, NIOCRXSYNC synchronize tx or rx queues, - * whose identity is set in NIOCREGIF through nr_ringid - */ - -/* - * struct nmreq overlays a struct ifreq - */ -struct nmreq { - char nr_name[IFNAMSIZ]; - uint32_t nr_version; /* API version */ -#define NETMAP_API 3 /* current version */ - uint32_t nr_offset; /* nifp offset in the shared region */ - uint32_t nr_memsize; /* size of the shared region */ - uint32_t nr_tx_slots; /* slots in tx rings */ - uint32_t nr_rx_slots; /* slots in rx rings */ - uint16_t nr_tx_rings; /* number of tx rings */ - uint16_t nr_rx_rings; /* number of rx rings */ - uint16_t nr_ringid; /* ring(s) we care about */ -#define NETMAP_HW_RING 0x4000 /* low bits indicate one hw ring */ -#define NETMAP_SW_RING 0x2000 /* process the sw ring */ -#define NETMAP_NO_TX_POLL 0x1000 /* no automatic txsync on poll */ -#define NETMAP_RING_MASK 0xfff /* the ring number */ - uint16_t spare1; - uint32_t spare2[4]; -}; - -/* - * FreeBSD uses the size value embedded in the _IOWR to determine - * how much to copy in/out. So we need it to match the actual - * data structure we pass. We put some spares in the structure - * to ease compatibility with other versions - */ -#define NIOCGINFO _IOWR('i', 145, struct nmreq) /* return IF info */ -#define NIOCREGIF _IOWR('i', 146, struct nmreq) /* interface register */ -#define NIOCUNREGIF _IO('i', 147) /* interface unregister */ -#define NIOCTXSYNC _IO('i', 148) /* sync tx queues */ -#define NIOCRXSYNC _IO('i', 149) /* sync rx queues */ -#endif /* !NIOCREGIF */ - -#endif /* _NET_NETMAP_H_ */ diff --git a/examples/netmap_compat/netmap/netmap_user.h b/examples/netmap_compat/netmap/netmap_user.h deleted file mode 100644 index f369592e3..000000000 --- a/examples/netmap_compat/netmap/netmap_user.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2011 Matteo Landi, Luigi Rizzo. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. Neither the name of the authors nor the names of their contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY MATTEO LANDI 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 MATTEO LANDI 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. - */ - -/* - * $FreeBSD: head/sys/net/netmap_user.h 231198 2012-02-08 11:43:29Z luigi $ - * $Id: netmap_user.h 10879 2012-04-12 22:48:59Z luigi $ - * - * This header contains the macros used to manipulate netmap structures - * and packets in userspace. See netmap(4) for more information. - * - * The address of the struct netmap_if, say nifp, is computed from the - * value returned from ioctl(.., NIOCREG, ...) and the mmap region: - * ioctl(fd, NIOCREG, &req); - * mem = mmap(0, ... ); - * nifp = NETMAP_IF(mem, req.nr_nifp); - * (so simple, we could just do it manually) - * - * From there: - * struct netmap_ring *NETMAP_TXRING(nifp, index) - * struct netmap_ring *NETMAP_RXRING(nifp, index) - * we can access ring->nr_cur, ring->nr_avail, ring->nr_flags - * - * ring->slot[i] gives us the i-th slot (we can access - * directly plen, flags, bufindex) - * - * char *buf = NETMAP_BUF(ring, index) returns a pointer to - * the i-th buffer - * - * Since rings are circular, we have macros to compute the next index - * i = NETMAP_RING_NEXT(ring, i); - */ - -#ifndef _NET_NETMAP_USER_H_ -#define _NET_NETMAP_USER_H_ - -#define NETMAP_IF(b, o) (struct netmap_if *)((char *)(b) + (o)) - -#define NETMAP_TXRING(nifp, index) \ - ((struct netmap_ring *)((char *)(nifp) + \ - (nifp)->ring_ofs[index] ) ) - -#define NETMAP_RXRING(nifp, index) \ - ((struct netmap_ring *)((char *)(nifp) + \ - (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] ) ) - -#define NETMAP_BUF(ring, index) \ - ((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size)) - -#define NETMAP_BUF_IDX(ring, buf) \ - ( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \ - (ring)->nr_buf_size ) - -#define NETMAP_RING_NEXT(r, i) \ - ((i)+1 == (r)->num_slots ? 0 : (i) + 1 ) - -#define NETMAP_RING_FIRST_RESERVED(r) \ - ( (r)->cur < (r)->reserved ? \ - (r)->cur + (r)->num_slots - (r)->reserved : \ - (r)->cur - (r)->reserved ) - -/* - * Return 1 if the given tx ring is empty. - */ -#define NETMAP_TX_RING_EMPTY(r) ((r)->avail >= (r)->num_slots - 1) - -#endif /* _NET_NETMAP_USER_H_ */