* [dpdk-dev] [PATCH 0/6] remove a few example applications @ 2019-10-03 13:19 Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 1/6] examples/exception_path: remove example from DPDK Bruce Richardson ` (8 more replies) 0 siblings, 9 replies; 27+ messages in thread From: Bruce Richardson @ 2019-10-03 13:19 UTC (permalink / raw) To: dev; +Cc: techboard, Bruce Richardson As discussed by the DPDK technical board e.g. [1][2] and on the DPDK mailing list [3], we have a lot of example applications shipped with DPDK - a number which increases with each DPDK release, and not all of which are probably needed any more. Therefore, this set removes 5 example applications from the repository. The removal of each app is relatively straight-forward, though the use of a table in the intro section of the sample app guide document makes removing each app individually more difficult, as the table needs to be reformed. Rather than increasing the diff by reformatting the table each time, or the opposite approach of doing all table removals in one shot at the end of the set, we have taken a compromise approach here, and each example table entry is cleared once the example is removed, and the table is finally rebalanced once at the end, by just compressing up the spaces on each side. [1] https://mails.dpdk.org/archives/dev/2019-May/132288.html [2] https://mails.dpdk.org/archives/dev/2019-June/135847.html [3] https://mails.dpdk.org/archives/dev/2019-July/138676.html Bruce Richardson (3): examples/exception_path: remove example from DPDK examples/l3fwd-vf: remove example from DPDK doc: close up gaps in sample app guide table Ciara Power (3): examples/quota-watermark: remove example from DPDK examples/netmap-compat: remove example from DPDK examples/load_balancer: remove example from DPDK MAINTAINERS | 15 - doc/guides/sample_app_ug/exception_path.rst | 281 ----- doc/guides/sample_app_ug/index.rst | 5 - doc/guides/sample_app_ug/intro.rst | 30 +- .../sample_app_ug/l3_forward_virtual.rst | 98 -- doc/guides/sample_app_ug/load_balancer.rst | 201 ---- .../sample_app_ug/netmap_compatibility.rst | 130 -- doc/guides/sample_app_ug/quota_watermark.rst | 465 ------- examples/Makefile | 5 - examples/exception_path/Makefile | 57 - examples/exception_path/main.c | 589 --------- examples/exception_path/meson.build | 11 - examples/l3fwd-vf/Makefile | 62 - examples/l3fwd-vf/main.c | 1072 ----------------- examples/l3fwd-vf/meson.build | 12 - examples/load_balancer/Makefile | 62 - examples/load_balancer/config.c | 1030 ---------------- examples/load_balancer/init.c | 520 -------- examples/load_balancer/main.c | 76 -- examples/load_balancer/main.h | 351 ------ examples/load_balancer/meson.build | 12 - examples/load_balancer/runtime.c | 642 ---------- examples/meson.build | 9 +- 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 -- examples/quota_watermark/Makefile | 16 - examples/quota_watermark/include/conf.h | 19 - examples/quota_watermark/meson.build | 10 - examples/quota_watermark/qw/Makefile | 22 - examples/quota_watermark/qw/args.c | 78 -- examples/quota_watermark/qw/args.h | 12 - examples/quota_watermark/qw/init.c | 164 --- examples/quota_watermark/qw/init.h | 14 - examples/quota_watermark/qw/main.c | 365 ------ examples/quota_watermark/qw/main.h | 31 - examples/quota_watermark/qwctl/Makefile | 22 - examples/quota_watermark/qwctl/commands.c | 196 --- examples/quota_watermark/qwctl/commands.h | 12 - examples/quota_watermark/qwctl/qwctl.c | 67 -- examples/quota_watermark/qwctl/qwctl.h | 12 - 46 files changed, 17 insertions(+), 8502 deletions(-) delete mode 100644 doc/guides/sample_app_ug/exception_path.rst delete mode 100644 doc/guides/sample_app_ug/l3_forward_virtual.rst delete mode 100644 doc/guides/sample_app_ug/load_balancer.rst delete mode 100644 doc/guides/sample_app_ug/netmap_compatibility.rst delete mode 100644 doc/guides/sample_app_ug/quota_watermark.rst delete mode 100644 examples/exception_path/Makefile delete mode 100644 examples/exception_path/main.c delete mode 100644 examples/exception_path/meson.build delete mode 100644 examples/l3fwd-vf/Makefile delete mode 100644 examples/l3fwd-vf/main.c delete mode 100644 examples/l3fwd-vf/meson.build delete mode 100644 examples/load_balancer/Makefile delete mode 100644 examples/load_balancer/config.c delete mode 100644 examples/load_balancer/init.c delete mode 100644 examples/load_balancer/main.c delete mode 100644 examples/load_balancer/main.h delete mode 100644 examples/load_balancer/meson.build delete mode 100644 examples/load_balancer/runtime.c 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 delete mode 100644 examples/quota_watermark/Makefile delete mode 100644 examples/quota_watermark/include/conf.h delete mode 100644 examples/quota_watermark/meson.build delete mode 100644 examples/quota_watermark/qw/Makefile delete mode 100644 examples/quota_watermark/qw/args.c delete mode 100644 examples/quota_watermark/qw/args.h delete mode 100644 examples/quota_watermark/qw/init.c delete mode 100644 examples/quota_watermark/qw/init.h delete mode 100644 examples/quota_watermark/qw/main.c delete mode 100644 examples/quota_watermark/qw/main.h delete mode 100644 examples/quota_watermark/qwctl/Makefile delete mode 100644 examples/quota_watermark/qwctl/commands.c delete mode 100644 examples/quota_watermark/qwctl/commands.h delete mode 100644 examples/quota_watermark/qwctl/qwctl.c delete mode 100644 examples/quota_watermark/qwctl/qwctl.h -- 2.21.0 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH 1/6] examples/exception_path: remove example from DPDK 2019-10-03 13:19 [dpdk-dev] [PATCH 0/6] remove a few example applications Bruce Richardson @ 2019-10-03 13:19 ` Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 2/6] examples/l3fwd-vf: " Bruce Richardson ` (7 subsequent siblings) 8 siblings, 0 replies; 27+ messages in thread From: Bruce Richardson @ 2019-10-03 13:19 UTC (permalink / raw) To: dev; +Cc: techboard, Bruce Richardson The example app shows the use of TUN/TAP with DPDK, but DPDK has a built-in TAP PMD, so this example is obsolete and so can be removed. Signed-off-by: Bruce Richardson <bruce.richardson@intel.com> --- MAINTAINERS | 3 - doc/guides/sample_app_ug/exception_path.rst | 281 ---------- doc/guides/sample_app_ug/index.rst | 1 - doc/guides/sample_app_ug/intro.rst | 2 +- examples/Makefile | 1 - examples/exception_path/Makefile | 57 -- examples/exception_path/main.c | 589 -------------------- examples/exception_path/meson.build | 11 - examples/meson.build | 2 +- 9 files changed, 2 insertions(+), 945 deletions(-) delete mode 100644 doc/guides/sample_app_ug/exception_path.rst delete mode 100644 examples/exception_path/Makefile delete mode 100644 examples/exception_path/main.c delete mode 100644 examples/exception_path/meson.build diff --git a/MAINTAINERS b/MAINTAINERS index b3d9aaddd..330a4d77d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1427,9 +1427,6 @@ Other Example Applications F: examples/ethtool/ F: doc/guides/sample_app_ug/ethtool.rst -F: examples/exception_path/ -F: doc/guides/sample_app_ug/exception_path.rst - M: Marko Kovacevic <marko.kovacevic@intel.com> F: examples/fips_validation/ F: doc/guides/sample_app_ug/fips_validation.rst diff --git a/doc/guides/sample_app_ug/exception_path.rst b/doc/guides/sample_app_ug/exception_path.rst deleted file mode 100644 index a5590870c..000000000 --- a/doc/guides/sample_app_ug/exception_path.rst +++ /dev/null @@ -1,281 +0,0 @@ -.. SPDX-License-Identifier: BSD-3-Clause - Copyright(c) 2010-2014 Intel Corporation. - -Exception Path Sample Application -================================= - -The Exception Path sample application is a simple example that demonstrates the use of the DPDK -to set up an exception path for packets to go through the Linux* kernel. -This is done by using virtual TAP network interfaces. -These can be read from and written to by the DPDK application and -appear to the kernel as a standard network interface. - -Overview --------- - -The application creates two threads for each NIC port being used. -One thread reads from the port and writes the data unmodified to a thread-specific TAP interface. -The second thread reads from a TAP interface and writes the data unmodified to the NIC port. - -The packet flow through the exception path application is as shown in the following figure. - -.. _figure_exception_path_example: - -.. figure:: img/exception_path_example.* - - Packet Flow - - -To make throughput measurements, kernel bridges must be setup to forward data between the bridges appropriately. - -Compiling the Application -------------------------- - -To compile the sample application see :doc:`compiling`. - -The application is located in the ``exception_path`` sub-directory. - -Running the Application ------------------------ - -The application requires a number of command line options: - -.. code-block:: console - - .build/exception_path [EAL options] -- -p PORTMASK -i IN_CORES -o OUT_CORES - -where: - -* -p PORTMASK: A hex bitmask of ports to use - -* -i IN_CORES: A hex bitmask of cores which read from NIC - -* -o OUT_CORES: A hex bitmask of cores which write to NIC - -Refer to the *DPDK Getting Started Guide* for general information on running applications -and the Environment Abstraction Layer (EAL) options. - -The number of bits set in each bitmask must be the same. -The coremask -c or the corelist -l parameter of the EAL options should include IN_CORES and OUT_CORES. -The same bit must not be set in IN_CORES and OUT_CORES. -The affinities between ports and cores are set beginning with the least significant bit of each mask, that is, -the port represented by the lowest bit in PORTMASK is read from by the core represented by the lowest bit in IN_CORES, -and written to by the core represented by the lowest bit in OUT_CORES. - -For example to run the application with two ports and four cores: - -.. code-block:: console - - ./build/exception_path -l 0-3 -n 4 -- -p 3 -i 3 -o c - -Getting Statistics -~~~~~~~~~~~~~~~~~~ - -While the application is running, statistics on packets sent and -received can be displayed by sending the SIGUSR1 signal to the application from another terminal: - -.. code-block:: console - - killall -USR1 exception_path - -The statistics can be reset by sending a SIGUSR2 signal in a similar way. - -Explanation ------------ - -The following sections provide some explanation of the code. - -Initialization -~~~~~~~~~~~~~~ - -Setup of the mbuf pool, driver and queues is similar to the setup done in the :ref:`l2_fwd_app_real_and_virtual`. -In addition, the TAP interfaces must also be created. -A TAP interface is created for each lcore that is being used. -The code for creating the TAP interface is as follows: - -.. code-block:: c - - /* - * Create a tap network interface, or use existing one with same name. - * If name[0]='\0' then a name is automatically assigned and returned in name. - */ - - static int tap_create(char *name) - { - struct ifreq ifr; - int fd, ret; - - fd = open("/dev/net/tun", O_RDWR); - if (fd < 0) - return fd; - - memset(&ifr, 0, sizeof(ifr)); - - /* TAP device without packet information */ - - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - if (name && *name) - rte_snprinf(ifr.ifr_name, IFNAMSIZ, name); - - ret = ioctl(fd, TUNSETIFF, (void *) &ifr); - - if (ret < 0) { - close(fd); - return ret; - - } - - if (name) - snprintf(name, IFNAMSIZ, ifr.ifr_name); - - return fd; - } - -The other step in the initialization process that is unique to this sample application -is the association of each port with two cores: - -* One core to read from the port and write to a TAP interface - -* A second core to read from a TAP interface and write to the port - -This is done using an array called port_ids[], which is indexed by the lcore IDs. -The population of this array is shown below: - -.. code-block:: c - - tx_port = 0; - rx_port = 0; - - RTE_LCORE_FOREACH(i) { - if (input_cores_mask & (1ULL << i)) { - /* Skip ports that are not enabled */ - while ((ports_mask & (1 << rx_port)) == 0) { - rx_port++; - if (rx_port > (sizeof(ports_mask) * 8)) - goto fail; /* not enough ports */ - } - port_ids[i] = rx_port++; - } else if (output_cores_mask & (1ULL << i)) { - /* Skip ports that are not enabled */ - while ((ports_mask & (1 << tx_port)) == 0) { - tx_port++; - if (tx_port > (sizeof(ports_mask) * 8)) - goto fail; /* not enough ports */ - } - port_ids[i] = tx_port++; - } - } - -Packet Forwarding -~~~~~~~~~~~~~~~~~ - -After the initialization steps are complete, the main_loop() function is run on each lcore. -This function first checks the lcore_id against the user provided input_cores_mask and output_cores_mask to see -if this core is reading from or writing to a TAP interface. - -For the case that reads from a NIC port, the packet reception is the same as in the L2 Forwarding sample application -(see :ref:`l2_fwd_app_rx_tx_packets`). -The packet transmission is done by calling write() with the file descriptor of the appropriate TAP interface -and then explicitly freeing the mbuf back to the pool. - -.. code-block:: c - - /* Loop forever reading from NIC and writing to tap */ - - for (;;) { - struct rte_mbuf *pkts_burst[PKT_BURST_SZ]; - unsigned i; - - const unsigned nb_rx = rte_eth_rx_burst(port_ids[lcore_id], 0, pkts_burst, PKT_BURST_SZ); - - lcore_stats[lcore_id].rx += nb_rx; - - for (i = 0; likely(i < nb_rx); i++) { - struct rte_mbuf *m = pkts_burst[i]; - int ret = write(tap_fd, rte_pktmbuf_mtod(m, void*), - - rte_pktmbuf_data_len(m)); - rte_pktmbuf_free(m); - if (unlikely(ret<0)) - lcore_stats[lcore_id].dropped++; - else - lcore_stats[lcore_id].tx++; - } - } - -For the other case that reads from a TAP interface and writes to a NIC port, -packets are retrieved by doing a read() from the file descriptor of the appropriate TAP interface. -This fills in the data into the mbuf, then other fields are set manually. -The packet can then be transmitted as normal. - -.. code-block:: c - - /* Loop forever reading from tap and writing to NIC */ - - for (;;) { - int ret; - struct rte_mbuf *m = rte_pktmbuf_alloc(pktmbuf_pool); - - if (m == NULL) - continue; - - ret = read(tap_fd, m->pkt.data, MAX_PACKET_SZ); lcore_stats[lcore_id].rx++; - if (unlikely(ret < 0)) { - FATAL_ERROR("Reading from %s interface failed", tap_name); - } - - m->pkt.nb_segs = 1; - m->pkt.next = NULL; - m->pkt.data_len = (uint16_t)ret; - - ret = rte_eth_tx_burst(port_ids[lcore_id], 0, &m, 1); - if (unlikely(ret < 1)) { - rte_pktmuf_free(m); - lcore_stats[lcore_id].dropped++; - } - else { - lcore_stats[lcore_id].tx++; - } - } - -To set up loops for measuring throughput, TAP interfaces can be connected using bridging. -The steps to do this are described in the section that follows. - -Managing TAP Interfaces and Bridges -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The Exception Path sample application creates TAP interfaces with names of the format tap_dpdk_nn, -where nn is the lcore ID. These TAP interfaces need to be configured for use: - -.. code-block:: console - - ifconfig tap_dpdk_00 up - -To set up a bridge between two interfaces so that packets sent to one interface can be read from another, -use the brctl tool: - -.. code-block:: console - - brctl addbr "br0" - brctl addif br0 tap_dpdk_00 - brctl addif br0 tap_dpdk_03 - ifconfig br0 up - -The TAP interfaces created by this application exist only when the application is running, -so the steps above need to be repeated each time the application is run. -To avoid this, persistent TAP interfaces can be created using openvpn: - -.. code-block:: console - - openvpn --mktun --dev tap_dpdk_00 - -If this method is used, then the steps above have to be done only once and -the same TAP interfaces can be reused each time the application is run. -To remove bridges and persistent TAP interfaces, the following commands are used: - -.. code-block:: console - - ifconfig br0 down - brctl delbr br0 - openvpn --rmtun --dev tap_dpdk_00 - diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst index f23f8f59e..076346a60 100644 --- a/doc/guides/sample_app_ug/index.rst +++ b/doc/guides/sample_app_ug/index.rst @@ -12,7 +12,6 @@ Sample Applications User Guides compiling cmd_line ethtool - exception_path hello_world skeleton rxtx_callbacks diff --git a/doc/guides/sample_app_ug/intro.rst b/doc/guides/sample_app_ug/intro.rst index 90704194a..7299253bf 100644 --- a/doc/guides/sample_app_ug/intro.rst +++ b/doc/guides/sample_app_ug/intro.rst @@ -39,7 +39,7 @@ applications that are available in the examples directory of DPDK: +---------------------------------------+--------------------------------------+ | Ethtool | Precision Time Protocol (PTP) Client | +---------------------------------------+--------------------------------------+ - | Exception Path | Quality of Service (QoS) Metering | + | | Quality of Service (QoS) Metering | +---------------------------------------+--------------------------------------+ | Hello World | QoS Scheduler | +---------------------------------------+--------------------------------------+ diff --git a/examples/Makefile b/examples/Makefile index de11dd487..c756497d1 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -17,7 +17,6 @@ ifeq ($(CONFIG_RTE_LIBRTE_POWER),y) DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += distributor endif DIRS-y += ethtool -DIRS-y += exception_path DIRS-$(CONFIG_RTE_LIBRTE_EFD) += server_node_efd DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += fips_validation DIRS-$(CONFIG_RTE_LIBRTE_FLOW_CLASSIFY) += flow_classify diff --git a/examples/exception_path/Makefile b/examples/exception_path/Makefile deleted file mode 100644 index 90c7f133a..000000000 --- a/examples/exception_path/Makefile +++ /dev/null @@ -1,57 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2010-2014 Intel Corporation - -# binary name -APP = exception_path - -# all source are stored in SRCS-y -SRCS-y := main.c - -# Build using pkg-config variables if possible -ifeq ($(shell pkg-config --exists libdpdk && echo 0),0) - -all: shared -.PHONY: shared static -shared: build/$(APP)-shared - ln -sf $(APP)-shared build/$(APP) -static: build/$(APP)-static - ln -sf $(APP)-static build/$(APP) - -PKGCONF=pkg-config --define-prefix - -PC_FILE := $(shell $(PKGCONF) --path libdpdk) -CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) -LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk) -LDFLAGS_STATIC = -Wl,-Bstatic $(shell $(PKGCONF) --static --libs libdpdk) - -build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) - -build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC) - -build: - @mkdir -p $@ - -.PHONY: clean -clean: - rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared - test -d build && rmdir -p build || true - -else - -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 - -CFLAGS += -O3 -CFLAGS += $(WERROR_FLAGS) - -include $(RTE_SDK)/mk/rte.extapp.mk - -endif diff --git a/examples/exception_path/main.c b/examples/exception_path/main.c deleted file mode 100644 index 0d79e5a24..000000000 --- a/examples/exception_path/main.c +++ /dev/null @@ -1,589 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> - -#include <netinet/in.h> -#include <net/if.h> -#ifdef RTE_EXEC_ENV_LINUX -#include <linux/if_tun.h> -#endif -#include <fcntl.h> -#include <sys/ioctl.h> -#include <unistd.h> -#include <signal.h> - -#include <rte_common.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_per_lcore.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_string_fns.h> -#include <rte_cycles.h> - -#ifndef APP_MAX_LCORE -#if (RTE_MAX_LCORE > 64) -#define APP_MAX_LCORE 64 -#else -#define APP_MAX_LCORE RTE_MAX_LCORE -#endif -#endif - -/* Macros for printing using RTE_LOG */ -#define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1 -#define FATAL_ERROR(fmt, args...) rte_exit(EXIT_FAILURE, fmt "\n", ##args) -#define PRINT_INFO(fmt, args...) RTE_LOG(INFO, APP, fmt "\n", ##args) - -/* Max ports than can be used (each port is associated with two lcores) */ -#define MAX_PORTS (APP_MAX_LCORE / 2) - -/* Max size of a single packet */ -#define MAX_PACKET_SZ (2048) - -/* Size of the data buffer in each mbuf */ -#define MBUF_DATA_SZ (MAX_PACKET_SZ + RTE_PKTMBUF_HEADROOM) - -/* Number of mbufs in mempool that is created */ -#define NB_MBUF 8192 - -/* How many packets to attempt to read from NIC in one go */ -#define PKT_BURST_SZ 32 - -/* How many objects (mbufs) to keep in per-lcore mempool cache */ -#define MEMPOOL_CACHE_SZ PKT_BURST_SZ - -/* Number of RX ring descriptors */ -#define NB_RXD 1024 - -/* Number of TX ring descriptors */ -#define NB_TXD 1024 - -/* - * RX and TX Prefetch, Host, and Write-back threshold values should be - * carefully set for optimal performance. Consult the network - * controller's datasheet and supporting DPDK documentation for guidance - * on how these parameters should be set. - */ - -/* Options for configuring ethernet port */ -static struct rte_eth_conf port_conf = { - .txmode = { - .mq_mode = ETH_MQ_TX_NONE, - }, -}; - -/* Mempool for mbufs */ -static struct rte_mempool * pktmbuf_pool = NULL; - -/* Mask of enabled ports */ -static uint32_t ports_mask = 0; - -/* Mask of cores that read from NIC and write to tap */ -static uint64_t input_cores_mask = 0; - -/* Mask of cores that read from tap and write to NIC */ -static uint64_t output_cores_mask = 0; - -/* Array storing port_id that is associated with each lcore */ -static uint16_t port_ids[APP_MAX_LCORE]; - -/* Structure type for recording lcore-specific stats */ -struct stats { - uint64_t rx; - uint64_t tx; - uint64_t dropped; -} __rte_cache_aligned; - -/* Array of lcore-specific stats */ -static struct stats lcore_stats[APP_MAX_LCORE]; - -/* Print out statistics on packets handled */ -static void -print_stats(void) -{ - unsigned i; - - printf("\n**Exception-Path example application statistics**\n" - "======= ====== ============ ============ ===============\n" - " Lcore Port RX TX Dropped on TX\n" - "------- ------ ------------ ------------ ---------------\n"); - RTE_LCORE_FOREACH(i) { - /* limit ourselves to application supported cores only */ - if (i >= APP_MAX_LCORE) - break; - printf("%6u %7u %13"PRIu64" %13"PRIu64" %16"PRIu64"\n", - i, (unsigned)port_ids[i], - lcore_stats[i].rx, lcore_stats[i].tx, - lcore_stats[i].dropped); - } - printf("======= ====== ============ ============ ===============\n"); -} - -/* Custom handling of signals to handle stats */ -static void -signal_handler(int signum) -{ - /* When we receive a USR1 signal, print stats */ - if (signum == SIGUSR1) { - print_stats(); - } - - /* When we receive a USR2 signal, reset stats */ - if (signum == SIGUSR2) { - memset(&lcore_stats, 0, sizeof(lcore_stats)); - printf("\n**Statistics have been reset**\n"); - return; - } -} - -#ifdef RTE_EXEC_ENV_LINUX -/* - * Create a tap network interface, or use existing one with same name. - * If name[0]='\0' then a name is automatically assigned and returned in name. - */ -static int tap_create(char *name) -{ - struct ifreq ifr; - int fd, ret; - - fd = open("/dev/net/tun", O_RDWR); - if (fd < 0) - return fd; - - memset(&ifr, 0, sizeof(ifr)); - - /* TAP device without packet information */ - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - - if (name && *name) - strlcpy(ifr.ifr_name, name, IFNAMSIZ); - - ret = ioctl(fd, TUNSETIFF, (void *) &ifr); - if (ret < 0) { - close(fd); - return ret; - } - - if (name) - strlcpy(name, ifr.ifr_name, IFNAMSIZ); - - return fd; -} -#else -/* - * Find a free tap network interface, or create a new one. - * The name is automatically assigned and returned in name. - */ -static int tap_create(char *name) -{ - int i, fd = -1; - char devname[PATH_MAX]; - - for (i = 0; i < 255; i++) { - snprintf(devname, sizeof(devname), "/dev/tap%d", i); - fd = open(devname, O_RDWR); - if (fd >= 0 || errno != EBUSY) - break; - } - - if (name) - snprintf(name, IFNAMSIZ, "tap%d", i); - - return fd; -} -#endif - -/* Main processing loop */ -static int -main_loop(__attribute__((unused)) void *arg) -{ - const unsigned lcore_id = rte_lcore_id(); - char tap_name[IFNAMSIZ]; - int tap_fd; - - if ((1ULL << lcore_id) & input_cores_mask) { - /* Create new tap interface */ - snprintf(tap_name, IFNAMSIZ, "tap_dpdk_%.2u", lcore_id); - tap_fd = tap_create(tap_name); - if (tap_fd < 0) - FATAL_ERROR("Could not create tap interface \"%s\" (%d)", - tap_name, tap_fd); - - PRINT_INFO("Lcore %u is reading from port %u and writing to %s", - lcore_id, (unsigned)port_ids[lcore_id], tap_name); - fflush(stdout); - /* Loop forever reading from NIC and writing to tap */ - for (;;) { - struct rte_mbuf *pkts_burst[PKT_BURST_SZ]; - unsigned i; - const unsigned nb_rx = - rte_eth_rx_burst(port_ids[lcore_id], 0, - pkts_burst, PKT_BURST_SZ); - lcore_stats[lcore_id].rx += nb_rx; - for (i = 0; likely(i < nb_rx); i++) { - struct rte_mbuf *m = pkts_burst[i]; - /* Ignore return val from write() */ - int ret = write(tap_fd, - rte_pktmbuf_mtod(m, void*), - rte_pktmbuf_data_len(m)); - rte_pktmbuf_free(m); - if (unlikely(ret < 0)) - lcore_stats[lcore_id].dropped++; - else - lcore_stats[lcore_id].tx++; - } - } - } - else if ((1ULL << lcore_id) & output_cores_mask) { - /* Create new tap interface */ - snprintf(tap_name, IFNAMSIZ, "tap_dpdk_%.2u", lcore_id); - tap_fd = tap_create(tap_name); - if (tap_fd < 0) - FATAL_ERROR("Could not create tap interface \"%s\" (%d)", - tap_name, tap_fd); - - PRINT_INFO("Lcore %u is reading from %s and writing to port %u", - lcore_id, tap_name, (unsigned)port_ids[lcore_id]); - fflush(stdout); - /* Loop forever reading from tap and writing to NIC */ - for (;;) { - int ret; - struct rte_mbuf *m = rte_pktmbuf_alloc(pktmbuf_pool); - if (m == NULL) - continue; - - ret = read(tap_fd, rte_pktmbuf_mtod(m, void *), - MAX_PACKET_SZ); - lcore_stats[lcore_id].rx++; - if (unlikely(ret < 0)) { - FATAL_ERROR("Reading from %s interface failed", - tap_name); - } - m->nb_segs = 1; - m->next = NULL; - m->pkt_len = (uint16_t)ret; - m->data_len = (uint16_t)ret; - ret = rte_eth_tx_burst(port_ids[lcore_id], 0, &m, 1); - if (unlikely(ret < 1)) { - rte_pktmbuf_free(m); - lcore_stats[lcore_id].dropped++; - } - else { - lcore_stats[lcore_id].tx++; - } - } - } - else { - PRINT_INFO("Lcore %u has nothing to do", lcore_id); - return 0; - } - /* - * Tap file is closed automatically when program exits. Putting close() - * here will cause the compiler to give an error about unreachable code. - */ -} - -/* Display usage instructions */ -static void -print_usage(const char *prgname) -{ - PRINT_INFO("\nUsage: %s [EAL options] -- -p PORTMASK -i IN_CORES -o OUT_CORES\n" - " -p PORTMASK: hex bitmask of ports to use\n" - " -i IN_CORES: hex bitmask of cores which read from NIC\n" - " -o OUT_CORES: hex bitmask of cores which write to NIC", - prgname); -} - -/* Convert string to unsigned number. 0 is returned if error occurs */ -static uint64_t -parse_unsigned(const char *portmask) -{ - char *end = NULL; - uint64_t num; - - num = strtoull(portmask, &end, 16); - if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) - return 0; - - return (uint64_t)num; -} - -/* Record affinities between ports and lcores in global port_ids[] array */ -static void -setup_port_lcore_affinities(void) -{ - unsigned long i; - uint16_t tx_port = 0; - uint16_t rx_port = 0; - - /* Setup port_ids[] array, and check masks were ok */ - for (i = 0; i < APP_MAX_LCORE; i++) { - if (!rte_lcore_is_enabled(i)) - continue; - if (input_cores_mask & (1ULL << i)) { - /* Skip ports that are not enabled */ - while ((ports_mask & (1 << rx_port)) == 0) { - rx_port++; - if (rx_port > (sizeof(ports_mask) * 8)) - goto fail; /* not enough ports */ - } - - port_ids[i] = rx_port++; - } else if (output_cores_mask & (1ULL << (i & 0x3f))) { - /* Skip ports that are not enabled */ - while ((ports_mask & (1 << tx_port)) == 0) { - tx_port++; - if (tx_port > (sizeof(ports_mask) * 8)) - goto fail; /* not enough ports */ - } - - port_ids[i] = tx_port++; - } - } - - if (rx_port != tx_port) - goto fail; /* uneven number of cores in masks */ - - if (ports_mask & (~((1 << rx_port) - 1))) - goto fail; /* unused ports */ - - return; -fail: - FATAL_ERROR("Invalid core/port masks specified on command line"); -} - -/* Parse the arguments given in the command line of the application */ -static void -parse_args(int argc, char **argv) -{ - int opt; - const char *prgname = argv[0]; - - /* Disable printing messages within getopt() */ - opterr = 0; - - /* Parse command line */ - while ((opt = getopt(argc, argv, "i:o:p:")) != EOF) { - switch (opt) { - case 'i': - input_cores_mask = parse_unsigned(optarg); - break; - case 'o': - output_cores_mask = parse_unsigned(optarg); - break; - case 'p': - ports_mask = parse_unsigned(optarg); - break; - default: - print_usage(prgname); - FATAL_ERROR("Invalid option specified"); - } - } - - /* Check that options were parsed ok */ - if (input_cores_mask == 0) { - print_usage(prgname); - FATAL_ERROR("IN_CORES not specified correctly"); - } - if (output_cores_mask == 0) { - print_usage(prgname); - FATAL_ERROR("OUT_CORES not specified correctly"); - } - if (ports_mask == 0) { - print_usage(prgname); - FATAL_ERROR("PORTMASK not specified correctly"); - } - - setup_port_lcore_affinities(); -} - -/* Initialise a single port on an Ethernet device */ -static void -init_port(uint16_t port) -{ - int ret; - uint16_t nb_rxd = NB_RXD; - uint16_t nb_txd = NB_TXD; - struct rte_eth_dev_info dev_info; - struct rte_eth_rxconf rxq_conf; - struct rte_eth_txconf txq_conf; - struct rte_eth_conf local_port_conf = port_conf; - - /* Initialise device and RX/TX queues */ - PRINT_INFO("Initialising port %u ...", port); - fflush(stdout); - rte_eth_dev_info_get(port, &dev_info); - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - ret = rte_eth_dev_configure(port, 1, 1, &local_port_conf); - if (ret < 0) - FATAL_ERROR("Could not configure port%u (%d)", port, ret); - - ret = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd); - if (ret < 0) - FATAL_ERROR("Could not adjust number of descriptors for port%u (%d)", - port, ret); - - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = local_port_conf.rxmode.offloads; - ret = rte_eth_rx_queue_setup(port, 0, nb_rxd, - rte_eth_dev_socket_id(port), - &rxq_conf, - pktmbuf_pool); - if (ret < 0) - FATAL_ERROR("Could not setup up RX queue for port%u (%d)", - port, ret); - - txq_conf = dev_info.default_txconf; - txq_conf.offloads = local_port_conf.txmode.offloads; - ret = rte_eth_tx_queue_setup(port, 0, nb_txd, - rte_eth_dev_socket_id(port), - &txq_conf); - if (ret < 0) - FATAL_ERROR("Could not setup up TX queue for port%u (%d)", - port, ret); - - ret = rte_eth_dev_start(port); - if (ret < 0) - FATAL_ERROR("Could not start port%u (%d)", port, ret); - - rte_eth_promiscuous_enable(port); -} - -/* Check the link status of all ports in up to 9s, and print them finally */ -static void -check_all_ports_link_status(uint32_t port_mask) -{ -#define CHECK_INTERVAL 100 /* 100ms */ -#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ - uint16_t portid; - uint8_t count, all_ports_up, print_flag = 0; - struct rte_eth_link link; - - printf("\nChecking link status"); - fflush(stdout); - for (count = 0; count <= MAX_CHECK_TIME; count++) { - all_ports_up = 1; - RTE_ETH_FOREACH_DEV(portid) { - if ((port_mask & (1 << portid)) == 0) - continue; - memset(&link, 0, sizeof(link)); - rte_eth_link_get_nowait(portid, &link); - /* print link status if flag set */ - if (print_flag == 1) { - if (link.link_status) - printf( - "Port%d Link Up. Speed %u Mbps - %s\n", - portid, link.link_speed, - (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? - ("full-duplex") : ("half-duplex\n")); - else - printf("Port %d Link Down\n", portid); - continue; - } - /* clear all_ports_up flag if any link down */ - if (link.link_status == ETH_LINK_DOWN) { - all_ports_up = 0; - break; - } - } - /* after finally printing all link status, get out */ - if (print_flag == 1) - break; - - if (all_ports_up == 0) { - printf("."); - fflush(stdout); - rte_delay_ms(CHECK_INTERVAL); - } - - /* set the print_flag if all ports up or timeout */ - if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { - print_flag = 1; - printf("done\n"); - } - } -} - -/* Initialise ports/queues etc. and start main loop on each core */ -int -main(int argc, char** argv) -{ - int ret; - unsigned i,high_port; - uint16_t nb_sys_ports, port; - - /* Associate signal_hanlder function with USR signals */ - signal(SIGUSR1, signal_handler); - signal(SIGUSR2, signal_handler); - - /* Initialise EAL */ - ret = rte_eal_init(argc, argv); - if (ret < 0) - FATAL_ERROR("Could not initialise EAL (%d)", ret); - argc -= ret; - argv += ret; - - /* Parse application arguments (after the EAL ones) */ - parse_args(argc, argv); - - /* Create the mbuf pool */ - pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, - MEMPOOL_CACHE_SZ, 0, MBUF_DATA_SZ, rte_socket_id()); - if (pktmbuf_pool == NULL) { - FATAL_ERROR("Could not initialise mbuf pool"); - return -1; - } - - /* Get number of ports found in scan */ - nb_sys_ports = rte_eth_dev_count_avail(); - if (nb_sys_ports == 0) - FATAL_ERROR("No supported Ethernet device found"); - /* Find highest port set in portmask */ - for (high_port = (sizeof(ports_mask) * 8) - 1; - (high_port != 0) && !(ports_mask & (1 << high_port)); - high_port--) - ; /* empty body */ - if (high_port > nb_sys_ports) - FATAL_ERROR("Port mask requires more ports than available"); - - /* Initialise each port */ - RTE_ETH_FOREACH_DEV(port) { - /* Skip ports that are not enabled */ - if ((ports_mask & (1 << port)) == 0) { - continue; - } - init_port(port); - } - check_all_ports_link_status(ports_mask); - - /* Launch per-lcore function on every lcore */ - rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER); - RTE_LCORE_FOREACH_SLAVE(i) { - if (rte_eal_wait_lcore(i) < 0) - return -1; - } - - return 0; -} diff --git a/examples/exception_path/meson.build b/examples/exception_path/meson.build deleted file mode 100644 index c34e11e36..000000000 --- a/examples/exception_path/meson.build +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2017 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' - -sources = files( - 'main.c' -) diff --git a/examples/meson.build b/examples/meson.build index a046b74ad..4663d9dea 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -13,7 +13,7 @@ all_examples = [ 'bbdev_app', 'bond', 'bpf', 'cmdline', 'distributor', 'ethtool', - 'eventdev_pipeline', 'exception_path', + 'eventdev_pipeline', 'fips_validation', 'flow_classify', 'flow_filtering', 'helloworld', 'ip_fragmentation', 'ip_pipeline', -- 2.21.0 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH 2/6] examples/l3fwd-vf: remove example from DPDK 2019-10-03 13:19 [dpdk-dev] [PATCH 0/6] remove a few example applications Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 1/6] examples/exception_path: remove example from DPDK Bruce Richardson @ 2019-10-03 13:19 ` Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 3/6] examples/quota-watermark: " Bruce Richardson ` (6 subsequent siblings) 8 siblings, 0 replies; 27+ messages in thread From: Bruce Richardson @ 2019-10-03 13:19 UTC (permalink / raw) To: dev; +Cc: techboard, Bruce Richardson The main l3fwd app should work with both PF and VF devices, so remove the VF-only l3fwd example. Signed-off-by: Bruce Richardson <bruce.richardson@intel.com> --- MAINTAINERS | 3 - doc/guides/sample_app_ug/index.rst | 1 - .../sample_app_ug/l3_forward_virtual.rst | 98 -- examples/Makefile | 1 - examples/l3fwd-vf/Makefile | 62 - examples/l3fwd-vf/main.c | 1072 ----------------- examples/l3fwd-vf/meson.build | 12 - examples/meson.build | 2 +- 8 files changed, 1 insertion(+), 1250 deletions(-) delete mode 100644 doc/guides/sample_app_ug/l3_forward_virtual.rst delete mode 100644 examples/l3fwd-vf/Makefile delete mode 100644 examples/l3fwd-vf/main.c delete mode 100644 examples/l3fwd-vf/meson.build diff --git a/MAINTAINERS b/MAINTAINERS index 330a4d77d..92c3f6af4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1458,9 +1458,6 @@ F: examples/l2fwd-cat/ F: examples/l3fwd/ F: doc/guides/sample_app_ug/l3_forward.rst -F: examples/l3fwd-vf/ -F: doc/guides/sample_app_ug/l3_forward_virtual.rst - F: examples/link_status_interrupt/ F: doc/guides/sample_app_ug/link_status_intr.rst diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst index 076346a60..d212f81fe 100644 --- a/doc/guides/sample_app_ug/index.rst +++ b/doc/guides/sample_app_ug/index.rst @@ -29,7 +29,6 @@ Sample Applications User Guides l3_forward l3_forward_power_man l3_forward_access_ctrl - l3_forward_virtual link_status_intr load_balancer server_node_efd diff --git a/doc/guides/sample_app_ug/l3_forward_virtual.rst b/doc/guides/sample_app_ug/l3_forward_virtual.rst deleted file mode 100644 index 21eab8da3..000000000 --- a/doc/guides/sample_app_ug/l3_forward_virtual.rst +++ /dev/null @@ -1,98 +0,0 @@ -.. SPDX-License-Identifier: BSD-3-Clause - Copyright(c) 2010-2014 Intel Corporation. - -L3 Forwarding in a Virtualization Environment Sample Application -================================================================ - -The L3 Forwarding in a Virtualization Environment sample application is a simple example of packet processing using the DPDK. -The application performs L3 forwarding that takes advantage of Single Root I/O Virtualization (SR-IOV) features -in a virtualized environment. - -Overview --------- - -The application demonstrates the use of the hash and LPM libraries in the DPDK to implement packet forwarding. -The initialization and run-time paths are very similar to those of the :doc:`l3_forward`. -The forwarding decision is taken based on information read from the input packet. - -The lookup method is either hash-based or LPM-based and is selected at compile time. -When the selected lookup method is hash-based, a hash object is used to emulate the flow classification stage. -The hash object is used in correlation with the flow table to map each input packet to its flow at runtime. - -The hash lookup key is represented by the DiffServ 5-tuple composed of the following fields read from the input packet: -Source IP Address, Destination IP Address, Protocol, Source Port and Destination Port. -The ID of the output interface for the input packet is read from the identified flow table entry. -The set of flows used by the application is statically configured and loaded into the hash at initialization time. -When the selected lookup method is LPM based, an LPM object is used to emulate the forwarding stage for IPv4 packets. -The LPM object is used as the routing table to identify the next hop for each input packet at runtime. - -The LPM lookup key is represented by the Destination IP Address field read from the input packet. -The ID of the output interface for the input packet is the next hop returned by the LPM lookup. -The set of LPM rules used by the application is statically configured and loaded into the LPM object at the initialization time. - -.. note:: - - Please refer to :ref:`l2_fwd_vf_setup` for virtualized test case setup. - -Compiling the Application -------------------------- - -To compile the sample application see :doc:`compiling`. - -The application is located in the ``l3fwd-vf`` sub-directory. - -Running the Application ------------------------ - -The application has a number of command line options: - -.. code-block:: console - - ./build/l3fwd-vf [EAL options] -- -p PORTMASK --config(port,queue,lcore)[,(port,queue,lcore)] [--no-numa] - -where, - -* --p PORTMASK: Hexadecimal bitmask of ports to configure - -* --config (port,queue,lcore)[,(port,queue,lcore]: determines which queues from which ports are mapped to which cores - -* --no-numa: optional, disables numa awareness - -For example, consider a dual processor socket platform with 8 physical cores, where cores 0-7 and 16-23 appear on socket 0, -while cores 8-15 and 24-31 appear on socket 1. - -To enable L3 forwarding between two ports, assuming that both ports are in the same socket, using two cores, cores 1 and 2, -(which are in the same socket too), use the following command: - -.. code-block:: console - - ./build/l3fwd-vf -l 1,2 -n 4 -- -p 0x3 --config="(0,0,1),(1,0,2)" - -In this command: - -* The -l option enables cores 1 and 2 - -* The -p option enables ports 0 and 1 - -* The --config option enables one queue on each port and maps each (port,queue) pair to a specific core. - The following table shows the mapping in this example: - - +----------+-----------+-----------+------------------------------------+ - | **Port** | **Queue** | **lcore** | **Description** | - | | | | | - +==========+===========+===========+====================================+ - | 0 | 0 | 1 | Map queue 0 from port 0 to lcore 1 | - | | | | | - +----------+-----------+-----------+------------------------------------+ - | 1 | 0 | 2 | Map queue 0 from port 1 to lcore 2 | - | | | | | - +----------+-----------+-----------+------------------------------------+ - -Refer to the *DPDK Getting Started Guide* for general information on running applications -and the Environment Abstraction Layer (EAL) options. - -Explanation ------------ - -The operation of this application is similar to that of the basic L3 Forwarding Sample Application. -See :ref:`l3_fwd_explanation` for more information. diff --git a/examples/Makefile b/examples/Makefile index c756497d1..5dd8a72e5 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -46,7 +46,6 @@ endif DIRS-$(CONFIG_RTE_LIBRTE_ACL) += l3fwd-acl ifeq ($(CONFIG_RTE_LIBRTE_LPM)$(CONFIG_RTE_LIBRTE_HASH),yy) DIRS-$(CONFIG_RTE_LIBRTE_POWER) += l3fwd-power -DIRS-y += l3fwd-vf endif DIRS-y += link_status_interrupt DIRS-$(CONFIG_RTE_LIBRTE_LPM) += load_balancer diff --git a/examples/l3fwd-vf/Makefile b/examples/l3fwd-vf/Makefile deleted file mode 100644 index 7b186a23c..000000000 --- a/examples/l3fwd-vf/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2010-2014 Intel Corporation - -# binary name -APP = l3fwd-vf - -# all source are stored in SRCS-y -SRCS-y := main.c - -# Build using pkg-config variables if possible -ifeq ($(shell pkg-config --exists libdpdk && echo 0),0) - -all: shared -.PHONY: shared static -shared: build/$(APP)-shared - ln -sf $(APP)-shared build/$(APP) -static: build/$(APP)-static - ln -sf $(APP)-static build/$(APP) - -PKGCONF=pkg-config --define-prefix - -PC_FILE := $(shell $(PKGCONF) --path libdpdk) -CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) -LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk) -LDFLAGS_STATIC = -Wl,-Bstatic $(shell $(PKGCONF) --static --libs libdpdk) - -build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) - -build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC) - -build: - @mkdir -p $@ - -.PHONY: clean -clean: - rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared - test -d build && rmdir -p build || true - -else # Build using legacy build system - -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 - -CFLAGS += -O3 $(USER_FLAGS) -CFLAGS += $(WERROR_FLAGS) - -# workaround for a gcc bug with noreturn attribute -# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603 -ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y) -CFLAGS_main.o += -Wno-return-type -endif - -include $(RTE_SDK)/mk/rte.extapp.mk -endif diff --git a/examples/l3fwd-vf/main.c b/examples/l3fwd-vf/main.c deleted file mode 100644 index 572e74cf5..000000000 --- a/examples/l3fwd-vf/main.c +++ /dev/null @@ -1,1072 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> -#include <signal.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_spinlock.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_udp.h> -#include <rte_string_fns.h> - -#define APP_LOOKUP_EXACT_MATCH 0 -#define APP_LOOKUP_LPM 1 -#define DO_RFC_1812_CHECKS - -//#define APP_LOOKUP_METHOD APP_LOOKUP_EXACT_MATCH -#ifndef APP_LOOKUP_METHOD -#define APP_LOOKUP_METHOD APP_LOOKUP_LPM -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH) -#include <rte_hash.h> -#elif (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) -#include <rte_lpm.h> -#else -#error "APP_LOOKUP_METHOD set to incorrect value" -#endif - -#define RTE_LOGTYPE_L3FWD RTE_LOGTYPE_USER1 - -#define MEMPOOL_CACHE_SIZE 256 - -/* - * This expression is used to calculate the number of mbufs needed depending on user input, taking - * into account memory for rx and tx hardware rings, cache per lcore and mtable per port per lcore. - * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum value of 8192 - */ - -#define NB_MBUF RTE_MAX ( \ - (nb_ports*nb_rx_queue*nb_rxd + \ - nb_ports*nb_lcores*MAX_PKT_BURST + \ - nb_ports*n_tx_queue*nb_txd + \ - nb_lcores*MEMPOOL_CACHE_SIZE), \ - (unsigned)8192) - -#define MAX_PKT_BURST 32 -#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */ - -#define NB_SOCKETS 8 - -#define SOCKET0 0 - -/* Configure how many packets ahead to prefetch, when reading packets */ -#define PREFETCH_OFFSET 3 - -/* - * Configurable number of RX/TX ring descriptors - */ -#define RTE_TEST_RX_DESC_DEFAULT 1024 -#define RTE_TEST_TX_DESC_DEFAULT 1024 -static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; -static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; - -/* ethernet addresses of ports */ -static struct rte_ether_addr ports_eth_addr[RTE_MAX_ETHPORTS]; - -/* mask of enabled ports */ -static uint32_t enabled_port_mask = 0; -static int numa_on = 1; /**< NUMA is enabled by default. */ - -struct mbuf_table { - uint16_t len; - struct rte_mbuf *m_table[MAX_PKT_BURST]; -}; - -struct lcore_rx_queue { - uint16_t port_id; - uint8_t queue_id; -} __rte_cache_aligned; - -#define MAX_RX_QUEUE_PER_LCORE 16 -#define MAX_TX_QUEUE_PER_PORT 1 -#define MAX_RX_QUEUE_PER_PORT 1 - -#define MAX_LCORE_PARAMS 1024 -struct lcore_params { - uint16_t port_id; - uint8_t queue_id; - uint8_t lcore_id; -} __rte_cache_aligned; - -static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS]; -static struct lcore_params lcore_params_array_default[] = { - {0, 0, 2}, - {0, 1, 2}, - {0, 2, 2}, - {1, 0, 2}, - {1, 1, 2}, - {1, 2, 2}, - {2, 0, 2}, - {3, 0, 3}, - {3, 1, 3}, -}; - -static struct lcore_params * lcore_params = lcore_params_array_default; -static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) / - sizeof(lcore_params_array_default[0]); - -static struct rte_eth_conf port_conf = { - .rxmode = { - .mq_mode = ETH_MQ_RX_RSS, - .max_rx_pkt_len = RTE_ETHER_MAX_LEN, - .split_hdr_size = 0, - .offloads = DEV_RX_OFFLOAD_CHECKSUM, - }, - .rx_adv_conf = { - .rss_conf = { - .rss_key = NULL, - .rss_hf = ETH_RSS_IP, - }, - }, - .txmode = { - .mq_mode = ETH_MQ_TX_NONE, - }, -}; - -static struct rte_mempool * pktmbuf_pool[NB_SOCKETS]; - - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH) - -#ifdef RTE_ARCH_X86 -#include <rte_hash_crc.h> -#define DEFAULT_HASH_FUNC rte_hash_crc -#else -#include <rte_jhash.h> -#define DEFAULT_HASH_FUNC rte_jhash -#endif - -struct ipv4_5tuple { - uint32_t ip_dst; - uint32_t ip_src; - uint16_t port_dst; - uint16_t port_src; - uint8_t proto; -} __attribute__((__packed__)); - -struct l3fwd_route { - struct ipv4_5tuple key; - uint8_t if_out; -}; - -static struct l3fwd_route l3fwd_route_array[] = { - {{RTE_IPV4(100,10,0,1), RTE_IPV4(200,10,0,1), 101, 11, IPPROTO_TCP}, 0}, - {{RTE_IPV4(100,20,0,2), RTE_IPV4(200,20,0,2), 102, 12, IPPROTO_TCP}, 1}, - {{RTE_IPV4(100,30,0,3), RTE_IPV4(200,30,0,3), 103, 13, IPPROTO_TCP}, 2}, - {{RTE_IPV4(100,40,0,4), RTE_IPV4(200,40,0,4), 104, 14, IPPROTO_TCP}, 3}, -}; - -typedef struct rte_hash lookup_struct_t; -static lookup_struct_t *l3fwd_lookup_struct[NB_SOCKETS]; - -#define L3FWD_HASH_ENTRIES 1024 -struct rte_hash_parameters l3fwd_hash_params = { - .name = "l3fwd_hash_0", - .entries = L3FWD_HASH_ENTRIES, - .key_len = sizeof(struct ipv4_5tuple), - .hash_func = DEFAULT_HASH_FUNC, - .hash_func_init_val = 0, - .socket_id = SOCKET0, -}; - -#define L3FWD_NUM_ROUTES \ - (sizeof(l3fwd_route_array) / sizeof(l3fwd_route_array[0])) - -static uint8_t l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned; -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) -struct l3fwd_route { - uint32_t ip; - uint8_t depth; - uint8_t if_out; -}; - -static struct l3fwd_route l3fwd_route_array[] = { - {RTE_IPV4(1,1,1,0), 24, 0}, - {RTE_IPV4(2,1,1,0), 24, 1}, - {RTE_IPV4(3,1,1,0), 24, 2}, - {RTE_IPV4(4,1,1,0), 24, 3}, - {RTE_IPV4(5,1,1,0), 24, 4}, - {RTE_IPV4(6,1,1,0), 24, 5}, - {RTE_IPV4(7,1,1,0), 24, 6}, - {RTE_IPV4(8,1,1,0), 24, 7}, -}; - -#define L3FWD_NUM_ROUTES \ - (sizeof(l3fwd_route_array) / sizeof(l3fwd_route_array[0])) - -#define L3FWD_LPM_MAX_RULES 1024 - -typedef struct rte_lpm lookup_struct_t; -static lookup_struct_t *l3fwd_lookup_struct[NB_SOCKETS]; -#endif - -struct lcore_conf { - uint16_t n_rx_queue; - struct lcore_rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE]; - uint16_t tx_queue_id; - struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS]; - lookup_struct_t * lookup_struct; -} __rte_cache_aligned; - -static struct lcore_conf lcore_conf[RTE_MAX_LCORE]; -static rte_spinlock_t spinlock_conf[RTE_MAX_ETHPORTS] = {RTE_SPINLOCK_INITIALIZER}; -/* Send burst of packets on an output interface */ -static inline int -send_burst(struct lcore_conf *qconf, uint16_t n, uint16_t port) -{ - struct rte_mbuf **m_table; - int ret; - uint16_t queueid; - - queueid = qconf->tx_queue_id; - m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table; - - rte_spinlock_lock(&spinlock_conf[port]); - ret = rte_eth_tx_burst(port, queueid, m_table, n); - rte_spinlock_unlock(&spinlock_conf[port]); - - if (unlikely(ret < n)) { - do { - rte_pktmbuf_free(m_table[ret]); - } while (++ret < n); - } - - return 0; -} - -/* Enqueue a single packet, and send burst if queue is filled */ -static inline int -send_single_packet(struct rte_mbuf *m, uint16_t port) -{ - uint32_t lcore_id; - uint16_t len; - struct lcore_conf *qconf; - - lcore_id = rte_lcore_id(); - - qconf = &lcore_conf[lcore_id]; - len = qconf->tx_mbufs[port].len; - qconf->tx_mbufs[port].m_table[len] = m; - len++; - - /* enough pkts to be sent */ - if (unlikely(len == MAX_PKT_BURST)) { - send_burst(qconf, MAX_PKT_BURST, port); - len = 0; - } - - qconf->tx_mbufs[port].len = len; - return 0; -} - -#ifdef DO_RFC_1812_CHECKS -static inline int -is_valid_ipv4_pkt(struct rte_ipv4_hdr *pkt, uint32_t link_len) -{ - /* From http://www.rfc-editor.org/rfc/rfc1812.txt section 5.2.2 */ - /* - * 1. The packet length reported by the Link Layer must be large - * enough to hold the minimum length legal IP datagram (20 bytes). - */ - if (link_len < sizeof(struct rte_ipv4_hdr)) - return -1; - - /* 2. The IP checksum must be correct. */ - /* this is checked in H/W */ - - /* - * 3. The IP version number must be 4. If the version number is not 4 - * then the packet may be another version of IP, such as IPng or - * ST-II. - */ - if (((pkt->version_ihl) >> 4) != 4) - return -3; - /* - * 4. The IP header length field must be large enough to hold the - * minimum length legal IP datagram (20 bytes = 5 words). - */ - if ((pkt->version_ihl & 0xf) < 5) - return -4; - - /* - * 5. The IP total length field must be large enough to hold the IP - * datagram header, whose length is specified in the IP header length - * field. - */ - if (rte_cpu_to_be_16(pkt->total_length) < sizeof(struct rte_ipv4_hdr)) - return -5; - - return 0; -} -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH) -static void -print_key(struct ipv4_5tuple key) -{ - printf("IP dst = %08x, IP src = %08x, port dst = %d, port src = %d, proto = %d\n", - (unsigned)key.ip_dst, (unsigned)key.ip_src, key.port_dst, key.port_src, key.proto); -} - -static inline uint16_t -get_dst_port(struct rte_ipv4_hdr *ipv4_hdr, uint16_t portid, - lookup_struct_t *l3fwd_lookup_struct) -{ - struct ipv4_5tuple key; - struct rte_tcp_hdr *tcp; - struct rte_udp_hdr *udp; - int ret = 0; - - key.ip_dst = rte_be_to_cpu_32(ipv4_hdr->dst_addr); - key.ip_src = rte_be_to_cpu_32(ipv4_hdr->src_addr); - key.proto = ipv4_hdr->next_proto_id; - - switch (ipv4_hdr->next_proto_id) { - case IPPROTO_TCP: - tcp = (struct rte_tcp_hdr *)((unsigned char *) ipv4_hdr + - sizeof(struct rte_ipv4_hdr)); - key.port_dst = rte_be_to_cpu_16(tcp->dst_port); - key.port_src = rte_be_to_cpu_16(tcp->src_port); - break; - - case IPPROTO_UDP: - udp = (struct rte_udp_hdr *)((unsigned char *) ipv4_hdr + - sizeof(struct rte_ipv4_hdr)); - key.port_dst = rte_be_to_cpu_16(udp->dst_port); - key.port_src = rte_be_to_cpu_16(udp->src_port); - break; - - default: - key.port_dst = 0; - key.port_src = 0; - } - - /* Find destination port */ - ret = rte_hash_lookup(l3fwd_lookup_struct, (const void *)&key); - return ((ret < 0) ? portid : l3fwd_out_if[ret]); -} -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) -static inline uint32_t -get_dst_port(struct rte_ipv4_hdr *ipv4_hdr, uint16_t portid, - lookup_struct_t *l3fwd_lookup_struct) -{ - uint32_t next_hop; - - return ((rte_lpm_lookup(l3fwd_lookup_struct, - rte_be_to_cpu_32(ipv4_hdr->dst_addr), &next_hop) == 0) ? - next_hop : portid); -} -#endif - -static inline void -l3fwd_simple_forward(struct rte_mbuf *m, uint16_t portid, - lookup_struct_t *l3fwd_lookup_struct) -{ - struct rte_ether_hdr *eth_hdr; - struct rte_ipv4_hdr *ipv4_hdr; - void *tmp; - uint16_t dst_port; - - eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *); - - ipv4_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *, - sizeof(struct rte_ether_hdr)); - -#ifdef DO_RFC_1812_CHECKS - /* Check to make sure the packet is valid (RFC1812) */ - if (is_valid_ipv4_pkt(ipv4_hdr, m->pkt_len) < 0) { - rte_pktmbuf_free(m); - return; - } -#endif - - dst_port = get_dst_port(ipv4_hdr, portid, l3fwd_lookup_struct); - if (dst_port >= RTE_MAX_ETHPORTS || (enabled_port_mask & 1 << dst_port) == 0) - dst_port = portid; - - /* 02:00:00:00:00:xx */ - tmp = ð_hdr->d_addr.addr_bytes[0]; - *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40); - -#ifdef DO_RFC_1812_CHECKS - /* Update time to live and header checksum */ - --(ipv4_hdr->time_to_live); - ++(ipv4_hdr->hdr_checksum); -#endif - - /* src addr */ - rte_ether_addr_copy(&ports_eth_addr[dst_port], ð_hdr->s_addr); - - send_single_packet(m, dst_port); - -} - -/* main processing loop */ -static int -main_loop(__attribute__((unused)) void *dummy) -{ - struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; - unsigned lcore_id; - uint64_t prev_tsc, diff_tsc, cur_tsc; - int i, j, nb_rx; - uint8_t queueid; - uint16_t portid; - struct lcore_conf *qconf; - const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US; - - prev_tsc = 0; - - lcore_id = rte_lcore_id(); - qconf = &lcore_conf[lcore_id]; - - if (qconf->n_rx_queue == 0) { - RTE_LOG(INFO, L3FWD, "lcore %u has nothing to do\n", lcore_id); - return 0; - } - - RTE_LOG(INFO, L3FWD, "entering main loop on lcore %u\n", lcore_id); - - for (i = 0; i < qconf->n_rx_queue; i++) { - - portid = qconf->rx_queue_list[i].port_id; - queueid = qconf->rx_queue_list[i].queue_id; - RTE_LOG(INFO, L3FWD, " --lcoreid=%u portid=%u rxqueueid=%hhu\n", - lcore_id, portid, queueid); - } - - while (1) { - - cur_tsc = rte_rdtsc(); - - /* - * TX burst queue drain - */ - diff_tsc = cur_tsc - prev_tsc; - if (unlikely(diff_tsc > drain_tsc)) { - - /* - * This could be optimized (use queueid instead of - * portid), but it is not called so often - */ - for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { - if (qconf->tx_mbufs[portid].len == 0) - continue; - send_burst(&lcore_conf[lcore_id], - qconf->tx_mbufs[portid].len, - portid); - qconf->tx_mbufs[portid].len = 0; - } - - prev_tsc = cur_tsc; - } - - /* - * Read packet from RX queues - */ - for (i = 0; i < qconf->n_rx_queue; ++i) { - - portid = qconf->rx_queue_list[i].port_id; - queueid = qconf->rx_queue_list[i].queue_id; - nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst, MAX_PKT_BURST); - - /* Prefetch first packets */ - for (j = 0; j < PREFETCH_OFFSET && j < nb_rx; j++) { - rte_prefetch0(rte_pktmbuf_mtod( - pkts_burst[j], void *)); - } - - /* Prefetch and forward already prefetched packets */ - for (j = 0; j < (nb_rx - PREFETCH_OFFSET); j++) { - rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[ - j + PREFETCH_OFFSET], void *)); - l3fwd_simple_forward(pkts_burst[j], portid, qconf->lookup_struct); - } - - /* Forward remaining prefetched packets */ - for (; j < nb_rx; j++) { - l3fwd_simple_forward(pkts_burst[j], portid, qconf->lookup_struct); - } - } - } -} - -static int -check_lcore_params(void) -{ - uint8_t queue, lcore; - uint16_t i; - int socketid; - - for (i = 0; i < nb_lcore_params; ++i) { - queue = lcore_params[i].queue_id; - if (queue >= MAX_RX_QUEUE_PER_PORT) { - printf("invalid queue number: %hhu\n", queue); - return -1; - } - lcore = lcore_params[i].lcore_id; - if (!rte_lcore_is_enabled(lcore)) { - printf("error: lcore %hhu is not enabled in lcore mask\n", lcore); - return -1; - } - if ((socketid = rte_lcore_to_socket_id(lcore) != 0) && - (numa_on == 0)) { - printf("warning: lcore %hhu is on socket %d with numa off \n", - lcore, socketid); - } - } - return 0; -} - -static int -check_port_config(void) -{ - unsigned portid; - uint16_t i; - - for (i = 0; i < nb_lcore_params; ++i) { - portid = lcore_params[i].port_id; - if ((enabled_port_mask & (1 << portid)) == 0) { - printf("port %u is not enabled in port mask\n", portid); - return -1; - } - if (!rte_eth_dev_is_valid_port(portid)) { - printf("port %u is not present on the board\n", portid); - return -1; - } - } - return 0; -} - -static uint8_t -get_port_n_rx_queues(const uint16_t port) -{ - int queue = -1; - uint16_t i; - - for (i = 0; i < nb_lcore_params; ++i) { - if (lcore_params[i].port_id == port && lcore_params[i].queue_id > queue) - queue = lcore_params[i].queue_id; - } - return (uint8_t)(++queue); -} - -static int -init_lcore_rx_queues(void) -{ - uint16_t i, nb_rx_queue; - uint8_t lcore; - - for (i = 0; i < nb_lcore_params; ++i) { - lcore = lcore_params[i].lcore_id; - nb_rx_queue = lcore_conf[lcore].n_rx_queue; - if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) { - printf("error: too many queues (%u) for lcore: %u\n", - (unsigned)nb_rx_queue + 1, (unsigned)lcore); - return -1; - } else { - lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id = - lcore_params[i].port_id; - lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id = - lcore_params[i].queue_id; - lcore_conf[lcore].n_rx_queue++; - } - } - return 0; -} - -/* display usage */ -static void -print_usage(const char *prgname) -{ - printf ("%s [EAL options] -- -p PORTMASK" - " [--config (port,queue,lcore)[,(port,queue,lcore]]\n" - " -p PORTMASK: hexadecimal bitmask of ports to configure\n" - " --config (port,queue,lcore): rx queues configuration\n" - " --no-numa: optional, disable numa awareness\n", - prgname); -} - -/* Custom handling of signals to handle process terminal */ -static void -signal_handler(int signum) -{ - uint16_t portid; - - /* When we receive a SIGINT signal */ - if (signum == SIGINT) { - RTE_ETH_FOREACH_DEV(portid) { - /* skip ports that are not enabled */ - if ((enabled_port_mask & (1 << portid)) == 0) - continue; - rte_eth_dev_close(portid); - } - } - rte_exit(EXIT_SUCCESS, "\n User forced exit\n"); -} -static int -parse_portmask(const char *portmask) -{ - char *end = NULL; - unsigned long pm; - - /* parse hexadecimal string */ - pm = strtoul(portmask, &end, 16); - if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) - return -1; - - if (pm == 0) - return -1; - - return pm; -} - -static int -parse_config(const char *q_arg) -{ - char s[256]; - const char *p, *p0 = q_arg; - char *end; - enum fieldnames { - FLD_PORT = 0, - FLD_QUEUE, - FLD_LCORE, - _NUM_FLD - }; - unsigned long int_fld[_NUM_FLD]; - char *str_fld[_NUM_FLD]; - int i; - unsigned size; - - nb_lcore_params = 0; - - while ((p = strchr(p0,'(')) != NULL) { - ++p; - if((p0 = strchr(p,')')) == NULL) - return -1; - - size = p0 - p; - if(size >= sizeof(s)) - return -1; - - snprintf(s, sizeof(s), "%.*s", size, p); - if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != _NUM_FLD) - return -1; - for (i = 0; i < _NUM_FLD; i++){ - errno = 0; - int_fld[i] = strtoul(str_fld[i], &end, 0); - if (errno != 0 || end == str_fld[i] || int_fld[i] > 255) - return -1; - } - if (nb_lcore_params >= MAX_LCORE_PARAMS) { - printf("exceeded max number of lcore params: %hu\n", - nb_lcore_params); - return -1; - } - lcore_params_array[nb_lcore_params].port_id = int_fld[FLD_PORT]; - lcore_params_array[nb_lcore_params].queue_id = (uint8_t)int_fld[FLD_QUEUE]; - lcore_params_array[nb_lcore_params].lcore_id = (uint8_t)int_fld[FLD_LCORE]; - ++nb_lcore_params; - } - lcore_params = lcore_params_array; - return 0; -} - -/* Parse the argument given in the command line of the application */ -static int -parse_args(int argc, char **argv) -{ - int opt, ret; - char **argvopt; - int option_index; - char *prgname = argv[0]; - static struct option lgopts[] = { - {"config", 1, 0, 0}, - {"no-numa", 0, 0, 0}, - {NULL, 0, 0, 0} - }; - - argvopt = argv; - - while ((opt = getopt_long(argc, argvopt, "p:", - lgopts, &option_index)) != EOF) { - - switch (opt) { - /* portmask */ - case 'p': - enabled_port_mask = parse_portmask(optarg); - if (enabled_port_mask == 0) { - printf("invalid portmask\n"); - print_usage(prgname); - return -1; - } - break; - - /* long options */ - case 0: - if (!strcmp(lgopts[option_index].name, "config")) { - ret = parse_config(optarg); - if (ret) { - printf("invalid config\n"); - print_usage(prgname); - return -1; - } - } - - if (!strcmp(lgopts[option_index].name, "no-numa")) { - printf("numa is disabled \n"); - numa_on = 0; - } - break; - - default: - print_usage(prgname); - return -1; - } - } - - if (optind >= 0) - argv[optind-1] = prgname; - - ret = optind-1; - optind = 1; /* reset getopt lib */ - return ret; -} - -static void -print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr) -{ - char buf[RTE_ETHER_ADDR_FMT_SIZE]; - rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr); - printf("%s%s", name, buf); -} - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH) -static void -setup_hash(int socketid) -{ - unsigned i; - int ret; - char s[64]; - - /* create hashes */ - snprintf(s, sizeof(s), "l3fwd_hash_%d", socketid); - l3fwd_hash_params.name = s; - l3fwd_hash_params.socket_id = socketid; - l3fwd_lookup_struct[socketid] = rte_hash_create(&l3fwd_hash_params); - if (l3fwd_lookup_struct[socketid] == NULL) - rte_exit(EXIT_FAILURE, "Unable to create the l3fwd hash on " - "socket %d\n", socketid); - - /* populate the hash */ - for (i = 0; i < L3FWD_NUM_ROUTES; i++) { - ret = rte_hash_add_key (l3fwd_lookup_struct[socketid], - (void *) &l3fwd_route_array[i].key); - if (ret < 0) { - rte_exit(EXIT_FAILURE, "Unable to add entry %u to the" - "l3fwd hash on socket %d\n", i, socketid); - } - l3fwd_out_if[ret] = l3fwd_route_array[i].if_out; - printf("Hash: Adding key\n"); - print_key(l3fwd_route_array[i].key); - } -} -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) -static void -setup_lpm(int socketid) -{ - unsigned i; - int ret; - char s[64]; - - struct rte_lpm_config lpm_ipv4_config; - - lpm_ipv4_config.max_rules = L3FWD_LPM_MAX_RULES; - lpm_ipv4_config.number_tbl8s = 256; - lpm_ipv4_config.flags = 0; - - /* create the LPM table */ - snprintf(s, sizeof(s), "L3FWD_LPM_%d", socketid); - l3fwd_lookup_struct[socketid] = - rte_lpm_create(s, socketid, &lpm_ipv4_config); - if (l3fwd_lookup_struct[socketid] == NULL) - rte_exit(EXIT_FAILURE, "Unable to create the l3fwd LPM table" - " on socket %d\n", socketid); - - /* populate the LPM table */ - for (i = 0; i < L3FWD_NUM_ROUTES; i++) { - ret = rte_lpm_add(l3fwd_lookup_struct[socketid], - l3fwd_route_array[i].ip, - l3fwd_route_array[i].depth, - l3fwd_route_array[i].if_out); - - if (ret < 0) { - rte_exit(EXIT_FAILURE, "Unable to add entry %u to the " - "l3fwd LPM table on socket %d\n", - i, socketid); - } - - printf("LPM: Adding route 0x%08x / %d (%d)\n", - (unsigned)l3fwd_route_array[i].ip, - l3fwd_route_array[i].depth, - l3fwd_route_array[i].if_out); - } -} -#endif - -static int -init_mem(unsigned nb_mbuf) -{ - struct lcore_conf *qconf; - int socketid; - unsigned lcore_id; - char s[64]; - - for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { - if (rte_lcore_is_enabled(lcore_id) == 0) - continue; - - if (numa_on) - socketid = rte_lcore_to_socket_id(lcore_id); - else - socketid = 0; - - if (socketid >= NB_SOCKETS) { - rte_exit(EXIT_FAILURE, "Socket %d of lcore %u is out of range %d\n", - socketid, lcore_id, NB_SOCKETS); - } - if (pktmbuf_pool[socketid] == NULL) { - snprintf(s, sizeof(s), "mbuf_pool_%d", socketid); - pktmbuf_pool[socketid] = rte_pktmbuf_pool_create(s, - nb_mbuf, MEMPOOL_CACHE_SIZE, 0, - RTE_MBUF_DEFAULT_BUF_SIZE, socketid); - if (pktmbuf_pool[socketid] == NULL) - rte_exit(EXIT_FAILURE, "Cannot init mbuf pool on socket %d\n", socketid); - else - printf("Allocated mbuf pool on socket %d\n", socketid); - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) - setup_lpm(socketid); -#else - setup_hash(socketid); -#endif - } - qconf = &lcore_conf[lcore_id]; - qconf->lookup_struct = l3fwd_lookup_struct[socketid]; - } - return 0; -} - -int -main(int argc, char **argv) -{ - struct lcore_conf *qconf; - struct rte_eth_dev_info dev_info; - struct rte_eth_txconf *txconf; - int ret; - unsigned nb_ports; - uint16_t queueid, portid; - unsigned lcore_id; - uint32_t nb_lcores; - uint16_t n_tx_queue; - uint8_t nb_rx_queue, queue, socketid; - - signal(SIGINT, signal_handler); - /* init EAL */ - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n"); - argc -= ret; - argv += ret; - - /* parse application arguments (after the EAL ones) */ - ret = parse_args(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid L3FWD-VF parameters\n"); - - if (check_lcore_params() < 0) - rte_exit(EXIT_FAILURE, "check_lcore_params failed\n"); - - ret = init_lcore_rx_queues(); - if (ret < 0) - rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n"); - - nb_ports = rte_eth_dev_count_avail(); - - if (check_port_config() < 0) - rte_exit(EXIT_FAILURE, "check_port_config failed\n"); - - nb_lcores = rte_lcore_count(); - - /* initialize all ports */ - RTE_ETH_FOREACH_DEV(portid) { - struct rte_eth_conf local_port_conf = port_conf; - - /* skip ports that are not enabled */ - if ((enabled_port_mask & (1 << portid)) == 0) { - printf("\nSkipping disabled port %d\n", portid); - continue; - } - - /* init port */ - printf("Initializing port %d ... ", portid ); - fflush(stdout); - - /* must always equal(=1) */ - nb_rx_queue = get_port_n_rx_queues(portid); - n_tx_queue = MAX_TX_QUEUE_PER_PORT; - - printf("Creating queues: nb_rxq=%d nb_txq=%u... ", - nb_rx_queue, (unsigned)1 ); - - rte_eth_dev_info_get(portid, &dev_info); - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - - local_port_conf.rx_adv_conf.rss_conf.rss_hf &= - dev_info.flow_type_rss_offloads; - if (local_port_conf.rx_adv_conf.rss_conf.rss_hf != - port_conf.rx_adv_conf.rss_conf.rss_hf) { - printf("Port %u modified RSS hash function based on hardware support," - "requested:%#"PRIx64" configured:%#"PRIx64"\n", - portid, - port_conf.rx_adv_conf.rss_conf.rss_hf, - local_port_conf.rx_adv_conf.rss_conf.rss_hf); - } - - ret = rte_eth_dev_configure(portid, nb_rx_queue, - n_tx_queue, &local_port_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%d\n", - ret, portid); - - ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, - &nb_txd); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Cannot adjust number of descriptors: err=%d, port=%d\n", - ret, portid); - - rte_eth_macaddr_get(portid, &ports_eth_addr[portid]); - print_ethaddr(" Address:", &ports_eth_addr[portid]); - printf(", "); - - ret = init_mem(NB_MBUF); - if (ret < 0) - rte_exit(EXIT_FAILURE, "init_mem failed\n"); - - /* init one TX queue */ - socketid = (uint8_t)rte_lcore_to_socket_id(rte_get_master_lcore()); - - printf("txq=%d,%d,%d ", portid, 0, socketid); - fflush(stdout); - - txconf = &dev_info.default_txconf; - txconf->offloads = local_port_conf.txmode.offloads; - ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, - socketid, txconf); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: err=%d, " - "port=%d\n", ret, portid); - - printf("\n"); - } - - for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { - struct rte_eth_rxconf rxq_conf; - - if (rte_lcore_is_enabled(lcore_id) == 0) - continue; - qconf = &lcore_conf[lcore_id]; - qconf->tx_queue_id = 0; - - printf("\nInitializing rx queues on lcore %u ... ", lcore_id ); - fflush(stdout); - /* init RX queues */ - for(queue = 0; queue < qconf->n_rx_queue; ++queue) { - portid = qconf->rx_queue_list[queue].port_id; - queueid = qconf->rx_queue_list[queue].queue_id; - - if (numa_on) - socketid = (uint8_t)rte_lcore_to_socket_id(lcore_id); - else - socketid = 0; - - printf("rxq=%d,%d,%d ", portid, queueid, socketid); - fflush(stdout); - - rte_eth_dev_info_get(portid, &dev_info); - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = port_conf.rxmode.offloads; - ret = rte_eth_rx_queue_setup(portid, queueid, nb_rxd, - socketid, &rxq_conf, - pktmbuf_pool[socketid]); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: err=%d," - "port=%d\n", ret, portid); - } - } - printf("\n"); - - /* start ports */ - RTE_ETH_FOREACH_DEV(portid) { - if ((enabled_port_mask & (1 << portid)) == 0) { - continue; - } - /* Start device */ - ret = rte_eth_dev_start(portid); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, port=%d\n", - ret, portid); - - printf("done: Port %d\n", portid); - - } - - /* launch per-lcore init on every lcore */ - rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER); - RTE_LCORE_FOREACH_SLAVE(lcore_id) { - if (rte_eal_wait_lcore(lcore_id) < 0) - return -1; - } - - return 0; -} diff --git a/examples/l3fwd-vf/meson.build b/examples/l3fwd-vf/meson.build deleted file mode 100644 index 226286e74..000000000 --- a/examples/l3fwd-vf/meson.build +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2017 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' - -deps += ['lpm', 'hash'] -sources = files( - 'main.c' -) diff --git a/examples/meson.build b/examples/meson.build index 4663d9dea..81ac8199a 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -23,7 +23,7 @@ all_examples = [ 'l2fwd-crypto', 'l2fwd-jobstats', 'l2fwd-keepalive', 'l3fwd', 'l3fwd-acl', 'l3fwd-power', - 'l3fwd-vf', 'link_status_interrupt', + 'link_status_interrupt', 'load_balancer', 'multi_process/client_server_mp/mp_client', 'multi_process/client_server_mp/mp_server', -- 2.21.0 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH 3/6] examples/quota-watermark: remove example from DPDK 2019-10-03 13:19 [dpdk-dev] [PATCH 0/6] remove a few example applications Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 1/6] examples/exception_path: remove example from DPDK Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 2/6] examples/l3fwd-vf: " Bruce Richardson @ 2019-10-03 13:19 ` Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 4/6] examples/netmap-compat: " Bruce Richardson ` (5 subsequent siblings) 8 siblings, 0 replies; 27+ messages in thread From: Bruce Richardson @ 2019-10-03 13:19 UTC (permalink / raw) To: dev; +Cc: techboard, Ciara Power From: Ciara Power <ciara.power@intel.com> Original DPDK rings code had explicit support for a single watermark per-ring, but more recent releases of DPDK had a more general mechanism where each enqueue or dequeue call could return the remaining elements/free-slots in the ring. Therefore, this example is not as relevant as before and can be removed. Signed-off-by: Ciara Power <ciara.power@intel.com> --- MAINTAINERS | 3 - doc/guides/sample_app_ug/index.rst | 1 - doc/guides/sample_app_ug/intro.rst | 2 +- doc/guides/sample_app_ug/quota_watermark.rst | 465 ------------------- examples/Makefile | 1 - examples/meson.build | 2 +- examples/quota_watermark/Makefile | 16 - examples/quota_watermark/include/conf.h | 19 - examples/quota_watermark/meson.build | 10 - examples/quota_watermark/qw/Makefile | 22 - examples/quota_watermark/qw/args.c | 78 ---- examples/quota_watermark/qw/args.h | 12 - examples/quota_watermark/qw/init.c | 164 ------- examples/quota_watermark/qw/init.h | 14 - examples/quota_watermark/qw/main.c | 365 --------------- examples/quota_watermark/qw/main.h | 31 -- examples/quota_watermark/qwctl/Makefile | 22 - examples/quota_watermark/qwctl/commands.c | 196 -------- examples/quota_watermark/qwctl/commands.h | 12 - examples/quota_watermark/qwctl/qwctl.c | 67 --- examples/quota_watermark/qwctl/qwctl.h | 12 - 21 files changed, 2 insertions(+), 1512 deletions(-) delete mode 100644 doc/guides/sample_app_ug/quota_watermark.rst delete mode 100644 examples/quota_watermark/Makefile delete mode 100644 examples/quota_watermark/include/conf.h delete mode 100644 examples/quota_watermark/meson.build delete mode 100644 examples/quota_watermark/qw/Makefile delete mode 100644 examples/quota_watermark/qw/args.c delete mode 100644 examples/quota_watermark/qw/args.h delete mode 100644 examples/quota_watermark/qw/init.c delete mode 100644 examples/quota_watermark/qw/init.h delete mode 100644 examples/quota_watermark/qw/main.c delete mode 100644 examples/quota_watermark/qw/main.h delete mode 100644 examples/quota_watermark/qwctl/Makefile delete mode 100644 examples/quota_watermark/qwctl/commands.c delete mode 100644 examples/quota_watermark/qwctl/commands.h delete mode 100644 examples/quota_watermark/qwctl/qwctl.c delete mode 100644 examples/quota_watermark/qwctl/qwctl.h diff --git a/MAINTAINERS b/MAINTAINERS index 92c3f6af4..7be363327 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1474,9 +1474,6 @@ F: doc/guides/sample_app_ug/performance_thread.rst F: examples/ptpclient/ -F: examples/quota_watermark/ -F: doc/guides/sample_app_ug/quota_watermark.rst - M: Bruce Richardson <bruce.richardson@intel.com> M: John McNamara <john.mcnamara@intel.com> F: examples/rxtx_callbacks/ diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst index d212f81fe..dafe8553f 100644 --- a/doc/guides/sample_app_ug/index.rst +++ b/doc/guides/sample_app_ug/index.rst @@ -36,7 +36,6 @@ Sample Applications User Guides multi_process qos_metering qos_scheduler - quota_watermark timer packet_ordering vmdq_dcb_forwarding diff --git a/doc/guides/sample_app_ug/intro.rst b/doc/guides/sample_app_ug/intro.rst index 7299253bf..6e0af6301 100644 --- a/doc/guides/sample_app_ug/intro.rst +++ b/doc/guides/sample_app_ug/intro.rst @@ -43,7 +43,7 @@ applications that are available in the examples directory of DPDK: +---------------------------------------+--------------------------------------+ | Hello World | QoS Scheduler | +---------------------------------------+--------------------------------------+ - | Internet Protocol (IP) Fragmentation | Quota and Watermark | + | Internet Protocol (IP) Fragmentation | | +---------------------------------------+--------------------------------------+ | IP Pipeline | RX/TX Callbacks | +---------------------------------------+--------------------------------------+ diff --git a/doc/guides/sample_app_ug/quota_watermark.rst b/doc/guides/sample_app_ug/quota_watermark.rst deleted file mode 100644 index 125e6fb73..000000000 --- a/doc/guides/sample_app_ug/quota_watermark.rst +++ /dev/null @@ -1,465 +0,0 @@ -.. SPDX-License-Identifier: BSD-3-Clause - Copyright(c) 2010-2017 Intel Corporation. - -Quota and Watermark Sample Application -====================================== - -The Quota and Watermark sample application is a simple example of packet -processing using Data Plane Development Kit (DPDK) that showcases the use -of a quota as the maximum number of packets enqueue/dequeue at a time and -low and high thresholds, or watermarks, to signal low and high ring usage -respectively. - -Additionally, it shows how the thresholds can be used to feedback congestion notifications to data producers by -temporarily stopping processing overloaded rings and sending Ethernet flow control frames. - -This sample application is split in two parts: - -* qw - The core quota and watermark sample application - -* qwctl - A command line tool to alter quota and watermarks while qw is running - -Overview --------- - -The Quota and Watermark sample application performs forwarding for each packet that is received on a given port. -The destination port is the adjacent port from the enabled port mask, that is, -if the first four ports are enabled (port mask 0xf), ports 0 and 1 forward into each other, -and ports 2 and 3 forward into each other. -The MAC addresses of the forwarded Ethernet frames are not affected. - -Internally, packets are pulled from the ports by the master logical core and put on a variable length processing pipeline, -each stage of which being connected by rings, as shown in :numref:`figure_pipeline_overview`. - -.. _figure_pipeline_overview: - -.. figure:: img/pipeline_overview.* - - Pipeline Overview - - -An adjustable quota value controls how many packets are being moved through the pipeline per enqueue and dequeue. -Adjustable threshold values associated with the rings control a back-off mechanism that -tries to prevent the pipeline from being overloaded by: - -* Stopping enqueuing on rings for which the usage has crossed the high watermark threshold - -* Sending Ethernet pause frames - -* Only resuming enqueuing on a ring once its usage goes below a global low watermark threshold - -This mechanism allows congestion notifications to go up the ring pipeline and -eventually lead to an Ethernet flow control frame being send to the source. - -On top of serving as an example of quota and watermark usage, -this application can be used to benchmark ring based processing pipelines performance using a traffic- generator, -as shown in :numref:`figure_ring_pipeline_perf_setup`. - -.. _figure_ring_pipeline_perf_setup: - -.. figure:: img/ring_pipeline_perf_setup.* - - Ring-based Processing Pipeline Performance Setup - -Compiling the Application -------------------------- - -To compile the sample application see :doc:`compiling`. - -The application is located in the ``quota_watermark`` sub-directory. - -Running the Application ------------------------ - -The core application, qw, has to be started first. - -Once it is up and running, one can alter quota and watermarks while it runs using the control application, qwctl. - -Running the Core Application -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The application requires a single command line option: - -.. code-block:: console - - ./qw/build/qw [EAL options] -- -p PORTMASK - -where, - --p PORTMASK: A hexadecimal bitmask of the ports to configure - -To run the application in a linux environment with four logical cores and ports 0 and 2, -issue the following command: - -.. code-block:: console - - ./qw/build/qw -l 0-3 -n 4 -- -p 5 - -Refer to the *DPDK Getting Started Guide* for general information on running applications and -the Environment Abstraction Layer (EAL) options. - -Running the Control Application -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The control application requires a number of command line options: - -.. code-block:: console - - ./qwctl/build/qwctl [EAL options] --proc-type=secondary - -The --proc-type=secondary option is necessary for the EAL to properly initialize the control application to -use the same huge pages as the core application and thus be able to access its rings. - -To run the application in a linux environment on logical core 0, issue the following command: - -.. code-block:: console - - ./qwctl/build/qwctl -l 0 -n 4 --proc-type=secondary - -Refer to the *DPDK Getting Started* Guide for general information on running applications and -the Environment Abstraction Layer (EAL) options. - -qwctl is an interactive command line that let the user change variables in a running instance of qw. -The help command gives a list of available commands: - -.. code-block:: console - - $ qwctl > help - -Code Overview -------------- - -The following sections provide a quick guide to the application's source code. - -Core Application - qw -~~~~~~~~~~~~~~~~~~~~~ - -EAL and Drivers Setup -^^^^^^^^^^^^^^^^^^^^^ - -The EAL arguments are parsed at the beginning of the main() function: - -.. code-block:: c - - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot initialize EAL\n"); - - argc -= ret; - argv += ret; - -Then, a call to init_dpdk(), defined in init.c, is made to initialize the poll mode drivers: - -.. code-block:: c - - void - init_dpdk(void) - { - int ret; - - /* Bind the drivers to usable devices */ - - ret = rte_pci_probe(); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_pci_probe(): error %d\n", ret); - - if (rte_eth_dev_count_avail() < 2) - rte_exit(EXIT_FAILURE, "Not enough Ethernet port available\n"); - } - -To fully understand this code, it is recommended to study the chapters that relate to the *Poll Mode Driver* -in the *DPDK Getting Started Guide* and the *DPDK API Reference*. - -Shared Variables Setup -^^^^^^^^^^^^^^^^^^^^^^ - -The quota and high and low watermark shared variables are put into an rte_memzone using a call to setup_shared_variables(): - -.. code-block:: c - - void - setup_shared_variables(void) - { - const struct rte_memzone *qw_memzone; - - qw_memzone = rte_memzone_reserve(QUOTA_WATERMARK_MEMZONE_NAME, - 3 * sizeof(int), rte_socket_id(), 0); - if (qw_memzone == NULL) - rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno)); - - quota = qw_memzone->addr; - low_watermark = (unsigned int *) qw_memzone->addr + 1; - high_watermark = (unsigned int *) qw_memzone->addr + 2; - } - -These three variables are initialized to a default value in main() and -can be changed while qw is running using the qwctl control program. - -Application Arguments -^^^^^^^^^^^^^^^^^^^^^ - -The qw application only takes one argument: a port mask that specifies which ports should be used by the application. -At least two ports are needed to run the application and there should be an even number of ports given in the port mask. - -The port mask parsing is done in parse_qw_args(), defined in args.c. - -Mbuf Pool Initialization -^^^^^^^^^^^^^^^^^^^^^^^^ - -Once the application's arguments are parsed, an mbuf pool is created. -It contains a set of mbuf objects that are used by the driver and the application to store network packets: - -.. code-block:: c - - /* Create a pool of mbuf to store packets */ - mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", MBUF_PER_POOL, 32, 0, - MBUF_DATA_SIZE, rte_socket_id()); - - if (mbuf_pool == NULL) - rte_panic("%s\n", rte_strerror(rte_errno)); - -The rte_mempool is a generic structure used to handle pools of objects. -In this case, it is necessary to create a pool that will be used by the driver. - -The number of allocated pkt mbufs is MBUF_PER_POOL, with a data room size -of MBUF_DATA_SIZE each. -A per-lcore cache of 32 mbufs is kept. -The memory is allocated in on the master lcore's socket, but it is possible to extend this code to allocate one mbuf pool per socket. - -The rte_pktmbuf_pool_create() function uses the default mbuf pool and mbuf -initializers, respectively rte_pktmbuf_pool_init() and rte_pktmbuf_init(). -An advanced application may want to use the mempool API to create the -mbuf pool with more control. - -Ports Configuration and Pairing -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Each port in the port mask is configured and a corresponding ring is created in the master lcore's array of rings. -This ring is the first in the pipeline and will hold the packets directly coming from the port. - -.. code-block:: c - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) - if (is_bit_set(port_id, portmask)) { - configure_eth_port(port_id); - init_ring(master_lcore_id, port_id); - } - - pair_ports(); - -The configure_eth_port() and init_ring() functions are used to configure a port and a ring respectively and are defined in init.c. -They make use of the DPDK APIs defined in rte_eth.h and rte_ring.h. - -pair_ports() builds the port_pairs[] array so that its key-value pairs are a mapping between reception and transmission ports. -It is defined in init.c. - -Logical Cores Assignment -^^^^^^^^^^^^^^^^^^^^^^^^ - -The application uses the master logical core to poll all the ports for new packets and enqueue them on a ring associated with the port. - -Each logical core except the last runs pipeline_stage() after a ring for each used port is initialized on that core. -pipeline_stage() on core X dequeues packets from core X-1's rings and enqueue them on its own rings. See :numref:`figure_threads_pipelines`. - -.. code-block:: c - - /* Start pipeline_stage() on all the available slave lcore but the last */ - - for (lcore_id = 0 ; lcore_id < last_lcore_id; lcore_id++) { - if (rte_lcore_is_enabled(lcore_id) && lcore_id != master_lcore_id) { - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) - if (is_bit_set(port_id, portmask)) - init_ring(lcore_id, port_id); - - rte_eal_remote_launch(pipeline_stage, NULL, lcore_id); - } - } - -The last available logical core runs send_stage(), -which is the last stage of the pipeline dequeuing packets from the last ring in the pipeline and -sending them out on the destination port setup by pair_ports(). - -.. code-block:: c - - /* Start send_stage() on the last slave core */ - - rte_eal_remote_launch(send_stage, NULL, last_lcore_id); - -Receive, Process and Transmit Packets -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. _figure_threads_pipelines: - -.. figure:: img/threads_pipelines.* - - Threads and Pipelines - - -In the receive_stage() function running on the master logical core, -the main task is to read ingress packets from the RX ports and enqueue them -on the port's corresponding first ring in the pipeline. -This is done using the following code: - -.. code-block:: c - - lcore_id = rte_lcore_id(); - - /* Process each port round robin style */ - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - if (!is_bit_set(port_id, portmask)) - continue; - - ring = rings[lcore_id][port_id]; - - if (ring_state[port_id] != RING_READY) { - if (rte_ring_count(ring) > *low_watermark) - continue; - else - ring_state[port_id] = RING_READY; - } - - /* Enqueue received packets on the RX ring */ - nb_rx_pkts = rte_eth_rx_burst(port_id, 0, pkts, - (uint16_t) *quota); - ret = rte_ring_enqueue_bulk(ring, (void *) pkts, - nb_rx_pkts, &free); - if (RING_SIZE - free > *high_watermark) { - ring_state[port_id] = RING_OVERLOADED; - send_pause_frame(port_id, 1337); - } - - if (ret == 0) { - - /* - * Return mbufs to the pool, - * effectively dropping packets - */ - for (i = 0; i < nb_rx_pkts; i++) - rte_pktmbuf_free(pkts[i]); - } - } - -For each port in the port mask, the corresponding ring's pointer is fetched into ring and that ring's state is checked: - -* If it is in the RING_READY state, \*quota packets are grabbed from the port and put on the ring. - Should this operation make the ring's usage cross its high watermark, - the ring is marked as overloaded and an Ethernet flow control frame is sent to the source. - -* If it is not in the RING_READY state, this port is ignored until the ring's usage crosses the \*low_watermark value. - -The pipeline_stage() function's task is to process and move packets from the preceding pipeline stage. -This thread is running on most of the logical cores to create and arbitrarily long pipeline. - -.. code-block:: c - - lcore_id = rte_lcore_id(); - - previous_lcore_id = get_previous_lcore_id(lcore_id); - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - if (!is_bit_set(port_id, portmask)) - continue; - - tx = rings[lcore_id][port_id]; - rx = rings[previous_lcore_id][port_id]; - - if (ring_state[port_id] != RING_READY) { - if (rte_ring_count(tx) > *low_watermark) - continue; - else - ring_state[port_id] = RING_READY; - } - - /* Dequeue up to quota mbuf from rx */ - nb_dq_pkts = rte_ring_dequeue_burst(rx, pkts, - *quota, NULL); - if (unlikely(nb_dq_pkts < 0)) - continue; - - /* Enqueue them on tx */ - ret = rte_ring_enqueue_bulk(tx, pkts, - nb_dq_pkts, &free); - if (RING_SIZE - free > *high_watermark) - ring_state[port_id] = RING_OVERLOADED; - - if (ret == 0) { - - /* - * Return mbufs to the pool, - * effectively dropping packets - */ - for (i = 0; i < nb_dq_pkts; i++) - rte_pktmbuf_free(pkts[i]); - } - } - -The thread's logic works mostly like receive_stage(), -except that packets are moved from ring to ring instead of port to ring. - -In this example, no actual processing is done on the packets, -but pipeline_stage() is an ideal place to perform any processing required by the application. - -Finally, the send_stage() function's task is to read packets from the last ring in a pipeline and -send them on the destination port defined in the port_pairs[] array. -It is running on the last available logical core only. - -.. code-block:: c - - lcore_id = rte_lcore_id(); - - previous_lcore_id = get_previous_lcore_id(lcore_id); - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - if (!is_bit_set(port_id, portmask)) continue; - - dest_port_id = port_pairs[port_id]; - tx = rings[previous_lcore_id][port_id]; - - if (rte_ring_empty(tx)) continue; - - /* Dequeue packets from tx and send them */ - - nb_dq_pkts = rte_ring_dequeue_burst(tx, (void *) tx_pkts, *quota); - nb_tx_pkts = rte_eth_tx_burst(dest_port_id, 0, tx_pkts, nb_dq_pkts); - } - -For each port in the port mask, up to \*quota packets are pulled from the last ring in its pipeline and -sent on the destination port paired with the current port. - -Control Application - qwctl -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The qwctl application uses the rte_cmdline library to provide the user with an interactive command line that -can be used to modify and inspect parameters in a running qw application. -Those parameters are the global quota and low_watermark value as well as each ring's built-in high watermark. - -Command Definitions -^^^^^^^^^^^^^^^^^^^ - -The available commands are defined in commands.c. - -It is advised to use the cmdline sample application user guide as a reference for everything related to the rte_cmdline library. - -Accessing Shared Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The setup_shared_variables() function retrieves the shared variables quota and -low_watermark from the rte_memzone previously created by qw. - -.. code-block:: c - - static void - setup_shared_variables(void) - { - const struct rte_memzone *qw_memzone; - - qw_memzone = rte_memzone_lookup(QUOTA_WATERMARK_MEMZONE_NAME); - if (qw_memzone == NULL) - rte_exit(EXIT_FAILURE, "Couldn't find memzone\n"); - - quota = qw_memzone->addr; - - low_watermark = (unsigned int *) qw_memzone->addr + 1; - high_watermark = (unsigned int *) qw_memzone->addr + 2; - } diff --git a/examples/Makefile b/examples/Makefile index 5dd8a72e5..02ff86534 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -59,7 +59,6 @@ endif DIRS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ptpclient DIRS-$(CONFIG_RTE_LIBRTE_METER) += qos_meter DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += qos_sched -DIRS-y += quota_watermark DIRS-$(CONFIG_RTE_ETHDEV_RXTX_CALLBACKS) += rxtx_callbacks DIRS-y += service_cores DIRS-y += skeleton diff --git a/examples/meson.build b/examples/meson.build index 81ac8199a..6c26fffb4 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -33,7 +33,7 @@ all_examples = [ 'netmap_compat', 'ntb', 'packet_ordering', 'performance-thread', 'ptpclient', 'qos_meter', 'qos_sched', - 'quota_watermark', 'rxtx_callbacks', + 'rxtx_callbacks', 'server_node_efd', 'service_cores', 'skeleton', 'tep_termination', 'timer', 'vdpa', diff --git a/examples/quota_watermark/Makefile b/examples/quota_watermark/Makefile deleted file mode 100644 index 8ef053198..000000000 --- a/examples/quota_watermark/Makefile +++ /dev/null @@ -1,16 +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 - -DIRS-$(CONFIG_RTE_EXEC_ENV_LINUX) += qw -DIRS-$(CONFIG_RTE_EXEC_ENV_LINUX) += qwctl - -include $(RTE_SDK)/mk/rte.extsubdir.mk diff --git a/examples/quota_watermark/include/conf.h b/examples/quota_watermark/include/conf.h deleted file mode 100644 index 4f29aa64b..000000000 --- a/examples/quota_watermark/include/conf.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _CONF_H_ -#define _CONF_H_ - -#define RING_SIZE 1024 -#define MAX_PKT_QUOTA 64 - -#define RX_DESC_PER_QUEUE 1024 -#define TX_DESC_PER_QUEUE 1024 - -#define MBUF_DATA_SIZE RTE_MBUF_DEFAULT_BUF_SIZE -#define MBUF_PER_POOL 8192 - -#define QUOTA_WATERMARK_MEMZONE_NAME "qw_global_vars" - -#endif /* _CONF_H_ */ diff --git a/examples/quota_watermark/meson.build b/examples/quota_watermark/meson.build deleted file mode 100644 index c370d7476..000000000 --- a/examples/quota_watermark/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/quota_watermark/qw/Makefile b/examples/quota_watermark/qw/Makefile deleted file mode 100644 index 3f10f01c3..000000000 --- a/examples/quota_watermark/qw/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 - -# binary name -APP = qw - -# all source are stored in SRCS-y -SRCS-y := args.c init.c main.c - -CFLAGS += -O3 -DQW_SOFTWARE_FC -CFLAGS += $(WERROR_FLAGS) - -include $(RTE_SDK)/mk/rte.extapp.mk diff --git a/examples/quota_watermark/qw/args.c b/examples/quota_watermark/qw/args.c deleted file mode 100644 index a750ec258..000000000 --- a/examples/quota_watermark/qw/args.c +++ /dev/null @@ -1,78 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include <rte_common.h> -#include <rte_lcore.h> - -#include "args.h" - - -unsigned int portmask = 0; - - -static void -usage(const char *prgname) -{ - fprintf(stderr, "Usage: %s [EAL args] -- -p <portmask>\n" - "-p PORTMASK: hexadecimal bitmask of NIC ports to configure\n", - prgname); -} - -static unsigned long -parse_portmask(const char *portmask_str) -{ - return strtoul(portmask_str, NULL, 16); -} - -static void -check_core_count(void) -{ - if (rte_lcore_count() < 3) - rte_exit(EXIT_FAILURE, - "At least 3 cores need to be passed in the coremask\n"); -} - -static void -check_portmask_value(unsigned int portmask) -{ - unsigned int port_nb = 0; - - port_nb = __builtin_popcount(portmask); - - if (port_nb == 0) - rte_exit(EXIT_FAILURE, - "At least 2 ports need to be passed in the portmask\n"); - - if (port_nb % 2 != 0) - rte_exit(EXIT_FAILURE, - "An even number of ports is required in the portmask\n"); -} - -int -parse_qw_args(int argc, char **argv) -{ - int opt; - - while ((opt = getopt(argc, argv, "h:p:")) != -1) { - switch (opt) { - case 'h': - usage(argv[0]); - break; - case 'p': - portmask = parse_portmask(optarg); - break; - default: - usage(argv[0]); - } - } - - check_core_count(); - check_portmask_value(portmask); - - return 0; -} diff --git a/examples/quota_watermark/qw/args.h b/examples/quota_watermark/qw/args.h deleted file mode 100644 index ab777db01..000000000 --- a/examples/quota_watermark/qw/args.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _ARGS_H_ -#define _ARGS_H_ - -extern unsigned int portmask; - -int parse_qw_args(int argc, char **argv); - -#endif /* _ARGS_H_ */ diff --git a/examples/quota_watermark/qw/init.c b/examples/quota_watermark/qw/init.c deleted file mode 100644 index 5a0f64f45..000000000 --- a/examples/quota_watermark/qw/init.c +++ /dev/null @@ -1,164 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <fcntl.h> -#include <unistd.h> -#include <sys/mman.h> - -#include <rte_eal.h> - -#include <rte_common.h> -#include <rte_errno.h> -#include <rte_ethdev.h> -#include <rte_memzone.h> -#include <rte_ring.h> -#include <rte_string_fns.h> - -#include "args.h" -#include "init.h" -#include "main.h" -#include "../include/conf.h" - - -static struct rte_eth_conf port_conf = { - .rxmode = { - .split_hdr_size = 0, - }, - .txmode = { - .mq_mode = ETH_DCB_NONE, - }, -}; - -static struct rte_eth_fc_conf fc_conf = { - .mode = RTE_FC_TX_PAUSE, - .high_water = 80 * 510 / 100, - .low_water = 60 * 510 / 100, - .pause_time = 1337, - .send_xon = 0, -}; - - -void configure_eth_port(uint16_t port_id) -{ - int ret; - uint16_t nb_rxd = RX_DESC_PER_QUEUE; - uint16_t nb_txd = TX_DESC_PER_QUEUE; - struct rte_eth_rxconf rxq_conf; - struct rte_eth_txconf txq_conf; - struct rte_eth_dev_info dev_info; - struct rte_eth_conf local_port_conf = port_conf; - - rte_eth_dev_stop(port_id); - - rte_eth_dev_info_get(port_id, &dev_info); - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - ret = rte_eth_dev_configure(port_id, 1, 1, &local_port_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot configure port %u (error %d)\n", - (unsigned int) port_id, ret); - - ret = rte_eth_dev_adjust_nb_rx_tx_desc(port_id, &nb_rxd, &nb_txd); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Cannot adjust number of descriptors for port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Initialize the port's RX queue */ - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = local_port_conf.rxmode.offloads; - ret = rte_eth_rx_queue_setup(port_id, 0, nb_rxd, - rte_eth_dev_socket_id(port_id), - &rxq_conf, - mbuf_pool); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Failed to setup RX queue on port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Initialize the port's TX queue */ - txq_conf = dev_info.default_txconf; - txq_conf.offloads = local_port_conf.txmode.offloads; - ret = rte_eth_tx_queue_setup(port_id, 0, nb_txd, - rte_eth_dev_socket_id(port_id), - &txq_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Failed to setup TX queue on port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Initialize the port's flow control */ - ret = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Failed to setup hardware flow control on port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Start the port */ - ret = rte_eth_dev_start(port_id); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Failed to start port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Put it in promiscuous mode */ - rte_eth_promiscuous_enable(port_id); -} - -void -init_dpdk(void) -{ - if (rte_eth_dev_count_avail() < 2) - rte_exit(EXIT_FAILURE, "Not enough ethernet port available\n"); -} - -void init_ring(int lcore_id, uint16_t port_id) -{ - struct rte_ring *ring; - char ring_name[RTE_RING_NAMESIZE]; - - snprintf(ring_name, RTE_RING_NAMESIZE, - "core%d_port%d", lcore_id, port_id); - ring = rte_ring_create(ring_name, RING_SIZE, rte_socket_id(), - RING_F_SP_ENQ | RING_F_SC_DEQ); - - if (ring == NULL) - rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno)); - - *high_watermark = 80 * RING_SIZE / 100; - - rings[lcore_id][port_id] = ring; -} - -void -pair_ports(void) -{ - uint16_t i, j; - - /* Pair ports with their "closest neighbour" in the portmask */ - for (i = 0; i < RTE_MAX_ETHPORTS; i++) - if (is_bit_set(i, portmask)) - for (j = i + 1; j < RTE_MAX_ETHPORTS; j++) - if (is_bit_set(j, portmask)) { - port_pairs[i] = j; - port_pairs[j] = i; - i = j; - break; - } -} - -void -setup_shared_variables(void) -{ - const struct rte_memzone *qw_memzone; - - qw_memzone = rte_memzone_reserve(QUOTA_WATERMARK_MEMZONE_NAME, - 3 * sizeof(int), rte_socket_id(), 0); - if (qw_memzone == NULL) - rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno)); - - quota = qw_memzone->addr; - low_watermark = (unsigned int *) qw_memzone->addr + 1; - high_watermark = (unsigned int *) qw_memzone->addr + 2; -} diff --git a/examples/quota_watermark/qw/init.h b/examples/quota_watermark/qw/init.h deleted file mode 100644 index e0c90df72..000000000 --- a/examples/quota_watermark/qw/init.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _INIT_H_ -#define _INIT_H_ - -void configure_eth_port(uint16_t port_id); -void init_dpdk(void); -void init_ring(int lcore_id, uint16_t port_id); -void pair_ports(void); -void setup_shared_variables(void); - -#endif /* _INIT_H_ */ diff --git a/examples/quota_watermark/qw/main.c b/examples/quota_watermark/qw/main.c deleted file mode 100644 index a61360b99..000000000 --- a/examples/quota_watermark/qw/main.c +++ /dev/null @@ -1,365 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <rte_eal.h> - -#include <rte_common.h> -#include <rte_debug.h> -#include <rte_errno.h> -#include <rte_ethdev.h> -#include <rte_launch.h> -#include <rte_lcore.h> -#include <rte_log.h> -#include <rte_mbuf.h> -#include <rte_ring.h> - -#include <rte_byteorder.h> - -#include "args.h" -#include "main.h" -#include "init.h" -#include "../include/conf.h" - - -#ifdef QW_SOFTWARE_FC -#define SEND_PAUSE_FRAME(port_id, duration) send_pause_frame(port_id, duration) -#else -#define SEND_PAUSE_FRAME(port_id, duration) do { } while(0) -#endif - -#define ETHER_TYPE_FLOW_CONTROL 0x8808 - -struct ether_fc_frame { - uint16_t opcode; - uint16_t param; -} __attribute__((__packed__)); - - -int *quota; -unsigned int *low_watermark; -unsigned int *high_watermark; - -uint16_t port_pairs[RTE_MAX_ETHPORTS]; - -struct rte_ring *rings[RTE_MAX_LCORE][RTE_MAX_ETHPORTS]; -struct rte_mempool *mbuf_pool; - - -static void send_pause_frame(uint16_t port_id, uint16_t duration) -{ - struct rte_mbuf *mbuf; - struct ether_fc_frame *pause_frame; - struct rte_ether_hdr *hdr; - struct rte_ether_addr mac_addr; - - RTE_LOG_DP(DEBUG, USER1, - "Sending PAUSE frame (duration=%d) on port %d\n", - duration, port_id); - - /* Get a mbuf from the pool */ - mbuf = rte_pktmbuf_alloc(mbuf_pool); - if (unlikely(mbuf == NULL)) - return; - - /* Prepare a PAUSE frame */ - hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr *); - pause_frame = (struct ether_fc_frame *) &hdr[1]; - - rte_eth_macaddr_get(port_id, &mac_addr); - rte_ether_addr_copy(&mac_addr, &hdr->s_addr); - - void *tmp = &hdr->d_addr.addr_bytes[0]; - *((uint64_t *)tmp) = 0x010000C28001ULL; - - hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_FLOW_CONTROL); - - pause_frame->opcode = rte_cpu_to_be_16(0x0001); - pause_frame->param = rte_cpu_to_be_16(duration); - - mbuf->pkt_len = 60; - mbuf->data_len = 60; - - rte_eth_tx_burst(port_id, 0, &mbuf, 1); -} - -/** - * Get the previous enabled lcore ID - * - * @param lcore_id - * The current lcore ID. - * @return - * The previous enabled lcore_id or -1 if not found. - */ -static unsigned int -get_previous_lcore_id(unsigned int lcore_id) -{ - int i; - - for (i = lcore_id - 1; i >= 0; i--) - if (rte_lcore_is_enabled(i)) - return i; - - return -1; -} - -/** - * Get the last enabled lcore ID - * - * @return - * The last enabled lcore_id. - */ -static unsigned int -get_last_lcore_id(void) -{ - int i; - - for (i = RTE_MAX_LCORE; i >= 0; i--) - if (rte_lcore_is_enabled(i)) - return i; - - return 0; -} - -static void -receive_stage(__attribute__((unused)) void *args) -{ - int i, ret; - - uint16_t port_id; - uint16_t nb_rx_pkts; - - unsigned int lcore_id; - unsigned int free; - - struct rte_mbuf *pkts[MAX_PKT_QUOTA]; - struct rte_ring *ring; - enum ring_state ring_state[RTE_MAX_ETHPORTS] = { RING_READY }; - - lcore_id = rte_lcore_id(); - - RTE_LOG(INFO, USER1, - "%s() started on core %u\n", __func__, lcore_id); - - while (1) { - - /* Process each port round robin style */ - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - - if (!is_bit_set(port_id, portmask)) - continue; - - ring = rings[lcore_id][port_id]; - - if (ring_state[port_id] != RING_READY) { - if (rte_ring_count(ring) > *low_watermark) - continue; - else - ring_state[port_id] = RING_READY; - } - - /* Enqueue received packets on the RX ring */ - nb_rx_pkts = rte_eth_rx_burst(port_id, 0, pkts, - (uint16_t) *quota); - ret = rte_ring_enqueue_bulk(ring, (void *) pkts, - nb_rx_pkts, &free); - if (RING_SIZE - free > *high_watermark) { - ring_state[port_id] = RING_OVERLOADED; - send_pause_frame(port_id, 1337); - } - - if (ret == 0) { - - /* - * Return mbufs to the pool, - * effectively dropping packets - */ - for (i = 0; i < nb_rx_pkts; i++) - rte_pktmbuf_free(pkts[i]); - } - } - } -} - -static int -pipeline_stage(__attribute__((unused)) void *args) -{ - int i, ret; - int nb_dq_pkts; - - uint16_t port_id; - - unsigned int lcore_id, previous_lcore_id; - unsigned int free; - - void *pkts[MAX_PKT_QUOTA]; - struct rte_ring *rx, *tx; - enum ring_state ring_state[RTE_MAX_ETHPORTS] = { RING_READY }; - - lcore_id = rte_lcore_id(); - previous_lcore_id = get_previous_lcore_id(lcore_id); - - RTE_LOG(INFO, USER1, - "%s() started on core %u - processing packets from core %u\n", - __func__, lcore_id, previous_lcore_id); - - while (1) { - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - - if (!is_bit_set(port_id, portmask)) - continue; - - tx = rings[lcore_id][port_id]; - rx = rings[previous_lcore_id][port_id]; - - if (ring_state[port_id] != RING_READY) { - if (rte_ring_count(tx) > *low_watermark) - continue; - else - ring_state[port_id] = RING_READY; - } - - /* Dequeue up to quota mbuf from rx */ - nb_dq_pkts = rte_ring_dequeue_burst(rx, pkts, - *quota, NULL); - if (unlikely(nb_dq_pkts < 0)) - continue; - - /* Enqueue them on tx */ - ret = rte_ring_enqueue_bulk(tx, pkts, - nb_dq_pkts, &free); - if (RING_SIZE - free > *high_watermark) - ring_state[port_id] = RING_OVERLOADED; - - if (ret == 0) { - - /* - * Return mbufs to the pool, - * effectively dropping packets - */ - for (i = 0; i < nb_dq_pkts; i++) - rte_pktmbuf_free(pkts[i]); - } - } - } - - return 0; -} - -static int -send_stage(__attribute__((unused)) void *args) -{ - uint16_t nb_dq_pkts; - - uint16_t port_id; - uint16_t dest_port_id; - - unsigned int lcore_id, previous_lcore_id; - - struct rte_ring *tx; - struct rte_mbuf *tx_pkts[MAX_PKT_QUOTA]; - - lcore_id = rte_lcore_id(); - previous_lcore_id = get_previous_lcore_id(lcore_id); - - RTE_LOG(INFO, USER1, - "%s() started on core %u - processing packets from core %u\n", - __func__, lcore_id, previous_lcore_id); - - while (1) { - - /* Process each ring round robin style */ - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - - if (!is_bit_set(port_id, portmask)) - continue; - - dest_port_id = port_pairs[port_id]; - tx = rings[previous_lcore_id][port_id]; - - if (rte_ring_empty(tx)) - continue; - - /* Dequeue packets from tx and send them */ - nb_dq_pkts = (uint16_t) rte_ring_dequeue_burst(tx, - (void *) tx_pkts, *quota, NULL); - rte_eth_tx_burst(dest_port_id, 0, tx_pkts, nb_dq_pkts); - - /* TODO: Check if nb_dq_pkts == nb_tx_pkts? */ - } - } - - return 0; -} - -int -main(int argc, char **argv) -{ - int ret; - unsigned int lcore_id, master_lcore_id, last_lcore_id; - - uint16_t port_id; - - rte_log_set_global_level(RTE_LOG_INFO); - - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot initialize EAL\n"); - - argc -= ret; - argv += ret; - - init_dpdk(); - setup_shared_variables(); - - *quota = 32; - *low_watermark = 60 * RING_SIZE / 100; - - last_lcore_id = get_last_lcore_id(); - master_lcore_id = rte_get_master_lcore(); - - /* Parse the application's arguments */ - ret = parse_qw_args(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid quota/watermark argument(s)\n"); - - /* Create a pool of mbuf to store packets */ - mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", MBUF_PER_POOL, 32, 0, - MBUF_DATA_SIZE, rte_socket_id()); - if (mbuf_pool == NULL) - rte_panic("%s\n", rte_strerror(rte_errno)); - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) - if (is_bit_set(port_id, portmask)) { - configure_eth_port(port_id); - init_ring(master_lcore_id, port_id); - } - - pair_ports(); - - /* - * Start pipeline_connect() on all the available slave lcores - * but the last - */ - for (lcore_id = 0 ; lcore_id < last_lcore_id; lcore_id++) { - if (rte_lcore_is_enabled(lcore_id) && - lcore_id != master_lcore_id) { - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) - if (is_bit_set(port_id, portmask)) - init_ring(lcore_id, port_id); - - rte_eal_remote_launch(pipeline_stage, - NULL, lcore_id); - } - } - - /* Start send_stage() on the last slave core */ - rte_eal_remote_launch(send_stage, NULL, last_lcore_id); - - /* Start receive_stage() on the master core */ - receive_stage(NULL); - - return 0; -} diff --git a/examples/quota_watermark/qw/main.h b/examples/quota_watermark/qw/main.h deleted file mode 100644 index 9903ddc8c..000000000 --- a/examples/quota_watermark/qw/main.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _MAIN_H_ -#define _MAIN_H_ - -#include "../include/conf.h" - -enum ring_state { - RING_READY, - RING_OVERLOADED, -}; - -extern int *quota; -extern unsigned int *low_watermark; -extern unsigned int *high_watermark; - -extern uint16_t port_pairs[RTE_MAX_ETHPORTS]; - -extern struct rte_ring *rings[RTE_MAX_LCORE][RTE_MAX_ETHPORTS]; -extern struct rte_mempool *mbuf_pool; - - -static inline int -is_bit_set(int i, unsigned int mask) -{ - return (1 << i) & mask; -} - -#endif /* _MAIN_H_ */ diff --git a/examples/quota_watermark/qwctl/Makefile b/examples/quota_watermark/qwctl/Makefile deleted file mode 100644 index a40f28025..000000000 --- a/examples/quota_watermark/qwctl/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 - -# binary name -APP = qwctl - -# all source are stored in SRCS-y -SRCS-y := commands.c qwctl.c - -CFLAGS += -O3 -CFLAGS += $(WERROR_FLAGS) - -include $(RTE_SDK)/mk/rte.extapp.mk diff --git a/examples/quota_watermark/qwctl/commands.c b/examples/quota_watermark/qwctl/commands.c deleted file mode 100644 index a1c646b9f..000000000 --- a/examples/quota_watermark/qwctl/commands.c +++ /dev/null @@ -1,196 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <termios.h> - -#include <cmdline_rdline.h> -#include <cmdline_parse.h> -#include <cmdline_parse_num.h> -#include <cmdline_parse_string.h> -#include <cmdline.h> - -#include <rte_ring.h> - -#include "qwctl.h" -#include "../include/conf.h" - - -/** - * help command - */ - -struct cmd_help_tokens { - cmdline_fixed_string_t verb; -}; - -cmdline_parse_token_string_t cmd_help_verb = - TOKEN_STRING_INITIALIZER(struct cmd_help_tokens, verb, "help"); - -static void -cmd_help_handler(__attribute__((unused)) void *parsed_result, - struct cmdline *cl, - __attribute__((unused)) void *data) -{ - cmdline_printf(cl, "Available commands:\n" - "- help\n" - "- set [ring_name|variable] <value>\n" - "- show [ring_name|variable]\n" - "\n" - "Available variables:\n" - "- low_watermark\n" - "- quota\n" - "- ring names follow the core%%u_port%%u format\n"); -} - -cmdline_parse_inst_t cmd_help = { - .f = cmd_help_handler, - .data = NULL, - .help_str = "show help", - .tokens = { - (void *) &cmd_help_verb, - NULL, - }, -}; - - -/** - * set command - */ - -struct cmd_set_tokens { - cmdline_fixed_string_t verb; - cmdline_fixed_string_t variable; - uint32_t value; -}; - -cmdline_parse_token_string_t cmd_set_verb = - TOKEN_STRING_INITIALIZER(struct cmd_set_tokens, verb, "set"); - -cmdline_parse_token_string_t cmd_set_variable = - TOKEN_STRING_INITIALIZER(struct cmd_set_tokens, variable, NULL); - -cmdline_parse_token_num_t cmd_set_value = - TOKEN_NUM_INITIALIZER(struct cmd_set_tokens, value, UINT32); - -static void -cmd_set_handler(__attribute__((unused)) void *parsed_result, - struct cmdline *cl, - __attribute__((unused)) void *data) -{ - struct cmd_set_tokens *tokens = parsed_result; - struct rte_ring *ring; - - if (!strcmp(tokens->variable, "quota")) { - - if (tokens->value > 0 && tokens->value <= MAX_PKT_QUOTA) - *quota = tokens->value; - else - cmdline_printf(cl, "quota must be between 1 and %u\n", - MAX_PKT_QUOTA); - } - - else if (!strcmp(tokens->variable, "low_watermark")) { - - if (tokens->value <= 100) - *low_watermark = tokens->value * RING_SIZE / 100; - else - cmdline_printf(cl, - "low_watermark must be between 0%% and 100%%\n"); - } - - else { - - ring = rte_ring_lookup(tokens->variable); - if (ring == NULL) - cmdline_printf(cl, "Cannot find ring \"%s\"\n", - tokens->variable); - else - if (tokens->value >= *low_watermark * 100 / RING_SIZE - && tokens->value <= 100) - *high_watermark = tokens->value * - RING_SIZE / 100; - else - cmdline_printf(cl, - "ring high watermark must be between %u%% and 100%%\n", - *low_watermark * 100 / RING_SIZE); - } -} - -cmdline_parse_inst_t cmd_set = { - .f = cmd_set_handler, - .data = NULL, - .help_str = "Set a variable value", - .tokens = { - (void *) &cmd_set_verb, - (void *) &cmd_set_variable, - (void *) &cmd_set_value, - NULL, - }, -}; - - -/** - * show command - */ - -struct cmd_show_tokens { - cmdline_fixed_string_t verb; - cmdline_fixed_string_t variable; -}; - -cmdline_parse_token_string_t cmd_show_verb = - TOKEN_STRING_INITIALIZER(struct cmd_show_tokens, verb, "show"); - -cmdline_parse_token_string_t cmd_show_variable = - TOKEN_STRING_INITIALIZER(struct cmd_show_tokens, - variable, NULL); - - -static void -cmd_show_handler(__attribute__((unused)) void *parsed_result, - struct cmdline *cl, - __attribute__((unused)) void *data) -{ - struct cmd_show_tokens *tokens = parsed_result; - struct rte_ring *ring; - - if (!strcmp(tokens->variable, "quota")) - cmdline_printf(cl, "Global quota: %d\n", *quota); - - else if (!strcmp(tokens->variable, "low_watermark")) - cmdline_printf(cl, "Global low_watermark: %u\n", - *low_watermark); - - else { - - ring = rte_ring_lookup(tokens->variable); - if (ring == NULL) - cmdline_printf(cl, "Cannot find ring \"%s\"\n", - tokens->variable); - else - rte_ring_dump(stdout, ring); - } -} - -cmdline_parse_inst_t cmd_show = { - .f = cmd_show_handler, - .data = NULL, - .help_str = "Show a variable value", - .tokens = { - (void *) &cmd_show_verb, - (void *) &cmd_show_variable, - NULL, - }, -}; - - -cmdline_parse_ctx_t qwctl_ctx[] = { - (cmdline_parse_inst_t *)&cmd_help, - (cmdline_parse_inst_t *)&cmd_set, - (cmdline_parse_inst_t *)&cmd_show, - NULL, -}; diff --git a/examples/quota_watermark/qwctl/commands.h b/examples/quota_watermark/qwctl/commands.h deleted file mode 100644 index 4a4e97475..000000000 --- a/examples/quota_watermark/qwctl/commands.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _COMMANDS_H_ -#define _COMMANDS_H_ - -#include <cmdline_parse.h> - -extern cmdline_parse_ctx_t qwctl_ctx[]; - -#endif /* _COMMANDS_H_ */ diff --git a/examples/quota_watermark/qwctl/qwctl.c b/examples/quota_watermark/qwctl/qwctl.c deleted file mode 100644 index 2f7914c80..000000000 --- a/examples/quota_watermark/qwctl/qwctl.c +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <fcntl.h> -#include <stdio.h> -#include <termios.h> -#include <unistd.h> -#include <sys/mman.h> - -#include <rte_eal.h> - -#include <rte_log.h> -#include <rte_memzone.h> - -#include <cmdline_rdline.h> -#include <cmdline_parse.h> -#include <cmdline_socket.h> -#include <cmdline.h> - - -#include "qwctl.h" -#include "commands.h" -#include "../include/conf.h" - - -int *quota; -unsigned int *low_watermark; -unsigned int *high_watermark; - - -static void -setup_shared_variables(void) -{ - const struct rte_memzone *qw_memzone; - - qw_memzone = rte_memzone_lookup(QUOTA_WATERMARK_MEMZONE_NAME); - if (qw_memzone == NULL) - rte_exit(EXIT_FAILURE, "Couldn't find memzone\n"); - - quota = qw_memzone->addr; - low_watermark = (unsigned int *) qw_memzone->addr + 1; - high_watermark = (unsigned int *) qw_memzone->addr + 2; -} - -int main(int argc, char **argv) -{ - int ret; - struct cmdline *cl; - - rte_log_set_global_level(RTE_LOG_INFO); - - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot initialize EAL\n"); - - setup_shared_variables(); - - cl = cmdline_stdin_new(qwctl_ctx, "qwctl> "); - if (cl == NULL) - rte_exit(EXIT_FAILURE, "Cannot create cmdline instance\n"); - - cmdline_interact(cl); - cmdline_stdin_exit(cl); - - return 0; -} diff --git a/examples/quota_watermark/qwctl/qwctl.h b/examples/quota_watermark/qwctl/qwctl.h deleted file mode 100644 index 2a4559388..000000000 --- a/examples/quota_watermark/qwctl/qwctl.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _MAIN_H_ -#define _MAIN_H_ - -extern int *quota; -extern unsigned int *low_watermark; -extern unsigned int *high_watermark; - -#endif /* _MAIN_H_ */ -- 2.21.0 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH 4/6] examples/netmap-compat: remove example from DPDK 2019-10-03 13:19 [dpdk-dev] [PATCH 0/6] remove a few example applications Bruce Richardson ` (2 preceding siblings ...) 2019-10-03 13:19 ` [dpdk-dev] [PATCH 3/6] examples/quota-watermark: " Bruce Richardson @ 2019-10-03 13:19 ` Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 5/6] examples/load_balancer: " Bruce Richardson ` (4 subsequent siblings) 8 siblings, 0 replies; 27+ messages in thread From: Bruce Richardson @ 2019-10-03 13:19 UTC (permalink / raw) To: dev; +Cc: techboard, Ciara Power From: Ciara Power <ciara.power@intel.com> 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 <ciara.power@intel.com> --- 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 <john.mcnamara@intel.com> 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 <fcntl.h> -#include <getopt.h> -#include <inttypes.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/mman.h> - -#include <rte_eal.h> -#include <rte_ethdev.h> -#include <rte_mbuf.h> -#include <rte_mempool.h> -#include <rte_string_fns.h> -#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 <errno.h> -#include <inttypes.h> -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <net/if.h> -#include <sys/types.h> -#include <sys/resource.h> -#include <sys/mman.h> - -#include <rte_common.h> -#include <rte_errno.h> -#include <rte_ethdev.h> -#include <rte_log.h> -#include <rte_malloc.h> -#include <rte_mbuf.h> -#include <rte_spinlock.h> -#include <rte_string_fns.h> - -#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 <poll.h> -#include <linux/ioctl.h> -#include <net/if.h> - -#include <rte_ethdev.h> -#include <rte_mempool.h> - -#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_ */ -- 2.21.0 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH 5/6] examples/load_balancer: remove example from DPDK 2019-10-03 13:19 [dpdk-dev] [PATCH 0/6] remove a few example applications Bruce Richardson ` (3 preceding siblings ...) 2019-10-03 13:19 ` [dpdk-dev] [PATCH 4/6] examples/netmap-compat: " Bruce Richardson @ 2019-10-03 13:19 ` Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 6/6] doc: close up gaps in sample app guide table Bruce Richardson ` (3 subsequent siblings) 8 siblings, 0 replies; 27+ messages in thread From: Bruce Richardson @ 2019-10-03 13:19 UTC (permalink / raw) To: dev; +Cc: techboard, Ciara Power From: Ciara Power <ciara.power@intel.com> This example can be removed because DPDK now has a range of libraries, especially rte_eventdev, that did not exist previously for load balancing, making this less relevant. Also, modern NIC cards have greater ability to do load balancing, e.g. using RSS, over a wider range of fields than earlier cards did. Signed-off-by: Ciara Power <ciara.power@intel.com> --- MAINTAINERS | 3 - doc/guides/sample_app_ug/index.rst | 1 - doc/guides/sample_app_ug/intro.rst | 2 +- doc/guides/sample_app_ug/load_balancer.rst | 201 ---- examples/Makefile | 1 - examples/load_balancer/Makefile | 62 -- examples/load_balancer/config.c | 1030 -------------------- examples/load_balancer/init.c | 520 ---------- examples/load_balancer/main.c | 76 -- examples/load_balancer/main.h | 351 ------- examples/load_balancer/meson.build | 12 - examples/load_balancer/runtime.c | 642 ------------ examples/meson.build | 1 - 13 files changed, 1 insertion(+), 2901 deletions(-) delete mode 100644 doc/guides/sample_app_ug/load_balancer.rst delete mode 100644 examples/load_balancer/Makefile delete mode 100644 examples/load_balancer/config.c delete mode 100644 examples/load_balancer/init.c delete mode 100644 examples/load_balancer/main.c delete mode 100644 examples/load_balancer/main.h delete mode 100644 examples/load_balancer/meson.build delete mode 100644 examples/load_balancer/runtime.c diff --git a/MAINTAINERS b/MAINTAINERS index 6b9fa4dc2..3db771bd7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1461,9 +1461,6 @@ F: doc/guides/sample_app_ug/l3_forward.rst F: examples/link_status_interrupt/ F: doc/guides/sample_app_ug/link_status_intr.rst -F: examples/load_balancer/ -F: doc/guides/sample_app_ug/load_balancer.rst - L-threads - EXPERIMENTAL M: John McNamara <john.mcnamara@intel.com> F: examples/performance-thread/ diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst index 5f4924df6..191eebb56 100644 --- a/doc/guides/sample_app_ug/index.rst +++ b/doc/guides/sample_app_ug/index.rst @@ -30,7 +30,6 @@ Sample Applications User Guides l3_forward_power_man l3_forward_access_ctrl link_status_intr - load_balancer server_node_efd service_cores multi_process diff --git a/doc/guides/sample_app_ug/intro.rst b/doc/guides/sample_app_ug/intro.rst index 39af887da..981e50f94 100644 --- a/doc/guides/sample_app_ug/intro.rst +++ b/doc/guides/sample_app_ug/intro.rst @@ -61,7 +61,7 @@ applications that are available in the examples directory of DPDK: +---------------------------------------+--------------------------------------+ | Link Status Interrupt | VMDQ Forwarding | +---------------------------------------+--------------------------------------+ - | Load Balancer | VMDQ and DCB Forwarding | + | | VMDQ and DCB Forwarding | +---------------------------------------+--------------------------------------+ | Multi-process | VM Power Management | +---------------------------------------+--------------------------------------+ diff --git a/doc/guides/sample_app_ug/load_balancer.rst b/doc/guides/sample_app_ug/load_balancer.rst deleted file mode 100644 index 8f2abdfb8..000000000 --- a/doc/guides/sample_app_ug/load_balancer.rst +++ /dev/null @@ -1,201 +0,0 @@ -.. SPDX-License-Identifier: BSD-3-Clause - Copyright(c) 2010-2014 Intel Corporation. - -Load Balancer Sample Application -================================ - -The Load Balancer sample application demonstrates the concept of isolating the packet I/O task -from the application-specific workload. -Depending on the performance target, -a number of logical cores (lcores) are dedicated to handle the interaction with the NIC ports (I/O lcores), -while the rest of the lcores are dedicated to performing the application processing (worker lcores). -The worker lcores are totally oblivious to the intricacies of the packet I/O activity and -use the NIC-agnostic interface provided by software rings to exchange packets with the I/O cores. - -Overview --------- - -The architecture of the Load Balance application is presented in the following figure. - -.. _figure_load_bal_app_arch: - -.. figure:: img/load_bal_app_arch.* - - Load Balancer Application Architecture - - -For the sake of simplicity, the diagram illustrates a specific case of two I/O RX and two I/O TX lcores off loading the packet I/O -overhead incurred by four NIC ports from four worker cores, with each I/O lcore handling RX/TX for two NIC ports. - -I/O RX Logical Cores -~~~~~~~~~~~~~~~~~~~~ - -Each I/O RX lcore performs packet RX from its assigned NIC RX rings and then distributes the received packets to the worker threads. -The application allows each I/O RX lcore to communicate with any of the worker threads, -therefore each (I/O RX lcore, worker lcore) pair is connected through a dedicated single producer - single consumer software ring. - -The worker lcore to handle the current packet is determined by reading a predefined 1-byte field from the input packet: - -worker_id = packet[load_balancing_field] % n_workers - -Since all the packets that are part of the same traffic flow are expected to have the same value for the load balancing field, -this scheme also ensures that all the packets that are part of the same traffic flow are directed to the same worker lcore (flow affinity) -in the same order they enter the system (packet ordering). - -I/O TX Logical Cores -~~~~~~~~~~~~~~~~~~~~ - -Each I/O lcore owns the packet TX for a predefined set of NIC ports. To enable each worker thread to send packets to any NIC TX port, -the application creates a software ring for each (worker lcore, NIC TX port) pair, -with each I/O TX core handling those software rings that are associated with NIC ports that it handles. - -Worker Logical Cores -~~~~~~~~~~~~~~~~~~~~ - -Each worker lcore reads packets from its set of input software rings and -routes them to the NIC ports for transmission by dispatching them to output software rings. -The routing logic is LPM based, with all the worker threads sharing the same LPM rules. - -Compiling the Application -------------------------- - -To compile the sample application see :doc:`compiling`. - -The application is located in the ``load_balancer`` sub-directory. - -Running the Application ------------------------ - -To successfully run the application, -the command line used to start the application has to be in sync with the traffic flows configured on the traffic generator side. - -For examples of application command lines and traffic generator flows, please refer to the DPDK Test Report. -For more details on how to set up and run the sample applications provided with DPDK package, -please refer to the *DPDK Getting Started Guide*. - -Explanation ------------ - -Application Configuration -~~~~~~~~~~~~~~~~~~~~~~~~~ - -The application run-time configuration is done through the application command line parameters. -Any parameter that is not specified as mandatory is optional, -with the default value hard-coded in the main.h header file from the application folder. - -The list of application command line parameters is listed below: - -#. --rx "(PORT, QUEUE, LCORE), ...": The list of NIC RX ports and queues handled by the I/O RX lcores. - This parameter also implicitly defines the list of I/O RX lcores. This is a mandatory parameter. - -#. --tx "(PORT, LCORE), ... ": The list of NIC TX ports handled by the I/O TX lcores. - This parameter also implicitly defines the list of I/O TX lcores. - This is a mandatory parameter. - -#. --w "LCORE, ...": The list of the worker lcores. This is a mandatory parameter. - -#. --lpm "IP / PREFIX => PORT; ...": The list of LPM rules used by the worker lcores for packet forwarding. - This is a mandatory parameter. - -#. --rsz "A, B, C, D": Ring sizes: - - #. A = The size (in number of buffer descriptors) of each of the NIC RX rings read by the I/O RX lcores. - - #. B = The size (in number of elements) of each of the software rings used by the I/O RX lcores to send packets to worker lcores. - - #. C = The size (in number of elements) of each of the software rings used by the worker lcores to send packets to I/O TX lcores. - - #. D = The size (in number of buffer descriptors) of each of the NIC TX rings written by I/O TX lcores. - -#. --bsz "(A, B), (C, D), (E, F)": Burst sizes: - - #. A = The I/O RX lcore read burst size from NIC RX. - - #. B = The I/O RX lcore write burst size to the output software rings. - - #. C = The worker lcore read burst size from the input software rings. - - #. D = The worker lcore write burst size to the output software rings. - - #. E = The I/O TX lcore read burst size from the input software rings. - - #. F = The I/O TX lcore write burst size to the NIC TX. - -#. --pos-lb POS: The position of the 1-byte field within the input packet used by the I/O RX lcores - to identify the worker lcore for the current packet. - This field needs to be within the first 64 bytes of the input packet. - -The infrastructure of software rings connecting I/O lcores and worker lcores is built by the application -as a result of the application configuration provided by the user through the application command line parameters. - -A specific lcore performing the I/O RX role for a specific set of NIC ports can also perform the I/O TX role -for the same or a different set of NIC ports. -A specific lcore cannot perform both the I/O role (either RX or TX) and the worker role during the same session. - -Example: - -.. code-block:: console - - ./load_balancer -l 3-7 -n 4 -- --rx "(0,0,3),(1,0,3)" --tx "(0,3),(1,3)" --w "4,5,6,7" --lpm "1.0.0.0/24=>0; 1.0.1.0/24=>1;" --pos-lb 29 - -There is a single I/O lcore (lcore 3) that handles RX and TX for two NIC ports (ports 0 and 1) that -handles packets to/from four worker lcores (lcores 4, 5, 6 and 7) that -are assigned worker IDs 0 to 3 (worker ID for lcore 4 is 0, for lcore 5 is 1, for lcore 6 is 2 and for lcore 7 is 3). - -Assuming that all the input packets are IPv4 packets with no VLAN label and the source IP address of the current packet is A.B.C.D, -the worker lcore for the current packet is determined by byte D (which is byte 29). -There are two LPM rules that are used by each worker lcore to route packets to the output NIC ports. - -The following table illustrates the packet flow through the system for several possible traffic flows: - -+------------+----------------+-----------------+------------------------------+--------------+ -| **Flow #** | **Source** | **Destination** | **Worker ID (Worker lcore)** | **Output** | -| | **IP Address** | **IP Address** | | **NIC Port** | -| | | | | | -+============+================+=================+==============================+==============+ -| 1 | 0.0.0.0 | 1.0.0.1 | 0 (4) | 0 | -| | | | | | -+------------+----------------+-----------------+------------------------------+--------------+ -| 2 | 0.0.0.1 | 1.0.1.2 | 1 (5) | 1 | -| | | | | | -+------------+----------------+-----------------+------------------------------+--------------+ -| 3 | 0.0.0.14 | 1.0.0.3 | 2 (6) | 0 | -| | | | | | -+------------+----------------+-----------------+------------------------------+--------------+ -| 4 | 0.0.0.15 | 1.0.1.4 | 3 (7) | 1 | -| | | | | | -+------------+----------------+-----------------+------------------------------+--------------+ - -NUMA Support -~~~~~~~~~~~~ - -The application has built-in performance enhancements for the NUMA case: - -#. One buffer pool per each CPU socket. - -#. One LPM table per each CPU socket. - -#. Memory for the NIC RX or TX rings is allocated on the same socket with the lcore handling the respective ring. - -In the case where multiple CPU sockets are used in the system, -it is recommended to enable at least one lcore to fulfill the I/O role for the NIC ports that -are directly attached to that CPU socket through the PCI Express* bus. -It is always recommended to handle the packet I/O with lcores from the same CPU socket as the NICs. - -Depending on whether the I/O RX lcore (same CPU socket as NIC RX), -the worker lcore and the I/O TX lcore (same CPU socket as NIC TX) handling a specific input packet, -are on the same or different CPU sockets, the following run-time scenarios are possible: - -#. AAA: The packet is received, processed and transmitted without going across CPU sockets. - -#. AAB: The packet is received and processed on socket A, - but as it has to be transmitted on a NIC port connected to socket B, - the packet is sent to socket B through software rings. - -#. ABB: The packet is received on socket A, but as it has to be processed by a worker lcore on socket B, - the packet is sent to socket B through software rings. - The packet is transmitted by a NIC port connected to the same CPU socket as the worker lcore that processed it. - -#. ABC: The packet is received on socket A, it is processed by an lcore on socket B, - then it has to be transmitted out by a NIC connected to socket C. - The performance price for crossing the CPU socket boundary is paid twice for this packet. diff --git a/examples/Makefile b/examples/Makefile index 6bba09ce9..62d0865c5 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -48,7 +48,6 @@ ifeq ($(CONFIG_RTE_LIBRTE_LPM)$(CONFIG_RTE_LIBRTE_HASH),yy) DIRS-$(CONFIG_RTE_LIBRTE_POWER) += l3fwd-power endif DIRS-y += link_status_interrupt -DIRS-$(CONFIG_RTE_LIBRTE_LPM) += load_balancer DIRS-y += multi_process DIRS-y += ntb DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += packet_ordering diff --git a/examples/load_balancer/Makefile b/examples/load_balancer/Makefile deleted file mode 100644 index caae8a107..000000000 --- a/examples/load_balancer/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2010-2014 Intel Corporation - -# binary name -APP = load_balancer - -# all source are stored in SRCS-y -SRCS-y := main.c config.c init.c runtime.c - -# Build using pkg-config variables if possible -ifeq ($(shell pkg-config --exists libdpdk && echo 0),0) - -all: shared -.PHONY: shared static -shared: build/$(APP)-shared - ln -sf $(APP)-shared build/$(APP) -static: build/$(APP)-static - ln -sf $(APP)-static build/$(APP) - -PKGCONF=pkg-config --define-prefix - -PC_FILE := $(shell $(PKGCONF) --path libdpdk) -CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) -LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk) -LDFLAGS_STATIC = -Wl,-Bstatic $(shell $(PKGCONF) --static --libs libdpdk) - -build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) - -build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC) - -build: - @mkdir -p $@ - -.PHONY: clean -clean: - rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared - test -d build && rmdir -p build || true - -else # Build using legacy build system - -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 - -CFLAGS += -O3 -g -CFLAGS += $(WERROR_FLAGS) - -# workaround for a gcc bug with noreturn attribute -# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603 -ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y) -CFLAGS_main.o += -Wno-return-type -endif - -include $(RTE_SDK)/mk/rte.extapp.mk -endif diff --git a/examples/load_balancer/config.c b/examples/load_balancer/config.c deleted file mode 100644 index 972c85c5b..000000000 --- a/examples/load_balancer/config.c +++ /dev/null @@ -1,1030 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_lpm.h> -#include <rte_string_fns.h> - -#include "main.h" - -struct app_params app; - -static const char usage[] = -" \n" -" load_balancer <EAL PARAMS> -- <APP PARAMS> \n" -" \n" -"Application manadatory parameters: \n" -" --rx \"(PORT, QUEUE, LCORE), ...\" : List of NIC RX ports and queues \n" -" handled by the I/O RX lcores \n" -" --tx \"(PORT, LCORE), ...\" : List of NIC TX ports handled by the I/O TX \n" -" lcores \n" -" --w \"LCORE, ...\" : List of the worker lcores \n" -" --lpm \"IP / PREFIX => PORT; ...\" : List of LPM rules used by the worker \n" -" lcores for packet forwarding \n" -" \n" -"Application optional parameters: \n" -" --rsz \"A, B, C, D\" : Ring sizes \n" -" A = Size (in number of buffer descriptors) of each of the NIC RX \n" -" rings read by the I/O RX lcores (default value is %u) \n" -" B = Size (in number of elements) of each of the SW rings used by the\n" -" I/O RX lcores to send packets to worker lcores (default value is\n" -" %u) \n" -" C = Size (in number of elements) of each of the SW rings used by the\n" -" worker lcores to send packets to I/O TX lcores (default value is\n" -" %u) \n" -" D = Size (in number of buffer descriptors) of each of the NIC TX \n" -" rings written by I/O TX lcores (default value is %u) \n" -" --bsz \"(A, B), (C, D), (E, F)\" : Burst sizes \n" -" A = I/O RX lcore read burst size from NIC RX (default value is %u) \n" -" B = I/O RX lcore write burst size to output SW rings (default value \n" -" is %u) \n" -" C = Worker lcore read burst size from input SW rings (default value \n" -" is %u) \n" -" D = Worker lcore write burst size to output SW rings (default value \n" -" is %u) \n" -" E = I/O TX lcore read burst size from input SW rings (default value \n" -" is %u) \n" -" F = I/O TX lcore write burst size to NIC TX (default value is %u) \n" -" --pos-lb POS : Position of the 1-byte field within the input packet used by\n" -" the I/O RX lcores to identify the worker lcore for the current \n" -" packet (default value is %u) \n"; - -void -app_print_usage(void) -{ - printf(usage, - APP_DEFAULT_NIC_RX_RING_SIZE, - APP_DEFAULT_RING_RX_SIZE, - APP_DEFAULT_RING_TX_SIZE, - APP_DEFAULT_NIC_TX_RING_SIZE, - APP_DEFAULT_BURST_SIZE_IO_RX_READ, - APP_DEFAULT_BURST_SIZE_IO_RX_WRITE, - APP_DEFAULT_BURST_SIZE_WORKER_READ, - APP_DEFAULT_BURST_SIZE_WORKER_WRITE, - APP_DEFAULT_BURST_SIZE_IO_TX_READ, - APP_DEFAULT_BURST_SIZE_IO_TX_WRITE, - APP_DEFAULT_IO_RX_LB_POS - ); -} - -#ifndef APP_ARG_RX_MAX_CHARS -#define APP_ARG_RX_MAX_CHARS 4096 -#endif - -#ifndef APP_ARG_RX_MAX_TUPLES -#define APP_ARG_RX_MAX_TUPLES 128 -#endif - -static int -str_to_unsigned_array( - const char *s, size_t sbuflen, - char separator, - unsigned num_vals, - unsigned *vals) -{ - char str[sbuflen+1]; - char *splits[num_vals]; - char *endptr = NULL; - int i, num_splits = 0; - - /* copy s so we don't modify original string */ - strlcpy(str, s, sizeof(str)); - num_splits = rte_strsplit(str, sizeof(str), splits, num_vals, separator); - - errno = 0; - for (i = 0; i < num_splits; i++) { - vals[i] = strtoul(splits[i], &endptr, 0); - if (errno != 0 || *endptr != '\0') - return -1; - } - - return num_splits; -} - -static int -str_to_unsigned_vals( - const char *s, - size_t sbuflen, - char separator, - unsigned num_vals, ...) -{ - unsigned i, vals[num_vals]; - va_list ap; - - num_vals = str_to_unsigned_array(s, sbuflen, separator, num_vals, vals); - - va_start(ap, num_vals); - for (i = 0; i < num_vals; i++) { - unsigned *u = va_arg(ap, unsigned *); - *u = vals[i]; - } - va_end(ap); - return num_vals; -} - -static int -parse_arg_rx(const char *arg) -{ - const char *p0 = arg, *p = arg; - uint32_t n_tuples; - - if (strnlen(arg, APP_ARG_RX_MAX_CHARS + 1) == APP_ARG_RX_MAX_CHARS + 1) { - return -1; - } - - n_tuples = 0; - while ((p = strchr(p0,'(')) != NULL) { - struct app_lcore_params *lp; - uint32_t port, queue, lcore, i; - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 3, &port, &queue, &lcore) != 3)) { - return -2; - } - - /* Enable port and queue for later initialization */ - if ((port >= APP_MAX_NIC_PORTS) || (queue >= APP_MAX_RX_QUEUES_PER_NIC_PORT)) { - return -3; - } - if (app.nic_rx_queue_mask[port][queue] != 0) { - return -4; - } - app.nic_rx_queue_mask[port][queue] = 1; - - /* Check and assign (port, queue) to I/O lcore */ - if (rte_lcore_is_enabled(lcore) == 0) { - return -5; - } - - if (lcore >= APP_MAX_LCORES) { - return -6; - } - lp = &app.lcore_params[lcore]; - if (lp->type == e_APP_LCORE_WORKER) { - return -7; - } - lp->type = e_APP_LCORE_IO; - const size_t n_queues = RTE_MIN(lp->io.rx.n_nic_queues, - RTE_DIM(lp->io.rx.nic_queues)); - for (i = 0; i < n_queues; i ++) { - if ((lp->io.rx.nic_queues[i].port == port) && - (lp->io.rx.nic_queues[i].queue == queue)) { - return -8; - } - } - if (lp->io.rx.n_nic_queues >= APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE) { - return -9; - } - lp->io.rx.nic_queues[lp->io.rx.n_nic_queues].port = port; - lp->io.rx.nic_queues[lp->io.rx.n_nic_queues].queue = (uint8_t) queue; - lp->io.rx.n_nic_queues ++; - - n_tuples ++; - if (n_tuples > APP_ARG_RX_MAX_TUPLES) { - return -10; - } - } - - if (n_tuples == 0) { - return -11; - } - - return 0; -} - -#ifndef APP_ARG_TX_MAX_CHARS -#define APP_ARG_TX_MAX_CHARS 4096 -#endif - -#ifndef APP_ARG_TX_MAX_TUPLES -#define APP_ARG_TX_MAX_TUPLES 128 -#endif - -static int -parse_arg_tx(const char *arg) -{ - const char *p0 = arg, *p = arg; - uint32_t n_tuples; - - if (strnlen(arg, APP_ARG_TX_MAX_CHARS + 1) == APP_ARG_TX_MAX_CHARS + 1) { - return -1; - } - - n_tuples = 0; - while ((p = strchr(p0,'(')) != NULL) { - struct app_lcore_params *lp; - uint32_t port, lcore, i; - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 2, &port, &lcore) != 2)) { - return -2; - } - - /* Enable port and queue for later initialization */ - if (port >= APP_MAX_NIC_PORTS) { - return -3; - } - if (app.nic_tx_port_mask[port] != 0) { - return -4; - } - app.nic_tx_port_mask[port] = 1; - - /* Check and assign (port, queue) to I/O lcore */ - if (rte_lcore_is_enabled(lcore) == 0) { - return -5; - } - - if (lcore >= APP_MAX_LCORES) { - return -6; - } - lp = &app.lcore_params[lcore]; - if (lp->type == e_APP_LCORE_WORKER) { - return -7; - } - lp->type = e_APP_LCORE_IO; - const size_t n_ports = RTE_MIN(lp->io.tx.n_nic_ports, - RTE_DIM(lp->io.tx.nic_ports)); - for (i = 0; i < n_ports; i ++) { - if (lp->io.tx.nic_ports[i] == port) { - return -8; - } - } - if (lp->io.tx.n_nic_ports >= APP_MAX_NIC_TX_PORTS_PER_IO_LCORE) { - return -9; - } - lp->io.tx.nic_ports[lp->io.tx.n_nic_ports] = port; - lp->io.tx.n_nic_ports ++; - - n_tuples ++; - if (n_tuples > APP_ARG_TX_MAX_TUPLES) { - return -10; - } - } - - if (n_tuples == 0) { - return -11; - } - - return 0; -} - -#ifndef APP_ARG_W_MAX_CHARS -#define APP_ARG_W_MAX_CHARS 4096 -#endif - -#ifndef APP_ARG_W_MAX_TUPLES -#define APP_ARG_W_MAX_TUPLES APP_MAX_WORKER_LCORES -#endif - -static int -parse_arg_w(const char *arg) -{ - const char *p = arg; - uint32_t n_tuples; - - if (strnlen(arg, APP_ARG_W_MAX_CHARS + 1) == APP_ARG_W_MAX_CHARS + 1) { - return -1; - } - - n_tuples = 0; - while (*p != 0) { - struct app_lcore_params *lp; - uint32_t lcore; - - errno = 0; - lcore = strtoul(p, NULL, 0); - if (errno != 0) { - return -2; - } - - /* Check and enable worker lcore */ - if (rte_lcore_is_enabled(lcore) == 0) { - return -3; - } - - if (lcore >= APP_MAX_LCORES) { - return -4; - } - lp = &app.lcore_params[lcore]; - if (lp->type == e_APP_LCORE_IO) { - return -5; - } - lp->type = e_APP_LCORE_WORKER; - - n_tuples ++; - if (n_tuples > APP_ARG_W_MAX_TUPLES) { - return -6; - } - - p = strchr(p, ','); - if (p == NULL) { - break; - } - p ++; - } - - if (n_tuples == 0) { - return -7; - } - - if ((n_tuples & (n_tuples - 1)) != 0) { - return -8; - } - - return 0; -} - -#ifndef APP_ARG_LPM_MAX_CHARS -#define APP_ARG_LPM_MAX_CHARS 4096 -#endif - -static int -parse_arg_lpm(const char *arg) -{ - const char *p = arg, *p0; - - if (strnlen(arg, APP_ARG_LPM_MAX_CHARS + 1) == APP_ARG_TX_MAX_CHARS + 1) { - return -1; - } - - while (*p != 0) { - uint32_t ip_a, ip_b, ip_c, ip_d, ip, depth, if_out; - char *endptr; - - p0 = strchr(p, '/'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, '.', 4, &ip_a, &ip_b, &ip_c, &ip_d) != 4)) { - return -2; - } - - p = p0 + 1; - errno = 0; - depth = strtoul(p, &endptr, 0); - if (errno != 0 || *endptr != '=') { - return -3; - } - p = strchr(p, '>'); - if (p == NULL) { - return -4; - } - if_out = strtoul(++p, &endptr, 0); - if (errno != 0 || (*endptr != '\0' && *endptr != ';')) { - return -5; - } - - if ((ip_a >= 256) || (ip_b >= 256) || (ip_c >= 256) || (ip_d >= 256) || - (depth == 0) || (depth >= 32) || - (if_out >= APP_MAX_NIC_PORTS)) { - return -6; - } - ip = (ip_a << 24) | (ip_b << 16) | (ip_c << 8) | ip_d; - - if (app.n_lpm_rules >= APP_MAX_LPM_RULES) { - return -7; - } - app.lpm_rules[app.n_lpm_rules].ip = ip; - app.lpm_rules[app.n_lpm_rules].depth = (uint8_t) depth; - app.lpm_rules[app.n_lpm_rules].if_out = (uint8_t) if_out; - app.n_lpm_rules ++; - - p = strchr(p, ';'); - if (p == NULL) { - return -8; - } - p ++; - } - - if (app.n_lpm_rules == 0) { - return -9; - } - - return 0; -} - -static int -app_check_lpm_table(void) -{ - uint32_t rule; - - /* For each rule, check that the output I/F is enabled */ - for (rule = 0; rule < app.n_lpm_rules; rule ++) - { - uint32_t port = app.lpm_rules[rule].if_out; - - if (app.nic_tx_port_mask[port] == 0) { - return -1; - } - } - - return 0; -} - -static int -app_check_every_rx_port_is_tx_enabled(void) -{ - uint16_t port; - - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - if ((app_get_nic_rx_queues_per_port(port) > 0) && (app.nic_tx_port_mask[port] == 0)) { - return -1; - } - } - - return 0; -} - -#ifndef APP_ARG_RSZ_CHARS -#define APP_ARG_RSZ_CHARS 63 -#endif - -static int -parse_arg_rsz(const char *arg) -{ - if (strnlen(arg, APP_ARG_RSZ_CHARS + 1) == APP_ARG_RSZ_CHARS + 1) { - return -1; - } - - if (str_to_unsigned_vals(arg, APP_ARG_RSZ_CHARS, ',', 4, - &app.nic_rx_ring_size, - &app.ring_rx_size, - &app.ring_tx_size, - &app.nic_tx_ring_size) != 4) - return -2; - - - if ((app.nic_rx_ring_size == 0) || - (app.nic_tx_ring_size == 0) || - (app.ring_rx_size == 0) || - (app.ring_tx_size == 0)) { - return -3; - } - - return 0; -} - -#ifndef APP_ARG_BSZ_CHARS -#define APP_ARG_BSZ_CHARS 63 -#endif - -static int -parse_arg_bsz(const char *arg) -{ - const char *p = arg, *p0; - if (strnlen(arg, APP_ARG_BSZ_CHARS + 1) == APP_ARG_BSZ_CHARS + 1) { - return -1; - } - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 2, &app.burst_size_io_rx_read, &app.burst_size_io_rx_write) != 2)) { - return -2; - } - - p = strchr(p0, '('); - if (p == NULL) { - return -3; - } - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 2, &app.burst_size_worker_read, &app.burst_size_worker_write) != 2)) { - return -4; - } - - p = strchr(p0, '('); - if (p == NULL) { - return -5; - } - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 2, &app.burst_size_io_tx_read, &app.burst_size_io_tx_write) != 2)) { - return -6; - } - - if ((app.burst_size_io_rx_read == 0) || - (app.burst_size_io_rx_write == 0) || - (app.burst_size_worker_read == 0) || - (app.burst_size_worker_write == 0) || - (app.burst_size_io_tx_read == 0) || - (app.burst_size_io_tx_write == 0)) { - return -7; - } - - if ((app.burst_size_io_rx_read > APP_MBUF_ARRAY_SIZE) || - (app.burst_size_io_rx_write > APP_MBUF_ARRAY_SIZE) || - (app.burst_size_worker_read > APP_MBUF_ARRAY_SIZE) || - (app.burst_size_worker_write > APP_MBUF_ARRAY_SIZE) || - ((2 * app.burst_size_io_tx_read) > APP_MBUF_ARRAY_SIZE) || - (app.burst_size_io_tx_write > APP_MBUF_ARRAY_SIZE)) { - return -8; - } - - return 0; -} - -#ifndef APP_ARG_NUMERICAL_SIZE_CHARS -#define APP_ARG_NUMERICAL_SIZE_CHARS 15 -#endif - -static int -parse_arg_pos_lb(const char *arg) -{ - uint32_t x; - char *endpt; - - if (strnlen(arg, APP_ARG_NUMERICAL_SIZE_CHARS + 1) == APP_ARG_NUMERICAL_SIZE_CHARS + 1) { - return -1; - } - - errno = 0; - x = strtoul(arg, &endpt, 10); - if (errno != 0 || endpt == arg || *endpt != '\0'){ - return -2; - } - - if (x >= 64) { - return -3; - } - - app.pos_lb = (uint8_t) x; - - return 0; -} - -/* Parse the argument given in the command line of the application */ -int -app_parse_args(int argc, char **argv) -{ - int opt, ret; - char **argvopt; - int option_index; - char *prgname = argv[0]; - static struct option lgopts[] = { - {"rx", 1, 0, 0}, - {"tx", 1, 0, 0}, - {"w", 1, 0, 0}, - {"lpm", 1, 0, 0}, - {"rsz", 1, 0, 0}, - {"bsz", 1, 0, 0}, - {"pos-lb", 1, 0, 0}, - {NULL, 0, 0, 0} - }; - uint32_t arg_w = 0; - uint32_t arg_rx = 0; - uint32_t arg_tx = 0; - uint32_t arg_lpm = 0; - uint32_t arg_rsz = 0; - uint32_t arg_bsz = 0; - uint32_t arg_pos_lb = 0; - - argvopt = argv; - - while ((opt = getopt_long(argc, argvopt, "", - lgopts, &option_index)) != EOF) { - - switch (opt) { - /* long options */ - case 0: - if (!strcmp(lgopts[option_index].name, "rx")) { - arg_rx = 1; - ret = parse_arg_rx(optarg); - if (ret) { - printf("Incorrect value for --rx argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "tx")) { - arg_tx = 1; - ret = parse_arg_tx(optarg); - if (ret) { - printf("Incorrect value for --tx argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "w")) { - arg_w = 1; - ret = parse_arg_w(optarg); - if (ret) { - printf("Incorrect value for --w argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "lpm")) { - arg_lpm = 1; - ret = parse_arg_lpm(optarg); - if (ret) { - printf("Incorrect value for --lpm argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "rsz")) { - arg_rsz = 1; - ret = parse_arg_rsz(optarg); - if (ret) { - printf("Incorrect value for --rsz argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "bsz")) { - arg_bsz = 1; - ret = parse_arg_bsz(optarg); - if (ret) { - printf("Incorrect value for --bsz argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "pos-lb")) { - arg_pos_lb = 1; - ret = parse_arg_pos_lb(optarg); - if (ret) { - printf("Incorrect value for --pos-lb argument (%d)\n", ret); - return -1; - } - } - break; - - default: - return -1; - } - } - - /* Check that all mandatory arguments are provided */ - if ((arg_rx == 0) || (arg_tx == 0) || (arg_w == 0) || (arg_lpm == 0)){ - printf("Not all mandatory arguments are present\n"); - return -1; - } - - /* Assign default values for the optional arguments not provided */ - if (arg_rsz == 0) { - app.nic_rx_ring_size = APP_DEFAULT_NIC_RX_RING_SIZE; - app.nic_tx_ring_size = APP_DEFAULT_NIC_TX_RING_SIZE; - app.ring_rx_size = APP_DEFAULT_RING_RX_SIZE; - app.ring_tx_size = APP_DEFAULT_RING_TX_SIZE; - } - - if (arg_bsz == 0) { - app.burst_size_io_rx_read = APP_DEFAULT_BURST_SIZE_IO_RX_READ; - app.burst_size_io_rx_write = APP_DEFAULT_BURST_SIZE_IO_RX_WRITE; - app.burst_size_io_tx_read = APP_DEFAULT_BURST_SIZE_IO_TX_READ; - app.burst_size_io_tx_write = APP_DEFAULT_BURST_SIZE_IO_TX_WRITE; - app.burst_size_worker_read = APP_DEFAULT_BURST_SIZE_WORKER_READ; - app.burst_size_worker_write = APP_DEFAULT_BURST_SIZE_WORKER_WRITE; - } - - if (arg_pos_lb == 0) { - app.pos_lb = APP_DEFAULT_IO_RX_LB_POS; - } - - /* Check cross-consistency of arguments */ - if ((ret = app_check_lpm_table()) < 0) { - printf("At least one LPM rule is inconsistent (%d)\n", ret); - return -1; - } - if (app_check_every_rx_port_is_tx_enabled() < 0) { - printf("On LPM lookup miss, packet is sent back on the input port.\n"); - printf("At least one RX port is not enabled for TX.\n"); - return -2; - } - - if (optind >= 0) - argv[optind - 1] = prgname; - - ret = optind - 1; - optind = 1; /* reset getopt lib */ - return ret; -} - -int -app_get_nic_rx_queues_per_port(uint16_t port) -{ - uint32_t i, count; - - if (port >= APP_MAX_NIC_PORTS) { - return -1; - } - - count = 0; - for (i = 0; i < APP_MAX_RX_QUEUES_PER_NIC_PORT; i ++) { - if (app.nic_rx_queue_mask[port][i] == 1) { - count ++; - } - } - - return count; -} - -int -app_get_lcore_for_nic_rx(uint16_t port, uint8_t queue, uint32_t *lcore_out) -{ - uint32_t lcore; - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - uint32_t i; - - if (app.lcore_params[lcore].type != e_APP_LCORE_IO) { - continue; - } - - const size_t n_queues = RTE_MIN(lp->rx.n_nic_queues, - RTE_DIM(lp->rx.nic_queues)); - for (i = 0; i < n_queues; i ++) { - if ((lp->rx.nic_queues[i].port == port) && - (lp->rx.nic_queues[i].queue == queue)) { - *lcore_out = lcore; - return 0; - } - } - } - - return -1; -} - -int -app_get_lcore_for_nic_tx(uint16_t port, uint32_t *lcore_out) -{ - uint32_t lcore; - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - uint32_t i; - - if (app.lcore_params[lcore].type != e_APP_LCORE_IO) { - continue; - } - - const size_t n_ports = RTE_MIN(lp->tx.n_nic_ports, - RTE_DIM(lp->tx.nic_ports)); - for (i = 0; i < n_ports; i ++) { - if (lp->tx.nic_ports[i] == port) { - *lcore_out = lcore; - return 0; - } - } - } - - return -1; -} - -int -app_is_socket_used(uint32_t socket) -{ - uint32_t lcore; - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - if (app.lcore_params[lcore].type == e_APP_LCORE_DISABLED) { - continue; - } - - if (socket == rte_lcore_to_socket_id(lcore)) { - return 1; - } - } - - return 0; -} - -uint32_t -app_get_lcores_io_rx(void) -{ - uint32_t lcore, count; - - count = 0; - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp_io = &app.lcore_params[lcore].io; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp_io->rx.n_nic_queues == 0)) { - continue; - } - - count ++; - } - - return count; -} - -uint32_t -app_get_lcores_worker(void) -{ - uint32_t lcore, count; - - count = 0; - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - count ++; - } - - if (count > APP_MAX_WORKER_LCORES) { - rte_panic("Algorithmic error (too many worker lcores)\n"); - return 0; - } - - return count; -} - -void -app_print_params(void) -{ - unsigned port, queue, lcore, rule, i, j; - - /* Print NIC RX configuration */ - printf("NIC RX ports: "); - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - uint32_t n_rx_queues = app_get_nic_rx_queues_per_port(port); - - if (n_rx_queues == 0) { - continue; - } - - printf("%u (", port); - for (queue = 0; queue < APP_MAX_RX_QUEUES_PER_NIC_PORT; queue ++) { - if (app.nic_rx_queue_mask[port][queue] == 1) { - printf("%u ", queue); - } - } - printf(") "); - } - printf(";\n"); - - /* Print I/O lcore RX params */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp->rx.n_nic_queues == 0)) { - continue; - } - - printf("I/O lcore %u (socket %u): ", lcore, rte_lcore_to_socket_id(lcore)); - - printf("RX ports "); - for (i = 0; i < lp->rx.n_nic_queues; i ++) { - printf("(%u, %u) ", - (unsigned) lp->rx.nic_queues[i].port, - (unsigned) lp->rx.nic_queues[i].queue); - } - printf("; "); - - printf("Output rings "); - for (i = 0; i < lp->rx.n_rings; i ++) { - printf("%p ", lp->rx.rings[i]); - } - printf(";\n"); - } - - /* Print worker lcore RX params */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp = &app.lcore_params[lcore].worker; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - printf("Worker lcore %u (socket %u) ID %u: ", - lcore, - rte_lcore_to_socket_id(lcore), - (unsigned)lp->worker_id); - - printf("Input rings "); - for (i = 0; i < lp->n_rings_in; i ++) { - printf("%p ", lp->rings_in[i]); - } - - printf(";\n"); - } - - printf("\n"); - - /* Print NIC TX configuration */ - printf("NIC TX ports: "); - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - if (app.nic_tx_port_mask[port] == 1) { - printf("%u ", port); - } - } - printf(";\n"); - - /* Print I/O TX lcore params */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - uint32_t n_workers = app_get_lcores_worker(); - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp->tx.n_nic_ports == 0)) { - continue; - } - - printf("I/O lcore %u (socket %u): ", lcore, rte_lcore_to_socket_id(lcore)); - - printf("Input rings per TX port "); - for (i = 0; i < lp->tx.n_nic_ports; i ++) { - port = lp->tx.nic_ports[i]; - - printf("%u (", port); - for (j = 0; j < n_workers; j ++) { - printf("%p ", lp->tx.rings[port][j]); - } - printf(") "); - - } - - printf(";\n"); - } - - /* Print worker lcore TX params */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp = &app.lcore_params[lcore].worker; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - printf("Worker lcore %u (socket %u) ID %u: \n", - lcore, - rte_lcore_to_socket_id(lcore), - (unsigned)lp->worker_id); - - printf("Output rings per TX port "); - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - if (lp->rings_out[port] != NULL) { - printf("%u (%p) ", port, lp->rings_out[port]); - } - } - - printf(";\n"); - } - - /* Print LPM rules */ - printf("LPM rules: \n"); - for (rule = 0; rule < app.n_lpm_rules; rule ++) { - uint32_t ip = app.lpm_rules[rule].ip; - uint8_t depth = app.lpm_rules[rule].depth; - uint8_t if_out = app.lpm_rules[rule].if_out; - - printf("\t%u: %u.%u.%u.%u/%u => %u;\n", - rule, - (unsigned) (ip & 0xFF000000) >> 24, - (unsigned) (ip & 0x00FF0000) >> 16, - (unsigned) (ip & 0x0000FF00) >> 8, - (unsigned) ip & 0x000000FF, - (unsigned) depth, - (unsigned) if_out - ); - } - - /* Rings */ - printf("Ring sizes: NIC RX = %u; Worker in = %u; Worker out = %u; NIC TX = %u;\n", - (unsigned) app.nic_rx_ring_size, - (unsigned) app.ring_rx_size, - (unsigned) app.ring_tx_size, - (unsigned) app.nic_tx_ring_size); - - /* Bursts */ - printf("Burst sizes: I/O RX (rd = %u, wr = %u); Worker (rd = %u, wr = %u); I/O TX (rd = %u, wr = %u)\n", - (unsigned) app.burst_size_io_rx_read, - (unsigned) app.burst_size_io_rx_write, - (unsigned) app.burst_size_worker_read, - (unsigned) app.burst_size_worker_write, - (unsigned) app.burst_size_io_tx_read, - (unsigned) app.burst_size_io_tx_write); -} diff --git a/examples/load_balancer/init.c b/examples/load_balancer/init.c deleted file mode 100644 index 3ab7d0211..000000000 --- a/examples/load_balancer/init.c +++ /dev/null @@ -1,520 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_ring.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_string_fns.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_lpm.h> - -#include "main.h" - -static struct rte_eth_conf port_conf = { - .rxmode = { - .mq_mode = ETH_MQ_RX_RSS, - .split_hdr_size = 0, - .offloads = DEV_RX_OFFLOAD_CHECKSUM, - }, - .rx_adv_conf = { - .rss_conf = { - .rss_key = NULL, - .rss_hf = ETH_RSS_IP, - }, - }, - .txmode = { - .mq_mode = ETH_MQ_TX_NONE, - }, -}; - -static void -app_assign_worker_ids(void) -{ - uint32_t lcore, worker_id; - - /* Assign ID for each worker */ - worker_id = 0; - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp_worker = &app.lcore_params[lcore].worker; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - lp_worker->worker_id = worker_id; - worker_id ++; - } -} - -static void -app_init_mbuf_pools(void) -{ - unsigned socket, lcore; - - /* Init the buffer pools */ - for (socket = 0; socket < APP_MAX_SOCKETS; socket ++) { - char name[32]; - if (app_is_socket_used(socket) == 0) { - continue; - } - - snprintf(name, sizeof(name), "mbuf_pool_%u", socket); - printf("Creating the mbuf pool for socket %u ...\n", socket); - app.pools[socket] = rte_pktmbuf_pool_create( - name, APP_DEFAULT_MEMPOOL_BUFFERS, - APP_DEFAULT_MEMPOOL_CACHE_SIZE, - 0, APP_DEFAULT_MBUF_DATA_SIZE, socket); - if (app.pools[socket] == NULL) { - rte_panic("Cannot create mbuf pool on socket %u\n", socket); - } - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - if (app.lcore_params[lcore].type == e_APP_LCORE_DISABLED) { - continue; - } - - socket = rte_lcore_to_socket_id(lcore); - app.lcore_params[lcore].pool = app.pools[socket]; - } -} - -static void -app_init_lpm_tables(void) -{ - unsigned socket, lcore; - - /* Init the LPM tables */ - for (socket = 0; socket < APP_MAX_SOCKETS; socket ++) { - char name[32]; - uint32_t rule; - - if (app_is_socket_used(socket) == 0) { - continue; - } - - struct rte_lpm_config lpm_config; - - lpm_config.max_rules = APP_MAX_LPM_RULES; - lpm_config.number_tbl8s = 256; - lpm_config.flags = 0; - snprintf(name, sizeof(name), "lpm_table_%u", socket); - printf("Creating the LPM table for socket %u ...\n", socket); - app.lpm_tables[socket] = rte_lpm_create( - name, - socket, - &lpm_config); - if (app.lpm_tables[socket] == NULL) { - rte_panic("Unable to create LPM table on socket %u\n", socket); - } - - for (rule = 0; rule < app.n_lpm_rules; rule ++) { - int ret; - - ret = rte_lpm_add(app.lpm_tables[socket], - app.lpm_rules[rule].ip, - app.lpm_rules[rule].depth, - app.lpm_rules[rule].if_out); - - if (ret < 0) { - rte_panic("Unable to add entry %u (%x/%u => %u) to the LPM table on socket %u (%d)\n", - (unsigned) rule, - (unsigned) app.lpm_rules[rule].ip, - (unsigned) app.lpm_rules[rule].depth, - (unsigned) app.lpm_rules[rule].if_out, - socket, - ret); - } - } - - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - socket = rte_lcore_to_socket_id(lcore); - app.lcore_params[lcore].worker.lpm_table = app.lpm_tables[socket]; - } -} - -static void -app_init_rings_rx(void) -{ - unsigned lcore; - - /* Initialize the rings for the RX side */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp_io = &app.lcore_params[lcore].io; - unsigned socket_io, lcore_worker; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp_io->rx.n_nic_queues == 0)) { - continue; - } - - socket_io = rte_lcore_to_socket_id(lcore); - - for (lcore_worker = 0; lcore_worker < APP_MAX_LCORES; lcore_worker ++) { - char name[32]; - struct app_lcore_params_worker *lp_worker = &app.lcore_params[lcore_worker].worker; - struct rte_ring *ring = NULL; - - if (app.lcore_params[lcore_worker].type != e_APP_LCORE_WORKER) { - continue; - } - - printf("Creating ring to connect I/O lcore %u (socket %u) with worker lcore %u ...\n", - lcore, - socket_io, - lcore_worker); - snprintf(name, sizeof(name), "app_ring_rx_s%u_io%u_w%u", - socket_io, - lcore, - lcore_worker); - ring = rte_ring_create( - name, - app.ring_rx_size, - socket_io, - RING_F_SP_ENQ | RING_F_SC_DEQ); - if (ring == NULL) { - rte_panic("Cannot create ring to connect I/O core %u with worker core %u\n", - lcore, - lcore_worker); - } - - lp_io->rx.rings[lp_io->rx.n_rings] = ring; - lp_io->rx.n_rings ++; - - lp_worker->rings_in[lp_worker->n_rings_in] = ring; - lp_worker->n_rings_in ++; - } - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp_io = &app.lcore_params[lcore].io; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp_io->rx.n_nic_queues == 0)) { - continue; - } - - if (lp_io->rx.n_rings != app_get_lcores_worker()) { - rte_panic("Algorithmic error (I/O RX rings)\n"); - } - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp_worker = &app.lcore_params[lcore].worker; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - if (lp_worker->n_rings_in != app_get_lcores_io_rx()) { - rte_panic("Algorithmic error (worker input rings)\n"); - } - } -} - -static void -app_init_rings_tx(void) -{ - unsigned lcore; - - /* Initialize the rings for the TX side */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp_worker = &app.lcore_params[lcore].worker; - unsigned port; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - char name[32]; - struct app_lcore_params_io *lp_io = NULL; - struct rte_ring *ring; - uint32_t socket_io, lcore_io; - - if (app.nic_tx_port_mask[port] == 0) { - continue; - } - - if (app_get_lcore_for_nic_tx(port, &lcore_io) < 0) { - rte_panic("Algorithmic error (no I/O core to handle TX of port %u)\n", - port); - } - - lp_io = &app.lcore_params[lcore_io].io; - socket_io = rte_lcore_to_socket_id(lcore_io); - - printf("Creating ring to connect worker lcore %u with TX port %u (through I/O lcore %u) (socket %u) ...\n", - lcore, port, (unsigned)lcore_io, (unsigned)socket_io); - snprintf(name, sizeof(name), "app_ring_tx_s%u_w%u_p%u", socket_io, lcore, port); - ring = rte_ring_create( - name, - app.ring_tx_size, - socket_io, - RING_F_SP_ENQ | RING_F_SC_DEQ); - if (ring == NULL) { - rte_panic("Cannot create ring to connect worker core %u with TX port %u\n", - lcore, - port); - } - - lp_worker->rings_out[port] = ring; - lp_io->tx.rings[port][lp_worker->worker_id] = ring; - } - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp_io = &app.lcore_params[lcore].io; - unsigned i; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp_io->tx.n_nic_ports == 0)) { - continue; - } - - for (i = 0; i < lp_io->tx.n_nic_ports; i ++){ - unsigned port, j; - - port = lp_io->tx.nic_ports[i]; - for (j = 0; j < app_get_lcores_worker(); j ++) { - if (lp_io->tx.rings[port][j] == NULL) { - rte_panic("Algorithmic error (I/O TX rings)\n"); - } - } - } - } -} - -/* Check the link status of all ports in up to 9s, and print them finally */ -static void -check_all_ports_link_status(uint16_t port_num, uint32_t port_mask) -{ -#define CHECK_INTERVAL 100 /* 100ms */ -#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ - uint16_t portid; - uint8_t count, all_ports_up, print_flag = 0; - struct rte_eth_link link; - uint32_t n_rx_queues, n_tx_queues; - - printf("\nChecking link status"); - fflush(stdout); - for (count = 0; count <= MAX_CHECK_TIME; count++) { - all_ports_up = 1; - for (portid = 0; portid < port_num; portid++) { - if ((port_mask & (1 << portid)) == 0) - continue; - n_rx_queues = app_get_nic_rx_queues_per_port(portid); - n_tx_queues = app.nic_tx_port_mask[portid]; - if ((n_rx_queues == 0) && (n_tx_queues == 0)) - continue; - memset(&link, 0, sizeof(link)); - rte_eth_link_get_nowait(portid, &link); - /* print link status if flag set */ - if (print_flag == 1) { - if (link.link_status) - printf( - "Port%d Link Up - speed %uMbps - %s\n", - portid, link.link_speed, - (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? - ("full-duplex") : ("half-duplex\n")); - else - printf("Port %d Link Down\n", portid); - continue; - } - /* clear all_ports_up flag if any link down */ - if (link.link_status == ETH_LINK_DOWN) { - all_ports_up = 0; - break; - } - } - /* after finally printing all link status, get out */ - if (print_flag == 1) - break; - - if (all_ports_up == 0) { - printf("."); - fflush(stdout); - rte_delay_ms(CHECK_INTERVAL); - } - - /* set the print_flag if all ports up or timeout */ - if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { - print_flag = 1; - printf("done\n"); - } - } -} - -static void -app_init_nics(void) -{ - unsigned socket; - uint32_t lcore; - uint16_t port; - uint8_t queue; - int ret; - uint32_t n_rx_queues, n_tx_queues; - - /* Init NIC ports and queues, then start the ports */ - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - struct rte_mempool *pool; - uint16_t nic_rx_ring_size; - uint16_t nic_tx_ring_size; - struct rte_eth_rxconf rxq_conf; - struct rte_eth_txconf txq_conf; - struct rte_eth_dev_info dev_info; - struct rte_eth_conf local_port_conf = port_conf; - - n_rx_queues = app_get_nic_rx_queues_per_port(port); - n_tx_queues = app.nic_tx_port_mask[port]; - - if ((n_rx_queues == 0) && (n_tx_queues == 0)) { - continue; - } - - /* Init port */ - printf("Initializing NIC port %u ...\n", port); - rte_eth_dev_info_get(port, &dev_info); - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - - local_port_conf.rx_adv_conf.rss_conf.rss_hf &= - dev_info.flow_type_rss_offloads; - if (local_port_conf.rx_adv_conf.rss_conf.rss_hf != - port_conf.rx_adv_conf.rss_conf.rss_hf) { - printf("Port %u modified RSS hash function based on hardware support," - "requested:%#"PRIx64" configured:%#"PRIx64"\n", - port, - port_conf.rx_adv_conf.rss_conf.rss_hf, - local_port_conf.rx_adv_conf.rss_conf.rss_hf); - } - - ret = rte_eth_dev_configure( - port, - (uint8_t) n_rx_queues, - (uint8_t) n_tx_queues, - &local_port_conf); - if (ret < 0) { - rte_panic("Cannot init NIC port %u (%d)\n", port, ret); - } - rte_eth_promiscuous_enable(port); - - nic_rx_ring_size = app.nic_rx_ring_size; - nic_tx_ring_size = app.nic_tx_ring_size; - ret = rte_eth_dev_adjust_nb_rx_tx_desc( - port, &nic_rx_ring_size, &nic_tx_ring_size); - if (ret < 0) { - rte_panic("Cannot adjust number of descriptors for port %u (%d)\n", - port, ret); - } - app.nic_rx_ring_size = nic_rx_ring_size; - app.nic_tx_ring_size = nic_tx_ring_size; - - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = local_port_conf.rxmode.offloads; - /* Init RX queues */ - for (queue = 0; queue < APP_MAX_RX_QUEUES_PER_NIC_PORT; queue ++) { - if (app.nic_rx_queue_mask[port][queue] == 0) { - continue; - } - - app_get_lcore_for_nic_rx(port, queue, &lcore); - socket = rte_lcore_to_socket_id(lcore); - pool = app.lcore_params[lcore].pool; - - printf("Initializing NIC port %u RX queue %u ...\n", - port, queue); - ret = rte_eth_rx_queue_setup( - port, - queue, - (uint16_t) app.nic_rx_ring_size, - socket, - &rxq_conf, - pool); - if (ret < 0) { - rte_panic("Cannot init RX queue %u for port %u (%d)\n", - queue, port, ret); - } - } - - txq_conf = dev_info.default_txconf; - txq_conf.offloads = local_port_conf.txmode.offloads; - /* Init TX queues */ - if (app.nic_tx_port_mask[port] == 1) { - app_get_lcore_for_nic_tx(port, &lcore); - socket = rte_lcore_to_socket_id(lcore); - printf("Initializing NIC port %u TX queue 0 ...\n", - port); - ret = rte_eth_tx_queue_setup( - port, - 0, - (uint16_t) app.nic_tx_ring_size, - socket, - &txq_conf); - if (ret < 0) { - rte_panic("Cannot init TX queue 0 for port %d (%d)\n", - port, - ret); - } - } - - /* Start port */ - ret = rte_eth_dev_start(port); - if (ret < 0) { - rte_panic("Cannot start port %d (%d)\n", port, ret); - } - } - - check_all_ports_link_status(APP_MAX_NIC_PORTS, (~0x0)); -} - -void -app_init(void) -{ - app_assign_worker_ids(); - app_init_mbuf_pools(); - app_init_lpm_tables(); - app_init_rings_rx(); - app_init_rings_tx(); - app_init_nics(); - - printf("Initialization completed.\n"); -} diff --git a/examples/load_balancer/main.c b/examples/load_balancer/main.c deleted file mode 100644 index d3dcb235d..000000000 --- a/examples/load_balancer/main.c +++ /dev/null @@ -1,76 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> -#include <unistd.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_lpm.h> - -#include "main.h" - -int -main(int argc, char **argv) -{ - uint32_t lcore; - int ret; - - /* Init EAL */ - ret = rte_eal_init(argc, argv); - if (ret < 0) - return -1; - argc -= ret; - argv += ret; - - /* Parse application arguments (after the EAL ones) */ - ret = app_parse_args(argc, argv); - if (ret < 0) { - app_print_usage(); - return -1; - } - - /* Init */ - app_init(); - app_print_params(); - - /* Launch per-lcore init on every lcore */ - rte_eal_mp_remote_launch(app_lcore_main_loop, NULL, CALL_MASTER); - RTE_LCORE_FOREACH_SLAVE(lcore) { - if (rte_eal_wait_lcore(lcore) < 0) { - return -1; - } - } - - return 0; -} diff --git a/examples/load_balancer/main.h b/examples/load_balancer/main.h deleted file mode 100644 index 9fefb62ed..000000000 --- a/examples/load_balancer/main.h +++ /dev/null @@ -1,351 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _MAIN_H_ -#define _MAIN_H_ - -/* Logical cores */ -#ifndef APP_MAX_SOCKETS -#define APP_MAX_SOCKETS 2 -#endif - -#ifndef APP_MAX_LCORES -#define APP_MAX_LCORES RTE_MAX_LCORE -#endif - -#ifndef APP_MAX_NIC_PORTS -#define APP_MAX_NIC_PORTS RTE_MAX_ETHPORTS -#endif - -#ifndef APP_MAX_RX_QUEUES_PER_NIC_PORT -#define APP_MAX_RX_QUEUES_PER_NIC_PORT 128 -#endif - -#ifndef APP_MAX_TX_QUEUES_PER_NIC_PORT -#define APP_MAX_TX_QUEUES_PER_NIC_PORT 128 -#endif - -#ifndef APP_MAX_IO_LCORES -#if (APP_MAX_LCORES > 16) -#define APP_MAX_IO_LCORES 16 -#else -#define APP_MAX_IO_LCORES APP_MAX_LCORES -#endif -#endif -#if (APP_MAX_IO_LCORES > APP_MAX_LCORES) -#error "APP_MAX_IO_LCORES is too big" -#endif - -#ifndef APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE -#define APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE 16 -#endif - -#ifndef APP_MAX_NIC_TX_PORTS_PER_IO_LCORE -#define APP_MAX_NIC_TX_PORTS_PER_IO_LCORE 16 -#endif -#if (APP_MAX_NIC_TX_PORTS_PER_IO_LCORE > APP_MAX_NIC_PORTS) -#error "APP_MAX_NIC_TX_PORTS_PER_IO_LCORE too big" -#endif - -#ifndef APP_MAX_WORKER_LCORES -#if (APP_MAX_LCORES > 16) -#define APP_MAX_WORKER_LCORES 16 -#else -#define APP_MAX_WORKER_LCORES APP_MAX_LCORES -#endif -#endif -#if (APP_MAX_WORKER_LCORES > APP_MAX_LCORES) -#error "APP_MAX_WORKER_LCORES is too big" -#endif - - -/* Mempools */ -#ifndef APP_DEFAULT_MBUF_DATA_SIZE -#define APP_DEFAULT_MBUF_DATA_SIZE RTE_MBUF_DEFAULT_BUF_SIZE -#endif - -#ifndef APP_DEFAULT_MEMPOOL_BUFFERS -#define APP_DEFAULT_MEMPOOL_BUFFERS 8192 * 4 -#endif - -#ifndef APP_DEFAULT_MEMPOOL_CACHE_SIZE -#define APP_DEFAULT_MEMPOOL_CACHE_SIZE 256 -#endif - -/* LPM Tables */ -#ifndef APP_MAX_LPM_RULES -#define APP_MAX_LPM_RULES 1024 -#endif - -/* NIC RX */ -#ifndef APP_DEFAULT_NIC_RX_RING_SIZE -#define APP_DEFAULT_NIC_RX_RING_SIZE 1024 -#endif - -/* - * RX and TX Prefetch, Host, and Write-back threshold values should be - * carefully set for optimal performance. Consult the network - * controller's datasheet and supporting DPDK documentation for guidance - * on how these parameters should be set. - */ -#ifndef APP_DEFAULT_NIC_RX_PTHRESH -#define APP_DEFAULT_NIC_RX_PTHRESH 8 -#endif - -#ifndef APP_DEFAULT_NIC_RX_HTHRESH -#define APP_DEFAULT_NIC_RX_HTHRESH 8 -#endif - -#ifndef APP_DEFAULT_NIC_RX_WTHRESH -#define APP_DEFAULT_NIC_RX_WTHRESH 4 -#endif - -#ifndef APP_DEFAULT_NIC_RX_FREE_THRESH -#define APP_DEFAULT_NIC_RX_FREE_THRESH 64 -#endif - -#ifndef APP_DEFAULT_NIC_RX_DROP_EN -#define APP_DEFAULT_NIC_RX_DROP_EN 0 -#endif - -/* NIC TX */ -#ifndef APP_DEFAULT_NIC_TX_RING_SIZE -#define APP_DEFAULT_NIC_TX_RING_SIZE 1024 -#endif - -/* - * These default values are optimized for use with the Intel(R) 82599 10 GbE - * Controller and the DPDK ixgbe PMD. Consider using other values for other - * network controllers and/or network drivers. - */ -#ifndef APP_DEFAULT_NIC_TX_PTHRESH -#define APP_DEFAULT_NIC_TX_PTHRESH 36 -#endif - -#ifndef APP_DEFAULT_NIC_TX_HTHRESH -#define APP_DEFAULT_NIC_TX_HTHRESH 0 -#endif - -#ifndef APP_DEFAULT_NIC_TX_WTHRESH -#define APP_DEFAULT_NIC_TX_WTHRESH 0 -#endif - -#ifndef APP_DEFAULT_NIC_TX_FREE_THRESH -#define APP_DEFAULT_NIC_TX_FREE_THRESH 0 -#endif - -#ifndef APP_DEFAULT_NIC_TX_RS_THRESH -#define APP_DEFAULT_NIC_TX_RS_THRESH 0 -#endif - -/* Software Rings */ -#ifndef APP_DEFAULT_RING_RX_SIZE -#define APP_DEFAULT_RING_RX_SIZE 1024 -#endif - -#ifndef APP_DEFAULT_RING_TX_SIZE -#define APP_DEFAULT_RING_TX_SIZE 1024 -#endif - -/* Bursts */ -#ifndef APP_MBUF_ARRAY_SIZE -#define APP_MBUF_ARRAY_SIZE 512 -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_IO_RX_READ -#define APP_DEFAULT_BURST_SIZE_IO_RX_READ 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_IO_RX_READ > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_IO_RX_READ is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_IO_RX_WRITE -#define APP_DEFAULT_BURST_SIZE_IO_RX_WRITE 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_IO_RX_WRITE > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_IO_RX_WRITE is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_IO_TX_READ -#define APP_DEFAULT_BURST_SIZE_IO_TX_READ 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_IO_TX_READ > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_IO_TX_READ is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_IO_TX_WRITE -#define APP_DEFAULT_BURST_SIZE_IO_TX_WRITE 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_IO_TX_WRITE > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_IO_TX_WRITE is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_WORKER_READ -#define APP_DEFAULT_BURST_SIZE_WORKER_READ 144 -#endif -#if ((2 * APP_DEFAULT_BURST_SIZE_WORKER_READ) > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_WORKER_READ is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_WORKER_WRITE -#define APP_DEFAULT_BURST_SIZE_WORKER_WRITE 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_WORKER_WRITE > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_WORKER_WRITE is too big" -#endif - -/* Load balancing logic */ -#ifndef APP_DEFAULT_IO_RX_LB_POS -#define APP_DEFAULT_IO_RX_LB_POS 29 -#endif -#if (APP_DEFAULT_IO_RX_LB_POS >= 64) -#error "APP_DEFAULT_IO_RX_LB_POS is too big" -#endif - -struct app_mbuf_array { - struct rte_mbuf *array[APP_MBUF_ARRAY_SIZE]; - uint32_t n_mbufs; -}; - -enum app_lcore_type { - e_APP_LCORE_DISABLED = 0, - e_APP_LCORE_IO, - e_APP_LCORE_WORKER -}; - -struct app_lcore_params_io { - /* I/O RX */ - struct { - /* NIC */ - struct { - uint16_t port; - uint8_t queue; - } nic_queues[APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE]; - uint32_t n_nic_queues; - - /* Rings */ - struct rte_ring *rings[APP_MAX_WORKER_LCORES]; - uint32_t n_rings; - - /* Internal buffers */ - struct app_mbuf_array mbuf_in; - struct app_mbuf_array mbuf_out[APP_MAX_WORKER_LCORES]; - uint8_t mbuf_out_flush[APP_MAX_WORKER_LCORES]; - - /* Stats */ - uint32_t nic_queues_count[APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE]; - uint32_t nic_queues_iters[APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE]; - uint32_t rings_count[APP_MAX_WORKER_LCORES]; - uint32_t rings_iters[APP_MAX_WORKER_LCORES]; - } rx; - - /* I/O TX */ - struct { - /* Rings */ - struct rte_ring *rings[APP_MAX_NIC_PORTS][APP_MAX_WORKER_LCORES]; - - /* NIC */ - uint16_t nic_ports[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - uint32_t n_nic_ports; - - /* Internal buffers */ - struct app_mbuf_array mbuf_out[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - uint8_t mbuf_out_flush[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - - /* Stats */ - uint32_t rings_count[APP_MAX_NIC_PORTS][APP_MAX_WORKER_LCORES]; - uint32_t rings_iters[APP_MAX_NIC_PORTS][APP_MAX_WORKER_LCORES]; - uint32_t nic_ports_count[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - uint32_t nic_ports_iters[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - } tx; -}; - -struct app_lcore_params_worker { - /* Rings */ - struct rte_ring *rings_in[APP_MAX_IO_LCORES]; - uint32_t n_rings_in; - struct rte_ring *rings_out[APP_MAX_NIC_PORTS]; - - /* LPM table */ - struct rte_lpm *lpm_table; - uint32_t worker_id; - - /* Internal buffers */ - struct app_mbuf_array mbuf_in; - struct app_mbuf_array mbuf_out[APP_MAX_NIC_PORTS]; - uint8_t mbuf_out_flush[APP_MAX_NIC_PORTS]; - - /* Stats */ - uint32_t rings_in_count[APP_MAX_IO_LCORES]; - uint32_t rings_in_iters[APP_MAX_IO_LCORES]; - uint32_t rings_out_count[APP_MAX_NIC_PORTS]; - uint32_t rings_out_iters[APP_MAX_NIC_PORTS]; -}; - -struct app_lcore_params { - union { - struct app_lcore_params_io io; - struct app_lcore_params_worker worker; - }; - enum app_lcore_type type; - struct rte_mempool *pool; -} __rte_cache_aligned; - -struct app_lpm_rule { - uint32_t ip; - uint8_t depth; - uint8_t if_out; -}; - -struct app_params { - /* lcore */ - struct app_lcore_params lcore_params[APP_MAX_LCORES]; - - /* NIC */ - uint8_t nic_rx_queue_mask[APP_MAX_NIC_PORTS][APP_MAX_RX_QUEUES_PER_NIC_PORT]; - uint8_t nic_tx_port_mask[APP_MAX_NIC_PORTS]; - - /* mbuf pools */ - struct rte_mempool *pools[APP_MAX_SOCKETS]; - - /* LPM tables */ - struct rte_lpm *lpm_tables[APP_MAX_SOCKETS]; - struct app_lpm_rule lpm_rules[APP_MAX_LPM_RULES]; - uint32_t n_lpm_rules; - - /* rings */ - uint32_t nic_rx_ring_size; - uint32_t nic_tx_ring_size; - uint32_t ring_rx_size; - uint32_t ring_tx_size; - - /* burst size */ - uint32_t burst_size_io_rx_read; - uint32_t burst_size_io_rx_write; - uint32_t burst_size_io_tx_read; - uint32_t burst_size_io_tx_write; - uint32_t burst_size_worker_read; - uint32_t burst_size_worker_write; - - /* load balancing */ - uint8_t pos_lb; -} __rte_cache_aligned; - -extern struct app_params app; - -int app_parse_args(int argc, char **argv); -void app_print_usage(void); -void app_init(void); -int app_lcore_main_loop(void *arg); - -int app_get_nic_rx_queues_per_port(uint16_t port); -int app_get_lcore_for_nic_rx(uint16_t port, uint8_t queue, - uint32_t *lcore_out); -int app_get_lcore_for_nic_tx(uint16_t port, uint32_t *lcore_out); -int app_is_socket_used(uint32_t socket); -uint32_t app_get_lcores_io_rx(void); -uint32_t app_get_lcores_worker(void); -void app_print_params(void); - -#endif /* _MAIN_H_ */ diff --git a/examples/load_balancer/meson.build b/examples/load_balancer/meson.build deleted file mode 100644 index 4f7ac3999..000000000 --- a/examples/load_balancer/meson.build +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2017 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' - -deps += 'lpm' -sources = files( - 'config.c', 'init.c', 'main.c', 'runtime.c' -) diff --git a/examples/load_balancer/runtime.c b/examples/load_balancer/runtime.c deleted file mode 100644 index f0aad1513..000000000 --- a/examples/load_balancer/runtime.c +++ /dev/null @@ -1,642 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_ring.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_lpm.h> - -#include "main.h" - -#ifndef APP_LCORE_IO_FLUSH -#define APP_LCORE_IO_FLUSH 1000000 -#endif - -#ifndef APP_LCORE_WORKER_FLUSH -#define APP_LCORE_WORKER_FLUSH 1000000 -#endif - -#ifndef APP_STATS -#define APP_STATS 1000000 -#endif - -#define APP_IO_RX_DROP_ALL_PACKETS 0 -#define APP_WORKER_DROP_ALL_PACKETS 0 -#define APP_IO_TX_DROP_ALL_PACKETS 0 - -#ifndef APP_IO_RX_PREFETCH_ENABLE -#define APP_IO_RX_PREFETCH_ENABLE 1 -#endif - -#ifndef APP_WORKER_PREFETCH_ENABLE -#define APP_WORKER_PREFETCH_ENABLE 1 -#endif - -#ifndef APP_IO_TX_PREFETCH_ENABLE -#define APP_IO_TX_PREFETCH_ENABLE 1 -#endif - -#if APP_IO_RX_PREFETCH_ENABLE -#define APP_IO_RX_PREFETCH0(p) rte_prefetch0(p) -#define APP_IO_RX_PREFETCH1(p) rte_prefetch1(p) -#else -#define APP_IO_RX_PREFETCH0(p) -#define APP_IO_RX_PREFETCH1(p) -#endif - -#if APP_WORKER_PREFETCH_ENABLE -#define APP_WORKER_PREFETCH0(p) rte_prefetch0(p) -#define APP_WORKER_PREFETCH1(p) rte_prefetch1(p) -#else -#define APP_WORKER_PREFETCH0(p) -#define APP_WORKER_PREFETCH1(p) -#endif - -#if APP_IO_TX_PREFETCH_ENABLE -#define APP_IO_TX_PREFETCH0(p) rte_prefetch0(p) -#define APP_IO_TX_PREFETCH1(p) rte_prefetch1(p) -#else -#define APP_IO_TX_PREFETCH0(p) -#define APP_IO_TX_PREFETCH1(p) -#endif - -static inline void -app_lcore_io_rx_buffer_to_send ( - struct app_lcore_params_io *lp, - uint32_t worker, - struct rte_mbuf *mbuf, - uint32_t bsz) -{ - uint32_t pos; - int ret; - - pos = lp->rx.mbuf_out[worker].n_mbufs; - lp->rx.mbuf_out[worker].array[pos ++] = mbuf; - if (likely(pos < bsz)) { - lp->rx.mbuf_out[worker].n_mbufs = pos; - return; - } - - ret = rte_ring_sp_enqueue_bulk( - lp->rx.rings[worker], - (void **) lp->rx.mbuf_out[worker].array, - bsz, - NULL); - - if (unlikely(ret == 0)) { - uint32_t k; - for (k = 0; k < bsz; k ++) { - struct rte_mbuf *m = lp->rx.mbuf_out[worker].array[k]; - rte_pktmbuf_free(m); - } - } - - lp->rx.mbuf_out[worker].n_mbufs = 0; - lp->rx.mbuf_out_flush[worker] = 0; - -#if APP_STATS - lp->rx.rings_iters[worker] ++; - if (likely(ret == 0)) { - lp->rx.rings_count[worker] ++; - } - if (unlikely(lp->rx.rings_iters[worker] == APP_STATS)) { - unsigned lcore = rte_lcore_id(); - - printf("\tI/O RX %u out (worker %u): enq success rate = %.2f\n", - lcore, - (unsigned)worker, - ((double) lp->rx.rings_count[worker]) / ((double) lp->rx.rings_iters[worker])); - lp->rx.rings_iters[worker] = 0; - lp->rx.rings_count[worker] = 0; - } -#endif -} - -static inline void -app_lcore_io_rx( - struct app_lcore_params_io *lp, - uint32_t n_workers, - uint32_t bsz_rd, - uint32_t bsz_wr, - uint8_t pos_lb) -{ - struct rte_mbuf *mbuf_1_0, *mbuf_1_1, *mbuf_2_0, *mbuf_2_1; - uint8_t *data_1_0, *data_1_1 = NULL; - uint32_t i; - - for (i = 0; i < lp->rx.n_nic_queues; i ++) { - uint16_t port = lp->rx.nic_queues[i].port; - uint8_t queue = lp->rx.nic_queues[i].queue; - uint32_t n_mbufs, j; - - n_mbufs = rte_eth_rx_burst( - port, - queue, - lp->rx.mbuf_in.array, - (uint16_t) bsz_rd); - - if (unlikely(n_mbufs == 0)) { - continue; - } - -#if APP_STATS - lp->rx.nic_queues_iters[i] ++; - lp->rx.nic_queues_count[i] += n_mbufs; - if (unlikely(lp->rx.nic_queues_iters[i] == APP_STATS)) { - struct rte_eth_stats stats; - unsigned lcore = rte_lcore_id(); - - rte_eth_stats_get(port, &stats); - - printf("I/O RX %u in (NIC port %u): NIC drop ratio = %.2f avg burst size = %.2f\n", - lcore, - port, - (double) stats.imissed / (double) (stats.imissed + stats.ipackets), - ((double) lp->rx.nic_queues_count[i]) / ((double) lp->rx.nic_queues_iters[i])); - lp->rx.nic_queues_iters[i] = 0; - lp->rx.nic_queues_count[i] = 0; - } -#endif - -#if APP_IO_RX_DROP_ALL_PACKETS - for (j = 0; j < n_mbufs; j ++) { - struct rte_mbuf *pkt = lp->rx.mbuf_in.array[j]; - rte_pktmbuf_free(pkt); - } - - continue; -#endif - - mbuf_1_0 = lp->rx.mbuf_in.array[0]; - mbuf_1_1 = lp->rx.mbuf_in.array[1]; - data_1_0 = rte_pktmbuf_mtod(mbuf_1_0, uint8_t *); - if (likely(n_mbufs > 1)) { - data_1_1 = rte_pktmbuf_mtod(mbuf_1_1, uint8_t *); - } - - mbuf_2_0 = lp->rx.mbuf_in.array[2]; - mbuf_2_1 = lp->rx.mbuf_in.array[3]; - APP_IO_RX_PREFETCH0(mbuf_2_0); - APP_IO_RX_PREFETCH0(mbuf_2_1); - - for (j = 0; j + 3 < n_mbufs; j += 2) { - struct rte_mbuf *mbuf_0_0, *mbuf_0_1; - uint8_t *data_0_0, *data_0_1; - uint32_t worker_0, worker_1; - - mbuf_0_0 = mbuf_1_0; - mbuf_0_1 = mbuf_1_1; - data_0_0 = data_1_0; - data_0_1 = data_1_1; - - mbuf_1_0 = mbuf_2_0; - mbuf_1_1 = mbuf_2_1; - data_1_0 = rte_pktmbuf_mtod(mbuf_2_0, uint8_t *); - data_1_1 = rte_pktmbuf_mtod(mbuf_2_1, uint8_t *); - APP_IO_RX_PREFETCH0(data_1_0); - APP_IO_RX_PREFETCH0(data_1_1); - - mbuf_2_0 = lp->rx.mbuf_in.array[j+4]; - mbuf_2_1 = lp->rx.mbuf_in.array[j+5]; - APP_IO_RX_PREFETCH0(mbuf_2_0); - APP_IO_RX_PREFETCH0(mbuf_2_1); - - worker_0 = data_0_0[pos_lb] & (n_workers - 1); - worker_1 = data_0_1[pos_lb] & (n_workers - 1); - - app_lcore_io_rx_buffer_to_send(lp, worker_0, mbuf_0_0, bsz_wr); - app_lcore_io_rx_buffer_to_send(lp, worker_1, mbuf_0_1, bsz_wr); - } - - /* Handle the last 1, 2 (when n_mbufs is even) or 3 (when n_mbufs is odd) packets */ - for ( ; j < n_mbufs; j += 1) { - struct rte_mbuf *mbuf; - uint8_t *data; - uint32_t worker; - - mbuf = mbuf_1_0; - mbuf_1_0 = mbuf_1_1; - mbuf_1_1 = mbuf_2_0; - mbuf_2_0 = mbuf_2_1; - - data = rte_pktmbuf_mtod(mbuf, uint8_t *); - - APP_IO_RX_PREFETCH0(mbuf_1_0); - - worker = data[pos_lb] & (n_workers - 1); - - app_lcore_io_rx_buffer_to_send(lp, worker, mbuf, bsz_wr); - } - } -} - -static inline void -app_lcore_io_rx_flush(struct app_lcore_params_io *lp, uint32_t n_workers) -{ - uint32_t worker; - - for (worker = 0; worker < n_workers; worker ++) { - int ret; - - if (likely((lp->rx.mbuf_out_flush[worker] == 0) || - (lp->rx.mbuf_out[worker].n_mbufs == 0))) { - lp->rx.mbuf_out_flush[worker] = 1; - continue; - } - - ret = rte_ring_sp_enqueue_bulk( - lp->rx.rings[worker], - (void **) lp->rx.mbuf_out[worker].array, - lp->rx.mbuf_out[worker].n_mbufs, - NULL); - - if (unlikely(ret == 0)) { - uint32_t k; - for (k = 0; k < lp->rx.mbuf_out[worker].n_mbufs; k ++) { - struct rte_mbuf *pkt_to_free = lp->rx.mbuf_out[worker].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - - lp->rx.mbuf_out[worker].n_mbufs = 0; - lp->rx.mbuf_out_flush[worker] = 1; - } -} - -static inline void -app_lcore_io_tx( - struct app_lcore_params_io *lp, - uint32_t n_workers, - uint32_t bsz_rd, - uint32_t bsz_wr) -{ - uint32_t worker; - - for (worker = 0; worker < n_workers; worker ++) { - uint32_t i; - - for (i = 0; i < lp->tx.n_nic_ports; i ++) { - uint16_t port = lp->tx.nic_ports[i]; - struct rte_ring *ring = lp->tx.rings[port][worker]; - uint32_t n_mbufs, n_pkts; - int ret; - - n_mbufs = lp->tx.mbuf_out[port].n_mbufs; - ret = rte_ring_sc_dequeue_bulk( - ring, - (void **) &lp->tx.mbuf_out[port].array[n_mbufs], - bsz_rd, - NULL); - - if (unlikely(ret == 0)) - continue; - - n_mbufs += bsz_rd; - -#if APP_IO_TX_DROP_ALL_PACKETS - { - uint32_t j; - APP_IO_TX_PREFETCH0(lp->tx.mbuf_out[port].array[0]); - APP_IO_TX_PREFETCH0(lp->tx.mbuf_out[port].array[1]); - - for (j = 0; j < n_mbufs; j ++) { - if (likely(j < n_mbufs - 2)) { - APP_IO_TX_PREFETCH0(lp->tx.mbuf_out[port].array[j + 2]); - } - - rte_pktmbuf_free(lp->tx.mbuf_out[port].array[j]); - } - - lp->tx.mbuf_out[port].n_mbufs = 0; - - continue; - } -#endif - - if (unlikely(n_mbufs < bsz_wr)) { - lp->tx.mbuf_out[port].n_mbufs = n_mbufs; - continue; - } - - n_pkts = rte_eth_tx_burst( - port, - 0, - lp->tx.mbuf_out[port].array, - (uint16_t) n_mbufs); - -#if APP_STATS - lp->tx.nic_ports_iters[port] ++; - lp->tx.nic_ports_count[port] += n_pkts; - if (unlikely(lp->tx.nic_ports_iters[port] == APP_STATS)) { - unsigned lcore = rte_lcore_id(); - - printf("\t\t\tI/O TX %u out (port %u): avg burst size = %.2f\n", - lcore, - port, - ((double) lp->tx.nic_ports_count[port]) / ((double) lp->tx.nic_ports_iters[port])); - lp->tx.nic_ports_iters[port] = 0; - lp->tx.nic_ports_count[port] = 0; - } -#endif - - if (unlikely(n_pkts < n_mbufs)) { - uint32_t k; - for (k = n_pkts; k < n_mbufs; k ++) { - struct rte_mbuf *pkt_to_free = lp->tx.mbuf_out[port].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - lp->tx.mbuf_out[port].n_mbufs = 0; - lp->tx.mbuf_out_flush[port] = 0; - } - } -} - -static inline void -app_lcore_io_tx_flush(struct app_lcore_params_io *lp) -{ - uint16_t port; - uint32_t i; - - for (i = 0; i < lp->tx.n_nic_ports; i++) { - uint32_t n_pkts; - - port = lp->tx.nic_ports[i]; - if (likely((lp->tx.mbuf_out_flush[port] == 0) || - (lp->tx.mbuf_out[port].n_mbufs == 0))) { - lp->tx.mbuf_out_flush[port] = 1; - continue; - } - - n_pkts = rte_eth_tx_burst( - port, - 0, - lp->tx.mbuf_out[port].array, - (uint16_t) lp->tx.mbuf_out[port].n_mbufs); - - if (unlikely(n_pkts < lp->tx.mbuf_out[port].n_mbufs)) { - uint32_t k; - for (k = n_pkts; k < lp->tx.mbuf_out[port].n_mbufs; k ++) { - struct rte_mbuf *pkt_to_free = lp->tx.mbuf_out[port].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - - lp->tx.mbuf_out[port].n_mbufs = 0; - lp->tx.mbuf_out_flush[port] = 1; - } -} - -static void -app_lcore_main_loop_io(void) -{ - uint32_t lcore = rte_lcore_id(); - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - uint32_t n_workers = app_get_lcores_worker(); - uint64_t i = 0; - - uint32_t bsz_rx_rd = app.burst_size_io_rx_read; - uint32_t bsz_rx_wr = app.burst_size_io_rx_write; - uint32_t bsz_tx_rd = app.burst_size_io_tx_read; - uint32_t bsz_tx_wr = app.burst_size_io_tx_write; - - uint8_t pos_lb = app.pos_lb; - - for ( ; ; ) { - if (APP_LCORE_IO_FLUSH && (unlikely(i == APP_LCORE_IO_FLUSH))) { - if (likely(lp->rx.n_nic_queues > 0)) { - app_lcore_io_rx_flush(lp, n_workers); - } - - if (likely(lp->tx.n_nic_ports > 0)) { - app_lcore_io_tx_flush(lp); - } - - i = 0; - } - - if (likely(lp->rx.n_nic_queues > 0)) { - app_lcore_io_rx(lp, n_workers, bsz_rx_rd, bsz_rx_wr, pos_lb); - } - - if (likely(lp->tx.n_nic_ports > 0)) { - app_lcore_io_tx(lp, n_workers, bsz_tx_rd, bsz_tx_wr); - } - - i ++; - } -} - -static inline void -app_lcore_worker( - struct app_lcore_params_worker *lp, - uint32_t bsz_rd, - uint32_t bsz_wr) -{ - uint32_t i; - - for (i = 0; i < lp->n_rings_in; i ++) { - struct rte_ring *ring_in = lp->rings_in[i]; - uint32_t j; - int ret; - - ret = rte_ring_sc_dequeue_bulk( - ring_in, - (void **) lp->mbuf_in.array, - bsz_rd, - NULL); - - if (unlikely(ret == 0)) - continue; - -#if APP_WORKER_DROP_ALL_PACKETS - for (j = 0; j < bsz_rd; j ++) { - struct rte_mbuf *pkt = lp->mbuf_in.array[j]; - rte_pktmbuf_free(pkt); - } - - continue; -#endif - - APP_WORKER_PREFETCH1(rte_pktmbuf_mtod(lp->mbuf_in.array[0], unsigned char *)); - APP_WORKER_PREFETCH0(lp->mbuf_in.array[1]); - - for (j = 0; j < bsz_rd; j ++) { - struct rte_mbuf *pkt; - struct rte_ipv4_hdr *ipv4_hdr; - uint32_t ipv4_dst, pos; - uint32_t port; - - if (likely(j < bsz_rd - 1)) { - APP_WORKER_PREFETCH1(rte_pktmbuf_mtod(lp->mbuf_in.array[j+1], unsigned char *)); - } - if (likely(j < bsz_rd - 2)) { - APP_WORKER_PREFETCH0(lp->mbuf_in.array[j+2]); - } - - pkt = lp->mbuf_in.array[j]; - ipv4_hdr = rte_pktmbuf_mtod_offset( - pkt, struct rte_ipv4_hdr *, - sizeof(struct rte_ether_hdr)); - ipv4_dst = rte_be_to_cpu_32(ipv4_hdr->dst_addr); - - if (unlikely(rte_lpm_lookup(lp->lpm_table, ipv4_dst, &port) != 0)) { - port = pkt->port; - } - - pos = lp->mbuf_out[port].n_mbufs; - - lp->mbuf_out[port].array[pos ++] = pkt; - if (likely(pos < bsz_wr)) { - lp->mbuf_out[port].n_mbufs = pos; - continue; - } - - ret = rte_ring_sp_enqueue_bulk( - lp->rings_out[port], - (void **) lp->mbuf_out[port].array, - bsz_wr, - NULL); - -#if APP_STATS - lp->rings_out_iters[port] ++; - if (ret > 0) { - lp->rings_out_count[port] += 1; - } - if (lp->rings_out_iters[port] == APP_STATS){ - printf("\t\tWorker %u out (NIC port %u): enq success rate = %.2f\n", - (unsigned) lp->worker_id, - port, - ((double) lp->rings_out_count[port]) / ((double) lp->rings_out_iters[port])); - lp->rings_out_iters[port] = 0; - lp->rings_out_count[port] = 0; - } -#endif - - if (unlikely(ret == 0)) { - uint32_t k; - for (k = 0; k < bsz_wr; k ++) { - struct rte_mbuf *pkt_to_free = lp->mbuf_out[port].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - - lp->mbuf_out[port].n_mbufs = 0; - lp->mbuf_out_flush[port] = 0; - } - } -} - -static inline void -app_lcore_worker_flush(struct app_lcore_params_worker *lp) -{ - uint32_t port; - - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - int ret; - - if (unlikely(lp->rings_out[port] == NULL)) { - continue; - } - - if (likely((lp->mbuf_out_flush[port] == 0) || - (lp->mbuf_out[port].n_mbufs == 0))) { - lp->mbuf_out_flush[port] = 1; - continue; - } - - ret = rte_ring_sp_enqueue_bulk( - lp->rings_out[port], - (void **) lp->mbuf_out[port].array, - lp->mbuf_out[port].n_mbufs, - NULL); - - if (unlikely(ret == 0)) { - uint32_t k; - for (k = 0; k < lp->mbuf_out[port].n_mbufs; k ++) { - struct rte_mbuf *pkt_to_free = lp->mbuf_out[port].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - - lp->mbuf_out[port].n_mbufs = 0; - lp->mbuf_out_flush[port] = 1; - } -} - -static void -app_lcore_main_loop_worker(void) { - uint32_t lcore = rte_lcore_id(); - struct app_lcore_params_worker *lp = &app.lcore_params[lcore].worker; - uint64_t i = 0; - - uint32_t bsz_rd = app.burst_size_worker_read; - uint32_t bsz_wr = app.burst_size_worker_write; - - for ( ; ; ) { - if (APP_LCORE_WORKER_FLUSH && (unlikely(i == APP_LCORE_WORKER_FLUSH))) { - app_lcore_worker_flush(lp); - i = 0; - } - - app_lcore_worker(lp, bsz_rd, bsz_wr); - - i ++; - } -} - -int -app_lcore_main_loop(__attribute__((unused)) void *arg) -{ - struct app_lcore_params *lp; - unsigned lcore; - - lcore = rte_lcore_id(); - lp = &app.lcore_params[lcore]; - - if (lp->type == e_APP_LCORE_IO) { - printf("Logical core %u (I/O) main loop.\n", lcore); - app_lcore_main_loop_io(); - } - - if (lp->type == e_APP_LCORE_WORKER) { - printf("Logical core %u (worker %u) main loop.\n", - lcore, - (unsigned) lp->worker.worker_id); - app_lcore_main_loop_worker(); - } - - return 0; -} diff --git a/examples/meson.build b/examples/meson.build index f0356f2a1..e4580f74a 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -24,7 +24,6 @@ all_examples = [ 'l2fwd-keepalive', 'l3fwd', 'l3fwd-acl', 'l3fwd-power', 'link_status_interrupt', - 'load_balancer', 'multi_process/client_server_mp/mp_client', 'multi_process/client_server_mp/mp_server', 'multi_process/hotplug_mp', -- 2.21.0 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH 6/6] doc: close up gaps in sample app guide table 2019-10-03 13:19 [dpdk-dev] [PATCH 0/6] remove a few example applications Bruce Richardson ` (4 preceding siblings ...) 2019-10-03 13:19 ` [dpdk-dev] [PATCH 5/6] examples/load_balancer: " Bruce Richardson @ 2019-10-03 13:19 ` Bruce Richardson 2019-10-23 15:19 ` Thomas Monjalon 2019-10-23 15:21 ` [dpdk-dev] [dpdk-techboard] [PATCH 0/6] remove a few example applications Stephen Hemminger ` (2 subsequent siblings) 8 siblings, 1 reply; 27+ messages in thread From: Bruce Richardson @ 2019-10-03 13:19 UTC (permalink / raw) To: dev; +Cc: techboard, Bruce Richardson Following the removal of some sample applications, close up the gaps introduced in the table so that it is formatted nicely for the next release. Signed-off-by: Bruce Richardson <bruce.richardson@intel.com> --- doc/guides/sample_app_ug/intro.rst | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/doc/guides/sample_app_ug/intro.rst b/doc/guides/sample_app_ug/intro.rst index 981e50f94..dcfe70db2 100644 --- a/doc/guides/sample_app_ug/intro.rst +++ b/doc/guides/sample_app_ug/intro.rst @@ -31,37 +31,33 @@ applications that are available in the examples directory of DPDK: .. table:: **Some of the DPDK Sample applications** +---------------------------------------+--------------------------------------+ - | Bonding | | + | Bonding | Packet Ordering | +---------------------------------------+--------------------------------------+ - | Command Line | Packet Ordering | + | Command Line | Performance Thread | +---------------------------------------+--------------------------------------+ - | Distributor | Performance Thread | + | Distributor | Precision Time Protocol (PTP) Client | +---------------------------------------+--------------------------------------+ - | Ethtool | Precision Time Protocol (PTP) Client | - +---------------------------------------+--------------------------------------+ - | | Quality of Service (QoS) Metering | + | Ethtool | Quality of Service (QoS) Metering | +---------------------------------------+--------------------------------------+ | Hello World | QoS Scheduler | +---------------------------------------+--------------------------------------+ - | Internet Protocol (IP) Fragmentation | | - +---------------------------------------+--------------------------------------+ - | IP Pipeline | RX/TX Callbacks | + | Internet Protocol (IP) Fragmentation | RX/TX Callbacks | +---------------------------------------+--------------------------------------+ - | IP Reassembly | Server node EFD | + | IP Pipeline | Server node EFD | +---------------------------------------+--------------------------------------+ - | IPsec Security Gateway | Basic Forwarding/Skeleton App | + | IP Reassembly | Basic Forwarding/Skeleton App | +---------------------------------------+--------------------------------------+ - | IPv4 multicast | Tunnel End Point (TEP) termination | + | IPsec Security Gateway | Tunnel End Point (TEP) termination | +---------------------------------------+--------------------------------------+ - | Kernel NIC Interface | Timer | + | IPv4 multicast | Timer | +---------------------------------------+--------------------------------------+ - | Network Layer 2 Forwarding + variants | Vhost | + | Kernel NIC Interface | Vhost | +---------------------------------------+--------------------------------------+ - | Network Layer 3 Forwarding + variants | Vhost Xen | + | Network Layer 2 Forwarding + variants | Vhost Xen | +---------------------------------------+--------------------------------------+ - | Link Status Interrupt | VMDQ Forwarding | + | Network Layer 3 Forwarding + variants | VMDQ Forwarding | +---------------------------------------+--------------------------------------+ - | | VMDQ and DCB Forwarding | + | Link Status Interrupt | VMDQ and DCB Forwarding | +---------------------------------------+--------------------------------------+ | Multi-process | VM Power Management | +---------------------------------------+--------------------------------------+ -- 2.21.0 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [dpdk-dev] [PATCH 6/6] doc: close up gaps in sample app guide table 2019-10-03 13:19 ` [dpdk-dev] [PATCH 6/6] doc: close up gaps in sample app guide table Bruce Richardson @ 2019-10-23 15:19 ` Thomas Monjalon 0 siblings, 0 replies; 27+ messages in thread From: Thomas Monjalon @ 2019-10-23 15:19 UTC (permalink / raw) To: Bruce Richardson; +Cc: dev 03/10/2019 15:19, Bruce Richardson: > Following the removal of some sample applications, close up the gaps > introduced in the table so that it is formatted nicely for the next > release. > > Signed-off-by: Bruce Richardson <bruce.richardson@intel.com> I don't think we should maintain such table. Either it is a normal list, or we drop the whole listing. > .. table:: **Some of the DPDK Sample applications** > > +---------------------------------------+--------------------------------------+ > - | Bonding | | > + | Bonding | Packet Ordering | > +---------------------------------------+--------------------------------------+ > - | Command Line | Packet Ordering | > + | Command Line | Performance Thread | > +---------------------------------------+--------------------------------------+ > - | Distributor | Performance Thread | > + | Distributor | Precision Time Protocol (PTP) Client | > +---------------------------------------+--------------------------------------+ > - | Ethtool | Precision Time Protocol (PTP) Client | > - +---------------------------------------+--------------------------------------+ > - | | Quality of Service (QoS) Metering | > + | Ethtool | Quality of Service (QoS) Metering | > +---------------------------------------+--------------------------------------+ > | Hello World | QoS Scheduler | > +---------------------------------------+--------------------------------------+ > - | Internet Protocol (IP) Fragmentation | | > - +---------------------------------------+--------------------------------------+ > - | IP Pipeline | RX/TX Callbacks | > + | Internet Protocol (IP) Fragmentation | RX/TX Callbacks | > +---------------------------------------+--------------------------------------+ > - | IP Reassembly | Server node EFD | > + | IP Pipeline | Server node EFD | > +---------------------------------------+--------------------------------------+ > - | IPsec Security Gateway | Basic Forwarding/Skeleton App | > + | IP Reassembly | Basic Forwarding/Skeleton App | > +---------------------------------------+--------------------------------------+ > - | IPv4 multicast | Tunnel End Point (TEP) termination | > + | IPsec Security Gateway | Tunnel End Point (TEP) termination | > +---------------------------------------+--------------------------------------+ > - | Kernel NIC Interface | Timer | > + | IPv4 multicast | Timer | > +---------------------------------------+--------------------------------------+ > - | Network Layer 2 Forwarding + variants | Vhost | > + | Kernel NIC Interface | Vhost | > +---------------------------------------+--------------------------------------+ > - | Network Layer 3 Forwarding + variants | Vhost Xen | > + | Network Layer 2 Forwarding + variants | Vhost Xen | > +---------------------------------------+--------------------------------------+ > - | Link Status Interrupt | VMDQ Forwarding | > + | Network Layer 3 Forwarding + variants | VMDQ Forwarding | > +---------------------------------------+--------------------------------------+ > - | | VMDQ and DCB Forwarding | > + | Link Status Interrupt | VMDQ and DCB Forwarding | > +---------------------------------------+--------------------------------------+ > | Multi-process | VM Power Management | > +---------------------------------------+--------------------------------------+ ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [dpdk-dev] [dpdk-techboard] [PATCH 0/6] remove a few example applications 2019-10-03 13:19 [dpdk-dev] [PATCH 0/6] remove a few example applications Bruce Richardson ` (5 preceding siblings ...) 2019-10-03 13:19 ` [dpdk-dev] [PATCH 6/6] doc: close up gaps in sample app guide table Bruce Richardson @ 2019-10-23 15:21 ` Stephen Hemminger 2019-10-23 15:53 ` Hemant Agrawal 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 " Ciara Power 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 " Ciara Power 8 siblings, 1 reply; 27+ messages in thread From: Stephen Hemminger @ 2019-10-23 15:21 UTC (permalink / raw) To: Bruce Richardson; +Cc: dev, techboard On Thu, 3 Oct 2019 14:19:12 +0100 Bruce Richardson <bruce.richardson@intel.com> wrote: > As discussed by the DPDK technical board e.g. [1][2] and on the DPDK > mailing list [3], we have a lot of example applications shipped with > DPDK - a number which increases with each DPDK release, and not all of > which are probably needed any more. Therefore, this set removes 5 > example applications from the repository. > > The removal of each app is relatively straight-forward, though the use > of a table in the intro section of the sample app guide document makes > removing each app individually more difficult, as the table needs to be > reformed. Rather than increasing the diff by reformatting the table each > time, or the opposite approach of doing all table removals in one shot > at the end of the set, we have taken a compromise approach here, and > each example table entry is cleared once the example is removed, and the > table is finally rebalanced once at the end, by just compressing up the > spaces on each side. > > [1] https://mails.dpdk.org/archives/dev/2019-May/132288.html > [2] https://mails.dpdk.org/archives/dev/2019-June/135847.html > [3] https://mails.dpdk.org/archives/dev/2019-July/138676.html > > > Bruce Richardson (3): > examples/exception_path: remove example from DPDK > examples/l3fwd-vf: remove example from DPDK > doc: close up gaps in sample app guide table > > Ciara Power (3): > examples/quota-watermark: remove example from DPDK > examples/netmap-compat: remove example from DPDK > examples/load_balancer: remove example from DPDK > > MAINTAINERS | 15 - > doc/guides/sample_app_ug/exception_path.rst | 281 ----- > doc/guides/sample_app_ug/index.rst | 5 - > doc/guides/sample_app_ug/intro.rst | 30 +- > .../sample_app_ug/l3_forward_virtual.rst | 98 -- > doc/guides/sample_app_ug/load_balancer.rst | 201 ---- > .../sample_app_ug/netmap_compatibility.rst | 130 -- > doc/guides/sample_app_ug/quota_watermark.rst | 465 ------- > examples/Makefile | 5 - > examples/exception_path/Makefile | 57 - > examples/exception_path/main.c | 589 --------- > examples/exception_path/meson.build | 11 - > examples/l3fwd-vf/Makefile | 62 - > examples/l3fwd-vf/main.c | 1072 ----------------- > examples/l3fwd-vf/meson.build | 12 - > examples/load_balancer/Makefile | 62 - > examples/load_balancer/config.c | 1030 ---------------- > examples/load_balancer/init.c | 520 -------- > examples/load_balancer/main.c | 76 -- > examples/load_balancer/main.h | 351 ------ > examples/load_balancer/meson.build | 12 - > examples/load_balancer/runtime.c | 642 ---------- > examples/meson.build | 9 +- > 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 -- > examples/quota_watermark/Makefile | 16 - > examples/quota_watermark/include/conf.h | 19 - > examples/quota_watermark/meson.build | 10 - > examples/quota_watermark/qw/Makefile | 22 - > examples/quota_watermark/qw/args.c | 78 -- > examples/quota_watermark/qw/args.h | 12 - > examples/quota_watermark/qw/init.c | 164 --- > examples/quota_watermark/qw/init.h | 14 - > examples/quota_watermark/qw/main.c | 365 ------ > examples/quota_watermark/qw/main.h | 31 - > examples/quota_watermark/qwctl/Makefile | 22 - > examples/quota_watermark/qwctl/commands.c | 196 --- > examples/quota_watermark/qwctl/commands.h | 12 - > examples/quota_watermark/qwctl/qwctl.c | 67 -- > examples/quota_watermark/qwctl/qwctl.h | 12 - > 46 files changed, 17 insertions(+), 8502 deletions(-) > delete mode 100644 doc/guides/sample_app_ug/exception_path.rst > delete mode 100644 doc/guides/sample_app_ug/l3_forward_virtual.rst > delete mode 100644 doc/guides/sample_app_ug/load_balancer.rst > delete mode 100644 doc/guides/sample_app_ug/netmap_compatibility.rst > delete mode 100644 doc/guides/sample_app_ug/quota_watermark.rst > delete mode 100644 examples/exception_path/Makefile > delete mode 100644 examples/exception_path/main.c > delete mode 100644 examples/exception_path/meson.build > delete mode 100644 examples/l3fwd-vf/Makefile > delete mode 100644 examples/l3fwd-vf/main.c > delete mode 100644 examples/l3fwd-vf/meson.build > delete mode 100644 examples/load_balancer/Makefile > delete mode 100644 examples/load_balancer/config.c > delete mode 100644 examples/load_balancer/init.c > delete mode 100644 examples/load_balancer/main.c > delete mode 100644 examples/load_balancer/main.h > delete mode 100644 examples/load_balancer/meson.build > delete mode 100644 examples/load_balancer/runtime.c > 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 > delete mode 100644 examples/quota_watermark/Makefile > delete mode 100644 examples/quota_watermark/include/conf.h > delete mode 100644 examples/quota_watermark/meson.build > delete mode 100644 examples/quota_watermark/qw/Makefile > delete mode 100644 examples/quota_watermark/qw/args.c > delete mode 100644 examples/quota_watermark/qw/args.h > delete mode 100644 examples/quota_watermark/qw/init.c > delete mode 100644 examples/quota_watermark/qw/init.h > delete mode 100644 examples/quota_watermark/qw/main.c > delete mode 100644 examples/quota_watermark/qw/main.h > delete mode 100644 examples/quota_watermark/qwctl/Makefile > delete mode 100644 examples/quota_watermark/qwctl/commands.c > delete mode 100644 examples/quota_watermark/qwctl/commands.h > delete mode 100644 examples/quota_watermark/qwctl/qwctl.c > delete mode 100644 examples/quota_watermark/qwctl/qwctl.h > Ack for whole series, lets make this the smallest release Acked-by: Stephen Hemminger <stephen@networkplumber.org> ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [dpdk-dev] [dpdk-techboard] [PATCH 0/6] remove a few example applications 2019-10-23 15:21 ` [dpdk-dev] [dpdk-techboard] [PATCH 0/6] remove a few example applications Stephen Hemminger @ 2019-10-23 15:53 ` Hemant Agrawal 0 siblings, 0 replies; 27+ messages in thread From: Hemant Agrawal @ 2019-10-23 15:53 UTC (permalink / raw) To: Stephen Hemminger, Bruce Richardson; +Cc: dev, techboard Series- Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com> ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v2 0/6] remove a few example applications 2019-10-03 13:19 [dpdk-dev] [PATCH 0/6] remove a few example applications Bruce Richardson ` (6 preceding siblings ...) 2019-10-23 15:21 ` [dpdk-dev] [dpdk-techboard] [PATCH 0/6] remove a few example applications Stephen Hemminger @ 2019-10-24 13:31 ` Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 1/6] doc: remove unnecessary sample app guide table Ciara Power ` (6 more replies) 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 " Ciara Power 8 siblings, 7 replies; 27+ messages in thread From: Ciara Power @ 2019-10-24 13:31 UTC (permalink / raw) To: dev; +Cc: techboard, Ciara Power As discussed by the DPDK technical board e.g. [1][2] and on the DPDK mailing list [3], we have a lot of example applications shipped with DPDK - a number which increases with each DPDK release, and not all of which are probably needed any more. Therefore, this set removes 5 example applications from the repository. v2: Remove the table listing sample applications [1] https://mails.dpdk.org/archives/dev/2019-May/132288.html [2] https://mails.dpdk.org/archives/dev/2019-June/135847.html [3] https://mails.dpdk.org/archives/dev/2019-July/138676.html Bruce Richardson (2): examples/exception_path: remove example from DPDK examples/l3fwd-vf: remove example from DPDK Ciara Power (4): doc: remove unnecessary sample app guide table examples/quota-watermark: remove example from DPDK examples/netmap-compat: remove example from DPDK examples/load_balancer: remove example from DPDK MAINTAINERS | 15 - doc/guides/sample_app_ug/exception_path.rst | 281 ----- doc/guides/sample_app_ug/index.rst | 5 - doc/guides/sample_app_ug/intro.rst | 44 +- .../sample_app_ug/l3_forward_virtual.rst | 98 -- doc/guides/sample_app_ug/load_balancer.rst | 201 ---- .../sample_app_ug/netmap_compatibility.rst | 130 -- doc/guides/sample_app_ug/quota_watermark.rst | 465 ------- examples/Makefile | 5 - examples/exception_path/Makefile | 57 - examples/exception_path/main.c | 589 --------- examples/exception_path/meson.build | 11 - examples/l3fwd-vf/Makefile | 62 - examples/l3fwd-vf/main.c | 1072 ----------------- examples/l3fwd-vf/meson.build | 12 - examples/load_balancer/Makefile | 62 - examples/load_balancer/config.c | 1030 ---------------- examples/load_balancer/init.c | 520 -------- examples/load_balancer/main.c | 76 -- examples/load_balancer/main.h | 351 ------ examples/load_balancer/meson.build | 12 - examples/load_balancer/runtime.c | 642 ---------- examples/meson.build | 9 +- 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 -- examples/quota_watermark/Makefile | 16 - examples/quota_watermark/include/conf.h | 19 - examples/quota_watermark/meson.build | 10 - examples/quota_watermark/qw/Makefile | 22 - examples/quota_watermark/qw/args.c | 78 -- examples/quota_watermark/qw/args.h | 12 - examples/quota_watermark/qw/init.c | 164 --- examples/quota_watermark/qw/init.h | 14 - examples/quota_watermark/qw/main.c | 365 ------ examples/quota_watermark/qw/main.h | 31 - examples/quota_watermark/qwctl/Makefile | 22 - examples/quota_watermark/qwctl/commands.c | 196 --- examples/quota_watermark/qwctl/commands.h | 12 - examples/quota_watermark/qwctl/qwctl.c | 67 -- examples/quota_watermark/qwctl/qwctl.h | 12 - 46 files changed, 5 insertions(+), 8528 deletions(-) delete mode 100644 doc/guides/sample_app_ug/exception_path.rst delete mode 100644 doc/guides/sample_app_ug/l3_forward_virtual.rst delete mode 100644 doc/guides/sample_app_ug/load_balancer.rst delete mode 100644 doc/guides/sample_app_ug/netmap_compatibility.rst delete mode 100644 doc/guides/sample_app_ug/quota_watermark.rst delete mode 100644 examples/exception_path/Makefile delete mode 100644 examples/exception_path/main.c delete mode 100644 examples/exception_path/meson.build delete mode 100644 examples/l3fwd-vf/Makefile delete mode 100644 examples/l3fwd-vf/main.c delete mode 100644 examples/l3fwd-vf/meson.build delete mode 100644 examples/load_balancer/Makefile delete mode 100644 examples/load_balancer/config.c delete mode 100644 examples/load_balancer/init.c delete mode 100644 examples/load_balancer/main.c delete mode 100644 examples/load_balancer/main.h delete mode 100644 examples/load_balancer/meson.build delete mode 100644 examples/load_balancer/runtime.c 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 delete mode 100644 examples/quota_watermark/Makefile delete mode 100644 examples/quota_watermark/include/conf.h delete mode 100644 examples/quota_watermark/meson.build delete mode 100644 examples/quota_watermark/qw/Makefile delete mode 100644 examples/quota_watermark/qw/args.c delete mode 100644 examples/quota_watermark/qw/args.h delete mode 100644 examples/quota_watermark/qw/init.c delete mode 100644 examples/quota_watermark/qw/init.h delete mode 100644 examples/quota_watermark/qw/main.c delete mode 100644 examples/quota_watermark/qw/main.h delete mode 100644 examples/quota_watermark/qwctl/Makefile delete mode 100644 examples/quota_watermark/qwctl/commands.c delete mode 100644 examples/quota_watermark/qwctl/commands.h delete mode 100644 examples/quota_watermark/qwctl/qwctl.c delete mode 100644 examples/quota_watermark/qwctl/qwctl.h -- 2.17.1 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v2 1/6] doc: remove unnecessary sample app guide table 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 " Ciara Power @ 2019-10-24 13:31 ` Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 2/6] examples/exception_path: remove example from DPDK Ciara Power ` (5 subsequent siblings) 6 siblings, 0 replies; 27+ messages in thread From: Ciara Power @ 2019-10-24 13:31 UTC (permalink / raw) To: dev; +Cc: techboard, Ciara Power The table of examples in the sample application guide is now removed, as it was unnecessary and difficult to update when adding/removing examples. Signed-off-by: Ciara Power <ciara.power@intel.com> --- doc/guides/sample_app_ug/intro.rst | 44 +----------------------------- 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/doc/guides/sample_app_ug/intro.rst b/doc/guides/sample_app_ug/intro.rst index 90704194a..a7576837c 100644 --- a/doc/guides/sample_app_ug/intro.rst +++ b/doc/guides/sample_app_ug/intro.rst @@ -23,49 +23,7 @@ command-line options. The DPDK Sample Applications ---------------------------- -Table :numref:`table_sample_apps` shows a list of some of the main sample -applications that are available in the examples directory of DPDK: - - .. _table_sample_apps: - - .. table:: **Some of the DPDK Sample applications** - - +---------------------------------------+--------------------------------------+ - | Bonding | Netmap Compatibility | - +---------------------------------------+--------------------------------------+ - | Command Line | Packet Ordering | - +---------------------------------------+--------------------------------------+ - | Distributor | Performance Thread | - +---------------------------------------+--------------------------------------+ - | Ethtool | Precision Time Protocol (PTP) Client | - +---------------------------------------+--------------------------------------+ - | Exception Path | Quality of Service (QoS) Metering | - +---------------------------------------+--------------------------------------+ - | Hello World | QoS Scheduler | - +---------------------------------------+--------------------------------------+ - | Internet Protocol (IP) Fragmentation | Quota and Watermark | - +---------------------------------------+--------------------------------------+ - | IP Pipeline | RX/TX Callbacks | - +---------------------------------------+--------------------------------------+ - | IP Reassembly | Server node EFD | - +---------------------------------------+--------------------------------------+ - | IPsec Security Gateway | Basic Forwarding/Skeleton App | - +---------------------------------------+--------------------------------------+ - | IPv4 multicast | Tunnel End Point (TEP) termination | - +---------------------------------------+--------------------------------------+ - | Kernel NIC Interface | Timer | - +---------------------------------------+--------------------------------------+ - | Network Layer 2 Forwarding + variants | Vhost | - +---------------------------------------+--------------------------------------+ - | Network Layer 3 Forwarding + variants | Vhost Xen | - +---------------------------------------+--------------------------------------+ - | Link Status Interrupt | VMDQ Forwarding | - +---------------------------------------+--------------------------------------+ - | Load Balancer | VMDQ and DCB Forwarding | - +---------------------------------------+--------------------------------------+ - | Multi-process | VM Power Management | - +---------------------------------------+--------------------------------------+ - +There are many sample applications available in the examples directory of DPDK. These examples range from simple to reasonably complex but most are designed to demonstrate one particular feature of DPDK. Some of the more interesting examples are highlighted below. -- 2.17.1 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v2 2/6] examples/exception_path: remove example from DPDK 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 " Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 1/6] doc: remove unnecessary sample app guide table Ciara Power @ 2019-10-24 13:31 ` Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 3/6] examples/l3fwd-vf: " Ciara Power ` (4 subsequent siblings) 6 siblings, 0 replies; 27+ messages in thread From: Ciara Power @ 2019-10-24 13:31 UTC (permalink / raw) To: dev; +Cc: techboard, Bruce Richardson From: Bruce Richardson <bruce.richardson@intel.com> The example app shows the use of TUN/TAP with DPDK, but DPDK has a built-in TAP PMD, so this example is obsolete and so can be removed. Signed-off-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com> --- MAINTAINERS | 3 - doc/guides/sample_app_ug/exception_path.rst | 281 ---------- doc/guides/sample_app_ug/index.rst | 1 - examples/Makefile | 1 - examples/exception_path/Makefile | 57 -- examples/exception_path/main.c | 589 -------------------- examples/exception_path/meson.build | 11 - examples/meson.build | 2 +- 8 files changed, 1 insertion(+), 944 deletions(-) delete mode 100644 doc/guides/sample_app_ug/exception_path.rst delete mode 100644 examples/exception_path/Makefile delete mode 100644 examples/exception_path/main.c delete mode 100644 examples/exception_path/meson.build diff --git a/MAINTAINERS b/MAINTAINERS index b3d9aaddd..330a4d77d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1427,9 +1427,6 @@ Other Example Applications F: examples/ethtool/ F: doc/guides/sample_app_ug/ethtool.rst -F: examples/exception_path/ -F: doc/guides/sample_app_ug/exception_path.rst - M: Marko Kovacevic <marko.kovacevic@intel.com> F: examples/fips_validation/ F: doc/guides/sample_app_ug/fips_validation.rst diff --git a/doc/guides/sample_app_ug/exception_path.rst b/doc/guides/sample_app_ug/exception_path.rst deleted file mode 100644 index a5590870c..000000000 --- a/doc/guides/sample_app_ug/exception_path.rst +++ /dev/null @@ -1,281 +0,0 @@ -.. SPDX-License-Identifier: BSD-3-Clause - Copyright(c) 2010-2014 Intel Corporation. - -Exception Path Sample Application -================================= - -The Exception Path sample application is a simple example that demonstrates the use of the DPDK -to set up an exception path for packets to go through the Linux* kernel. -This is done by using virtual TAP network interfaces. -These can be read from and written to by the DPDK application and -appear to the kernel as a standard network interface. - -Overview --------- - -The application creates two threads for each NIC port being used. -One thread reads from the port and writes the data unmodified to a thread-specific TAP interface. -The second thread reads from a TAP interface and writes the data unmodified to the NIC port. - -The packet flow through the exception path application is as shown in the following figure. - -.. _figure_exception_path_example: - -.. figure:: img/exception_path_example.* - - Packet Flow - - -To make throughput measurements, kernel bridges must be setup to forward data between the bridges appropriately. - -Compiling the Application -------------------------- - -To compile the sample application see :doc:`compiling`. - -The application is located in the ``exception_path`` sub-directory. - -Running the Application ------------------------ - -The application requires a number of command line options: - -.. code-block:: console - - .build/exception_path [EAL options] -- -p PORTMASK -i IN_CORES -o OUT_CORES - -where: - -* -p PORTMASK: A hex bitmask of ports to use - -* -i IN_CORES: A hex bitmask of cores which read from NIC - -* -o OUT_CORES: A hex bitmask of cores which write to NIC - -Refer to the *DPDK Getting Started Guide* for general information on running applications -and the Environment Abstraction Layer (EAL) options. - -The number of bits set in each bitmask must be the same. -The coremask -c or the corelist -l parameter of the EAL options should include IN_CORES and OUT_CORES. -The same bit must not be set in IN_CORES and OUT_CORES. -The affinities between ports and cores are set beginning with the least significant bit of each mask, that is, -the port represented by the lowest bit in PORTMASK is read from by the core represented by the lowest bit in IN_CORES, -and written to by the core represented by the lowest bit in OUT_CORES. - -For example to run the application with two ports and four cores: - -.. code-block:: console - - ./build/exception_path -l 0-3 -n 4 -- -p 3 -i 3 -o c - -Getting Statistics -~~~~~~~~~~~~~~~~~~ - -While the application is running, statistics on packets sent and -received can be displayed by sending the SIGUSR1 signal to the application from another terminal: - -.. code-block:: console - - killall -USR1 exception_path - -The statistics can be reset by sending a SIGUSR2 signal in a similar way. - -Explanation ------------ - -The following sections provide some explanation of the code. - -Initialization -~~~~~~~~~~~~~~ - -Setup of the mbuf pool, driver and queues is similar to the setup done in the :ref:`l2_fwd_app_real_and_virtual`. -In addition, the TAP interfaces must also be created. -A TAP interface is created for each lcore that is being used. -The code for creating the TAP interface is as follows: - -.. code-block:: c - - /* - * Create a tap network interface, or use existing one with same name. - * If name[0]='\0' then a name is automatically assigned and returned in name. - */ - - static int tap_create(char *name) - { - struct ifreq ifr; - int fd, ret; - - fd = open("/dev/net/tun", O_RDWR); - if (fd < 0) - return fd; - - memset(&ifr, 0, sizeof(ifr)); - - /* TAP device without packet information */ - - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - if (name && *name) - rte_snprinf(ifr.ifr_name, IFNAMSIZ, name); - - ret = ioctl(fd, TUNSETIFF, (void *) &ifr); - - if (ret < 0) { - close(fd); - return ret; - - } - - if (name) - snprintf(name, IFNAMSIZ, ifr.ifr_name); - - return fd; - } - -The other step in the initialization process that is unique to this sample application -is the association of each port with two cores: - -* One core to read from the port and write to a TAP interface - -* A second core to read from a TAP interface and write to the port - -This is done using an array called port_ids[], which is indexed by the lcore IDs. -The population of this array is shown below: - -.. code-block:: c - - tx_port = 0; - rx_port = 0; - - RTE_LCORE_FOREACH(i) { - if (input_cores_mask & (1ULL << i)) { - /* Skip ports that are not enabled */ - while ((ports_mask & (1 << rx_port)) == 0) { - rx_port++; - if (rx_port > (sizeof(ports_mask) * 8)) - goto fail; /* not enough ports */ - } - port_ids[i] = rx_port++; - } else if (output_cores_mask & (1ULL << i)) { - /* Skip ports that are not enabled */ - while ((ports_mask & (1 << tx_port)) == 0) { - tx_port++; - if (tx_port > (sizeof(ports_mask) * 8)) - goto fail; /* not enough ports */ - } - port_ids[i] = tx_port++; - } - } - -Packet Forwarding -~~~~~~~~~~~~~~~~~ - -After the initialization steps are complete, the main_loop() function is run on each lcore. -This function first checks the lcore_id against the user provided input_cores_mask and output_cores_mask to see -if this core is reading from or writing to a TAP interface. - -For the case that reads from a NIC port, the packet reception is the same as in the L2 Forwarding sample application -(see :ref:`l2_fwd_app_rx_tx_packets`). -The packet transmission is done by calling write() with the file descriptor of the appropriate TAP interface -and then explicitly freeing the mbuf back to the pool. - -.. code-block:: c - - /* Loop forever reading from NIC and writing to tap */ - - for (;;) { - struct rte_mbuf *pkts_burst[PKT_BURST_SZ]; - unsigned i; - - const unsigned nb_rx = rte_eth_rx_burst(port_ids[lcore_id], 0, pkts_burst, PKT_BURST_SZ); - - lcore_stats[lcore_id].rx += nb_rx; - - for (i = 0; likely(i < nb_rx); i++) { - struct rte_mbuf *m = pkts_burst[i]; - int ret = write(tap_fd, rte_pktmbuf_mtod(m, void*), - - rte_pktmbuf_data_len(m)); - rte_pktmbuf_free(m); - if (unlikely(ret<0)) - lcore_stats[lcore_id].dropped++; - else - lcore_stats[lcore_id].tx++; - } - } - -For the other case that reads from a TAP interface and writes to a NIC port, -packets are retrieved by doing a read() from the file descriptor of the appropriate TAP interface. -This fills in the data into the mbuf, then other fields are set manually. -The packet can then be transmitted as normal. - -.. code-block:: c - - /* Loop forever reading from tap and writing to NIC */ - - for (;;) { - int ret; - struct rte_mbuf *m = rte_pktmbuf_alloc(pktmbuf_pool); - - if (m == NULL) - continue; - - ret = read(tap_fd, m->pkt.data, MAX_PACKET_SZ); lcore_stats[lcore_id].rx++; - if (unlikely(ret < 0)) { - FATAL_ERROR("Reading from %s interface failed", tap_name); - } - - m->pkt.nb_segs = 1; - m->pkt.next = NULL; - m->pkt.data_len = (uint16_t)ret; - - ret = rte_eth_tx_burst(port_ids[lcore_id], 0, &m, 1); - if (unlikely(ret < 1)) { - rte_pktmuf_free(m); - lcore_stats[lcore_id].dropped++; - } - else { - lcore_stats[lcore_id].tx++; - } - } - -To set up loops for measuring throughput, TAP interfaces can be connected using bridging. -The steps to do this are described in the section that follows. - -Managing TAP Interfaces and Bridges -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The Exception Path sample application creates TAP interfaces with names of the format tap_dpdk_nn, -where nn is the lcore ID. These TAP interfaces need to be configured for use: - -.. code-block:: console - - ifconfig tap_dpdk_00 up - -To set up a bridge between two interfaces so that packets sent to one interface can be read from another, -use the brctl tool: - -.. code-block:: console - - brctl addbr "br0" - brctl addif br0 tap_dpdk_00 - brctl addif br0 tap_dpdk_03 - ifconfig br0 up - -The TAP interfaces created by this application exist only when the application is running, -so the steps above need to be repeated each time the application is run. -To avoid this, persistent TAP interfaces can be created using openvpn: - -.. code-block:: console - - openvpn --mktun --dev tap_dpdk_00 - -If this method is used, then the steps above have to be done only once and -the same TAP interfaces can be reused each time the application is run. -To remove bridges and persistent TAP interfaces, the following commands are used: - -.. code-block:: console - - ifconfig br0 down - brctl delbr br0 - openvpn --rmtun --dev tap_dpdk_00 - diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst index f23f8f59e..076346a60 100644 --- a/doc/guides/sample_app_ug/index.rst +++ b/doc/guides/sample_app_ug/index.rst @@ -12,7 +12,6 @@ Sample Applications User Guides compiling cmd_line ethtool - exception_path hello_world skeleton rxtx_callbacks diff --git a/examples/Makefile b/examples/Makefile index de11dd487..c756497d1 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -17,7 +17,6 @@ ifeq ($(CONFIG_RTE_LIBRTE_POWER),y) DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += distributor endif DIRS-y += ethtool -DIRS-y += exception_path DIRS-$(CONFIG_RTE_LIBRTE_EFD) += server_node_efd DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += fips_validation DIRS-$(CONFIG_RTE_LIBRTE_FLOW_CLASSIFY) += flow_classify diff --git a/examples/exception_path/Makefile b/examples/exception_path/Makefile deleted file mode 100644 index 90c7f133a..000000000 --- a/examples/exception_path/Makefile +++ /dev/null @@ -1,57 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2010-2014 Intel Corporation - -# binary name -APP = exception_path - -# all source are stored in SRCS-y -SRCS-y := main.c - -# Build using pkg-config variables if possible -ifeq ($(shell pkg-config --exists libdpdk && echo 0),0) - -all: shared -.PHONY: shared static -shared: build/$(APP)-shared - ln -sf $(APP)-shared build/$(APP) -static: build/$(APP)-static - ln -sf $(APP)-static build/$(APP) - -PKGCONF=pkg-config --define-prefix - -PC_FILE := $(shell $(PKGCONF) --path libdpdk) -CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) -LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk) -LDFLAGS_STATIC = -Wl,-Bstatic $(shell $(PKGCONF) --static --libs libdpdk) - -build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) - -build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC) - -build: - @mkdir -p $@ - -.PHONY: clean -clean: - rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared - test -d build && rmdir -p build || true - -else - -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 - -CFLAGS += -O3 -CFLAGS += $(WERROR_FLAGS) - -include $(RTE_SDK)/mk/rte.extapp.mk - -endif diff --git a/examples/exception_path/main.c b/examples/exception_path/main.c deleted file mode 100644 index 0d79e5a24..000000000 --- a/examples/exception_path/main.c +++ /dev/null @@ -1,589 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> - -#include <netinet/in.h> -#include <net/if.h> -#ifdef RTE_EXEC_ENV_LINUX -#include <linux/if_tun.h> -#endif -#include <fcntl.h> -#include <sys/ioctl.h> -#include <unistd.h> -#include <signal.h> - -#include <rte_common.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_per_lcore.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_string_fns.h> -#include <rte_cycles.h> - -#ifndef APP_MAX_LCORE -#if (RTE_MAX_LCORE > 64) -#define APP_MAX_LCORE 64 -#else -#define APP_MAX_LCORE RTE_MAX_LCORE -#endif -#endif - -/* Macros for printing using RTE_LOG */ -#define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1 -#define FATAL_ERROR(fmt, args...) rte_exit(EXIT_FAILURE, fmt "\n", ##args) -#define PRINT_INFO(fmt, args...) RTE_LOG(INFO, APP, fmt "\n", ##args) - -/* Max ports than can be used (each port is associated with two lcores) */ -#define MAX_PORTS (APP_MAX_LCORE / 2) - -/* Max size of a single packet */ -#define MAX_PACKET_SZ (2048) - -/* Size of the data buffer in each mbuf */ -#define MBUF_DATA_SZ (MAX_PACKET_SZ + RTE_PKTMBUF_HEADROOM) - -/* Number of mbufs in mempool that is created */ -#define NB_MBUF 8192 - -/* How many packets to attempt to read from NIC in one go */ -#define PKT_BURST_SZ 32 - -/* How many objects (mbufs) to keep in per-lcore mempool cache */ -#define MEMPOOL_CACHE_SZ PKT_BURST_SZ - -/* Number of RX ring descriptors */ -#define NB_RXD 1024 - -/* Number of TX ring descriptors */ -#define NB_TXD 1024 - -/* - * RX and TX Prefetch, Host, and Write-back threshold values should be - * carefully set for optimal performance. Consult the network - * controller's datasheet and supporting DPDK documentation for guidance - * on how these parameters should be set. - */ - -/* Options for configuring ethernet port */ -static struct rte_eth_conf port_conf = { - .txmode = { - .mq_mode = ETH_MQ_TX_NONE, - }, -}; - -/* Mempool for mbufs */ -static struct rte_mempool * pktmbuf_pool = NULL; - -/* Mask of enabled ports */ -static uint32_t ports_mask = 0; - -/* Mask of cores that read from NIC and write to tap */ -static uint64_t input_cores_mask = 0; - -/* Mask of cores that read from tap and write to NIC */ -static uint64_t output_cores_mask = 0; - -/* Array storing port_id that is associated with each lcore */ -static uint16_t port_ids[APP_MAX_LCORE]; - -/* Structure type for recording lcore-specific stats */ -struct stats { - uint64_t rx; - uint64_t tx; - uint64_t dropped; -} __rte_cache_aligned; - -/* Array of lcore-specific stats */ -static struct stats lcore_stats[APP_MAX_LCORE]; - -/* Print out statistics on packets handled */ -static void -print_stats(void) -{ - unsigned i; - - printf("\n**Exception-Path example application statistics**\n" - "======= ====== ============ ============ ===============\n" - " Lcore Port RX TX Dropped on TX\n" - "------- ------ ------------ ------------ ---------------\n"); - RTE_LCORE_FOREACH(i) { - /* limit ourselves to application supported cores only */ - if (i >= APP_MAX_LCORE) - break; - printf("%6u %7u %13"PRIu64" %13"PRIu64" %16"PRIu64"\n", - i, (unsigned)port_ids[i], - lcore_stats[i].rx, lcore_stats[i].tx, - lcore_stats[i].dropped); - } - printf("======= ====== ============ ============ ===============\n"); -} - -/* Custom handling of signals to handle stats */ -static void -signal_handler(int signum) -{ - /* When we receive a USR1 signal, print stats */ - if (signum == SIGUSR1) { - print_stats(); - } - - /* When we receive a USR2 signal, reset stats */ - if (signum == SIGUSR2) { - memset(&lcore_stats, 0, sizeof(lcore_stats)); - printf("\n**Statistics have been reset**\n"); - return; - } -} - -#ifdef RTE_EXEC_ENV_LINUX -/* - * Create a tap network interface, or use existing one with same name. - * If name[0]='\0' then a name is automatically assigned and returned in name. - */ -static int tap_create(char *name) -{ - struct ifreq ifr; - int fd, ret; - - fd = open("/dev/net/tun", O_RDWR); - if (fd < 0) - return fd; - - memset(&ifr, 0, sizeof(ifr)); - - /* TAP device without packet information */ - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - - if (name && *name) - strlcpy(ifr.ifr_name, name, IFNAMSIZ); - - ret = ioctl(fd, TUNSETIFF, (void *) &ifr); - if (ret < 0) { - close(fd); - return ret; - } - - if (name) - strlcpy(name, ifr.ifr_name, IFNAMSIZ); - - return fd; -} -#else -/* - * Find a free tap network interface, or create a new one. - * The name is automatically assigned and returned in name. - */ -static int tap_create(char *name) -{ - int i, fd = -1; - char devname[PATH_MAX]; - - for (i = 0; i < 255; i++) { - snprintf(devname, sizeof(devname), "/dev/tap%d", i); - fd = open(devname, O_RDWR); - if (fd >= 0 || errno != EBUSY) - break; - } - - if (name) - snprintf(name, IFNAMSIZ, "tap%d", i); - - return fd; -} -#endif - -/* Main processing loop */ -static int -main_loop(__attribute__((unused)) void *arg) -{ - const unsigned lcore_id = rte_lcore_id(); - char tap_name[IFNAMSIZ]; - int tap_fd; - - if ((1ULL << lcore_id) & input_cores_mask) { - /* Create new tap interface */ - snprintf(tap_name, IFNAMSIZ, "tap_dpdk_%.2u", lcore_id); - tap_fd = tap_create(tap_name); - if (tap_fd < 0) - FATAL_ERROR("Could not create tap interface \"%s\" (%d)", - tap_name, tap_fd); - - PRINT_INFO("Lcore %u is reading from port %u and writing to %s", - lcore_id, (unsigned)port_ids[lcore_id], tap_name); - fflush(stdout); - /* Loop forever reading from NIC and writing to tap */ - for (;;) { - struct rte_mbuf *pkts_burst[PKT_BURST_SZ]; - unsigned i; - const unsigned nb_rx = - rte_eth_rx_burst(port_ids[lcore_id], 0, - pkts_burst, PKT_BURST_SZ); - lcore_stats[lcore_id].rx += nb_rx; - for (i = 0; likely(i < nb_rx); i++) { - struct rte_mbuf *m = pkts_burst[i]; - /* Ignore return val from write() */ - int ret = write(tap_fd, - rte_pktmbuf_mtod(m, void*), - rte_pktmbuf_data_len(m)); - rte_pktmbuf_free(m); - if (unlikely(ret < 0)) - lcore_stats[lcore_id].dropped++; - else - lcore_stats[lcore_id].tx++; - } - } - } - else if ((1ULL << lcore_id) & output_cores_mask) { - /* Create new tap interface */ - snprintf(tap_name, IFNAMSIZ, "tap_dpdk_%.2u", lcore_id); - tap_fd = tap_create(tap_name); - if (tap_fd < 0) - FATAL_ERROR("Could not create tap interface \"%s\" (%d)", - tap_name, tap_fd); - - PRINT_INFO("Lcore %u is reading from %s and writing to port %u", - lcore_id, tap_name, (unsigned)port_ids[lcore_id]); - fflush(stdout); - /* Loop forever reading from tap and writing to NIC */ - for (;;) { - int ret; - struct rte_mbuf *m = rte_pktmbuf_alloc(pktmbuf_pool); - if (m == NULL) - continue; - - ret = read(tap_fd, rte_pktmbuf_mtod(m, void *), - MAX_PACKET_SZ); - lcore_stats[lcore_id].rx++; - if (unlikely(ret < 0)) { - FATAL_ERROR("Reading from %s interface failed", - tap_name); - } - m->nb_segs = 1; - m->next = NULL; - m->pkt_len = (uint16_t)ret; - m->data_len = (uint16_t)ret; - ret = rte_eth_tx_burst(port_ids[lcore_id], 0, &m, 1); - if (unlikely(ret < 1)) { - rte_pktmbuf_free(m); - lcore_stats[lcore_id].dropped++; - } - else { - lcore_stats[lcore_id].tx++; - } - } - } - else { - PRINT_INFO("Lcore %u has nothing to do", lcore_id); - return 0; - } - /* - * Tap file is closed automatically when program exits. Putting close() - * here will cause the compiler to give an error about unreachable code. - */ -} - -/* Display usage instructions */ -static void -print_usage(const char *prgname) -{ - PRINT_INFO("\nUsage: %s [EAL options] -- -p PORTMASK -i IN_CORES -o OUT_CORES\n" - " -p PORTMASK: hex bitmask of ports to use\n" - " -i IN_CORES: hex bitmask of cores which read from NIC\n" - " -o OUT_CORES: hex bitmask of cores which write to NIC", - prgname); -} - -/* Convert string to unsigned number. 0 is returned if error occurs */ -static uint64_t -parse_unsigned(const char *portmask) -{ - char *end = NULL; - uint64_t num; - - num = strtoull(portmask, &end, 16); - if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) - return 0; - - return (uint64_t)num; -} - -/* Record affinities between ports and lcores in global port_ids[] array */ -static void -setup_port_lcore_affinities(void) -{ - unsigned long i; - uint16_t tx_port = 0; - uint16_t rx_port = 0; - - /* Setup port_ids[] array, and check masks were ok */ - for (i = 0; i < APP_MAX_LCORE; i++) { - if (!rte_lcore_is_enabled(i)) - continue; - if (input_cores_mask & (1ULL << i)) { - /* Skip ports that are not enabled */ - while ((ports_mask & (1 << rx_port)) == 0) { - rx_port++; - if (rx_port > (sizeof(ports_mask) * 8)) - goto fail; /* not enough ports */ - } - - port_ids[i] = rx_port++; - } else if (output_cores_mask & (1ULL << (i & 0x3f))) { - /* Skip ports that are not enabled */ - while ((ports_mask & (1 << tx_port)) == 0) { - tx_port++; - if (tx_port > (sizeof(ports_mask) * 8)) - goto fail; /* not enough ports */ - } - - port_ids[i] = tx_port++; - } - } - - if (rx_port != tx_port) - goto fail; /* uneven number of cores in masks */ - - if (ports_mask & (~((1 << rx_port) - 1))) - goto fail; /* unused ports */ - - return; -fail: - FATAL_ERROR("Invalid core/port masks specified on command line"); -} - -/* Parse the arguments given in the command line of the application */ -static void -parse_args(int argc, char **argv) -{ - int opt; - const char *prgname = argv[0]; - - /* Disable printing messages within getopt() */ - opterr = 0; - - /* Parse command line */ - while ((opt = getopt(argc, argv, "i:o:p:")) != EOF) { - switch (opt) { - case 'i': - input_cores_mask = parse_unsigned(optarg); - break; - case 'o': - output_cores_mask = parse_unsigned(optarg); - break; - case 'p': - ports_mask = parse_unsigned(optarg); - break; - default: - print_usage(prgname); - FATAL_ERROR("Invalid option specified"); - } - } - - /* Check that options were parsed ok */ - if (input_cores_mask == 0) { - print_usage(prgname); - FATAL_ERROR("IN_CORES not specified correctly"); - } - if (output_cores_mask == 0) { - print_usage(prgname); - FATAL_ERROR("OUT_CORES not specified correctly"); - } - if (ports_mask == 0) { - print_usage(prgname); - FATAL_ERROR("PORTMASK not specified correctly"); - } - - setup_port_lcore_affinities(); -} - -/* Initialise a single port on an Ethernet device */ -static void -init_port(uint16_t port) -{ - int ret; - uint16_t nb_rxd = NB_RXD; - uint16_t nb_txd = NB_TXD; - struct rte_eth_dev_info dev_info; - struct rte_eth_rxconf rxq_conf; - struct rte_eth_txconf txq_conf; - struct rte_eth_conf local_port_conf = port_conf; - - /* Initialise device and RX/TX queues */ - PRINT_INFO("Initialising port %u ...", port); - fflush(stdout); - rte_eth_dev_info_get(port, &dev_info); - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - ret = rte_eth_dev_configure(port, 1, 1, &local_port_conf); - if (ret < 0) - FATAL_ERROR("Could not configure port%u (%d)", port, ret); - - ret = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd); - if (ret < 0) - FATAL_ERROR("Could not adjust number of descriptors for port%u (%d)", - port, ret); - - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = local_port_conf.rxmode.offloads; - ret = rte_eth_rx_queue_setup(port, 0, nb_rxd, - rte_eth_dev_socket_id(port), - &rxq_conf, - pktmbuf_pool); - if (ret < 0) - FATAL_ERROR("Could not setup up RX queue for port%u (%d)", - port, ret); - - txq_conf = dev_info.default_txconf; - txq_conf.offloads = local_port_conf.txmode.offloads; - ret = rte_eth_tx_queue_setup(port, 0, nb_txd, - rte_eth_dev_socket_id(port), - &txq_conf); - if (ret < 0) - FATAL_ERROR("Could not setup up TX queue for port%u (%d)", - port, ret); - - ret = rte_eth_dev_start(port); - if (ret < 0) - FATAL_ERROR("Could not start port%u (%d)", port, ret); - - rte_eth_promiscuous_enable(port); -} - -/* Check the link status of all ports in up to 9s, and print them finally */ -static void -check_all_ports_link_status(uint32_t port_mask) -{ -#define CHECK_INTERVAL 100 /* 100ms */ -#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ - uint16_t portid; - uint8_t count, all_ports_up, print_flag = 0; - struct rte_eth_link link; - - printf("\nChecking link status"); - fflush(stdout); - for (count = 0; count <= MAX_CHECK_TIME; count++) { - all_ports_up = 1; - RTE_ETH_FOREACH_DEV(portid) { - if ((port_mask & (1 << portid)) == 0) - continue; - memset(&link, 0, sizeof(link)); - rte_eth_link_get_nowait(portid, &link); - /* print link status if flag set */ - if (print_flag == 1) { - if (link.link_status) - printf( - "Port%d Link Up. Speed %u Mbps - %s\n", - portid, link.link_speed, - (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? - ("full-duplex") : ("half-duplex\n")); - else - printf("Port %d Link Down\n", portid); - continue; - } - /* clear all_ports_up flag if any link down */ - if (link.link_status == ETH_LINK_DOWN) { - all_ports_up = 0; - break; - } - } - /* after finally printing all link status, get out */ - if (print_flag == 1) - break; - - if (all_ports_up == 0) { - printf("."); - fflush(stdout); - rte_delay_ms(CHECK_INTERVAL); - } - - /* set the print_flag if all ports up or timeout */ - if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { - print_flag = 1; - printf("done\n"); - } - } -} - -/* Initialise ports/queues etc. and start main loop on each core */ -int -main(int argc, char** argv) -{ - int ret; - unsigned i,high_port; - uint16_t nb_sys_ports, port; - - /* Associate signal_hanlder function with USR signals */ - signal(SIGUSR1, signal_handler); - signal(SIGUSR2, signal_handler); - - /* Initialise EAL */ - ret = rte_eal_init(argc, argv); - if (ret < 0) - FATAL_ERROR("Could not initialise EAL (%d)", ret); - argc -= ret; - argv += ret; - - /* Parse application arguments (after the EAL ones) */ - parse_args(argc, argv); - - /* Create the mbuf pool */ - pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, - MEMPOOL_CACHE_SZ, 0, MBUF_DATA_SZ, rte_socket_id()); - if (pktmbuf_pool == NULL) { - FATAL_ERROR("Could not initialise mbuf pool"); - return -1; - } - - /* Get number of ports found in scan */ - nb_sys_ports = rte_eth_dev_count_avail(); - if (nb_sys_ports == 0) - FATAL_ERROR("No supported Ethernet device found"); - /* Find highest port set in portmask */ - for (high_port = (sizeof(ports_mask) * 8) - 1; - (high_port != 0) && !(ports_mask & (1 << high_port)); - high_port--) - ; /* empty body */ - if (high_port > nb_sys_ports) - FATAL_ERROR("Port mask requires more ports than available"); - - /* Initialise each port */ - RTE_ETH_FOREACH_DEV(port) { - /* Skip ports that are not enabled */ - if ((ports_mask & (1 << port)) == 0) { - continue; - } - init_port(port); - } - check_all_ports_link_status(ports_mask); - - /* Launch per-lcore function on every lcore */ - rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER); - RTE_LCORE_FOREACH_SLAVE(i) { - if (rte_eal_wait_lcore(i) < 0) - return -1; - } - - return 0; -} diff --git a/examples/exception_path/meson.build b/examples/exception_path/meson.build deleted file mode 100644 index c34e11e36..000000000 --- a/examples/exception_path/meson.build +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2017 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' - -sources = files( - 'main.c' -) diff --git a/examples/meson.build b/examples/meson.build index a046b74ad..4663d9dea 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -13,7 +13,7 @@ all_examples = [ 'bbdev_app', 'bond', 'bpf', 'cmdline', 'distributor', 'ethtool', - 'eventdev_pipeline', 'exception_path', + 'eventdev_pipeline', 'fips_validation', 'flow_classify', 'flow_filtering', 'helloworld', 'ip_fragmentation', 'ip_pipeline', -- 2.17.1 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v2 3/6] examples/l3fwd-vf: remove example from DPDK 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 " Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 1/6] doc: remove unnecessary sample app guide table Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 2/6] examples/exception_path: remove example from DPDK Ciara Power @ 2019-10-24 13:31 ` Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 4/6] examples/quota-watermark: " Ciara Power ` (3 subsequent siblings) 6 siblings, 0 replies; 27+ messages in thread From: Ciara Power @ 2019-10-24 13:31 UTC (permalink / raw) To: dev; +Cc: techboard, Bruce Richardson From: Bruce Richardson <bruce.richardson@intel.com> The main l3fwd app should work with both PF and VF devices, so remove the VF-only l3fwd example. Signed-off-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com> --- MAINTAINERS | 3 - doc/guides/sample_app_ug/index.rst | 1 - .../sample_app_ug/l3_forward_virtual.rst | 98 -- examples/Makefile | 1 - examples/l3fwd-vf/Makefile | 62 - examples/l3fwd-vf/main.c | 1072 ----------------- examples/l3fwd-vf/meson.build | 12 - examples/meson.build | 2 +- 8 files changed, 1 insertion(+), 1250 deletions(-) delete mode 100644 doc/guides/sample_app_ug/l3_forward_virtual.rst delete mode 100644 examples/l3fwd-vf/Makefile delete mode 100644 examples/l3fwd-vf/main.c delete mode 100644 examples/l3fwd-vf/meson.build diff --git a/MAINTAINERS b/MAINTAINERS index 330a4d77d..92c3f6af4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1458,9 +1458,6 @@ F: examples/l2fwd-cat/ F: examples/l3fwd/ F: doc/guides/sample_app_ug/l3_forward.rst -F: examples/l3fwd-vf/ -F: doc/guides/sample_app_ug/l3_forward_virtual.rst - F: examples/link_status_interrupt/ F: doc/guides/sample_app_ug/link_status_intr.rst diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst index 076346a60..d212f81fe 100644 --- a/doc/guides/sample_app_ug/index.rst +++ b/doc/guides/sample_app_ug/index.rst @@ -29,7 +29,6 @@ Sample Applications User Guides l3_forward l3_forward_power_man l3_forward_access_ctrl - l3_forward_virtual link_status_intr load_balancer server_node_efd diff --git a/doc/guides/sample_app_ug/l3_forward_virtual.rst b/doc/guides/sample_app_ug/l3_forward_virtual.rst deleted file mode 100644 index 21eab8da3..000000000 --- a/doc/guides/sample_app_ug/l3_forward_virtual.rst +++ /dev/null @@ -1,98 +0,0 @@ -.. SPDX-License-Identifier: BSD-3-Clause - Copyright(c) 2010-2014 Intel Corporation. - -L3 Forwarding in a Virtualization Environment Sample Application -================================================================ - -The L3 Forwarding in a Virtualization Environment sample application is a simple example of packet processing using the DPDK. -The application performs L3 forwarding that takes advantage of Single Root I/O Virtualization (SR-IOV) features -in a virtualized environment. - -Overview --------- - -The application demonstrates the use of the hash and LPM libraries in the DPDK to implement packet forwarding. -The initialization and run-time paths are very similar to those of the :doc:`l3_forward`. -The forwarding decision is taken based on information read from the input packet. - -The lookup method is either hash-based or LPM-based and is selected at compile time. -When the selected lookup method is hash-based, a hash object is used to emulate the flow classification stage. -The hash object is used in correlation with the flow table to map each input packet to its flow at runtime. - -The hash lookup key is represented by the DiffServ 5-tuple composed of the following fields read from the input packet: -Source IP Address, Destination IP Address, Protocol, Source Port and Destination Port. -The ID of the output interface for the input packet is read from the identified flow table entry. -The set of flows used by the application is statically configured and loaded into the hash at initialization time. -When the selected lookup method is LPM based, an LPM object is used to emulate the forwarding stage for IPv4 packets. -The LPM object is used as the routing table to identify the next hop for each input packet at runtime. - -The LPM lookup key is represented by the Destination IP Address field read from the input packet. -The ID of the output interface for the input packet is the next hop returned by the LPM lookup. -The set of LPM rules used by the application is statically configured and loaded into the LPM object at the initialization time. - -.. note:: - - Please refer to :ref:`l2_fwd_vf_setup` for virtualized test case setup. - -Compiling the Application -------------------------- - -To compile the sample application see :doc:`compiling`. - -The application is located in the ``l3fwd-vf`` sub-directory. - -Running the Application ------------------------ - -The application has a number of command line options: - -.. code-block:: console - - ./build/l3fwd-vf [EAL options] -- -p PORTMASK --config(port,queue,lcore)[,(port,queue,lcore)] [--no-numa] - -where, - -* --p PORTMASK: Hexadecimal bitmask of ports to configure - -* --config (port,queue,lcore)[,(port,queue,lcore]: determines which queues from which ports are mapped to which cores - -* --no-numa: optional, disables numa awareness - -For example, consider a dual processor socket platform with 8 physical cores, where cores 0-7 and 16-23 appear on socket 0, -while cores 8-15 and 24-31 appear on socket 1. - -To enable L3 forwarding between two ports, assuming that both ports are in the same socket, using two cores, cores 1 and 2, -(which are in the same socket too), use the following command: - -.. code-block:: console - - ./build/l3fwd-vf -l 1,2 -n 4 -- -p 0x3 --config="(0,0,1),(1,0,2)" - -In this command: - -* The -l option enables cores 1 and 2 - -* The -p option enables ports 0 and 1 - -* The --config option enables one queue on each port and maps each (port,queue) pair to a specific core. - The following table shows the mapping in this example: - - +----------+-----------+-----------+------------------------------------+ - | **Port** | **Queue** | **lcore** | **Description** | - | | | | | - +==========+===========+===========+====================================+ - | 0 | 0 | 1 | Map queue 0 from port 0 to lcore 1 | - | | | | | - +----------+-----------+-----------+------------------------------------+ - | 1 | 0 | 2 | Map queue 0 from port 1 to lcore 2 | - | | | | | - +----------+-----------+-----------+------------------------------------+ - -Refer to the *DPDK Getting Started Guide* for general information on running applications -and the Environment Abstraction Layer (EAL) options. - -Explanation ------------ - -The operation of this application is similar to that of the basic L3 Forwarding Sample Application. -See :ref:`l3_fwd_explanation` for more information. diff --git a/examples/Makefile b/examples/Makefile index c756497d1..5dd8a72e5 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -46,7 +46,6 @@ endif DIRS-$(CONFIG_RTE_LIBRTE_ACL) += l3fwd-acl ifeq ($(CONFIG_RTE_LIBRTE_LPM)$(CONFIG_RTE_LIBRTE_HASH),yy) DIRS-$(CONFIG_RTE_LIBRTE_POWER) += l3fwd-power -DIRS-y += l3fwd-vf endif DIRS-y += link_status_interrupt DIRS-$(CONFIG_RTE_LIBRTE_LPM) += load_balancer diff --git a/examples/l3fwd-vf/Makefile b/examples/l3fwd-vf/Makefile deleted file mode 100644 index 7b186a23c..000000000 --- a/examples/l3fwd-vf/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2010-2014 Intel Corporation - -# binary name -APP = l3fwd-vf - -# all source are stored in SRCS-y -SRCS-y := main.c - -# Build using pkg-config variables if possible -ifeq ($(shell pkg-config --exists libdpdk && echo 0),0) - -all: shared -.PHONY: shared static -shared: build/$(APP)-shared - ln -sf $(APP)-shared build/$(APP) -static: build/$(APP)-static - ln -sf $(APP)-static build/$(APP) - -PKGCONF=pkg-config --define-prefix - -PC_FILE := $(shell $(PKGCONF) --path libdpdk) -CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) -LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk) -LDFLAGS_STATIC = -Wl,-Bstatic $(shell $(PKGCONF) --static --libs libdpdk) - -build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) - -build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC) - -build: - @mkdir -p $@ - -.PHONY: clean -clean: - rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared - test -d build && rmdir -p build || true - -else # Build using legacy build system - -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 - -CFLAGS += -O3 $(USER_FLAGS) -CFLAGS += $(WERROR_FLAGS) - -# workaround for a gcc bug with noreturn attribute -# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603 -ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y) -CFLAGS_main.o += -Wno-return-type -endif - -include $(RTE_SDK)/mk/rte.extapp.mk -endif diff --git a/examples/l3fwd-vf/main.c b/examples/l3fwd-vf/main.c deleted file mode 100644 index 572e74cf5..000000000 --- a/examples/l3fwd-vf/main.c +++ /dev/null @@ -1,1072 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> -#include <signal.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_spinlock.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_udp.h> -#include <rte_string_fns.h> - -#define APP_LOOKUP_EXACT_MATCH 0 -#define APP_LOOKUP_LPM 1 -#define DO_RFC_1812_CHECKS - -//#define APP_LOOKUP_METHOD APP_LOOKUP_EXACT_MATCH -#ifndef APP_LOOKUP_METHOD -#define APP_LOOKUP_METHOD APP_LOOKUP_LPM -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH) -#include <rte_hash.h> -#elif (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) -#include <rte_lpm.h> -#else -#error "APP_LOOKUP_METHOD set to incorrect value" -#endif - -#define RTE_LOGTYPE_L3FWD RTE_LOGTYPE_USER1 - -#define MEMPOOL_CACHE_SIZE 256 - -/* - * This expression is used to calculate the number of mbufs needed depending on user input, taking - * into account memory for rx and tx hardware rings, cache per lcore and mtable per port per lcore. - * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum value of 8192 - */ - -#define NB_MBUF RTE_MAX ( \ - (nb_ports*nb_rx_queue*nb_rxd + \ - nb_ports*nb_lcores*MAX_PKT_BURST + \ - nb_ports*n_tx_queue*nb_txd + \ - nb_lcores*MEMPOOL_CACHE_SIZE), \ - (unsigned)8192) - -#define MAX_PKT_BURST 32 -#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */ - -#define NB_SOCKETS 8 - -#define SOCKET0 0 - -/* Configure how many packets ahead to prefetch, when reading packets */ -#define PREFETCH_OFFSET 3 - -/* - * Configurable number of RX/TX ring descriptors - */ -#define RTE_TEST_RX_DESC_DEFAULT 1024 -#define RTE_TEST_TX_DESC_DEFAULT 1024 -static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; -static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; - -/* ethernet addresses of ports */ -static struct rte_ether_addr ports_eth_addr[RTE_MAX_ETHPORTS]; - -/* mask of enabled ports */ -static uint32_t enabled_port_mask = 0; -static int numa_on = 1; /**< NUMA is enabled by default. */ - -struct mbuf_table { - uint16_t len; - struct rte_mbuf *m_table[MAX_PKT_BURST]; -}; - -struct lcore_rx_queue { - uint16_t port_id; - uint8_t queue_id; -} __rte_cache_aligned; - -#define MAX_RX_QUEUE_PER_LCORE 16 -#define MAX_TX_QUEUE_PER_PORT 1 -#define MAX_RX_QUEUE_PER_PORT 1 - -#define MAX_LCORE_PARAMS 1024 -struct lcore_params { - uint16_t port_id; - uint8_t queue_id; - uint8_t lcore_id; -} __rte_cache_aligned; - -static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS]; -static struct lcore_params lcore_params_array_default[] = { - {0, 0, 2}, - {0, 1, 2}, - {0, 2, 2}, - {1, 0, 2}, - {1, 1, 2}, - {1, 2, 2}, - {2, 0, 2}, - {3, 0, 3}, - {3, 1, 3}, -}; - -static struct lcore_params * lcore_params = lcore_params_array_default; -static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) / - sizeof(lcore_params_array_default[0]); - -static struct rte_eth_conf port_conf = { - .rxmode = { - .mq_mode = ETH_MQ_RX_RSS, - .max_rx_pkt_len = RTE_ETHER_MAX_LEN, - .split_hdr_size = 0, - .offloads = DEV_RX_OFFLOAD_CHECKSUM, - }, - .rx_adv_conf = { - .rss_conf = { - .rss_key = NULL, - .rss_hf = ETH_RSS_IP, - }, - }, - .txmode = { - .mq_mode = ETH_MQ_TX_NONE, - }, -}; - -static struct rte_mempool * pktmbuf_pool[NB_SOCKETS]; - - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH) - -#ifdef RTE_ARCH_X86 -#include <rte_hash_crc.h> -#define DEFAULT_HASH_FUNC rte_hash_crc -#else -#include <rte_jhash.h> -#define DEFAULT_HASH_FUNC rte_jhash -#endif - -struct ipv4_5tuple { - uint32_t ip_dst; - uint32_t ip_src; - uint16_t port_dst; - uint16_t port_src; - uint8_t proto; -} __attribute__((__packed__)); - -struct l3fwd_route { - struct ipv4_5tuple key; - uint8_t if_out; -}; - -static struct l3fwd_route l3fwd_route_array[] = { - {{RTE_IPV4(100,10,0,1), RTE_IPV4(200,10,0,1), 101, 11, IPPROTO_TCP}, 0}, - {{RTE_IPV4(100,20,0,2), RTE_IPV4(200,20,0,2), 102, 12, IPPROTO_TCP}, 1}, - {{RTE_IPV4(100,30,0,3), RTE_IPV4(200,30,0,3), 103, 13, IPPROTO_TCP}, 2}, - {{RTE_IPV4(100,40,0,4), RTE_IPV4(200,40,0,4), 104, 14, IPPROTO_TCP}, 3}, -}; - -typedef struct rte_hash lookup_struct_t; -static lookup_struct_t *l3fwd_lookup_struct[NB_SOCKETS]; - -#define L3FWD_HASH_ENTRIES 1024 -struct rte_hash_parameters l3fwd_hash_params = { - .name = "l3fwd_hash_0", - .entries = L3FWD_HASH_ENTRIES, - .key_len = sizeof(struct ipv4_5tuple), - .hash_func = DEFAULT_HASH_FUNC, - .hash_func_init_val = 0, - .socket_id = SOCKET0, -}; - -#define L3FWD_NUM_ROUTES \ - (sizeof(l3fwd_route_array) / sizeof(l3fwd_route_array[0])) - -static uint8_t l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned; -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) -struct l3fwd_route { - uint32_t ip; - uint8_t depth; - uint8_t if_out; -}; - -static struct l3fwd_route l3fwd_route_array[] = { - {RTE_IPV4(1,1,1,0), 24, 0}, - {RTE_IPV4(2,1,1,0), 24, 1}, - {RTE_IPV4(3,1,1,0), 24, 2}, - {RTE_IPV4(4,1,1,0), 24, 3}, - {RTE_IPV4(5,1,1,0), 24, 4}, - {RTE_IPV4(6,1,1,0), 24, 5}, - {RTE_IPV4(7,1,1,0), 24, 6}, - {RTE_IPV4(8,1,1,0), 24, 7}, -}; - -#define L3FWD_NUM_ROUTES \ - (sizeof(l3fwd_route_array) / sizeof(l3fwd_route_array[0])) - -#define L3FWD_LPM_MAX_RULES 1024 - -typedef struct rte_lpm lookup_struct_t; -static lookup_struct_t *l3fwd_lookup_struct[NB_SOCKETS]; -#endif - -struct lcore_conf { - uint16_t n_rx_queue; - struct lcore_rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE]; - uint16_t tx_queue_id; - struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS]; - lookup_struct_t * lookup_struct; -} __rte_cache_aligned; - -static struct lcore_conf lcore_conf[RTE_MAX_LCORE]; -static rte_spinlock_t spinlock_conf[RTE_MAX_ETHPORTS] = {RTE_SPINLOCK_INITIALIZER}; -/* Send burst of packets on an output interface */ -static inline int -send_burst(struct lcore_conf *qconf, uint16_t n, uint16_t port) -{ - struct rte_mbuf **m_table; - int ret; - uint16_t queueid; - - queueid = qconf->tx_queue_id; - m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table; - - rte_spinlock_lock(&spinlock_conf[port]); - ret = rte_eth_tx_burst(port, queueid, m_table, n); - rte_spinlock_unlock(&spinlock_conf[port]); - - if (unlikely(ret < n)) { - do { - rte_pktmbuf_free(m_table[ret]); - } while (++ret < n); - } - - return 0; -} - -/* Enqueue a single packet, and send burst if queue is filled */ -static inline int -send_single_packet(struct rte_mbuf *m, uint16_t port) -{ - uint32_t lcore_id; - uint16_t len; - struct lcore_conf *qconf; - - lcore_id = rte_lcore_id(); - - qconf = &lcore_conf[lcore_id]; - len = qconf->tx_mbufs[port].len; - qconf->tx_mbufs[port].m_table[len] = m; - len++; - - /* enough pkts to be sent */ - if (unlikely(len == MAX_PKT_BURST)) { - send_burst(qconf, MAX_PKT_BURST, port); - len = 0; - } - - qconf->tx_mbufs[port].len = len; - return 0; -} - -#ifdef DO_RFC_1812_CHECKS -static inline int -is_valid_ipv4_pkt(struct rte_ipv4_hdr *pkt, uint32_t link_len) -{ - /* From http://www.rfc-editor.org/rfc/rfc1812.txt section 5.2.2 */ - /* - * 1. The packet length reported by the Link Layer must be large - * enough to hold the minimum length legal IP datagram (20 bytes). - */ - if (link_len < sizeof(struct rte_ipv4_hdr)) - return -1; - - /* 2. The IP checksum must be correct. */ - /* this is checked in H/W */ - - /* - * 3. The IP version number must be 4. If the version number is not 4 - * then the packet may be another version of IP, such as IPng or - * ST-II. - */ - if (((pkt->version_ihl) >> 4) != 4) - return -3; - /* - * 4. The IP header length field must be large enough to hold the - * minimum length legal IP datagram (20 bytes = 5 words). - */ - if ((pkt->version_ihl & 0xf) < 5) - return -4; - - /* - * 5. The IP total length field must be large enough to hold the IP - * datagram header, whose length is specified in the IP header length - * field. - */ - if (rte_cpu_to_be_16(pkt->total_length) < sizeof(struct rte_ipv4_hdr)) - return -5; - - return 0; -} -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH) -static void -print_key(struct ipv4_5tuple key) -{ - printf("IP dst = %08x, IP src = %08x, port dst = %d, port src = %d, proto = %d\n", - (unsigned)key.ip_dst, (unsigned)key.ip_src, key.port_dst, key.port_src, key.proto); -} - -static inline uint16_t -get_dst_port(struct rte_ipv4_hdr *ipv4_hdr, uint16_t portid, - lookup_struct_t *l3fwd_lookup_struct) -{ - struct ipv4_5tuple key; - struct rte_tcp_hdr *tcp; - struct rte_udp_hdr *udp; - int ret = 0; - - key.ip_dst = rte_be_to_cpu_32(ipv4_hdr->dst_addr); - key.ip_src = rte_be_to_cpu_32(ipv4_hdr->src_addr); - key.proto = ipv4_hdr->next_proto_id; - - switch (ipv4_hdr->next_proto_id) { - case IPPROTO_TCP: - tcp = (struct rte_tcp_hdr *)((unsigned char *) ipv4_hdr + - sizeof(struct rte_ipv4_hdr)); - key.port_dst = rte_be_to_cpu_16(tcp->dst_port); - key.port_src = rte_be_to_cpu_16(tcp->src_port); - break; - - case IPPROTO_UDP: - udp = (struct rte_udp_hdr *)((unsigned char *) ipv4_hdr + - sizeof(struct rte_ipv4_hdr)); - key.port_dst = rte_be_to_cpu_16(udp->dst_port); - key.port_src = rte_be_to_cpu_16(udp->src_port); - break; - - default: - key.port_dst = 0; - key.port_src = 0; - } - - /* Find destination port */ - ret = rte_hash_lookup(l3fwd_lookup_struct, (const void *)&key); - return ((ret < 0) ? portid : l3fwd_out_if[ret]); -} -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) -static inline uint32_t -get_dst_port(struct rte_ipv4_hdr *ipv4_hdr, uint16_t portid, - lookup_struct_t *l3fwd_lookup_struct) -{ - uint32_t next_hop; - - return ((rte_lpm_lookup(l3fwd_lookup_struct, - rte_be_to_cpu_32(ipv4_hdr->dst_addr), &next_hop) == 0) ? - next_hop : portid); -} -#endif - -static inline void -l3fwd_simple_forward(struct rte_mbuf *m, uint16_t portid, - lookup_struct_t *l3fwd_lookup_struct) -{ - struct rte_ether_hdr *eth_hdr; - struct rte_ipv4_hdr *ipv4_hdr; - void *tmp; - uint16_t dst_port; - - eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *); - - ipv4_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *, - sizeof(struct rte_ether_hdr)); - -#ifdef DO_RFC_1812_CHECKS - /* Check to make sure the packet is valid (RFC1812) */ - if (is_valid_ipv4_pkt(ipv4_hdr, m->pkt_len) < 0) { - rte_pktmbuf_free(m); - return; - } -#endif - - dst_port = get_dst_port(ipv4_hdr, portid, l3fwd_lookup_struct); - if (dst_port >= RTE_MAX_ETHPORTS || (enabled_port_mask & 1 << dst_port) == 0) - dst_port = portid; - - /* 02:00:00:00:00:xx */ - tmp = ð_hdr->d_addr.addr_bytes[0]; - *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40); - -#ifdef DO_RFC_1812_CHECKS - /* Update time to live and header checksum */ - --(ipv4_hdr->time_to_live); - ++(ipv4_hdr->hdr_checksum); -#endif - - /* src addr */ - rte_ether_addr_copy(&ports_eth_addr[dst_port], ð_hdr->s_addr); - - send_single_packet(m, dst_port); - -} - -/* main processing loop */ -static int -main_loop(__attribute__((unused)) void *dummy) -{ - struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; - unsigned lcore_id; - uint64_t prev_tsc, diff_tsc, cur_tsc; - int i, j, nb_rx; - uint8_t queueid; - uint16_t portid; - struct lcore_conf *qconf; - const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US; - - prev_tsc = 0; - - lcore_id = rte_lcore_id(); - qconf = &lcore_conf[lcore_id]; - - if (qconf->n_rx_queue == 0) { - RTE_LOG(INFO, L3FWD, "lcore %u has nothing to do\n", lcore_id); - return 0; - } - - RTE_LOG(INFO, L3FWD, "entering main loop on lcore %u\n", lcore_id); - - for (i = 0; i < qconf->n_rx_queue; i++) { - - portid = qconf->rx_queue_list[i].port_id; - queueid = qconf->rx_queue_list[i].queue_id; - RTE_LOG(INFO, L3FWD, " --lcoreid=%u portid=%u rxqueueid=%hhu\n", - lcore_id, portid, queueid); - } - - while (1) { - - cur_tsc = rte_rdtsc(); - - /* - * TX burst queue drain - */ - diff_tsc = cur_tsc - prev_tsc; - if (unlikely(diff_tsc > drain_tsc)) { - - /* - * This could be optimized (use queueid instead of - * portid), but it is not called so often - */ - for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { - if (qconf->tx_mbufs[portid].len == 0) - continue; - send_burst(&lcore_conf[lcore_id], - qconf->tx_mbufs[portid].len, - portid); - qconf->tx_mbufs[portid].len = 0; - } - - prev_tsc = cur_tsc; - } - - /* - * Read packet from RX queues - */ - for (i = 0; i < qconf->n_rx_queue; ++i) { - - portid = qconf->rx_queue_list[i].port_id; - queueid = qconf->rx_queue_list[i].queue_id; - nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst, MAX_PKT_BURST); - - /* Prefetch first packets */ - for (j = 0; j < PREFETCH_OFFSET && j < nb_rx; j++) { - rte_prefetch0(rte_pktmbuf_mtod( - pkts_burst[j], void *)); - } - - /* Prefetch and forward already prefetched packets */ - for (j = 0; j < (nb_rx - PREFETCH_OFFSET); j++) { - rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[ - j + PREFETCH_OFFSET], void *)); - l3fwd_simple_forward(pkts_burst[j], portid, qconf->lookup_struct); - } - - /* Forward remaining prefetched packets */ - for (; j < nb_rx; j++) { - l3fwd_simple_forward(pkts_burst[j], portid, qconf->lookup_struct); - } - } - } -} - -static int -check_lcore_params(void) -{ - uint8_t queue, lcore; - uint16_t i; - int socketid; - - for (i = 0; i < nb_lcore_params; ++i) { - queue = lcore_params[i].queue_id; - if (queue >= MAX_RX_QUEUE_PER_PORT) { - printf("invalid queue number: %hhu\n", queue); - return -1; - } - lcore = lcore_params[i].lcore_id; - if (!rte_lcore_is_enabled(lcore)) { - printf("error: lcore %hhu is not enabled in lcore mask\n", lcore); - return -1; - } - if ((socketid = rte_lcore_to_socket_id(lcore) != 0) && - (numa_on == 0)) { - printf("warning: lcore %hhu is on socket %d with numa off \n", - lcore, socketid); - } - } - return 0; -} - -static int -check_port_config(void) -{ - unsigned portid; - uint16_t i; - - for (i = 0; i < nb_lcore_params; ++i) { - portid = lcore_params[i].port_id; - if ((enabled_port_mask & (1 << portid)) == 0) { - printf("port %u is not enabled in port mask\n", portid); - return -1; - } - if (!rte_eth_dev_is_valid_port(portid)) { - printf("port %u is not present on the board\n", portid); - return -1; - } - } - return 0; -} - -static uint8_t -get_port_n_rx_queues(const uint16_t port) -{ - int queue = -1; - uint16_t i; - - for (i = 0; i < nb_lcore_params; ++i) { - if (lcore_params[i].port_id == port && lcore_params[i].queue_id > queue) - queue = lcore_params[i].queue_id; - } - return (uint8_t)(++queue); -} - -static int -init_lcore_rx_queues(void) -{ - uint16_t i, nb_rx_queue; - uint8_t lcore; - - for (i = 0; i < nb_lcore_params; ++i) { - lcore = lcore_params[i].lcore_id; - nb_rx_queue = lcore_conf[lcore].n_rx_queue; - if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) { - printf("error: too many queues (%u) for lcore: %u\n", - (unsigned)nb_rx_queue + 1, (unsigned)lcore); - return -1; - } else { - lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id = - lcore_params[i].port_id; - lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id = - lcore_params[i].queue_id; - lcore_conf[lcore].n_rx_queue++; - } - } - return 0; -} - -/* display usage */ -static void -print_usage(const char *prgname) -{ - printf ("%s [EAL options] -- -p PORTMASK" - " [--config (port,queue,lcore)[,(port,queue,lcore]]\n" - " -p PORTMASK: hexadecimal bitmask of ports to configure\n" - " --config (port,queue,lcore): rx queues configuration\n" - " --no-numa: optional, disable numa awareness\n", - prgname); -} - -/* Custom handling of signals to handle process terminal */ -static void -signal_handler(int signum) -{ - uint16_t portid; - - /* When we receive a SIGINT signal */ - if (signum == SIGINT) { - RTE_ETH_FOREACH_DEV(portid) { - /* skip ports that are not enabled */ - if ((enabled_port_mask & (1 << portid)) == 0) - continue; - rte_eth_dev_close(portid); - } - } - rte_exit(EXIT_SUCCESS, "\n User forced exit\n"); -} -static int -parse_portmask(const char *portmask) -{ - char *end = NULL; - unsigned long pm; - - /* parse hexadecimal string */ - pm = strtoul(portmask, &end, 16); - if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) - return -1; - - if (pm == 0) - return -1; - - return pm; -} - -static int -parse_config(const char *q_arg) -{ - char s[256]; - const char *p, *p0 = q_arg; - char *end; - enum fieldnames { - FLD_PORT = 0, - FLD_QUEUE, - FLD_LCORE, - _NUM_FLD - }; - unsigned long int_fld[_NUM_FLD]; - char *str_fld[_NUM_FLD]; - int i; - unsigned size; - - nb_lcore_params = 0; - - while ((p = strchr(p0,'(')) != NULL) { - ++p; - if((p0 = strchr(p,')')) == NULL) - return -1; - - size = p0 - p; - if(size >= sizeof(s)) - return -1; - - snprintf(s, sizeof(s), "%.*s", size, p); - if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != _NUM_FLD) - return -1; - for (i = 0; i < _NUM_FLD; i++){ - errno = 0; - int_fld[i] = strtoul(str_fld[i], &end, 0); - if (errno != 0 || end == str_fld[i] || int_fld[i] > 255) - return -1; - } - if (nb_lcore_params >= MAX_LCORE_PARAMS) { - printf("exceeded max number of lcore params: %hu\n", - nb_lcore_params); - return -1; - } - lcore_params_array[nb_lcore_params].port_id = int_fld[FLD_PORT]; - lcore_params_array[nb_lcore_params].queue_id = (uint8_t)int_fld[FLD_QUEUE]; - lcore_params_array[nb_lcore_params].lcore_id = (uint8_t)int_fld[FLD_LCORE]; - ++nb_lcore_params; - } - lcore_params = lcore_params_array; - return 0; -} - -/* Parse the argument given in the command line of the application */ -static int -parse_args(int argc, char **argv) -{ - int opt, ret; - char **argvopt; - int option_index; - char *prgname = argv[0]; - static struct option lgopts[] = { - {"config", 1, 0, 0}, - {"no-numa", 0, 0, 0}, - {NULL, 0, 0, 0} - }; - - argvopt = argv; - - while ((opt = getopt_long(argc, argvopt, "p:", - lgopts, &option_index)) != EOF) { - - switch (opt) { - /* portmask */ - case 'p': - enabled_port_mask = parse_portmask(optarg); - if (enabled_port_mask == 0) { - printf("invalid portmask\n"); - print_usage(prgname); - return -1; - } - break; - - /* long options */ - case 0: - if (!strcmp(lgopts[option_index].name, "config")) { - ret = parse_config(optarg); - if (ret) { - printf("invalid config\n"); - print_usage(prgname); - return -1; - } - } - - if (!strcmp(lgopts[option_index].name, "no-numa")) { - printf("numa is disabled \n"); - numa_on = 0; - } - break; - - default: - print_usage(prgname); - return -1; - } - } - - if (optind >= 0) - argv[optind-1] = prgname; - - ret = optind-1; - optind = 1; /* reset getopt lib */ - return ret; -} - -static void -print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr) -{ - char buf[RTE_ETHER_ADDR_FMT_SIZE]; - rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr); - printf("%s%s", name, buf); -} - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH) -static void -setup_hash(int socketid) -{ - unsigned i; - int ret; - char s[64]; - - /* create hashes */ - snprintf(s, sizeof(s), "l3fwd_hash_%d", socketid); - l3fwd_hash_params.name = s; - l3fwd_hash_params.socket_id = socketid; - l3fwd_lookup_struct[socketid] = rte_hash_create(&l3fwd_hash_params); - if (l3fwd_lookup_struct[socketid] == NULL) - rte_exit(EXIT_FAILURE, "Unable to create the l3fwd hash on " - "socket %d\n", socketid); - - /* populate the hash */ - for (i = 0; i < L3FWD_NUM_ROUTES; i++) { - ret = rte_hash_add_key (l3fwd_lookup_struct[socketid], - (void *) &l3fwd_route_array[i].key); - if (ret < 0) { - rte_exit(EXIT_FAILURE, "Unable to add entry %u to the" - "l3fwd hash on socket %d\n", i, socketid); - } - l3fwd_out_if[ret] = l3fwd_route_array[i].if_out; - printf("Hash: Adding key\n"); - print_key(l3fwd_route_array[i].key); - } -} -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) -static void -setup_lpm(int socketid) -{ - unsigned i; - int ret; - char s[64]; - - struct rte_lpm_config lpm_ipv4_config; - - lpm_ipv4_config.max_rules = L3FWD_LPM_MAX_RULES; - lpm_ipv4_config.number_tbl8s = 256; - lpm_ipv4_config.flags = 0; - - /* create the LPM table */ - snprintf(s, sizeof(s), "L3FWD_LPM_%d", socketid); - l3fwd_lookup_struct[socketid] = - rte_lpm_create(s, socketid, &lpm_ipv4_config); - if (l3fwd_lookup_struct[socketid] == NULL) - rte_exit(EXIT_FAILURE, "Unable to create the l3fwd LPM table" - " on socket %d\n", socketid); - - /* populate the LPM table */ - for (i = 0; i < L3FWD_NUM_ROUTES; i++) { - ret = rte_lpm_add(l3fwd_lookup_struct[socketid], - l3fwd_route_array[i].ip, - l3fwd_route_array[i].depth, - l3fwd_route_array[i].if_out); - - if (ret < 0) { - rte_exit(EXIT_FAILURE, "Unable to add entry %u to the " - "l3fwd LPM table on socket %d\n", - i, socketid); - } - - printf("LPM: Adding route 0x%08x / %d (%d)\n", - (unsigned)l3fwd_route_array[i].ip, - l3fwd_route_array[i].depth, - l3fwd_route_array[i].if_out); - } -} -#endif - -static int -init_mem(unsigned nb_mbuf) -{ - struct lcore_conf *qconf; - int socketid; - unsigned lcore_id; - char s[64]; - - for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { - if (rte_lcore_is_enabled(lcore_id) == 0) - continue; - - if (numa_on) - socketid = rte_lcore_to_socket_id(lcore_id); - else - socketid = 0; - - if (socketid >= NB_SOCKETS) { - rte_exit(EXIT_FAILURE, "Socket %d of lcore %u is out of range %d\n", - socketid, lcore_id, NB_SOCKETS); - } - if (pktmbuf_pool[socketid] == NULL) { - snprintf(s, sizeof(s), "mbuf_pool_%d", socketid); - pktmbuf_pool[socketid] = rte_pktmbuf_pool_create(s, - nb_mbuf, MEMPOOL_CACHE_SIZE, 0, - RTE_MBUF_DEFAULT_BUF_SIZE, socketid); - if (pktmbuf_pool[socketid] == NULL) - rte_exit(EXIT_FAILURE, "Cannot init mbuf pool on socket %d\n", socketid); - else - printf("Allocated mbuf pool on socket %d\n", socketid); - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) - setup_lpm(socketid); -#else - setup_hash(socketid); -#endif - } - qconf = &lcore_conf[lcore_id]; - qconf->lookup_struct = l3fwd_lookup_struct[socketid]; - } - return 0; -} - -int -main(int argc, char **argv) -{ - struct lcore_conf *qconf; - struct rte_eth_dev_info dev_info; - struct rte_eth_txconf *txconf; - int ret; - unsigned nb_ports; - uint16_t queueid, portid; - unsigned lcore_id; - uint32_t nb_lcores; - uint16_t n_tx_queue; - uint8_t nb_rx_queue, queue, socketid; - - signal(SIGINT, signal_handler); - /* init EAL */ - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n"); - argc -= ret; - argv += ret; - - /* parse application arguments (after the EAL ones) */ - ret = parse_args(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid L3FWD-VF parameters\n"); - - if (check_lcore_params() < 0) - rte_exit(EXIT_FAILURE, "check_lcore_params failed\n"); - - ret = init_lcore_rx_queues(); - if (ret < 0) - rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n"); - - nb_ports = rte_eth_dev_count_avail(); - - if (check_port_config() < 0) - rte_exit(EXIT_FAILURE, "check_port_config failed\n"); - - nb_lcores = rte_lcore_count(); - - /* initialize all ports */ - RTE_ETH_FOREACH_DEV(portid) { - struct rte_eth_conf local_port_conf = port_conf; - - /* skip ports that are not enabled */ - if ((enabled_port_mask & (1 << portid)) == 0) { - printf("\nSkipping disabled port %d\n", portid); - continue; - } - - /* init port */ - printf("Initializing port %d ... ", portid ); - fflush(stdout); - - /* must always equal(=1) */ - nb_rx_queue = get_port_n_rx_queues(portid); - n_tx_queue = MAX_TX_QUEUE_PER_PORT; - - printf("Creating queues: nb_rxq=%d nb_txq=%u... ", - nb_rx_queue, (unsigned)1 ); - - rte_eth_dev_info_get(portid, &dev_info); - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - - local_port_conf.rx_adv_conf.rss_conf.rss_hf &= - dev_info.flow_type_rss_offloads; - if (local_port_conf.rx_adv_conf.rss_conf.rss_hf != - port_conf.rx_adv_conf.rss_conf.rss_hf) { - printf("Port %u modified RSS hash function based on hardware support," - "requested:%#"PRIx64" configured:%#"PRIx64"\n", - portid, - port_conf.rx_adv_conf.rss_conf.rss_hf, - local_port_conf.rx_adv_conf.rss_conf.rss_hf); - } - - ret = rte_eth_dev_configure(portid, nb_rx_queue, - n_tx_queue, &local_port_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%d\n", - ret, portid); - - ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, - &nb_txd); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Cannot adjust number of descriptors: err=%d, port=%d\n", - ret, portid); - - rte_eth_macaddr_get(portid, &ports_eth_addr[portid]); - print_ethaddr(" Address:", &ports_eth_addr[portid]); - printf(", "); - - ret = init_mem(NB_MBUF); - if (ret < 0) - rte_exit(EXIT_FAILURE, "init_mem failed\n"); - - /* init one TX queue */ - socketid = (uint8_t)rte_lcore_to_socket_id(rte_get_master_lcore()); - - printf("txq=%d,%d,%d ", portid, 0, socketid); - fflush(stdout); - - txconf = &dev_info.default_txconf; - txconf->offloads = local_port_conf.txmode.offloads; - ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, - socketid, txconf); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: err=%d, " - "port=%d\n", ret, portid); - - printf("\n"); - } - - for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { - struct rte_eth_rxconf rxq_conf; - - if (rte_lcore_is_enabled(lcore_id) == 0) - continue; - qconf = &lcore_conf[lcore_id]; - qconf->tx_queue_id = 0; - - printf("\nInitializing rx queues on lcore %u ... ", lcore_id ); - fflush(stdout); - /* init RX queues */ - for(queue = 0; queue < qconf->n_rx_queue; ++queue) { - portid = qconf->rx_queue_list[queue].port_id; - queueid = qconf->rx_queue_list[queue].queue_id; - - if (numa_on) - socketid = (uint8_t)rte_lcore_to_socket_id(lcore_id); - else - socketid = 0; - - printf("rxq=%d,%d,%d ", portid, queueid, socketid); - fflush(stdout); - - rte_eth_dev_info_get(portid, &dev_info); - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = port_conf.rxmode.offloads; - ret = rte_eth_rx_queue_setup(portid, queueid, nb_rxd, - socketid, &rxq_conf, - pktmbuf_pool[socketid]); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: err=%d," - "port=%d\n", ret, portid); - } - } - printf("\n"); - - /* start ports */ - RTE_ETH_FOREACH_DEV(portid) { - if ((enabled_port_mask & (1 << portid)) == 0) { - continue; - } - /* Start device */ - ret = rte_eth_dev_start(portid); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, port=%d\n", - ret, portid); - - printf("done: Port %d\n", portid); - - } - - /* launch per-lcore init on every lcore */ - rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER); - RTE_LCORE_FOREACH_SLAVE(lcore_id) { - if (rte_eal_wait_lcore(lcore_id) < 0) - return -1; - } - - return 0; -} diff --git a/examples/l3fwd-vf/meson.build b/examples/l3fwd-vf/meson.build deleted file mode 100644 index 226286e74..000000000 --- a/examples/l3fwd-vf/meson.build +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2017 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' - -deps += ['lpm', 'hash'] -sources = files( - 'main.c' -) diff --git a/examples/meson.build b/examples/meson.build index 4663d9dea..81ac8199a 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -23,7 +23,7 @@ all_examples = [ 'l2fwd-crypto', 'l2fwd-jobstats', 'l2fwd-keepalive', 'l3fwd', 'l3fwd-acl', 'l3fwd-power', - 'l3fwd-vf', 'link_status_interrupt', + 'link_status_interrupt', 'load_balancer', 'multi_process/client_server_mp/mp_client', 'multi_process/client_server_mp/mp_server', -- 2.17.1 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v2 4/6] examples/quota-watermark: remove example from DPDK 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 " Ciara Power ` (2 preceding siblings ...) 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 3/6] examples/l3fwd-vf: " Ciara Power @ 2019-10-24 13:31 ` Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 5/6] examples/netmap-compat: " Ciara Power ` (2 subsequent siblings) 6 siblings, 0 replies; 27+ messages in thread From: Ciara Power @ 2019-10-24 13:31 UTC (permalink / raw) To: dev; +Cc: techboard, Ciara Power Original DPDK rings code had explicit support for a single watermark per-ring, but more recent releases of DPDK had a more general mechanism where each enqueue or dequeue call could return the remaining elements/free-slots in the ring. Therefore, this example is not as relevant as before and can be removed. Signed-off-by: Ciara Power <ciara.power@intel.com> Acked-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com> --- MAINTAINERS | 3 - doc/guides/sample_app_ug/index.rst | 1 - doc/guides/sample_app_ug/quota_watermark.rst | 465 ------------------- examples/Makefile | 1 - examples/meson.build | 2 +- examples/quota_watermark/Makefile | 16 - examples/quota_watermark/include/conf.h | 19 - examples/quota_watermark/meson.build | 10 - examples/quota_watermark/qw/Makefile | 22 - examples/quota_watermark/qw/args.c | 78 ---- examples/quota_watermark/qw/args.h | 12 - examples/quota_watermark/qw/init.c | 164 ------- examples/quota_watermark/qw/init.h | 14 - examples/quota_watermark/qw/main.c | 365 --------------- examples/quota_watermark/qw/main.h | 31 -- examples/quota_watermark/qwctl/Makefile | 22 - examples/quota_watermark/qwctl/commands.c | 196 -------- examples/quota_watermark/qwctl/commands.h | 12 - examples/quota_watermark/qwctl/qwctl.c | 67 --- examples/quota_watermark/qwctl/qwctl.h | 12 - 20 files changed, 1 insertion(+), 1511 deletions(-) delete mode 100644 doc/guides/sample_app_ug/quota_watermark.rst delete mode 100644 examples/quota_watermark/Makefile delete mode 100644 examples/quota_watermark/include/conf.h delete mode 100644 examples/quota_watermark/meson.build delete mode 100644 examples/quota_watermark/qw/Makefile delete mode 100644 examples/quota_watermark/qw/args.c delete mode 100644 examples/quota_watermark/qw/args.h delete mode 100644 examples/quota_watermark/qw/init.c delete mode 100644 examples/quota_watermark/qw/init.h delete mode 100644 examples/quota_watermark/qw/main.c delete mode 100644 examples/quota_watermark/qw/main.h delete mode 100644 examples/quota_watermark/qwctl/Makefile delete mode 100644 examples/quota_watermark/qwctl/commands.c delete mode 100644 examples/quota_watermark/qwctl/commands.h delete mode 100644 examples/quota_watermark/qwctl/qwctl.c delete mode 100644 examples/quota_watermark/qwctl/qwctl.h diff --git a/MAINTAINERS b/MAINTAINERS index 92c3f6af4..7be363327 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1474,9 +1474,6 @@ F: doc/guides/sample_app_ug/performance_thread.rst F: examples/ptpclient/ -F: examples/quota_watermark/ -F: doc/guides/sample_app_ug/quota_watermark.rst - M: Bruce Richardson <bruce.richardson@intel.com> M: John McNamara <john.mcnamara@intel.com> F: examples/rxtx_callbacks/ diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst index d212f81fe..dafe8553f 100644 --- a/doc/guides/sample_app_ug/index.rst +++ b/doc/guides/sample_app_ug/index.rst @@ -36,7 +36,6 @@ Sample Applications User Guides multi_process qos_metering qos_scheduler - quota_watermark timer packet_ordering vmdq_dcb_forwarding diff --git a/doc/guides/sample_app_ug/quota_watermark.rst b/doc/guides/sample_app_ug/quota_watermark.rst deleted file mode 100644 index 125e6fb73..000000000 --- a/doc/guides/sample_app_ug/quota_watermark.rst +++ /dev/null @@ -1,465 +0,0 @@ -.. SPDX-License-Identifier: BSD-3-Clause - Copyright(c) 2010-2017 Intel Corporation. - -Quota and Watermark Sample Application -====================================== - -The Quota and Watermark sample application is a simple example of packet -processing using Data Plane Development Kit (DPDK) that showcases the use -of a quota as the maximum number of packets enqueue/dequeue at a time and -low and high thresholds, or watermarks, to signal low and high ring usage -respectively. - -Additionally, it shows how the thresholds can be used to feedback congestion notifications to data producers by -temporarily stopping processing overloaded rings and sending Ethernet flow control frames. - -This sample application is split in two parts: - -* qw - The core quota and watermark sample application - -* qwctl - A command line tool to alter quota and watermarks while qw is running - -Overview --------- - -The Quota and Watermark sample application performs forwarding for each packet that is received on a given port. -The destination port is the adjacent port from the enabled port mask, that is, -if the first four ports are enabled (port mask 0xf), ports 0 and 1 forward into each other, -and ports 2 and 3 forward into each other. -The MAC addresses of the forwarded Ethernet frames are not affected. - -Internally, packets are pulled from the ports by the master logical core and put on a variable length processing pipeline, -each stage of which being connected by rings, as shown in :numref:`figure_pipeline_overview`. - -.. _figure_pipeline_overview: - -.. figure:: img/pipeline_overview.* - - Pipeline Overview - - -An adjustable quota value controls how many packets are being moved through the pipeline per enqueue and dequeue. -Adjustable threshold values associated with the rings control a back-off mechanism that -tries to prevent the pipeline from being overloaded by: - -* Stopping enqueuing on rings for which the usage has crossed the high watermark threshold - -* Sending Ethernet pause frames - -* Only resuming enqueuing on a ring once its usage goes below a global low watermark threshold - -This mechanism allows congestion notifications to go up the ring pipeline and -eventually lead to an Ethernet flow control frame being send to the source. - -On top of serving as an example of quota and watermark usage, -this application can be used to benchmark ring based processing pipelines performance using a traffic- generator, -as shown in :numref:`figure_ring_pipeline_perf_setup`. - -.. _figure_ring_pipeline_perf_setup: - -.. figure:: img/ring_pipeline_perf_setup.* - - Ring-based Processing Pipeline Performance Setup - -Compiling the Application -------------------------- - -To compile the sample application see :doc:`compiling`. - -The application is located in the ``quota_watermark`` sub-directory. - -Running the Application ------------------------ - -The core application, qw, has to be started first. - -Once it is up and running, one can alter quota and watermarks while it runs using the control application, qwctl. - -Running the Core Application -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The application requires a single command line option: - -.. code-block:: console - - ./qw/build/qw [EAL options] -- -p PORTMASK - -where, - --p PORTMASK: A hexadecimal bitmask of the ports to configure - -To run the application in a linux environment with four logical cores and ports 0 and 2, -issue the following command: - -.. code-block:: console - - ./qw/build/qw -l 0-3 -n 4 -- -p 5 - -Refer to the *DPDK Getting Started Guide* for general information on running applications and -the Environment Abstraction Layer (EAL) options. - -Running the Control Application -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The control application requires a number of command line options: - -.. code-block:: console - - ./qwctl/build/qwctl [EAL options] --proc-type=secondary - -The --proc-type=secondary option is necessary for the EAL to properly initialize the control application to -use the same huge pages as the core application and thus be able to access its rings. - -To run the application in a linux environment on logical core 0, issue the following command: - -.. code-block:: console - - ./qwctl/build/qwctl -l 0 -n 4 --proc-type=secondary - -Refer to the *DPDK Getting Started* Guide for general information on running applications and -the Environment Abstraction Layer (EAL) options. - -qwctl is an interactive command line that let the user change variables in a running instance of qw. -The help command gives a list of available commands: - -.. code-block:: console - - $ qwctl > help - -Code Overview -------------- - -The following sections provide a quick guide to the application's source code. - -Core Application - qw -~~~~~~~~~~~~~~~~~~~~~ - -EAL and Drivers Setup -^^^^^^^^^^^^^^^^^^^^^ - -The EAL arguments are parsed at the beginning of the main() function: - -.. code-block:: c - - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot initialize EAL\n"); - - argc -= ret; - argv += ret; - -Then, a call to init_dpdk(), defined in init.c, is made to initialize the poll mode drivers: - -.. code-block:: c - - void - init_dpdk(void) - { - int ret; - - /* Bind the drivers to usable devices */ - - ret = rte_pci_probe(); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_pci_probe(): error %d\n", ret); - - if (rte_eth_dev_count_avail() < 2) - rte_exit(EXIT_FAILURE, "Not enough Ethernet port available\n"); - } - -To fully understand this code, it is recommended to study the chapters that relate to the *Poll Mode Driver* -in the *DPDK Getting Started Guide* and the *DPDK API Reference*. - -Shared Variables Setup -^^^^^^^^^^^^^^^^^^^^^^ - -The quota and high and low watermark shared variables are put into an rte_memzone using a call to setup_shared_variables(): - -.. code-block:: c - - void - setup_shared_variables(void) - { - const struct rte_memzone *qw_memzone; - - qw_memzone = rte_memzone_reserve(QUOTA_WATERMARK_MEMZONE_NAME, - 3 * sizeof(int), rte_socket_id(), 0); - if (qw_memzone == NULL) - rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno)); - - quota = qw_memzone->addr; - low_watermark = (unsigned int *) qw_memzone->addr + 1; - high_watermark = (unsigned int *) qw_memzone->addr + 2; - } - -These three variables are initialized to a default value in main() and -can be changed while qw is running using the qwctl control program. - -Application Arguments -^^^^^^^^^^^^^^^^^^^^^ - -The qw application only takes one argument: a port mask that specifies which ports should be used by the application. -At least two ports are needed to run the application and there should be an even number of ports given in the port mask. - -The port mask parsing is done in parse_qw_args(), defined in args.c. - -Mbuf Pool Initialization -^^^^^^^^^^^^^^^^^^^^^^^^ - -Once the application's arguments are parsed, an mbuf pool is created. -It contains a set of mbuf objects that are used by the driver and the application to store network packets: - -.. code-block:: c - - /* Create a pool of mbuf to store packets */ - mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", MBUF_PER_POOL, 32, 0, - MBUF_DATA_SIZE, rte_socket_id()); - - if (mbuf_pool == NULL) - rte_panic("%s\n", rte_strerror(rte_errno)); - -The rte_mempool is a generic structure used to handle pools of objects. -In this case, it is necessary to create a pool that will be used by the driver. - -The number of allocated pkt mbufs is MBUF_PER_POOL, with a data room size -of MBUF_DATA_SIZE each. -A per-lcore cache of 32 mbufs is kept. -The memory is allocated in on the master lcore's socket, but it is possible to extend this code to allocate one mbuf pool per socket. - -The rte_pktmbuf_pool_create() function uses the default mbuf pool and mbuf -initializers, respectively rte_pktmbuf_pool_init() and rte_pktmbuf_init(). -An advanced application may want to use the mempool API to create the -mbuf pool with more control. - -Ports Configuration and Pairing -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Each port in the port mask is configured and a corresponding ring is created in the master lcore's array of rings. -This ring is the first in the pipeline and will hold the packets directly coming from the port. - -.. code-block:: c - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) - if (is_bit_set(port_id, portmask)) { - configure_eth_port(port_id); - init_ring(master_lcore_id, port_id); - } - - pair_ports(); - -The configure_eth_port() and init_ring() functions are used to configure a port and a ring respectively and are defined in init.c. -They make use of the DPDK APIs defined in rte_eth.h and rte_ring.h. - -pair_ports() builds the port_pairs[] array so that its key-value pairs are a mapping between reception and transmission ports. -It is defined in init.c. - -Logical Cores Assignment -^^^^^^^^^^^^^^^^^^^^^^^^ - -The application uses the master logical core to poll all the ports for new packets and enqueue them on a ring associated with the port. - -Each logical core except the last runs pipeline_stage() after a ring for each used port is initialized on that core. -pipeline_stage() on core X dequeues packets from core X-1's rings and enqueue them on its own rings. See :numref:`figure_threads_pipelines`. - -.. code-block:: c - - /* Start pipeline_stage() on all the available slave lcore but the last */ - - for (lcore_id = 0 ; lcore_id < last_lcore_id; lcore_id++) { - if (rte_lcore_is_enabled(lcore_id) && lcore_id != master_lcore_id) { - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) - if (is_bit_set(port_id, portmask)) - init_ring(lcore_id, port_id); - - rte_eal_remote_launch(pipeline_stage, NULL, lcore_id); - } - } - -The last available logical core runs send_stage(), -which is the last stage of the pipeline dequeuing packets from the last ring in the pipeline and -sending them out on the destination port setup by pair_ports(). - -.. code-block:: c - - /* Start send_stage() on the last slave core */ - - rte_eal_remote_launch(send_stage, NULL, last_lcore_id); - -Receive, Process and Transmit Packets -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. _figure_threads_pipelines: - -.. figure:: img/threads_pipelines.* - - Threads and Pipelines - - -In the receive_stage() function running on the master logical core, -the main task is to read ingress packets from the RX ports and enqueue them -on the port's corresponding first ring in the pipeline. -This is done using the following code: - -.. code-block:: c - - lcore_id = rte_lcore_id(); - - /* Process each port round robin style */ - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - if (!is_bit_set(port_id, portmask)) - continue; - - ring = rings[lcore_id][port_id]; - - if (ring_state[port_id] != RING_READY) { - if (rte_ring_count(ring) > *low_watermark) - continue; - else - ring_state[port_id] = RING_READY; - } - - /* Enqueue received packets on the RX ring */ - nb_rx_pkts = rte_eth_rx_burst(port_id, 0, pkts, - (uint16_t) *quota); - ret = rte_ring_enqueue_bulk(ring, (void *) pkts, - nb_rx_pkts, &free); - if (RING_SIZE - free > *high_watermark) { - ring_state[port_id] = RING_OVERLOADED; - send_pause_frame(port_id, 1337); - } - - if (ret == 0) { - - /* - * Return mbufs to the pool, - * effectively dropping packets - */ - for (i = 0; i < nb_rx_pkts; i++) - rte_pktmbuf_free(pkts[i]); - } - } - -For each port in the port mask, the corresponding ring's pointer is fetched into ring and that ring's state is checked: - -* If it is in the RING_READY state, \*quota packets are grabbed from the port and put on the ring. - Should this operation make the ring's usage cross its high watermark, - the ring is marked as overloaded and an Ethernet flow control frame is sent to the source. - -* If it is not in the RING_READY state, this port is ignored until the ring's usage crosses the \*low_watermark value. - -The pipeline_stage() function's task is to process and move packets from the preceding pipeline stage. -This thread is running on most of the logical cores to create and arbitrarily long pipeline. - -.. code-block:: c - - lcore_id = rte_lcore_id(); - - previous_lcore_id = get_previous_lcore_id(lcore_id); - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - if (!is_bit_set(port_id, portmask)) - continue; - - tx = rings[lcore_id][port_id]; - rx = rings[previous_lcore_id][port_id]; - - if (ring_state[port_id] != RING_READY) { - if (rte_ring_count(tx) > *low_watermark) - continue; - else - ring_state[port_id] = RING_READY; - } - - /* Dequeue up to quota mbuf from rx */ - nb_dq_pkts = rte_ring_dequeue_burst(rx, pkts, - *quota, NULL); - if (unlikely(nb_dq_pkts < 0)) - continue; - - /* Enqueue them on tx */ - ret = rte_ring_enqueue_bulk(tx, pkts, - nb_dq_pkts, &free); - if (RING_SIZE - free > *high_watermark) - ring_state[port_id] = RING_OVERLOADED; - - if (ret == 0) { - - /* - * Return mbufs to the pool, - * effectively dropping packets - */ - for (i = 0; i < nb_dq_pkts; i++) - rte_pktmbuf_free(pkts[i]); - } - } - -The thread's logic works mostly like receive_stage(), -except that packets are moved from ring to ring instead of port to ring. - -In this example, no actual processing is done on the packets, -but pipeline_stage() is an ideal place to perform any processing required by the application. - -Finally, the send_stage() function's task is to read packets from the last ring in a pipeline and -send them on the destination port defined in the port_pairs[] array. -It is running on the last available logical core only. - -.. code-block:: c - - lcore_id = rte_lcore_id(); - - previous_lcore_id = get_previous_lcore_id(lcore_id); - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - if (!is_bit_set(port_id, portmask)) continue; - - dest_port_id = port_pairs[port_id]; - tx = rings[previous_lcore_id][port_id]; - - if (rte_ring_empty(tx)) continue; - - /* Dequeue packets from tx and send them */ - - nb_dq_pkts = rte_ring_dequeue_burst(tx, (void *) tx_pkts, *quota); - nb_tx_pkts = rte_eth_tx_burst(dest_port_id, 0, tx_pkts, nb_dq_pkts); - } - -For each port in the port mask, up to \*quota packets are pulled from the last ring in its pipeline and -sent on the destination port paired with the current port. - -Control Application - qwctl -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The qwctl application uses the rte_cmdline library to provide the user with an interactive command line that -can be used to modify and inspect parameters in a running qw application. -Those parameters are the global quota and low_watermark value as well as each ring's built-in high watermark. - -Command Definitions -^^^^^^^^^^^^^^^^^^^ - -The available commands are defined in commands.c. - -It is advised to use the cmdline sample application user guide as a reference for everything related to the rte_cmdline library. - -Accessing Shared Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The setup_shared_variables() function retrieves the shared variables quota and -low_watermark from the rte_memzone previously created by qw. - -.. code-block:: c - - static void - setup_shared_variables(void) - { - const struct rte_memzone *qw_memzone; - - qw_memzone = rte_memzone_lookup(QUOTA_WATERMARK_MEMZONE_NAME); - if (qw_memzone == NULL) - rte_exit(EXIT_FAILURE, "Couldn't find memzone\n"); - - quota = qw_memzone->addr; - - low_watermark = (unsigned int *) qw_memzone->addr + 1; - high_watermark = (unsigned int *) qw_memzone->addr + 2; - } diff --git a/examples/Makefile b/examples/Makefile index 5dd8a72e5..02ff86534 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -59,7 +59,6 @@ endif DIRS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ptpclient DIRS-$(CONFIG_RTE_LIBRTE_METER) += qos_meter DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += qos_sched -DIRS-y += quota_watermark DIRS-$(CONFIG_RTE_ETHDEV_RXTX_CALLBACKS) += rxtx_callbacks DIRS-y += service_cores DIRS-y += skeleton diff --git a/examples/meson.build b/examples/meson.build index 81ac8199a..6c26fffb4 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -33,7 +33,7 @@ all_examples = [ 'netmap_compat', 'ntb', 'packet_ordering', 'performance-thread', 'ptpclient', 'qos_meter', 'qos_sched', - 'quota_watermark', 'rxtx_callbacks', + 'rxtx_callbacks', 'server_node_efd', 'service_cores', 'skeleton', 'tep_termination', 'timer', 'vdpa', diff --git a/examples/quota_watermark/Makefile b/examples/quota_watermark/Makefile deleted file mode 100644 index 8ef053198..000000000 --- a/examples/quota_watermark/Makefile +++ /dev/null @@ -1,16 +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 - -DIRS-$(CONFIG_RTE_EXEC_ENV_LINUX) += qw -DIRS-$(CONFIG_RTE_EXEC_ENV_LINUX) += qwctl - -include $(RTE_SDK)/mk/rte.extsubdir.mk diff --git a/examples/quota_watermark/include/conf.h b/examples/quota_watermark/include/conf.h deleted file mode 100644 index 4f29aa64b..000000000 --- a/examples/quota_watermark/include/conf.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _CONF_H_ -#define _CONF_H_ - -#define RING_SIZE 1024 -#define MAX_PKT_QUOTA 64 - -#define RX_DESC_PER_QUEUE 1024 -#define TX_DESC_PER_QUEUE 1024 - -#define MBUF_DATA_SIZE RTE_MBUF_DEFAULT_BUF_SIZE -#define MBUF_PER_POOL 8192 - -#define QUOTA_WATERMARK_MEMZONE_NAME "qw_global_vars" - -#endif /* _CONF_H_ */ diff --git a/examples/quota_watermark/meson.build b/examples/quota_watermark/meson.build deleted file mode 100644 index c370d7476..000000000 --- a/examples/quota_watermark/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/quota_watermark/qw/Makefile b/examples/quota_watermark/qw/Makefile deleted file mode 100644 index 3f10f01c3..000000000 --- a/examples/quota_watermark/qw/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 - -# binary name -APP = qw - -# all source are stored in SRCS-y -SRCS-y := args.c init.c main.c - -CFLAGS += -O3 -DQW_SOFTWARE_FC -CFLAGS += $(WERROR_FLAGS) - -include $(RTE_SDK)/mk/rte.extapp.mk diff --git a/examples/quota_watermark/qw/args.c b/examples/quota_watermark/qw/args.c deleted file mode 100644 index a750ec258..000000000 --- a/examples/quota_watermark/qw/args.c +++ /dev/null @@ -1,78 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include <rte_common.h> -#include <rte_lcore.h> - -#include "args.h" - - -unsigned int portmask = 0; - - -static void -usage(const char *prgname) -{ - fprintf(stderr, "Usage: %s [EAL args] -- -p <portmask>\n" - "-p PORTMASK: hexadecimal bitmask of NIC ports to configure\n", - prgname); -} - -static unsigned long -parse_portmask(const char *portmask_str) -{ - return strtoul(portmask_str, NULL, 16); -} - -static void -check_core_count(void) -{ - if (rte_lcore_count() < 3) - rte_exit(EXIT_FAILURE, - "At least 3 cores need to be passed in the coremask\n"); -} - -static void -check_portmask_value(unsigned int portmask) -{ - unsigned int port_nb = 0; - - port_nb = __builtin_popcount(portmask); - - if (port_nb == 0) - rte_exit(EXIT_FAILURE, - "At least 2 ports need to be passed in the portmask\n"); - - if (port_nb % 2 != 0) - rte_exit(EXIT_FAILURE, - "An even number of ports is required in the portmask\n"); -} - -int -parse_qw_args(int argc, char **argv) -{ - int opt; - - while ((opt = getopt(argc, argv, "h:p:")) != -1) { - switch (opt) { - case 'h': - usage(argv[0]); - break; - case 'p': - portmask = parse_portmask(optarg); - break; - default: - usage(argv[0]); - } - } - - check_core_count(); - check_portmask_value(portmask); - - return 0; -} diff --git a/examples/quota_watermark/qw/args.h b/examples/quota_watermark/qw/args.h deleted file mode 100644 index ab777db01..000000000 --- a/examples/quota_watermark/qw/args.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _ARGS_H_ -#define _ARGS_H_ - -extern unsigned int portmask; - -int parse_qw_args(int argc, char **argv); - -#endif /* _ARGS_H_ */ diff --git a/examples/quota_watermark/qw/init.c b/examples/quota_watermark/qw/init.c deleted file mode 100644 index 5a0f64f45..000000000 --- a/examples/quota_watermark/qw/init.c +++ /dev/null @@ -1,164 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <fcntl.h> -#include <unistd.h> -#include <sys/mman.h> - -#include <rte_eal.h> - -#include <rte_common.h> -#include <rte_errno.h> -#include <rte_ethdev.h> -#include <rte_memzone.h> -#include <rte_ring.h> -#include <rte_string_fns.h> - -#include "args.h" -#include "init.h" -#include "main.h" -#include "../include/conf.h" - - -static struct rte_eth_conf port_conf = { - .rxmode = { - .split_hdr_size = 0, - }, - .txmode = { - .mq_mode = ETH_DCB_NONE, - }, -}; - -static struct rte_eth_fc_conf fc_conf = { - .mode = RTE_FC_TX_PAUSE, - .high_water = 80 * 510 / 100, - .low_water = 60 * 510 / 100, - .pause_time = 1337, - .send_xon = 0, -}; - - -void configure_eth_port(uint16_t port_id) -{ - int ret; - uint16_t nb_rxd = RX_DESC_PER_QUEUE; - uint16_t nb_txd = TX_DESC_PER_QUEUE; - struct rte_eth_rxconf rxq_conf; - struct rte_eth_txconf txq_conf; - struct rte_eth_dev_info dev_info; - struct rte_eth_conf local_port_conf = port_conf; - - rte_eth_dev_stop(port_id); - - rte_eth_dev_info_get(port_id, &dev_info); - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - ret = rte_eth_dev_configure(port_id, 1, 1, &local_port_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot configure port %u (error %d)\n", - (unsigned int) port_id, ret); - - ret = rte_eth_dev_adjust_nb_rx_tx_desc(port_id, &nb_rxd, &nb_txd); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Cannot adjust number of descriptors for port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Initialize the port's RX queue */ - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = local_port_conf.rxmode.offloads; - ret = rte_eth_rx_queue_setup(port_id, 0, nb_rxd, - rte_eth_dev_socket_id(port_id), - &rxq_conf, - mbuf_pool); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Failed to setup RX queue on port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Initialize the port's TX queue */ - txq_conf = dev_info.default_txconf; - txq_conf.offloads = local_port_conf.txmode.offloads; - ret = rte_eth_tx_queue_setup(port_id, 0, nb_txd, - rte_eth_dev_socket_id(port_id), - &txq_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Failed to setup TX queue on port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Initialize the port's flow control */ - ret = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Failed to setup hardware flow control on port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Start the port */ - ret = rte_eth_dev_start(port_id); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Failed to start port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Put it in promiscuous mode */ - rte_eth_promiscuous_enable(port_id); -} - -void -init_dpdk(void) -{ - if (rte_eth_dev_count_avail() < 2) - rte_exit(EXIT_FAILURE, "Not enough ethernet port available\n"); -} - -void init_ring(int lcore_id, uint16_t port_id) -{ - struct rte_ring *ring; - char ring_name[RTE_RING_NAMESIZE]; - - snprintf(ring_name, RTE_RING_NAMESIZE, - "core%d_port%d", lcore_id, port_id); - ring = rte_ring_create(ring_name, RING_SIZE, rte_socket_id(), - RING_F_SP_ENQ | RING_F_SC_DEQ); - - if (ring == NULL) - rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno)); - - *high_watermark = 80 * RING_SIZE / 100; - - rings[lcore_id][port_id] = ring; -} - -void -pair_ports(void) -{ - uint16_t i, j; - - /* Pair ports with their "closest neighbour" in the portmask */ - for (i = 0; i < RTE_MAX_ETHPORTS; i++) - if (is_bit_set(i, portmask)) - for (j = i + 1; j < RTE_MAX_ETHPORTS; j++) - if (is_bit_set(j, portmask)) { - port_pairs[i] = j; - port_pairs[j] = i; - i = j; - break; - } -} - -void -setup_shared_variables(void) -{ - const struct rte_memzone *qw_memzone; - - qw_memzone = rte_memzone_reserve(QUOTA_WATERMARK_MEMZONE_NAME, - 3 * sizeof(int), rte_socket_id(), 0); - if (qw_memzone == NULL) - rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno)); - - quota = qw_memzone->addr; - low_watermark = (unsigned int *) qw_memzone->addr + 1; - high_watermark = (unsigned int *) qw_memzone->addr + 2; -} diff --git a/examples/quota_watermark/qw/init.h b/examples/quota_watermark/qw/init.h deleted file mode 100644 index e0c90df72..000000000 --- a/examples/quota_watermark/qw/init.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _INIT_H_ -#define _INIT_H_ - -void configure_eth_port(uint16_t port_id); -void init_dpdk(void); -void init_ring(int lcore_id, uint16_t port_id); -void pair_ports(void); -void setup_shared_variables(void); - -#endif /* _INIT_H_ */ diff --git a/examples/quota_watermark/qw/main.c b/examples/quota_watermark/qw/main.c deleted file mode 100644 index a61360b99..000000000 --- a/examples/quota_watermark/qw/main.c +++ /dev/null @@ -1,365 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <rte_eal.h> - -#include <rte_common.h> -#include <rte_debug.h> -#include <rte_errno.h> -#include <rte_ethdev.h> -#include <rte_launch.h> -#include <rte_lcore.h> -#include <rte_log.h> -#include <rte_mbuf.h> -#include <rte_ring.h> - -#include <rte_byteorder.h> - -#include "args.h" -#include "main.h" -#include "init.h" -#include "../include/conf.h" - - -#ifdef QW_SOFTWARE_FC -#define SEND_PAUSE_FRAME(port_id, duration) send_pause_frame(port_id, duration) -#else -#define SEND_PAUSE_FRAME(port_id, duration) do { } while(0) -#endif - -#define ETHER_TYPE_FLOW_CONTROL 0x8808 - -struct ether_fc_frame { - uint16_t opcode; - uint16_t param; -} __attribute__((__packed__)); - - -int *quota; -unsigned int *low_watermark; -unsigned int *high_watermark; - -uint16_t port_pairs[RTE_MAX_ETHPORTS]; - -struct rte_ring *rings[RTE_MAX_LCORE][RTE_MAX_ETHPORTS]; -struct rte_mempool *mbuf_pool; - - -static void send_pause_frame(uint16_t port_id, uint16_t duration) -{ - struct rte_mbuf *mbuf; - struct ether_fc_frame *pause_frame; - struct rte_ether_hdr *hdr; - struct rte_ether_addr mac_addr; - - RTE_LOG_DP(DEBUG, USER1, - "Sending PAUSE frame (duration=%d) on port %d\n", - duration, port_id); - - /* Get a mbuf from the pool */ - mbuf = rte_pktmbuf_alloc(mbuf_pool); - if (unlikely(mbuf == NULL)) - return; - - /* Prepare a PAUSE frame */ - hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr *); - pause_frame = (struct ether_fc_frame *) &hdr[1]; - - rte_eth_macaddr_get(port_id, &mac_addr); - rte_ether_addr_copy(&mac_addr, &hdr->s_addr); - - void *tmp = &hdr->d_addr.addr_bytes[0]; - *((uint64_t *)tmp) = 0x010000C28001ULL; - - hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_FLOW_CONTROL); - - pause_frame->opcode = rte_cpu_to_be_16(0x0001); - pause_frame->param = rte_cpu_to_be_16(duration); - - mbuf->pkt_len = 60; - mbuf->data_len = 60; - - rte_eth_tx_burst(port_id, 0, &mbuf, 1); -} - -/** - * Get the previous enabled lcore ID - * - * @param lcore_id - * The current lcore ID. - * @return - * The previous enabled lcore_id or -1 if not found. - */ -static unsigned int -get_previous_lcore_id(unsigned int lcore_id) -{ - int i; - - for (i = lcore_id - 1; i >= 0; i--) - if (rte_lcore_is_enabled(i)) - return i; - - return -1; -} - -/** - * Get the last enabled lcore ID - * - * @return - * The last enabled lcore_id. - */ -static unsigned int -get_last_lcore_id(void) -{ - int i; - - for (i = RTE_MAX_LCORE; i >= 0; i--) - if (rte_lcore_is_enabled(i)) - return i; - - return 0; -} - -static void -receive_stage(__attribute__((unused)) void *args) -{ - int i, ret; - - uint16_t port_id; - uint16_t nb_rx_pkts; - - unsigned int lcore_id; - unsigned int free; - - struct rte_mbuf *pkts[MAX_PKT_QUOTA]; - struct rte_ring *ring; - enum ring_state ring_state[RTE_MAX_ETHPORTS] = { RING_READY }; - - lcore_id = rte_lcore_id(); - - RTE_LOG(INFO, USER1, - "%s() started on core %u\n", __func__, lcore_id); - - while (1) { - - /* Process each port round robin style */ - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - - if (!is_bit_set(port_id, portmask)) - continue; - - ring = rings[lcore_id][port_id]; - - if (ring_state[port_id] != RING_READY) { - if (rte_ring_count(ring) > *low_watermark) - continue; - else - ring_state[port_id] = RING_READY; - } - - /* Enqueue received packets on the RX ring */ - nb_rx_pkts = rte_eth_rx_burst(port_id, 0, pkts, - (uint16_t) *quota); - ret = rte_ring_enqueue_bulk(ring, (void *) pkts, - nb_rx_pkts, &free); - if (RING_SIZE - free > *high_watermark) { - ring_state[port_id] = RING_OVERLOADED; - send_pause_frame(port_id, 1337); - } - - if (ret == 0) { - - /* - * Return mbufs to the pool, - * effectively dropping packets - */ - for (i = 0; i < nb_rx_pkts; i++) - rte_pktmbuf_free(pkts[i]); - } - } - } -} - -static int -pipeline_stage(__attribute__((unused)) void *args) -{ - int i, ret; - int nb_dq_pkts; - - uint16_t port_id; - - unsigned int lcore_id, previous_lcore_id; - unsigned int free; - - void *pkts[MAX_PKT_QUOTA]; - struct rte_ring *rx, *tx; - enum ring_state ring_state[RTE_MAX_ETHPORTS] = { RING_READY }; - - lcore_id = rte_lcore_id(); - previous_lcore_id = get_previous_lcore_id(lcore_id); - - RTE_LOG(INFO, USER1, - "%s() started on core %u - processing packets from core %u\n", - __func__, lcore_id, previous_lcore_id); - - while (1) { - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - - if (!is_bit_set(port_id, portmask)) - continue; - - tx = rings[lcore_id][port_id]; - rx = rings[previous_lcore_id][port_id]; - - if (ring_state[port_id] != RING_READY) { - if (rte_ring_count(tx) > *low_watermark) - continue; - else - ring_state[port_id] = RING_READY; - } - - /* Dequeue up to quota mbuf from rx */ - nb_dq_pkts = rte_ring_dequeue_burst(rx, pkts, - *quota, NULL); - if (unlikely(nb_dq_pkts < 0)) - continue; - - /* Enqueue them on tx */ - ret = rte_ring_enqueue_bulk(tx, pkts, - nb_dq_pkts, &free); - if (RING_SIZE - free > *high_watermark) - ring_state[port_id] = RING_OVERLOADED; - - if (ret == 0) { - - /* - * Return mbufs to the pool, - * effectively dropping packets - */ - for (i = 0; i < nb_dq_pkts; i++) - rte_pktmbuf_free(pkts[i]); - } - } - } - - return 0; -} - -static int -send_stage(__attribute__((unused)) void *args) -{ - uint16_t nb_dq_pkts; - - uint16_t port_id; - uint16_t dest_port_id; - - unsigned int lcore_id, previous_lcore_id; - - struct rte_ring *tx; - struct rte_mbuf *tx_pkts[MAX_PKT_QUOTA]; - - lcore_id = rte_lcore_id(); - previous_lcore_id = get_previous_lcore_id(lcore_id); - - RTE_LOG(INFO, USER1, - "%s() started on core %u - processing packets from core %u\n", - __func__, lcore_id, previous_lcore_id); - - while (1) { - - /* Process each ring round robin style */ - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - - if (!is_bit_set(port_id, portmask)) - continue; - - dest_port_id = port_pairs[port_id]; - tx = rings[previous_lcore_id][port_id]; - - if (rte_ring_empty(tx)) - continue; - - /* Dequeue packets from tx and send them */ - nb_dq_pkts = (uint16_t) rte_ring_dequeue_burst(tx, - (void *) tx_pkts, *quota, NULL); - rte_eth_tx_burst(dest_port_id, 0, tx_pkts, nb_dq_pkts); - - /* TODO: Check if nb_dq_pkts == nb_tx_pkts? */ - } - } - - return 0; -} - -int -main(int argc, char **argv) -{ - int ret; - unsigned int lcore_id, master_lcore_id, last_lcore_id; - - uint16_t port_id; - - rte_log_set_global_level(RTE_LOG_INFO); - - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot initialize EAL\n"); - - argc -= ret; - argv += ret; - - init_dpdk(); - setup_shared_variables(); - - *quota = 32; - *low_watermark = 60 * RING_SIZE / 100; - - last_lcore_id = get_last_lcore_id(); - master_lcore_id = rte_get_master_lcore(); - - /* Parse the application's arguments */ - ret = parse_qw_args(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid quota/watermark argument(s)\n"); - - /* Create a pool of mbuf to store packets */ - mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", MBUF_PER_POOL, 32, 0, - MBUF_DATA_SIZE, rte_socket_id()); - if (mbuf_pool == NULL) - rte_panic("%s\n", rte_strerror(rte_errno)); - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) - if (is_bit_set(port_id, portmask)) { - configure_eth_port(port_id); - init_ring(master_lcore_id, port_id); - } - - pair_ports(); - - /* - * Start pipeline_connect() on all the available slave lcores - * but the last - */ - for (lcore_id = 0 ; lcore_id < last_lcore_id; lcore_id++) { - if (rte_lcore_is_enabled(lcore_id) && - lcore_id != master_lcore_id) { - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) - if (is_bit_set(port_id, portmask)) - init_ring(lcore_id, port_id); - - rte_eal_remote_launch(pipeline_stage, - NULL, lcore_id); - } - } - - /* Start send_stage() on the last slave core */ - rte_eal_remote_launch(send_stage, NULL, last_lcore_id); - - /* Start receive_stage() on the master core */ - receive_stage(NULL); - - return 0; -} diff --git a/examples/quota_watermark/qw/main.h b/examples/quota_watermark/qw/main.h deleted file mode 100644 index 9903ddc8c..000000000 --- a/examples/quota_watermark/qw/main.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _MAIN_H_ -#define _MAIN_H_ - -#include "../include/conf.h" - -enum ring_state { - RING_READY, - RING_OVERLOADED, -}; - -extern int *quota; -extern unsigned int *low_watermark; -extern unsigned int *high_watermark; - -extern uint16_t port_pairs[RTE_MAX_ETHPORTS]; - -extern struct rte_ring *rings[RTE_MAX_LCORE][RTE_MAX_ETHPORTS]; -extern struct rte_mempool *mbuf_pool; - - -static inline int -is_bit_set(int i, unsigned int mask) -{ - return (1 << i) & mask; -} - -#endif /* _MAIN_H_ */ diff --git a/examples/quota_watermark/qwctl/Makefile b/examples/quota_watermark/qwctl/Makefile deleted file mode 100644 index a40f28025..000000000 --- a/examples/quota_watermark/qwctl/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 - -# binary name -APP = qwctl - -# all source are stored in SRCS-y -SRCS-y := commands.c qwctl.c - -CFLAGS += -O3 -CFLAGS += $(WERROR_FLAGS) - -include $(RTE_SDK)/mk/rte.extapp.mk diff --git a/examples/quota_watermark/qwctl/commands.c b/examples/quota_watermark/qwctl/commands.c deleted file mode 100644 index a1c646b9f..000000000 --- a/examples/quota_watermark/qwctl/commands.c +++ /dev/null @@ -1,196 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <termios.h> - -#include <cmdline_rdline.h> -#include <cmdline_parse.h> -#include <cmdline_parse_num.h> -#include <cmdline_parse_string.h> -#include <cmdline.h> - -#include <rte_ring.h> - -#include "qwctl.h" -#include "../include/conf.h" - - -/** - * help command - */ - -struct cmd_help_tokens { - cmdline_fixed_string_t verb; -}; - -cmdline_parse_token_string_t cmd_help_verb = - TOKEN_STRING_INITIALIZER(struct cmd_help_tokens, verb, "help"); - -static void -cmd_help_handler(__attribute__((unused)) void *parsed_result, - struct cmdline *cl, - __attribute__((unused)) void *data) -{ - cmdline_printf(cl, "Available commands:\n" - "- help\n" - "- set [ring_name|variable] <value>\n" - "- show [ring_name|variable]\n" - "\n" - "Available variables:\n" - "- low_watermark\n" - "- quota\n" - "- ring names follow the core%%u_port%%u format\n"); -} - -cmdline_parse_inst_t cmd_help = { - .f = cmd_help_handler, - .data = NULL, - .help_str = "show help", - .tokens = { - (void *) &cmd_help_verb, - NULL, - }, -}; - - -/** - * set command - */ - -struct cmd_set_tokens { - cmdline_fixed_string_t verb; - cmdline_fixed_string_t variable; - uint32_t value; -}; - -cmdline_parse_token_string_t cmd_set_verb = - TOKEN_STRING_INITIALIZER(struct cmd_set_tokens, verb, "set"); - -cmdline_parse_token_string_t cmd_set_variable = - TOKEN_STRING_INITIALIZER(struct cmd_set_tokens, variable, NULL); - -cmdline_parse_token_num_t cmd_set_value = - TOKEN_NUM_INITIALIZER(struct cmd_set_tokens, value, UINT32); - -static void -cmd_set_handler(__attribute__((unused)) void *parsed_result, - struct cmdline *cl, - __attribute__((unused)) void *data) -{ - struct cmd_set_tokens *tokens = parsed_result; - struct rte_ring *ring; - - if (!strcmp(tokens->variable, "quota")) { - - if (tokens->value > 0 && tokens->value <= MAX_PKT_QUOTA) - *quota = tokens->value; - else - cmdline_printf(cl, "quota must be between 1 and %u\n", - MAX_PKT_QUOTA); - } - - else if (!strcmp(tokens->variable, "low_watermark")) { - - if (tokens->value <= 100) - *low_watermark = tokens->value * RING_SIZE / 100; - else - cmdline_printf(cl, - "low_watermark must be between 0%% and 100%%\n"); - } - - else { - - ring = rte_ring_lookup(tokens->variable); - if (ring == NULL) - cmdline_printf(cl, "Cannot find ring \"%s\"\n", - tokens->variable); - else - if (tokens->value >= *low_watermark * 100 / RING_SIZE - && tokens->value <= 100) - *high_watermark = tokens->value * - RING_SIZE / 100; - else - cmdline_printf(cl, - "ring high watermark must be between %u%% and 100%%\n", - *low_watermark * 100 / RING_SIZE); - } -} - -cmdline_parse_inst_t cmd_set = { - .f = cmd_set_handler, - .data = NULL, - .help_str = "Set a variable value", - .tokens = { - (void *) &cmd_set_verb, - (void *) &cmd_set_variable, - (void *) &cmd_set_value, - NULL, - }, -}; - - -/** - * show command - */ - -struct cmd_show_tokens { - cmdline_fixed_string_t verb; - cmdline_fixed_string_t variable; -}; - -cmdline_parse_token_string_t cmd_show_verb = - TOKEN_STRING_INITIALIZER(struct cmd_show_tokens, verb, "show"); - -cmdline_parse_token_string_t cmd_show_variable = - TOKEN_STRING_INITIALIZER(struct cmd_show_tokens, - variable, NULL); - - -static void -cmd_show_handler(__attribute__((unused)) void *parsed_result, - struct cmdline *cl, - __attribute__((unused)) void *data) -{ - struct cmd_show_tokens *tokens = parsed_result; - struct rte_ring *ring; - - if (!strcmp(tokens->variable, "quota")) - cmdline_printf(cl, "Global quota: %d\n", *quota); - - else if (!strcmp(tokens->variable, "low_watermark")) - cmdline_printf(cl, "Global low_watermark: %u\n", - *low_watermark); - - else { - - ring = rte_ring_lookup(tokens->variable); - if (ring == NULL) - cmdline_printf(cl, "Cannot find ring \"%s\"\n", - tokens->variable); - else - rte_ring_dump(stdout, ring); - } -} - -cmdline_parse_inst_t cmd_show = { - .f = cmd_show_handler, - .data = NULL, - .help_str = "Show a variable value", - .tokens = { - (void *) &cmd_show_verb, - (void *) &cmd_show_variable, - NULL, - }, -}; - - -cmdline_parse_ctx_t qwctl_ctx[] = { - (cmdline_parse_inst_t *)&cmd_help, - (cmdline_parse_inst_t *)&cmd_set, - (cmdline_parse_inst_t *)&cmd_show, - NULL, -}; diff --git a/examples/quota_watermark/qwctl/commands.h b/examples/quota_watermark/qwctl/commands.h deleted file mode 100644 index 4a4e97475..000000000 --- a/examples/quota_watermark/qwctl/commands.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _COMMANDS_H_ -#define _COMMANDS_H_ - -#include <cmdline_parse.h> - -extern cmdline_parse_ctx_t qwctl_ctx[]; - -#endif /* _COMMANDS_H_ */ diff --git a/examples/quota_watermark/qwctl/qwctl.c b/examples/quota_watermark/qwctl/qwctl.c deleted file mode 100644 index 2f7914c80..000000000 --- a/examples/quota_watermark/qwctl/qwctl.c +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <fcntl.h> -#include <stdio.h> -#include <termios.h> -#include <unistd.h> -#include <sys/mman.h> - -#include <rte_eal.h> - -#include <rte_log.h> -#include <rte_memzone.h> - -#include <cmdline_rdline.h> -#include <cmdline_parse.h> -#include <cmdline_socket.h> -#include <cmdline.h> - - -#include "qwctl.h" -#include "commands.h" -#include "../include/conf.h" - - -int *quota; -unsigned int *low_watermark; -unsigned int *high_watermark; - - -static void -setup_shared_variables(void) -{ - const struct rte_memzone *qw_memzone; - - qw_memzone = rte_memzone_lookup(QUOTA_WATERMARK_MEMZONE_NAME); - if (qw_memzone == NULL) - rte_exit(EXIT_FAILURE, "Couldn't find memzone\n"); - - quota = qw_memzone->addr; - low_watermark = (unsigned int *) qw_memzone->addr + 1; - high_watermark = (unsigned int *) qw_memzone->addr + 2; -} - -int main(int argc, char **argv) -{ - int ret; - struct cmdline *cl; - - rte_log_set_global_level(RTE_LOG_INFO); - - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot initialize EAL\n"); - - setup_shared_variables(); - - cl = cmdline_stdin_new(qwctl_ctx, "qwctl> "); - if (cl == NULL) - rte_exit(EXIT_FAILURE, "Cannot create cmdline instance\n"); - - cmdline_interact(cl); - cmdline_stdin_exit(cl); - - return 0; -} diff --git a/examples/quota_watermark/qwctl/qwctl.h b/examples/quota_watermark/qwctl/qwctl.h deleted file mode 100644 index 2a4559388..000000000 --- a/examples/quota_watermark/qwctl/qwctl.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _MAIN_H_ -#define _MAIN_H_ - -extern int *quota; -extern unsigned int *low_watermark; -extern unsigned int *high_watermark; - -#endif /* _MAIN_H_ */ -- 2.17.1 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v2 5/6] examples/netmap-compat: remove example from DPDK 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 " Ciara Power ` (3 preceding siblings ...) 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 4/6] examples/quota-watermark: " Ciara Power @ 2019-10-24 13:31 ` Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 6/6] examples/load_balancer: " Ciara Power 2019-10-24 14:12 ` [dpdk-dev] [PATCH v2 0/6] remove a few example applications David Marchand 6 siblings, 0 replies; 27+ messages in thread From: Ciara Power @ 2019-10-24 13:31 UTC (permalink / raw) To: dev; +Cc: techboard, 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 <ciara.power@intel.com> Acked-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com> --- MAINTAINERS | 3 - doc/guides/sample_app_ug/index.rst | 1 - .../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 -- 13 files changed, 1 insertion(+), 1880 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 <john.mcnamara@intel.com> 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/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 <fcntl.h> -#include <getopt.h> -#include <inttypes.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/mman.h> - -#include <rte_eal.h> -#include <rte_ethdev.h> -#include <rte_mbuf.h> -#include <rte_mempool.h> -#include <rte_string_fns.h> -#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 <errno.h> -#include <inttypes.h> -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <net/if.h> -#include <sys/types.h> -#include <sys/resource.h> -#include <sys/mman.h> - -#include <rte_common.h> -#include <rte_errno.h> -#include <rte_ethdev.h> -#include <rte_log.h> -#include <rte_malloc.h> -#include <rte_mbuf.h> -#include <rte_spinlock.h> -#include <rte_string_fns.h> - -#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 <poll.h> -#include <linux/ioctl.h> -#include <net/if.h> - -#include <rte_ethdev.h> -#include <rte_mempool.h> - -#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_ */ -- 2.17.1 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v2 6/6] examples/load_balancer: remove example from DPDK 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 " Ciara Power ` (4 preceding siblings ...) 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 5/6] examples/netmap-compat: " Ciara Power @ 2019-10-24 13:31 ` Ciara Power 2019-10-24 14:12 ` [dpdk-dev] [PATCH v2 0/6] remove a few example applications David Marchand 6 siblings, 0 replies; 27+ messages in thread From: Ciara Power @ 2019-10-24 13:31 UTC (permalink / raw) To: dev; +Cc: techboard, Ciara Power This example can be removed because DPDK now has a range of libraries, especially rte_eventdev, that did not exist previously for load balancing, making this less relevant. Also, modern NIC cards have greater ability to do load balancing, e.g. using RSS, over a wider range of fields than earlier cards did. Signed-off-by: Ciara Power <ciara.power@intel.com> Acked-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com> --- MAINTAINERS | 3 - doc/guides/sample_app_ug/index.rst | 1 - doc/guides/sample_app_ug/load_balancer.rst | 201 ---- examples/Makefile | 1 - examples/load_balancer/Makefile | 62 -- examples/load_balancer/config.c | 1030 -------------------- examples/load_balancer/init.c | 520 ---------- examples/load_balancer/main.c | 76 -- examples/load_balancer/main.h | 351 ------- examples/load_balancer/meson.build | 12 - examples/load_balancer/runtime.c | 642 ------------ examples/meson.build | 1 - 12 files changed, 2900 deletions(-) delete mode 100644 doc/guides/sample_app_ug/load_balancer.rst delete mode 100644 examples/load_balancer/Makefile delete mode 100644 examples/load_balancer/config.c delete mode 100644 examples/load_balancer/init.c delete mode 100644 examples/load_balancer/main.c delete mode 100644 examples/load_balancer/main.h delete mode 100644 examples/load_balancer/meson.build delete mode 100644 examples/load_balancer/runtime.c diff --git a/MAINTAINERS b/MAINTAINERS index 6b9fa4dc2..3db771bd7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1461,9 +1461,6 @@ F: doc/guides/sample_app_ug/l3_forward.rst F: examples/link_status_interrupt/ F: doc/guides/sample_app_ug/link_status_intr.rst -F: examples/load_balancer/ -F: doc/guides/sample_app_ug/load_balancer.rst - L-threads - EXPERIMENTAL M: John McNamara <john.mcnamara@intel.com> F: examples/performance-thread/ diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst index 5f4924df6..191eebb56 100644 --- a/doc/guides/sample_app_ug/index.rst +++ b/doc/guides/sample_app_ug/index.rst @@ -30,7 +30,6 @@ Sample Applications User Guides l3_forward_power_man l3_forward_access_ctrl link_status_intr - load_balancer server_node_efd service_cores multi_process diff --git a/doc/guides/sample_app_ug/load_balancer.rst b/doc/guides/sample_app_ug/load_balancer.rst deleted file mode 100644 index 8f2abdfb8..000000000 --- a/doc/guides/sample_app_ug/load_balancer.rst +++ /dev/null @@ -1,201 +0,0 @@ -.. SPDX-License-Identifier: BSD-3-Clause - Copyright(c) 2010-2014 Intel Corporation. - -Load Balancer Sample Application -================================ - -The Load Balancer sample application demonstrates the concept of isolating the packet I/O task -from the application-specific workload. -Depending on the performance target, -a number of logical cores (lcores) are dedicated to handle the interaction with the NIC ports (I/O lcores), -while the rest of the lcores are dedicated to performing the application processing (worker lcores). -The worker lcores are totally oblivious to the intricacies of the packet I/O activity and -use the NIC-agnostic interface provided by software rings to exchange packets with the I/O cores. - -Overview --------- - -The architecture of the Load Balance application is presented in the following figure. - -.. _figure_load_bal_app_arch: - -.. figure:: img/load_bal_app_arch.* - - Load Balancer Application Architecture - - -For the sake of simplicity, the diagram illustrates a specific case of two I/O RX and two I/O TX lcores off loading the packet I/O -overhead incurred by four NIC ports from four worker cores, with each I/O lcore handling RX/TX for two NIC ports. - -I/O RX Logical Cores -~~~~~~~~~~~~~~~~~~~~ - -Each I/O RX lcore performs packet RX from its assigned NIC RX rings and then distributes the received packets to the worker threads. -The application allows each I/O RX lcore to communicate with any of the worker threads, -therefore each (I/O RX lcore, worker lcore) pair is connected through a dedicated single producer - single consumer software ring. - -The worker lcore to handle the current packet is determined by reading a predefined 1-byte field from the input packet: - -worker_id = packet[load_balancing_field] % n_workers - -Since all the packets that are part of the same traffic flow are expected to have the same value for the load balancing field, -this scheme also ensures that all the packets that are part of the same traffic flow are directed to the same worker lcore (flow affinity) -in the same order they enter the system (packet ordering). - -I/O TX Logical Cores -~~~~~~~~~~~~~~~~~~~~ - -Each I/O lcore owns the packet TX for a predefined set of NIC ports. To enable each worker thread to send packets to any NIC TX port, -the application creates a software ring for each (worker lcore, NIC TX port) pair, -with each I/O TX core handling those software rings that are associated with NIC ports that it handles. - -Worker Logical Cores -~~~~~~~~~~~~~~~~~~~~ - -Each worker lcore reads packets from its set of input software rings and -routes them to the NIC ports for transmission by dispatching them to output software rings. -The routing logic is LPM based, with all the worker threads sharing the same LPM rules. - -Compiling the Application -------------------------- - -To compile the sample application see :doc:`compiling`. - -The application is located in the ``load_balancer`` sub-directory. - -Running the Application ------------------------ - -To successfully run the application, -the command line used to start the application has to be in sync with the traffic flows configured on the traffic generator side. - -For examples of application command lines and traffic generator flows, please refer to the DPDK Test Report. -For more details on how to set up and run the sample applications provided with DPDK package, -please refer to the *DPDK Getting Started Guide*. - -Explanation ------------ - -Application Configuration -~~~~~~~~~~~~~~~~~~~~~~~~~ - -The application run-time configuration is done through the application command line parameters. -Any parameter that is not specified as mandatory is optional, -with the default value hard-coded in the main.h header file from the application folder. - -The list of application command line parameters is listed below: - -#. --rx "(PORT, QUEUE, LCORE), ...": The list of NIC RX ports and queues handled by the I/O RX lcores. - This parameter also implicitly defines the list of I/O RX lcores. This is a mandatory parameter. - -#. --tx "(PORT, LCORE), ... ": The list of NIC TX ports handled by the I/O TX lcores. - This parameter also implicitly defines the list of I/O TX lcores. - This is a mandatory parameter. - -#. --w "LCORE, ...": The list of the worker lcores. This is a mandatory parameter. - -#. --lpm "IP / PREFIX => PORT; ...": The list of LPM rules used by the worker lcores for packet forwarding. - This is a mandatory parameter. - -#. --rsz "A, B, C, D": Ring sizes: - - #. A = The size (in number of buffer descriptors) of each of the NIC RX rings read by the I/O RX lcores. - - #. B = The size (in number of elements) of each of the software rings used by the I/O RX lcores to send packets to worker lcores. - - #. C = The size (in number of elements) of each of the software rings used by the worker lcores to send packets to I/O TX lcores. - - #. D = The size (in number of buffer descriptors) of each of the NIC TX rings written by I/O TX lcores. - -#. --bsz "(A, B), (C, D), (E, F)": Burst sizes: - - #. A = The I/O RX lcore read burst size from NIC RX. - - #. B = The I/O RX lcore write burst size to the output software rings. - - #. C = The worker lcore read burst size from the input software rings. - - #. D = The worker lcore write burst size to the output software rings. - - #. E = The I/O TX lcore read burst size from the input software rings. - - #. F = The I/O TX lcore write burst size to the NIC TX. - -#. --pos-lb POS: The position of the 1-byte field within the input packet used by the I/O RX lcores - to identify the worker lcore for the current packet. - This field needs to be within the first 64 bytes of the input packet. - -The infrastructure of software rings connecting I/O lcores and worker lcores is built by the application -as a result of the application configuration provided by the user through the application command line parameters. - -A specific lcore performing the I/O RX role for a specific set of NIC ports can also perform the I/O TX role -for the same or a different set of NIC ports. -A specific lcore cannot perform both the I/O role (either RX or TX) and the worker role during the same session. - -Example: - -.. code-block:: console - - ./load_balancer -l 3-7 -n 4 -- --rx "(0,0,3),(1,0,3)" --tx "(0,3),(1,3)" --w "4,5,6,7" --lpm "1.0.0.0/24=>0; 1.0.1.0/24=>1;" --pos-lb 29 - -There is a single I/O lcore (lcore 3) that handles RX and TX for two NIC ports (ports 0 and 1) that -handles packets to/from four worker lcores (lcores 4, 5, 6 and 7) that -are assigned worker IDs 0 to 3 (worker ID for lcore 4 is 0, for lcore 5 is 1, for lcore 6 is 2 and for lcore 7 is 3). - -Assuming that all the input packets are IPv4 packets with no VLAN label and the source IP address of the current packet is A.B.C.D, -the worker lcore for the current packet is determined by byte D (which is byte 29). -There are two LPM rules that are used by each worker lcore to route packets to the output NIC ports. - -The following table illustrates the packet flow through the system for several possible traffic flows: - -+------------+----------------+-----------------+------------------------------+--------------+ -| **Flow #** | **Source** | **Destination** | **Worker ID (Worker lcore)** | **Output** | -| | **IP Address** | **IP Address** | | **NIC Port** | -| | | | | | -+============+================+=================+==============================+==============+ -| 1 | 0.0.0.0 | 1.0.0.1 | 0 (4) | 0 | -| | | | | | -+------------+----------------+-----------------+------------------------------+--------------+ -| 2 | 0.0.0.1 | 1.0.1.2 | 1 (5) | 1 | -| | | | | | -+------------+----------------+-----------------+------------------------------+--------------+ -| 3 | 0.0.0.14 | 1.0.0.3 | 2 (6) | 0 | -| | | | | | -+------------+----------------+-----------------+------------------------------+--------------+ -| 4 | 0.0.0.15 | 1.0.1.4 | 3 (7) | 1 | -| | | | | | -+------------+----------------+-----------------+------------------------------+--------------+ - -NUMA Support -~~~~~~~~~~~~ - -The application has built-in performance enhancements for the NUMA case: - -#. One buffer pool per each CPU socket. - -#. One LPM table per each CPU socket. - -#. Memory for the NIC RX or TX rings is allocated on the same socket with the lcore handling the respective ring. - -In the case where multiple CPU sockets are used in the system, -it is recommended to enable at least one lcore to fulfill the I/O role for the NIC ports that -are directly attached to that CPU socket through the PCI Express* bus. -It is always recommended to handle the packet I/O with lcores from the same CPU socket as the NICs. - -Depending on whether the I/O RX lcore (same CPU socket as NIC RX), -the worker lcore and the I/O TX lcore (same CPU socket as NIC TX) handling a specific input packet, -are on the same or different CPU sockets, the following run-time scenarios are possible: - -#. AAA: The packet is received, processed and transmitted without going across CPU sockets. - -#. AAB: The packet is received and processed on socket A, - but as it has to be transmitted on a NIC port connected to socket B, - the packet is sent to socket B through software rings. - -#. ABB: The packet is received on socket A, but as it has to be processed by a worker lcore on socket B, - the packet is sent to socket B through software rings. - The packet is transmitted by a NIC port connected to the same CPU socket as the worker lcore that processed it. - -#. ABC: The packet is received on socket A, it is processed by an lcore on socket B, - then it has to be transmitted out by a NIC connected to socket C. - The performance price for crossing the CPU socket boundary is paid twice for this packet. diff --git a/examples/Makefile b/examples/Makefile index 6bba09ce9..62d0865c5 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -48,7 +48,6 @@ ifeq ($(CONFIG_RTE_LIBRTE_LPM)$(CONFIG_RTE_LIBRTE_HASH),yy) DIRS-$(CONFIG_RTE_LIBRTE_POWER) += l3fwd-power endif DIRS-y += link_status_interrupt -DIRS-$(CONFIG_RTE_LIBRTE_LPM) += load_balancer DIRS-y += multi_process DIRS-y += ntb DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += packet_ordering diff --git a/examples/load_balancer/Makefile b/examples/load_balancer/Makefile deleted file mode 100644 index caae8a107..000000000 --- a/examples/load_balancer/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2010-2014 Intel Corporation - -# binary name -APP = load_balancer - -# all source are stored in SRCS-y -SRCS-y := main.c config.c init.c runtime.c - -# Build using pkg-config variables if possible -ifeq ($(shell pkg-config --exists libdpdk && echo 0),0) - -all: shared -.PHONY: shared static -shared: build/$(APP)-shared - ln -sf $(APP)-shared build/$(APP) -static: build/$(APP)-static - ln -sf $(APP)-static build/$(APP) - -PKGCONF=pkg-config --define-prefix - -PC_FILE := $(shell $(PKGCONF) --path libdpdk) -CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) -LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk) -LDFLAGS_STATIC = -Wl,-Bstatic $(shell $(PKGCONF) --static --libs libdpdk) - -build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) - -build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC) - -build: - @mkdir -p $@ - -.PHONY: clean -clean: - rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared - test -d build && rmdir -p build || true - -else # Build using legacy build system - -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 - -CFLAGS += -O3 -g -CFLAGS += $(WERROR_FLAGS) - -# workaround for a gcc bug with noreturn attribute -# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603 -ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y) -CFLAGS_main.o += -Wno-return-type -endif - -include $(RTE_SDK)/mk/rte.extapp.mk -endif diff --git a/examples/load_balancer/config.c b/examples/load_balancer/config.c deleted file mode 100644 index 972c85c5b..000000000 --- a/examples/load_balancer/config.c +++ /dev/null @@ -1,1030 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_lpm.h> -#include <rte_string_fns.h> - -#include "main.h" - -struct app_params app; - -static const char usage[] = -" \n" -" load_balancer <EAL PARAMS> -- <APP PARAMS> \n" -" \n" -"Application manadatory parameters: \n" -" --rx \"(PORT, QUEUE, LCORE), ...\" : List of NIC RX ports and queues \n" -" handled by the I/O RX lcores \n" -" --tx \"(PORT, LCORE), ...\" : List of NIC TX ports handled by the I/O TX \n" -" lcores \n" -" --w \"LCORE, ...\" : List of the worker lcores \n" -" --lpm \"IP / PREFIX => PORT; ...\" : List of LPM rules used by the worker \n" -" lcores for packet forwarding \n" -" \n" -"Application optional parameters: \n" -" --rsz \"A, B, C, D\" : Ring sizes \n" -" A = Size (in number of buffer descriptors) of each of the NIC RX \n" -" rings read by the I/O RX lcores (default value is %u) \n" -" B = Size (in number of elements) of each of the SW rings used by the\n" -" I/O RX lcores to send packets to worker lcores (default value is\n" -" %u) \n" -" C = Size (in number of elements) of each of the SW rings used by the\n" -" worker lcores to send packets to I/O TX lcores (default value is\n" -" %u) \n" -" D = Size (in number of buffer descriptors) of each of the NIC TX \n" -" rings written by I/O TX lcores (default value is %u) \n" -" --bsz \"(A, B), (C, D), (E, F)\" : Burst sizes \n" -" A = I/O RX lcore read burst size from NIC RX (default value is %u) \n" -" B = I/O RX lcore write burst size to output SW rings (default value \n" -" is %u) \n" -" C = Worker lcore read burst size from input SW rings (default value \n" -" is %u) \n" -" D = Worker lcore write burst size to output SW rings (default value \n" -" is %u) \n" -" E = I/O TX lcore read burst size from input SW rings (default value \n" -" is %u) \n" -" F = I/O TX lcore write burst size to NIC TX (default value is %u) \n" -" --pos-lb POS : Position of the 1-byte field within the input packet used by\n" -" the I/O RX lcores to identify the worker lcore for the current \n" -" packet (default value is %u) \n"; - -void -app_print_usage(void) -{ - printf(usage, - APP_DEFAULT_NIC_RX_RING_SIZE, - APP_DEFAULT_RING_RX_SIZE, - APP_DEFAULT_RING_TX_SIZE, - APP_DEFAULT_NIC_TX_RING_SIZE, - APP_DEFAULT_BURST_SIZE_IO_RX_READ, - APP_DEFAULT_BURST_SIZE_IO_RX_WRITE, - APP_DEFAULT_BURST_SIZE_WORKER_READ, - APP_DEFAULT_BURST_SIZE_WORKER_WRITE, - APP_DEFAULT_BURST_SIZE_IO_TX_READ, - APP_DEFAULT_BURST_SIZE_IO_TX_WRITE, - APP_DEFAULT_IO_RX_LB_POS - ); -} - -#ifndef APP_ARG_RX_MAX_CHARS -#define APP_ARG_RX_MAX_CHARS 4096 -#endif - -#ifndef APP_ARG_RX_MAX_TUPLES -#define APP_ARG_RX_MAX_TUPLES 128 -#endif - -static int -str_to_unsigned_array( - const char *s, size_t sbuflen, - char separator, - unsigned num_vals, - unsigned *vals) -{ - char str[sbuflen+1]; - char *splits[num_vals]; - char *endptr = NULL; - int i, num_splits = 0; - - /* copy s so we don't modify original string */ - strlcpy(str, s, sizeof(str)); - num_splits = rte_strsplit(str, sizeof(str), splits, num_vals, separator); - - errno = 0; - for (i = 0; i < num_splits; i++) { - vals[i] = strtoul(splits[i], &endptr, 0); - if (errno != 0 || *endptr != '\0') - return -1; - } - - return num_splits; -} - -static int -str_to_unsigned_vals( - const char *s, - size_t sbuflen, - char separator, - unsigned num_vals, ...) -{ - unsigned i, vals[num_vals]; - va_list ap; - - num_vals = str_to_unsigned_array(s, sbuflen, separator, num_vals, vals); - - va_start(ap, num_vals); - for (i = 0; i < num_vals; i++) { - unsigned *u = va_arg(ap, unsigned *); - *u = vals[i]; - } - va_end(ap); - return num_vals; -} - -static int -parse_arg_rx(const char *arg) -{ - const char *p0 = arg, *p = arg; - uint32_t n_tuples; - - if (strnlen(arg, APP_ARG_RX_MAX_CHARS + 1) == APP_ARG_RX_MAX_CHARS + 1) { - return -1; - } - - n_tuples = 0; - while ((p = strchr(p0,'(')) != NULL) { - struct app_lcore_params *lp; - uint32_t port, queue, lcore, i; - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 3, &port, &queue, &lcore) != 3)) { - return -2; - } - - /* Enable port and queue for later initialization */ - if ((port >= APP_MAX_NIC_PORTS) || (queue >= APP_MAX_RX_QUEUES_PER_NIC_PORT)) { - return -3; - } - if (app.nic_rx_queue_mask[port][queue] != 0) { - return -4; - } - app.nic_rx_queue_mask[port][queue] = 1; - - /* Check and assign (port, queue) to I/O lcore */ - if (rte_lcore_is_enabled(lcore) == 0) { - return -5; - } - - if (lcore >= APP_MAX_LCORES) { - return -6; - } - lp = &app.lcore_params[lcore]; - if (lp->type == e_APP_LCORE_WORKER) { - return -7; - } - lp->type = e_APP_LCORE_IO; - const size_t n_queues = RTE_MIN(lp->io.rx.n_nic_queues, - RTE_DIM(lp->io.rx.nic_queues)); - for (i = 0; i < n_queues; i ++) { - if ((lp->io.rx.nic_queues[i].port == port) && - (lp->io.rx.nic_queues[i].queue == queue)) { - return -8; - } - } - if (lp->io.rx.n_nic_queues >= APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE) { - return -9; - } - lp->io.rx.nic_queues[lp->io.rx.n_nic_queues].port = port; - lp->io.rx.nic_queues[lp->io.rx.n_nic_queues].queue = (uint8_t) queue; - lp->io.rx.n_nic_queues ++; - - n_tuples ++; - if (n_tuples > APP_ARG_RX_MAX_TUPLES) { - return -10; - } - } - - if (n_tuples == 0) { - return -11; - } - - return 0; -} - -#ifndef APP_ARG_TX_MAX_CHARS -#define APP_ARG_TX_MAX_CHARS 4096 -#endif - -#ifndef APP_ARG_TX_MAX_TUPLES -#define APP_ARG_TX_MAX_TUPLES 128 -#endif - -static int -parse_arg_tx(const char *arg) -{ - const char *p0 = arg, *p = arg; - uint32_t n_tuples; - - if (strnlen(arg, APP_ARG_TX_MAX_CHARS + 1) == APP_ARG_TX_MAX_CHARS + 1) { - return -1; - } - - n_tuples = 0; - while ((p = strchr(p0,'(')) != NULL) { - struct app_lcore_params *lp; - uint32_t port, lcore, i; - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 2, &port, &lcore) != 2)) { - return -2; - } - - /* Enable port and queue for later initialization */ - if (port >= APP_MAX_NIC_PORTS) { - return -3; - } - if (app.nic_tx_port_mask[port] != 0) { - return -4; - } - app.nic_tx_port_mask[port] = 1; - - /* Check and assign (port, queue) to I/O lcore */ - if (rte_lcore_is_enabled(lcore) == 0) { - return -5; - } - - if (lcore >= APP_MAX_LCORES) { - return -6; - } - lp = &app.lcore_params[lcore]; - if (lp->type == e_APP_LCORE_WORKER) { - return -7; - } - lp->type = e_APP_LCORE_IO; - const size_t n_ports = RTE_MIN(lp->io.tx.n_nic_ports, - RTE_DIM(lp->io.tx.nic_ports)); - for (i = 0; i < n_ports; i ++) { - if (lp->io.tx.nic_ports[i] == port) { - return -8; - } - } - if (lp->io.tx.n_nic_ports >= APP_MAX_NIC_TX_PORTS_PER_IO_LCORE) { - return -9; - } - lp->io.tx.nic_ports[lp->io.tx.n_nic_ports] = port; - lp->io.tx.n_nic_ports ++; - - n_tuples ++; - if (n_tuples > APP_ARG_TX_MAX_TUPLES) { - return -10; - } - } - - if (n_tuples == 0) { - return -11; - } - - return 0; -} - -#ifndef APP_ARG_W_MAX_CHARS -#define APP_ARG_W_MAX_CHARS 4096 -#endif - -#ifndef APP_ARG_W_MAX_TUPLES -#define APP_ARG_W_MAX_TUPLES APP_MAX_WORKER_LCORES -#endif - -static int -parse_arg_w(const char *arg) -{ - const char *p = arg; - uint32_t n_tuples; - - if (strnlen(arg, APP_ARG_W_MAX_CHARS + 1) == APP_ARG_W_MAX_CHARS + 1) { - return -1; - } - - n_tuples = 0; - while (*p != 0) { - struct app_lcore_params *lp; - uint32_t lcore; - - errno = 0; - lcore = strtoul(p, NULL, 0); - if (errno != 0) { - return -2; - } - - /* Check and enable worker lcore */ - if (rte_lcore_is_enabled(lcore) == 0) { - return -3; - } - - if (lcore >= APP_MAX_LCORES) { - return -4; - } - lp = &app.lcore_params[lcore]; - if (lp->type == e_APP_LCORE_IO) { - return -5; - } - lp->type = e_APP_LCORE_WORKER; - - n_tuples ++; - if (n_tuples > APP_ARG_W_MAX_TUPLES) { - return -6; - } - - p = strchr(p, ','); - if (p == NULL) { - break; - } - p ++; - } - - if (n_tuples == 0) { - return -7; - } - - if ((n_tuples & (n_tuples - 1)) != 0) { - return -8; - } - - return 0; -} - -#ifndef APP_ARG_LPM_MAX_CHARS -#define APP_ARG_LPM_MAX_CHARS 4096 -#endif - -static int -parse_arg_lpm(const char *arg) -{ - const char *p = arg, *p0; - - if (strnlen(arg, APP_ARG_LPM_MAX_CHARS + 1) == APP_ARG_TX_MAX_CHARS + 1) { - return -1; - } - - while (*p != 0) { - uint32_t ip_a, ip_b, ip_c, ip_d, ip, depth, if_out; - char *endptr; - - p0 = strchr(p, '/'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, '.', 4, &ip_a, &ip_b, &ip_c, &ip_d) != 4)) { - return -2; - } - - p = p0 + 1; - errno = 0; - depth = strtoul(p, &endptr, 0); - if (errno != 0 || *endptr != '=') { - return -3; - } - p = strchr(p, '>'); - if (p == NULL) { - return -4; - } - if_out = strtoul(++p, &endptr, 0); - if (errno != 0 || (*endptr != '\0' && *endptr != ';')) { - return -5; - } - - if ((ip_a >= 256) || (ip_b >= 256) || (ip_c >= 256) || (ip_d >= 256) || - (depth == 0) || (depth >= 32) || - (if_out >= APP_MAX_NIC_PORTS)) { - return -6; - } - ip = (ip_a << 24) | (ip_b << 16) | (ip_c << 8) | ip_d; - - if (app.n_lpm_rules >= APP_MAX_LPM_RULES) { - return -7; - } - app.lpm_rules[app.n_lpm_rules].ip = ip; - app.lpm_rules[app.n_lpm_rules].depth = (uint8_t) depth; - app.lpm_rules[app.n_lpm_rules].if_out = (uint8_t) if_out; - app.n_lpm_rules ++; - - p = strchr(p, ';'); - if (p == NULL) { - return -8; - } - p ++; - } - - if (app.n_lpm_rules == 0) { - return -9; - } - - return 0; -} - -static int -app_check_lpm_table(void) -{ - uint32_t rule; - - /* For each rule, check that the output I/F is enabled */ - for (rule = 0; rule < app.n_lpm_rules; rule ++) - { - uint32_t port = app.lpm_rules[rule].if_out; - - if (app.nic_tx_port_mask[port] == 0) { - return -1; - } - } - - return 0; -} - -static int -app_check_every_rx_port_is_tx_enabled(void) -{ - uint16_t port; - - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - if ((app_get_nic_rx_queues_per_port(port) > 0) && (app.nic_tx_port_mask[port] == 0)) { - return -1; - } - } - - return 0; -} - -#ifndef APP_ARG_RSZ_CHARS -#define APP_ARG_RSZ_CHARS 63 -#endif - -static int -parse_arg_rsz(const char *arg) -{ - if (strnlen(arg, APP_ARG_RSZ_CHARS + 1) == APP_ARG_RSZ_CHARS + 1) { - return -1; - } - - if (str_to_unsigned_vals(arg, APP_ARG_RSZ_CHARS, ',', 4, - &app.nic_rx_ring_size, - &app.ring_rx_size, - &app.ring_tx_size, - &app.nic_tx_ring_size) != 4) - return -2; - - - if ((app.nic_rx_ring_size == 0) || - (app.nic_tx_ring_size == 0) || - (app.ring_rx_size == 0) || - (app.ring_tx_size == 0)) { - return -3; - } - - return 0; -} - -#ifndef APP_ARG_BSZ_CHARS -#define APP_ARG_BSZ_CHARS 63 -#endif - -static int -parse_arg_bsz(const char *arg) -{ - const char *p = arg, *p0; - if (strnlen(arg, APP_ARG_BSZ_CHARS + 1) == APP_ARG_BSZ_CHARS + 1) { - return -1; - } - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 2, &app.burst_size_io_rx_read, &app.burst_size_io_rx_write) != 2)) { - return -2; - } - - p = strchr(p0, '('); - if (p == NULL) { - return -3; - } - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 2, &app.burst_size_worker_read, &app.burst_size_worker_write) != 2)) { - return -4; - } - - p = strchr(p0, '('); - if (p == NULL) { - return -5; - } - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 2, &app.burst_size_io_tx_read, &app.burst_size_io_tx_write) != 2)) { - return -6; - } - - if ((app.burst_size_io_rx_read == 0) || - (app.burst_size_io_rx_write == 0) || - (app.burst_size_worker_read == 0) || - (app.burst_size_worker_write == 0) || - (app.burst_size_io_tx_read == 0) || - (app.burst_size_io_tx_write == 0)) { - return -7; - } - - if ((app.burst_size_io_rx_read > APP_MBUF_ARRAY_SIZE) || - (app.burst_size_io_rx_write > APP_MBUF_ARRAY_SIZE) || - (app.burst_size_worker_read > APP_MBUF_ARRAY_SIZE) || - (app.burst_size_worker_write > APP_MBUF_ARRAY_SIZE) || - ((2 * app.burst_size_io_tx_read) > APP_MBUF_ARRAY_SIZE) || - (app.burst_size_io_tx_write > APP_MBUF_ARRAY_SIZE)) { - return -8; - } - - return 0; -} - -#ifndef APP_ARG_NUMERICAL_SIZE_CHARS -#define APP_ARG_NUMERICAL_SIZE_CHARS 15 -#endif - -static int -parse_arg_pos_lb(const char *arg) -{ - uint32_t x; - char *endpt; - - if (strnlen(arg, APP_ARG_NUMERICAL_SIZE_CHARS + 1) == APP_ARG_NUMERICAL_SIZE_CHARS + 1) { - return -1; - } - - errno = 0; - x = strtoul(arg, &endpt, 10); - if (errno != 0 || endpt == arg || *endpt != '\0'){ - return -2; - } - - if (x >= 64) { - return -3; - } - - app.pos_lb = (uint8_t) x; - - return 0; -} - -/* Parse the argument given in the command line of the application */ -int -app_parse_args(int argc, char **argv) -{ - int opt, ret; - char **argvopt; - int option_index; - char *prgname = argv[0]; - static struct option lgopts[] = { - {"rx", 1, 0, 0}, - {"tx", 1, 0, 0}, - {"w", 1, 0, 0}, - {"lpm", 1, 0, 0}, - {"rsz", 1, 0, 0}, - {"bsz", 1, 0, 0}, - {"pos-lb", 1, 0, 0}, - {NULL, 0, 0, 0} - }; - uint32_t arg_w = 0; - uint32_t arg_rx = 0; - uint32_t arg_tx = 0; - uint32_t arg_lpm = 0; - uint32_t arg_rsz = 0; - uint32_t arg_bsz = 0; - uint32_t arg_pos_lb = 0; - - argvopt = argv; - - while ((opt = getopt_long(argc, argvopt, "", - lgopts, &option_index)) != EOF) { - - switch (opt) { - /* long options */ - case 0: - if (!strcmp(lgopts[option_index].name, "rx")) { - arg_rx = 1; - ret = parse_arg_rx(optarg); - if (ret) { - printf("Incorrect value for --rx argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "tx")) { - arg_tx = 1; - ret = parse_arg_tx(optarg); - if (ret) { - printf("Incorrect value for --tx argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "w")) { - arg_w = 1; - ret = parse_arg_w(optarg); - if (ret) { - printf("Incorrect value for --w argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "lpm")) { - arg_lpm = 1; - ret = parse_arg_lpm(optarg); - if (ret) { - printf("Incorrect value for --lpm argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "rsz")) { - arg_rsz = 1; - ret = parse_arg_rsz(optarg); - if (ret) { - printf("Incorrect value for --rsz argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "bsz")) { - arg_bsz = 1; - ret = parse_arg_bsz(optarg); - if (ret) { - printf("Incorrect value for --bsz argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "pos-lb")) { - arg_pos_lb = 1; - ret = parse_arg_pos_lb(optarg); - if (ret) { - printf("Incorrect value for --pos-lb argument (%d)\n", ret); - return -1; - } - } - break; - - default: - return -1; - } - } - - /* Check that all mandatory arguments are provided */ - if ((arg_rx == 0) || (arg_tx == 0) || (arg_w == 0) || (arg_lpm == 0)){ - printf("Not all mandatory arguments are present\n"); - return -1; - } - - /* Assign default values for the optional arguments not provided */ - if (arg_rsz == 0) { - app.nic_rx_ring_size = APP_DEFAULT_NIC_RX_RING_SIZE; - app.nic_tx_ring_size = APP_DEFAULT_NIC_TX_RING_SIZE; - app.ring_rx_size = APP_DEFAULT_RING_RX_SIZE; - app.ring_tx_size = APP_DEFAULT_RING_TX_SIZE; - } - - if (arg_bsz == 0) { - app.burst_size_io_rx_read = APP_DEFAULT_BURST_SIZE_IO_RX_READ; - app.burst_size_io_rx_write = APP_DEFAULT_BURST_SIZE_IO_RX_WRITE; - app.burst_size_io_tx_read = APP_DEFAULT_BURST_SIZE_IO_TX_READ; - app.burst_size_io_tx_write = APP_DEFAULT_BURST_SIZE_IO_TX_WRITE; - app.burst_size_worker_read = APP_DEFAULT_BURST_SIZE_WORKER_READ; - app.burst_size_worker_write = APP_DEFAULT_BURST_SIZE_WORKER_WRITE; - } - - if (arg_pos_lb == 0) { - app.pos_lb = APP_DEFAULT_IO_RX_LB_POS; - } - - /* Check cross-consistency of arguments */ - if ((ret = app_check_lpm_table()) < 0) { - printf("At least one LPM rule is inconsistent (%d)\n", ret); - return -1; - } - if (app_check_every_rx_port_is_tx_enabled() < 0) { - printf("On LPM lookup miss, packet is sent back on the input port.\n"); - printf("At least one RX port is not enabled for TX.\n"); - return -2; - } - - if (optind >= 0) - argv[optind - 1] = prgname; - - ret = optind - 1; - optind = 1; /* reset getopt lib */ - return ret; -} - -int -app_get_nic_rx_queues_per_port(uint16_t port) -{ - uint32_t i, count; - - if (port >= APP_MAX_NIC_PORTS) { - return -1; - } - - count = 0; - for (i = 0; i < APP_MAX_RX_QUEUES_PER_NIC_PORT; i ++) { - if (app.nic_rx_queue_mask[port][i] == 1) { - count ++; - } - } - - return count; -} - -int -app_get_lcore_for_nic_rx(uint16_t port, uint8_t queue, uint32_t *lcore_out) -{ - uint32_t lcore; - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - uint32_t i; - - if (app.lcore_params[lcore].type != e_APP_LCORE_IO) { - continue; - } - - const size_t n_queues = RTE_MIN(lp->rx.n_nic_queues, - RTE_DIM(lp->rx.nic_queues)); - for (i = 0; i < n_queues; i ++) { - if ((lp->rx.nic_queues[i].port == port) && - (lp->rx.nic_queues[i].queue == queue)) { - *lcore_out = lcore; - return 0; - } - } - } - - return -1; -} - -int -app_get_lcore_for_nic_tx(uint16_t port, uint32_t *lcore_out) -{ - uint32_t lcore; - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - uint32_t i; - - if (app.lcore_params[lcore].type != e_APP_LCORE_IO) { - continue; - } - - const size_t n_ports = RTE_MIN(lp->tx.n_nic_ports, - RTE_DIM(lp->tx.nic_ports)); - for (i = 0; i < n_ports; i ++) { - if (lp->tx.nic_ports[i] == port) { - *lcore_out = lcore; - return 0; - } - } - } - - return -1; -} - -int -app_is_socket_used(uint32_t socket) -{ - uint32_t lcore; - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - if (app.lcore_params[lcore].type == e_APP_LCORE_DISABLED) { - continue; - } - - if (socket == rte_lcore_to_socket_id(lcore)) { - return 1; - } - } - - return 0; -} - -uint32_t -app_get_lcores_io_rx(void) -{ - uint32_t lcore, count; - - count = 0; - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp_io = &app.lcore_params[lcore].io; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp_io->rx.n_nic_queues == 0)) { - continue; - } - - count ++; - } - - return count; -} - -uint32_t -app_get_lcores_worker(void) -{ - uint32_t lcore, count; - - count = 0; - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - count ++; - } - - if (count > APP_MAX_WORKER_LCORES) { - rte_panic("Algorithmic error (too many worker lcores)\n"); - return 0; - } - - return count; -} - -void -app_print_params(void) -{ - unsigned port, queue, lcore, rule, i, j; - - /* Print NIC RX configuration */ - printf("NIC RX ports: "); - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - uint32_t n_rx_queues = app_get_nic_rx_queues_per_port(port); - - if (n_rx_queues == 0) { - continue; - } - - printf("%u (", port); - for (queue = 0; queue < APP_MAX_RX_QUEUES_PER_NIC_PORT; queue ++) { - if (app.nic_rx_queue_mask[port][queue] == 1) { - printf("%u ", queue); - } - } - printf(") "); - } - printf(";\n"); - - /* Print I/O lcore RX params */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp->rx.n_nic_queues == 0)) { - continue; - } - - printf("I/O lcore %u (socket %u): ", lcore, rte_lcore_to_socket_id(lcore)); - - printf("RX ports "); - for (i = 0; i < lp->rx.n_nic_queues; i ++) { - printf("(%u, %u) ", - (unsigned) lp->rx.nic_queues[i].port, - (unsigned) lp->rx.nic_queues[i].queue); - } - printf("; "); - - printf("Output rings "); - for (i = 0; i < lp->rx.n_rings; i ++) { - printf("%p ", lp->rx.rings[i]); - } - printf(";\n"); - } - - /* Print worker lcore RX params */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp = &app.lcore_params[lcore].worker; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - printf("Worker lcore %u (socket %u) ID %u: ", - lcore, - rte_lcore_to_socket_id(lcore), - (unsigned)lp->worker_id); - - printf("Input rings "); - for (i = 0; i < lp->n_rings_in; i ++) { - printf("%p ", lp->rings_in[i]); - } - - printf(";\n"); - } - - printf("\n"); - - /* Print NIC TX configuration */ - printf("NIC TX ports: "); - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - if (app.nic_tx_port_mask[port] == 1) { - printf("%u ", port); - } - } - printf(";\n"); - - /* Print I/O TX lcore params */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - uint32_t n_workers = app_get_lcores_worker(); - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp->tx.n_nic_ports == 0)) { - continue; - } - - printf("I/O lcore %u (socket %u): ", lcore, rte_lcore_to_socket_id(lcore)); - - printf("Input rings per TX port "); - for (i = 0; i < lp->tx.n_nic_ports; i ++) { - port = lp->tx.nic_ports[i]; - - printf("%u (", port); - for (j = 0; j < n_workers; j ++) { - printf("%p ", lp->tx.rings[port][j]); - } - printf(") "); - - } - - printf(";\n"); - } - - /* Print worker lcore TX params */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp = &app.lcore_params[lcore].worker; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - printf("Worker lcore %u (socket %u) ID %u: \n", - lcore, - rte_lcore_to_socket_id(lcore), - (unsigned)lp->worker_id); - - printf("Output rings per TX port "); - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - if (lp->rings_out[port] != NULL) { - printf("%u (%p) ", port, lp->rings_out[port]); - } - } - - printf(";\n"); - } - - /* Print LPM rules */ - printf("LPM rules: \n"); - for (rule = 0; rule < app.n_lpm_rules; rule ++) { - uint32_t ip = app.lpm_rules[rule].ip; - uint8_t depth = app.lpm_rules[rule].depth; - uint8_t if_out = app.lpm_rules[rule].if_out; - - printf("\t%u: %u.%u.%u.%u/%u => %u;\n", - rule, - (unsigned) (ip & 0xFF000000) >> 24, - (unsigned) (ip & 0x00FF0000) >> 16, - (unsigned) (ip & 0x0000FF00) >> 8, - (unsigned) ip & 0x000000FF, - (unsigned) depth, - (unsigned) if_out - ); - } - - /* Rings */ - printf("Ring sizes: NIC RX = %u; Worker in = %u; Worker out = %u; NIC TX = %u;\n", - (unsigned) app.nic_rx_ring_size, - (unsigned) app.ring_rx_size, - (unsigned) app.ring_tx_size, - (unsigned) app.nic_tx_ring_size); - - /* Bursts */ - printf("Burst sizes: I/O RX (rd = %u, wr = %u); Worker (rd = %u, wr = %u); I/O TX (rd = %u, wr = %u)\n", - (unsigned) app.burst_size_io_rx_read, - (unsigned) app.burst_size_io_rx_write, - (unsigned) app.burst_size_worker_read, - (unsigned) app.burst_size_worker_write, - (unsigned) app.burst_size_io_tx_read, - (unsigned) app.burst_size_io_tx_write); -} diff --git a/examples/load_balancer/init.c b/examples/load_balancer/init.c deleted file mode 100644 index 3ab7d0211..000000000 --- a/examples/load_balancer/init.c +++ /dev/null @@ -1,520 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_ring.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_string_fns.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_lpm.h> - -#include "main.h" - -static struct rte_eth_conf port_conf = { - .rxmode = { - .mq_mode = ETH_MQ_RX_RSS, - .split_hdr_size = 0, - .offloads = DEV_RX_OFFLOAD_CHECKSUM, - }, - .rx_adv_conf = { - .rss_conf = { - .rss_key = NULL, - .rss_hf = ETH_RSS_IP, - }, - }, - .txmode = { - .mq_mode = ETH_MQ_TX_NONE, - }, -}; - -static void -app_assign_worker_ids(void) -{ - uint32_t lcore, worker_id; - - /* Assign ID for each worker */ - worker_id = 0; - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp_worker = &app.lcore_params[lcore].worker; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - lp_worker->worker_id = worker_id; - worker_id ++; - } -} - -static void -app_init_mbuf_pools(void) -{ - unsigned socket, lcore; - - /* Init the buffer pools */ - for (socket = 0; socket < APP_MAX_SOCKETS; socket ++) { - char name[32]; - if (app_is_socket_used(socket) == 0) { - continue; - } - - snprintf(name, sizeof(name), "mbuf_pool_%u", socket); - printf("Creating the mbuf pool for socket %u ...\n", socket); - app.pools[socket] = rte_pktmbuf_pool_create( - name, APP_DEFAULT_MEMPOOL_BUFFERS, - APP_DEFAULT_MEMPOOL_CACHE_SIZE, - 0, APP_DEFAULT_MBUF_DATA_SIZE, socket); - if (app.pools[socket] == NULL) { - rte_panic("Cannot create mbuf pool on socket %u\n", socket); - } - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - if (app.lcore_params[lcore].type == e_APP_LCORE_DISABLED) { - continue; - } - - socket = rte_lcore_to_socket_id(lcore); - app.lcore_params[lcore].pool = app.pools[socket]; - } -} - -static void -app_init_lpm_tables(void) -{ - unsigned socket, lcore; - - /* Init the LPM tables */ - for (socket = 0; socket < APP_MAX_SOCKETS; socket ++) { - char name[32]; - uint32_t rule; - - if (app_is_socket_used(socket) == 0) { - continue; - } - - struct rte_lpm_config lpm_config; - - lpm_config.max_rules = APP_MAX_LPM_RULES; - lpm_config.number_tbl8s = 256; - lpm_config.flags = 0; - snprintf(name, sizeof(name), "lpm_table_%u", socket); - printf("Creating the LPM table for socket %u ...\n", socket); - app.lpm_tables[socket] = rte_lpm_create( - name, - socket, - &lpm_config); - if (app.lpm_tables[socket] == NULL) { - rte_panic("Unable to create LPM table on socket %u\n", socket); - } - - for (rule = 0; rule < app.n_lpm_rules; rule ++) { - int ret; - - ret = rte_lpm_add(app.lpm_tables[socket], - app.lpm_rules[rule].ip, - app.lpm_rules[rule].depth, - app.lpm_rules[rule].if_out); - - if (ret < 0) { - rte_panic("Unable to add entry %u (%x/%u => %u) to the LPM table on socket %u (%d)\n", - (unsigned) rule, - (unsigned) app.lpm_rules[rule].ip, - (unsigned) app.lpm_rules[rule].depth, - (unsigned) app.lpm_rules[rule].if_out, - socket, - ret); - } - } - - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - socket = rte_lcore_to_socket_id(lcore); - app.lcore_params[lcore].worker.lpm_table = app.lpm_tables[socket]; - } -} - -static void -app_init_rings_rx(void) -{ - unsigned lcore; - - /* Initialize the rings for the RX side */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp_io = &app.lcore_params[lcore].io; - unsigned socket_io, lcore_worker; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp_io->rx.n_nic_queues == 0)) { - continue; - } - - socket_io = rte_lcore_to_socket_id(lcore); - - for (lcore_worker = 0; lcore_worker < APP_MAX_LCORES; lcore_worker ++) { - char name[32]; - struct app_lcore_params_worker *lp_worker = &app.lcore_params[lcore_worker].worker; - struct rte_ring *ring = NULL; - - if (app.lcore_params[lcore_worker].type != e_APP_LCORE_WORKER) { - continue; - } - - printf("Creating ring to connect I/O lcore %u (socket %u) with worker lcore %u ...\n", - lcore, - socket_io, - lcore_worker); - snprintf(name, sizeof(name), "app_ring_rx_s%u_io%u_w%u", - socket_io, - lcore, - lcore_worker); - ring = rte_ring_create( - name, - app.ring_rx_size, - socket_io, - RING_F_SP_ENQ | RING_F_SC_DEQ); - if (ring == NULL) { - rte_panic("Cannot create ring to connect I/O core %u with worker core %u\n", - lcore, - lcore_worker); - } - - lp_io->rx.rings[lp_io->rx.n_rings] = ring; - lp_io->rx.n_rings ++; - - lp_worker->rings_in[lp_worker->n_rings_in] = ring; - lp_worker->n_rings_in ++; - } - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp_io = &app.lcore_params[lcore].io; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp_io->rx.n_nic_queues == 0)) { - continue; - } - - if (lp_io->rx.n_rings != app_get_lcores_worker()) { - rte_panic("Algorithmic error (I/O RX rings)\n"); - } - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp_worker = &app.lcore_params[lcore].worker; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - if (lp_worker->n_rings_in != app_get_lcores_io_rx()) { - rte_panic("Algorithmic error (worker input rings)\n"); - } - } -} - -static void -app_init_rings_tx(void) -{ - unsigned lcore; - - /* Initialize the rings for the TX side */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp_worker = &app.lcore_params[lcore].worker; - unsigned port; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - char name[32]; - struct app_lcore_params_io *lp_io = NULL; - struct rte_ring *ring; - uint32_t socket_io, lcore_io; - - if (app.nic_tx_port_mask[port] == 0) { - continue; - } - - if (app_get_lcore_for_nic_tx(port, &lcore_io) < 0) { - rte_panic("Algorithmic error (no I/O core to handle TX of port %u)\n", - port); - } - - lp_io = &app.lcore_params[lcore_io].io; - socket_io = rte_lcore_to_socket_id(lcore_io); - - printf("Creating ring to connect worker lcore %u with TX port %u (through I/O lcore %u) (socket %u) ...\n", - lcore, port, (unsigned)lcore_io, (unsigned)socket_io); - snprintf(name, sizeof(name), "app_ring_tx_s%u_w%u_p%u", socket_io, lcore, port); - ring = rte_ring_create( - name, - app.ring_tx_size, - socket_io, - RING_F_SP_ENQ | RING_F_SC_DEQ); - if (ring == NULL) { - rte_panic("Cannot create ring to connect worker core %u with TX port %u\n", - lcore, - port); - } - - lp_worker->rings_out[port] = ring; - lp_io->tx.rings[port][lp_worker->worker_id] = ring; - } - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp_io = &app.lcore_params[lcore].io; - unsigned i; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp_io->tx.n_nic_ports == 0)) { - continue; - } - - for (i = 0; i < lp_io->tx.n_nic_ports; i ++){ - unsigned port, j; - - port = lp_io->tx.nic_ports[i]; - for (j = 0; j < app_get_lcores_worker(); j ++) { - if (lp_io->tx.rings[port][j] == NULL) { - rte_panic("Algorithmic error (I/O TX rings)\n"); - } - } - } - } -} - -/* Check the link status of all ports in up to 9s, and print them finally */ -static void -check_all_ports_link_status(uint16_t port_num, uint32_t port_mask) -{ -#define CHECK_INTERVAL 100 /* 100ms */ -#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ - uint16_t portid; - uint8_t count, all_ports_up, print_flag = 0; - struct rte_eth_link link; - uint32_t n_rx_queues, n_tx_queues; - - printf("\nChecking link status"); - fflush(stdout); - for (count = 0; count <= MAX_CHECK_TIME; count++) { - all_ports_up = 1; - for (portid = 0; portid < port_num; portid++) { - if ((port_mask & (1 << portid)) == 0) - continue; - n_rx_queues = app_get_nic_rx_queues_per_port(portid); - n_tx_queues = app.nic_tx_port_mask[portid]; - if ((n_rx_queues == 0) && (n_tx_queues == 0)) - continue; - memset(&link, 0, sizeof(link)); - rte_eth_link_get_nowait(portid, &link); - /* print link status if flag set */ - if (print_flag == 1) { - if (link.link_status) - printf( - "Port%d Link Up - speed %uMbps - %s\n", - portid, link.link_speed, - (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? - ("full-duplex") : ("half-duplex\n")); - else - printf("Port %d Link Down\n", portid); - continue; - } - /* clear all_ports_up flag if any link down */ - if (link.link_status == ETH_LINK_DOWN) { - all_ports_up = 0; - break; - } - } - /* after finally printing all link status, get out */ - if (print_flag == 1) - break; - - if (all_ports_up == 0) { - printf("."); - fflush(stdout); - rte_delay_ms(CHECK_INTERVAL); - } - - /* set the print_flag if all ports up or timeout */ - if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { - print_flag = 1; - printf("done\n"); - } - } -} - -static void -app_init_nics(void) -{ - unsigned socket; - uint32_t lcore; - uint16_t port; - uint8_t queue; - int ret; - uint32_t n_rx_queues, n_tx_queues; - - /* Init NIC ports and queues, then start the ports */ - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - struct rte_mempool *pool; - uint16_t nic_rx_ring_size; - uint16_t nic_tx_ring_size; - struct rte_eth_rxconf rxq_conf; - struct rte_eth_txconf txq_conf; - struct rte_eth_dev_info dev_info; - struct rte_eth_conf local_port_conf = port_conf; - - n_rx_queues = app_get_nic_rx_queues_per_port(port); - n_tx_queues = app.nic_tx_port_mask[port]; - - if ((n_rx_queues == 0) && (n_tx_queues == 0)) { - continue; - } - - /* Init port */ - printf("Initializing NIC port %u ...\n", port); - rte_eth_dev_info_get(port, &dev_info); - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - - local_port_conf.rx_adv_conf.rss_conf.rss_hf &= - dev_info.flow_type_rss_offloads; - if (local_port_conf.rx_adv_conf.rss_conf.rss_hf != - port_conf.rx_adv_conf.rss_conf.rss_hf) { - printf("Port %u modified RSS hash function based on hardware support," - "requested:%#"PRIx64" configured:%#"PRIx64"\n", - port, - port_conf.rx_adv_conf.rss_conf.rss_hf, - local_port_conf.rx_adv_conf.rss_conf.rss_hf); - } - - ret = rte_eth_dev_configure( - port, - (uint8_t) n_rx_queues, - (uint8_t) n_tx_queues, - &local_port_conf); - if (ret < 0) { - rte_panic("Cannot init NIC port %u (%d)\n", port, ret); - } - rte_eth_promiscuous_enable(port); - - nic_rx_ring_size = app.nic_rx_ring_size; - nic_tx_ring_size = app.nic_tx_ring_size; - ret = rte_eth_dev_adjust_nb_rx_tx_desc( - port, &nic_rx_ring_size, &nic_tx_ring_size); - if (ret < 0) { - rte_panic("Cannot adjust number of descriptors for port %u (%d)\n", - port, ret); - } - app.nic_rx_ring_size = nic_rx_ring_size; - app.nic_tx_ring_size = nic_tx_ring_size; - - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = local_port_conf.rxmode.offloads; - /* Init RX queues */ - for (queue = 0; queue < APP_MAX_RX_QUEUES_PER_NIC_PORT; queue ++) { - if (app.nic_rx_queue_mask[port][queue] == 0) { - continue; - } - - app_get_lcore_for_nic_rx(port, queue, &lcore); - socket = rte_lcore_to_socket_id(lcore); - pool = app.lcore_params[lcore].pool; - - printf("Initializing NIC port %u RX queue %u ...\n", - port, queue); - ret = rte_eth_rx_queue_setup( - port, - queue, - (uint16_t) app.nic_rx_ring_size, - socket, - &rxq_conf, - pool); - if (ret < 0) { - rte_panic("Cannot init RX queue %u for port %u (%d)\n", - queue, port, ret); - } - } - - txq_conf = dev_info.default_txconf; - txq_conf.offloads = local_port_conf.txmode.offloads; - /* Init TX queues */ - if (app.nic_tx_port_mask[port] == 1) { - app_get_lcore_for_nic_tx(port, &lcore); - socket = rte_lcore_to_socket_id(lcore); - printf("Initializing NIC port %u TX queue 0 ...\n", - port); - ret = rte_eth_tx_queue_setup( - port, - 0, - (uint16_t) app.nic_tx_ring_size, - socket, - &txq_conf); - if (ret < 0) { - rte_panic("Cannot init TX queue 0 for port %d (%d)\n", - port, - ret); - } - } - - /* Start port */ - ret = rte_eth_dev_start(port); - if (ret < 0) { - rte_panic("Cannot start port %d (%d)\n", port, ret); - } - } - - check_all_ports_link_status(APP_MAX_NIC_PORTS, (~0x0)); -} - -void -app_init(void) -{ - app_assign_worker_ids(); - app_init_mbuf_pools(); - app_init_lpm_tables(); - app_init_rings_rx(); - app_init_rings_tx(); - app_init_nics(); - - printf("Initialization completed.\n"); -} diff --git a/examples/load_balancer/main.c b/examples/load_balancer/main.c deleted file mode 100644 index d3dcb235d..000000000 --- a/examples/load_balancer/main.c +++ /dev/null @@ -1,76 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> -#include <unistd.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_lpm.h> - -#include "main.h" - -int -main(int argc, char **argv) -{ - uint32_t lcore; - int ret; - - /* Init EAL */ - ret = rte_eal_init(argc, argv); - if (ret < 0) - return -1; - argc -= ret; - argv += ret; - - /* Parse application arguments (after the EAL ones) */ - ret = app_parse_args(argc, argv); - if (ret < 0) { - app_print_usage(); - return -1; - } - - /* Init */ - app_init(); - app_print_params(); - - /* Launch per-lcore init on every lcore */ - rte_eal_mp_remote_launch(app_lcore_main_loop, NULL, CALL_MASTER); - RTE_LCORE_FOREACH_SLAVE(lcore) { - if (rte_eal_wait_lcore(lcore) < 0) { - return -1; - } - } - - return 0; -} diff --git a/examples/load_balancer/main.h b/examples/load_balancer/main.h deleted file mode 100644 index 9fefb62ed..000000000 --- a/examples/load_balancer/main.h +++ /dev/null @@ -1,351 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _MAIN_H_ -#define _MAIN_H_ - -/* Logical cores */ -#ifndef APP_MAX_SOCKETS -#define APP_MAX_SOCKETS 2 -#endif - -#ifndef APP_MAX_LCORES -#define APP_MAX_LCORES RTE_MAX_LCORE -#endif - -#ifndef APP_MAX_NIC_PORTS -#define APP_MAX_NIC_PORTS RTE_MAX_ETHPORTS -#endif - -#ifndef APP_MAX_RX_QUEUES_PER_NIC_PORT -#define APP_MAX_RX_QUEUES_PER_NIC_PORT 128 -#endif - -#ifndef APP_MAX_TX_QUEUES_PER_NIC_PORT -#define APP_MAX_TX_QUEUES_PER_NIC_PORT 128 -#endif - -#ifndef APP_MAX_IO_LCORES -#if (APP_MAX_LCORES > 16) -#define APP_MAX_IO_LCORES 16 -#else -#define APP_MAX_IO_LCORES APP_MAX_LCORES -#endif -#endif -#if (APP_MAX_IO_LCORES > APP_MAX_LCORES) -#error "APP_MAX_IO_LCORES is too big" -#endif - -#ifndef APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE -#define APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE 16 -#endif - -#ifndef APP_MAX_NIC_TX_PORTS_PER_IO_LCORE -#define APP_MAX_NIC_TX_PORTS_PER_IO_LCORE 16 -#endif -#if (APP_MAX_NIC_TX_PORTS_PER_IO_LCORE > APP_MAX_NIC_PORTS) -#error "APP_MAX_NIC_TX_PORTS_PER_IO_LCORE too big" -#endif - -#ifndef APP_MAX_WORKER_LCORES -#if (APP_MAX_LCORES > 16) -#define APP_MAX_WORKER_LCORES 16 -#else -#define APP_MAX_WORKER_LCORES APP_MAX_LCORES -#endif -#endif -#if (APP_MAX_WORKER_LCORES > APP_MAX_LCORES) -#error "APP_MAX_WORKER_LCORES is too big" -#endif - - -/* Mempools */ -#ifndef APP_DEFAULT_MBUF_DATA_SIZE -#define APP_DEFAULT_MBUF_DATA_SIZE RTE_MBUF_DEFAULT_BUF_SIZE -#endif - -#ifndef APP_DEFAULT_MEMPOOL_BUFFERS -#define APP_DEFAULT_MEMPOOL_BUFFERS 8192 * 4 -#endif - -#ifndef APP_DEFAULT_MEMPOOL_CACHE_SIZE -#define APP_DEFAULT_MEMPOOL_CACHE_SIZE 256 -#endif - -/* LPM Tables */ -#ifndef APP_MAX_LPM_RULES -#define APP_MAX_LPM_RULES 1024 -#endif - -/* NIC RX */ -#ifndef APP_DEFAULT_NIC_RX_RING_SIZE -#define APP_DEFAULT_NIC_RX_RING_SIZE 1024 -#endif - -/* - * RX and TX Prefetch, Host, and Write-back threshold values should be - * carefully set for optimal performance. Consult the network - * controller's datasheet and supporting DPDK documentation for guidance - * on how these parameters should be set. - */ -#ifndef APP_DEFAULT_NIC_RX_PTHRESH -#define APP_DEFAULT_NIC_RX_PTHRESH 8 -#endif - -#ifndef APP_DEFAULT_NIC_RX_HTHRESH -#define APP_DEFAULT_NIC_RX_HTHRESH 8 -#endif - -#ifndef APP_DEFAULT_NIC_RX_WTHRESH -#define APP_DEFAULT_NIC_RX_WTHRESH 4 -#endif - -#ifndef APP_DEFAULT_NIC_RX_FREE_THRESH -#define APP_DEFAULT_NIC_RX_FREE_THRESH 64 -#endif - -#ifndef APP_DEFAULT_NIC_RX_DROP_EN -#define APP_DEFAULT_NIC_RX_DROP_EN 0 -#endif - -/* NIC TX */ -#ifndef APP_DEFAULT_NIC_TX_RING_SIZE -#define APP_DEFAULT_NIC_TX_RING_SIZE 1024 -#endif - -/* - * These default values are optimized for use with the Intel(R) 82599 10 GbE - * Controller and the DPDK ixgbe PMD. Consider using other values for other - * network controllers and/or network drivers. - */ -#ifndef APP_DEFAULT_NIC_TX_PTHRESH -#define APP_DEFAULT_NIC_TX_PTHRESH 36 -#endif - -#ifndef APP_DEFAULT_NIC_TX_HTHRESH -#define APP_DEFAULT_NIC_TX_HTHRESH 0 -#endif - -#ifndef APP_DEFAULT_NIC_TX_WTHRESH -#define APP_DEFAULT_NIC_TX_WTHRESH 0 -#endif - -#ifndef APP_DEFAULT_NIC_TX_FREE_THRESH -#define APP_DEFAULT_NIC_TX_FREE_THRESH 0 -#endif - -#ifndef APP_DEFAULT_NIC_TX_RS_THRESH -#define APP_DEFAULT_NIC_TX_RS_THRESH 0 -#endif - -/* Software Rings */ -#ifndef APP_DEFAULT_RING_RX_SIZE -#define APP_DEFAULT_RING_RX_SIZE 1024 -#endif - -#ifndef APP_DEFAULT_RING_TX_SIZE -#define APP_DEFAULT_RING_TX_SIZE 1024 -#endif - -/* Bursts */ -#ifndef APP_MBUF_ARRAY_SIZE -#define APP_MBUF_ARRAY_SIZE 512 -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_IO_RX_READ -#define APP_DEFAULT_BURST_SIZE_IO_RX_READ 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_IO_RX_READ > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_IO_RX_READ is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_IO_RX_WRITE -#define APP_DEFAULT_BURST_SIZE_IO_RX_WRITE 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_IO_RX_WRITE > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_IO_RX_WRITE is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_IO_TX_READ -#define APP_DEFAULT_BURST_SIZE_IO_TX_READ 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_IO_TX_READ > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_IO_TX_READ is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_IO_TX_WRITE -#define APP_DEFAULT_BURST_SIZE_IO_TX_WRITE 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_IO_TX_WRITE > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_IO_TX_WRITE is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_WORKER_READ -#define APP_DEFAULT_BURST_SIZE_WORKER_READ 144 -#endif -#if ((2 * APP_DEFAULT_BURST_SIZE_WORKER_READ) > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_WORKER_READ is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_WORKER_WRITE -#define APP_DEFAULT_BURST_SIZE_WORKER_WRITE 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_WORKER_WRITE > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_WORKER_WRITE is too big" -#endif - -/* Load balancing logic */ -#ifndef APP_DEFAULT_IO_RX_LB_POS -#define APP_DEFAULT_IO_RX_LB_POS 29 -#endif -#if (APP_DEFAULT_IO_RX_LB_POS >= 64) -#error "APP_DEFAULT_IO_RX_LB_POS is too big" -#endif - -struct app_mbuf_array { - struct rte_mbuf *array[APP_MBUF_ARRAY_SIZE]; - uint32_t n_mbufs; -}; - -enum app_lcore_type { - e_APP_LCORE_DISABLED = 0, - e_APP_LCORE_IO, - e_APP_LCORE_WORKER -}; - -struct app_lcore_params_io { - /* I/O RX */ - struct { - /* NIC */ - struct { - uint16_t port; - uint8_t queue; - } nic_queues[APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE]; - uint32_t n_nic_queues; - - /* Rings */ - struct rte_ring *rings[APP_MAX_WORKER_LCORES]; - uint32_t n_rings; - - /* Internal buffers */ - struct app_mbuf_array mbuf_in; - struct app_mbuf_array mbuf_out[APP_MAX_WORKER_LCORES]; - uint8_t mbuf_out_flush[APP_MAX_WORKER_LCORES]; - - /* Stats */ - uint32_t nic_queues_count[APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE]; - uint32_t nic_queues_iters[APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE]; - uint32_t rings_count[APP_MAX_WORKER_LCORES]; - uint32_t rings_iters[APP_MAX_WORKER_LCORES]; - } rx; - - /* I/O TX */ - struct { - /* Rings */ - struct rte_ring *rings[APP_MAX_NIC_PORTS][APP_MAX_WORKER_LCORES]; - - /* NIC */ - uint16_t nic_ports[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - uint32_t n_nic_ports; - - /* Internal buffers */ - struct app_mbuf_array mbuf_out[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - uint8_t mbuf_out_flush[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - - /* Stats */ - uint32_t rings_count[APP_MAX_NIC_PORTS][APP_MAX_WORKER_LCORES]; - uint32_t rings_iters[APP_MAX_NIC_PORTS][APP_MAX_WORKER_LCORES]; - uint32_t nic_ports_count[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - uint32_t nic_ports_iters[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - } tx; -}; - -struct app_lcore_params_worker { - /* Rings */ - struct rte_ring *rings_in[APP_MAX_IO_LCORES]; - uint32_t n_rings_in; - struct rte_ring *rings_out[APP_MAX_NIC_PORTS]; - - /* LPM table */ - struct rte_lpm *lpm_table; - uint32_t worker_id; - - /* Internal buffers */ - struct app_mbuf_array mbuf_in; - struct app_mbuf_array mbuf_out[APP_MAX_NIC_PORTS]; - uint8_t mbuf_out_flush[APP_MAX_NIC_PORTS]; - - /* Stats */ - uint32_t rings_in_count[APP_MAX_IO_LCORES]; - uint32_t rings_in_iters[APP_MAX_IO_LCORES]; - uint32_t rings_out_count[APP_MAX_NIC_PORTS]; - uint32_t rings_out_iters[APP_MAX_NIC_PORTS]; -}; - -struct app_lcore_params { - union { - struct app_lcore_params_io io; - struct app_lcore_params_worker worker; - }; - enum app_lcore_type type; - struct rte_mempool *pool; -} __rte_cache_aligned; - -struct app_lpm_rule { - uint32_t ip; - uint8_t depth; - uint8_t if_out; -}; - -struct app_params { - /* lcore */ - struct app_lcore_params lcore_params[APP_MAX_LCORES]; - - /* NIC */ - uint8_t nic_rx_queue_mask[APP_MAX_NIC_PORTS][APP_MAX_RX_QUEUES_PER_NIC_PORT]; - uint8_t nic_tx_port_mask[APP_MAX_NIC_PORTS]; - - /* mbuf pools */ - struct rte_mempool *pools[APP_MAX_SOCKETS]; - - /* LPM tables */ - struct rte_lpm *lpm_tables[APP_MAX_SOCKETS]; - struct app_lpm_rule lpm_rules[APP_MAX_LPM_RULES]; - uint32_t n_lpm_rules; - - /* rings */ - uint32_t nic_rx_ring_size; - uint32_t nic_tx_ring_size; - uint32_t ring_rx_size; - uint32_t ring_tx_size; - - /* burst size */ - uint32_t burst_size_io_rx_read; - uint32_t burst_size_io_rx_write; - uint32_t burst_size_io_tx_read; - uint32_t burst_size_io_tx_write; - uint32_t burst_size_worker_read; - uint32_t burst_size_worker_write; - - /* load balancing */ - uint8_t pos_lb; -} __rte_cache_aligned; - -extern struct app_params app; - -int app_parse_args(int argc, char **argv); -void app_print_usage(void); -void app_init(void); -int app_lcore_main_loop(void *arg); - -int app_get_nic_rx_queues_per_port(uint16_t port); -int app_get_lcore_for_nic_rx(uint16_t port, uint8_t queue, - uint32_t *lcore_out); -int app_get_lcore_for_nic_tx(uint16_t port, uint32_t *lcore_out); -int app_is_socket_used(uint32_t socket); -uint32_t app_get_lcores_io_rx(void); -uint32_t app_get_lcores_worker(void); -void app_print_params(void); - -#endif /* _MAIN_H_ */ diff --git a/examples/load_balancer/meson.build b/examples/load_balancer/meson.build deleted file mode 100644 index 4f7ac3999..000000000 --- a/examples/load_balancer/meson.build +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2017 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' - -deps += 'lpm' -sources = files( - 'config.c', 'init.c', 'main.c', 'runtime.c' -) diff --git a/examples/load_balancer/runtime.c b/examples/load_balancer/runtime.c deleted file mode 100644 index f0aad1513..000000000 --- a/examples/load_balancer/runtime.c +++ /dev/null @@ -1,642 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_ring.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_lpm.h> - -#include "main.h" - -#ifndef APP_LCORE_IO_FLUSH -#define APP_LCORE_IO_FLUSH 1000000 -#endif - -#ifndef APP_LCORE_WORKER_FLUSH -#define APP_LCORE_WORKER_FLUSH 1000000 -#endif - -#ifndef APP_STATS -#define APP_STATS 1000000 -#endif - -#define APP_IO_RX_DROP_ALL_PACKETS 0 -#define APP_WORKER_DROP_ALL_PACKETS 0 -#define APP_IO_TX_DROP_ALL_PACKETS 0 - -#ifndef APP_IO_RX_PREFETCH_ENABLE -#define APP_IO_RX_PREFETCH_ENABLE 1 -#endif - -#ifndef APP_WORKER_PREFETCH_ENABLE -#define APP_WORKER_PREFETCH_ENABLE 1 -#endif - -#ifndef APP_IO_TX_PREFETCH_ENABLE -#define APP_IO_TX_PREFETCH_ENABLE 1 -#endif - -#if APP_IO_RX_PREFETCH_ENABLE -#define APP_IO_RX_PREFETCH0(p) rte_prefetch0(p) -#define APP_IO_RX_PREFETCH1(p) rte_prefetch1(p) -#else -#define APP_IO_RX_PREFETCH0(p) -#define APP_IO_RX_PREFETCH1(p) -#endif - -#if APP_WORKER_PREFETCH_ENABLE -#define APP_WORKER_PREFETCH0(p) rte_prefetch0(p) -#define APP_WORKER_PREFETCH1(p) rte_prefetch1(p) -#else -#define APP_WORKER_PREFETCH0(p) -#define APP_WORKER_PREFETCH1(p) -#endif - -#if APP_IO_TX_PREFETCH_ENABLE -#define APP_IO_TX_PREFETCH0(p) rte_prefetch0(p) -#define APP_IO_TX_PREFETCH1(p) rte_prefetch1(p) -#else -#define APP_IO_TX_PREFETCH0(p) -#define APP_IO_TX_PREFETCH1(p) -#endif - -static inline void -app_lcore_io_rx_buffer_to_send ( - struct app_lcore_params_io *lp, - uint32_t worker, - struct rte_mbuf *mbuf, - uint32_t bsz) -{ - uint32_t pos; - int ret; - - pos = lp->rx.mbuf_out[worker].n_mbufs; - lp->rx.mbuf_out[worker].array[pos ++] = mbuf; - if (likely(pos < bsz)) { - lp->rx.mbuf_out[worker].n_mbufs = pos; - return; - } - - ret = rte_ring_sp_enqueue_bulk( - lp->rx.rings[worker], - (void **) lp->rx.mbuf_out[worker].array, - bsz, - NULL); - - if (unlikely(ret == 0)) { - uint32_t k; - for (k = 0; k < bsz; k ++) { - struct rte_mbuf *m = lp->rx.mbuf_out[worker].array[k]; - rte_pktmbuf_free(m); - } - } - - lp->rx.mbuf_out[worker].n_mbufs = 0; - lp->rx.mbuf_out_flush[worker] = 0; - -#if APP_STATS - lp->rx.rings_iters[worker] ++; - if (likely(ret == 0)) { - lp->rx.rings_count[worker] ++; - } - if (unlikely(lp->rx.rings_iters[worker] == APP_STATS)) { - unsigned lcore = rte_lcore_id(); - - printf("\tI/O RX %u out (worker %u): enq success rate = %.2f\n", - lcore, - (unsigned)worker, - ((double) lp->rx.rings_count[worker]) / ((double) lp->rx.rings_iters[worker])); - lp->rx.rings_iters[worker] = 0; - lp->rx.rings_count[worker] = 0; - } -#endif -} - -static inline void -app_lcore_io_rx( - struct app_lcore_params_io *lp, - uint32_t n_workers, - uint32_t bsz_rd, - uint32_t bsz_wr, - uint8_t pos_lb) -{ - struct rte_mbuf *mbuf_1_0, *mbuf_1_1, *mbuf_2_0, *mbuf_2_1; - uint8_t *data_1_0, *data_1_1 = NULL; - uint32_t i; - - for (i = 0; i < lp->rx.n_nic_queues; i ++) { - uint16_t port = lp->rx.nic_queues[i].port; - uint8_t queue = lp->rx.nic_queues[i].queue; - uint32_t n_mbufs, j; - - n_mbufs = rte_eth_rx_burst( - port, - queue, - lp->rx.mbuf_in.array, - (uint16_t) bsz_rd); - - if (unlikely(n_mbufs == 0)) { - continue; - } - -#if APP_STATS - lp->rx.nic_queues_iters[i] ++; - lp->rx.nic_queues_count[i] += n_mbufs; - if (unlikely(lp->rx.nic_queues_iters[i] == APP_STATS)) { - struct rte_eth_stats stats; - unsigned lcore = rte_lcore_id(); - - rte_eth_stats_get(port, &stats); - - printf("I/O RX %u in (NIC port %u): NIC drop ratio = %.2f avg burst size = %.2f\n", - lcore, - port, - (double) stats.imissed / (double) (stats.imissed + stats.ipackets), - ((double) lp->rx.nic_queues_count[i]) / ((double) lp->rx.nic_queues_iters[i])); - lp->rx.nic_queues_iters[i] = 0; - lp->rx.nic_queues_count[i] = 0; - } -#endif - -#if APP_IO_RX_DROP_ALL_PACKETS - for (j = 0; j < n_mbufs; j ++) { - struct rte_mbuf *pkt = lp->rx.mbuf_in.array[j]; - rte_pktmbuf_free(pkt); - } - - continue; -#endif - - mbuf_1_0 = lp->rx.mbuf_in.array[0]; - mbuf_1_1 = lp->rx.mbuf_in.array[1]; - data_1_0 = rte_pktmbuf_mtod(mbuf_1_0, uint8_t *); - if (likely(n_mbufs > 1)) { - data_1_1 = rte_pktmbuf_mtod(mbuf_1_1, uint8_t *); - } - - mbuf_2_0 = lp->rx.mbuf_in.array[2]; - mbuf_2_1 = lp->rx.mbuf_in.array[3]; - APP_IO_RX_PREFETCH0(mbuf_2_0); - APP_IO_RX_PREFETCH0(mbuf_2_1); - - for (j = 0; j + 3 < n_mbufs; j += 2) { - struct rte_mbuf *mbuf_0_0, *mbuf_0_1; - uint8_t *data_0_0, *data_0_1; - uint32_t worker_0, worker_1; - - mbuf_0_0 = mbuf_1_0; - mbuf_0_1 = mbuf_1_1; - data_0_0 = data_1_0; - data_0_1 = data_1_1; - - mbuf_1_0 = mbuf_2_0; - mbuf_1_1 = mbuf_2_1; - data_1_0 = rte_pktmbuf_mtod(mbuf_2_0, uint8_t *); - data_1_1 = rte_pktmbuf_mtod(mbuf_2_1, uint8_t *); - APP_IO_RX_PREFETCH0(data_1_0); - APP_IO_RX_PREFETCH0(data_1_1); - - mbuf_2_0 = lp->rx.mbuf_in.array[j+4]; - mbuf_2_1 = lp->rx.mbuf_in.array[j+5]; - APP_IO_RX_PREFETCH0(mbuf_2_0); - APP_IO_RX_PREFETCH0(mbuf_2_1); - - worker_0 = data_0_0[pos_lb] & (n_workers - 1); - worker_1 = data_0_1[pos_lb] & (n_workers - 1); - - app_lcore_io_rx_buffer_to_send(lp, worker_0, mbuf_0_0, bsz_wr); - app_lcore_io_rx_buffer_to_send(lp, worker_1, mbuf_0_1, bsz_wr); - } - - /* Handle the last 1, 2 (when n_mbufs is even) or 3 (when n_mbufs is odd) packets */ - for ( ; j < n_mbufs; j += 1) { - struct rte_mbuf *mbuf; - uint8_t *data; - uint32_t worker; - - mbuf = mbuf_1_0; - mbuf_1_0 = mbuf_1_1; - mbuf_1_1 = mbuf_2_0; - mbuf_2_0 = mbuf_2_1; - - data = rte_pktmbuf_mtod(mbuf, uint8_t *); - - APP_IO_RX_PREFETCH0(mbuf_1_0); - - worker = data[pos_lb] & (n_workers - 1); - - app_lcore_io_rx_buffer_to_send(lp, worker, mbuf, bsz_wr); - } - } -} - -static inline void -app_lcore_io_rx_flush(struct app_lcore_params_io *lp, uint32_t n_workers) -{ - uint32_t worker; - - for (worker = 0; worker < n_workers; worker ++) { - int ret; - - if (likely((lp->rx.mbuf_out_flush[worker] == 0) || - (lp->rx.mbuf_out[worker].n_mbufs == 0))) { - lp->rx.mbuf_out_flush[worker] = 1; - continue; - } - - ret = rte_ring_sp_enqueue_bulk( - lp->rx.rings[worker], - (void **) lp->rx.mbuf_out[worker].array, - lp->rx.mbuf_out[worker].n_mbufs, - NULL); - - if (unlikely(ret == 0)) { - uint32_t k; - for (k = 0; k < lp->rx.mbuf_out[worker].n_mbufs; k ++) { - struct rte_mbuf *pkt_to_free = lp->rx.mbuf_out[worker].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - - lp->rx.mbuf_out[worker].n_mbufs = 0; - lp->rx.mbuf_out_flush[worker] = 1; - } -} - -static inline void -app_lcore_io_tx( - struct app_lcore_params_io *lp, - uint32_t n_workers, - uint32_t bsz_rd, - uint32_t bsz_wr) -{ - uint32_t worker; - - for (worker = 0; worker < n_workers; worker ++) { - uint32_t i; - - for (i = 0; i < lp->tx.n_nic_ports; i ++) { - uint16_t port = lp->tx.nic_ports[i]; - struct rte_ring *ring = lp->tx.rings[port][worker]; - uint32_t n_mbufs, n_pkts; - int ret; - - n_mbufs = lp->tx.mbuf_out[port].n_mbufs; - ret = rte_ring_sc_dequeue_bulk( - ring, - (void **) &lp->tx.mbuf_out[port].array[n_mbufs], - bsz_rd, - NULL); - - if (unlikely(ret == 0)) - continue; - - n_mbufs += bsz_rd; - -#if APP_IO_TX_DROP_ALL_PACKETS - { - uint32_t j; - APP_IO_TX_PREFETCH0(lp->tx.mbuf_out[port].array[0]); - APP_IO_TX_PREFETCH0(lp->tx.mbuf_out[port].array[1]); - - for (j = 0; j < n_mbufs; j ++) { - if (likely(j < n_mbufs - 2)) { - APP_IO_TX_PREFETCH0(lp->tx.mbuf_out[port].array[j + 2]); - } - - rte_pktmbuf_free(lp->tx.mbuf_out[port].array[j]); - } - - lp->tx.mbuf_out[port].n_mbufs = 0; - - continue; - } -#endif - - if (unlikely(n_mbufs < bsz_wr)) { - lp->tx.mbuf_out[port].n_mbufs = n_mbufs; - continue; - } - - n_pkts = rte_eth_tx_burst( - port, - 0, - lp->tx.mbuf_out[port].array, - (uint16_t) n_mbufs); - -#if APP_STATS - lp->tx.nic_ports_iters[port] ++; - lp->tx.nic_ports_count[port] += n_pkts; - if (unlikely(lp->tx.nic_ports_iters[port] == APP_STATS)) { - unsigned lcore = rte_lcore_id(); - - printf("\t\t\tI/O TX %u out (port %u): avg burst size = %.2f\n", - lcore, - port, - ((double) lp->tx.nic_ports_count[port]) / ((double) lp->tx.nic_ports_iters[port])); - lp->tx.nic_ports_iters[port] = 0; - lp->tx.nic_ports_count[port] = 0; - } -#endif - - if (unlikely(n_pkts < n_mbufs)) { - uint32_t k; - for (k = n_pkts; k < n_mbufs; k ++) { - struct rte_mbuf *pkt_to_free = lp->tx.mbuf_out[port].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - lp->tx.mbuf_out[port].n_mbufs = 0; - lp->tx.mbuf_out_flush[port] = 0; - } - } -} - -static inline void -app_lcore_io_tx_flush(struct app_lcore_params_io *lp) -{ - uint16_t port; - uint32_t i; - - for (i = 0; i < lp->tx.n_nic_ports; i++) { - uint32_t n_pkts; - - port = lp->tx.nic_ports[i]; - if (likely((lp->tx.mbuf_out_flush[port] == 0) || - (lp->tx.mbuf_out[port].n_mbufs == 0))) { - lp->tx.mbuf_out_flush[port] = 1; - continue; - } - - n_pkts = rte_eth_tx_burst( - port, - 0, - lp->tx.mbuf_out[port].array, - (uint16_t) lp->tx.mbuf_out[port].n_mbufs); - - if (unlikely(n_pkts < lp->tx.mbuf_out[port].n_mbufs)) { - uint32_t k; - for (k = n_pkts; k < lp->tx.mbuf_out[port].n_mbufs; k ++) { - struct rte_mbuf *pkt_to_free = lp->tx.mbuf_out[port].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - - lp->tx.mbuf_out[port].n_mbufs = 0; - lp->tx.mbuf_out_flush[port] = 1; - } -} - -static void -app_lcore_main_loop_io(void) -{ - uint32_t lcore = rte_lcore_id(); - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - uint32_t n_workers = app_get_lcores_worker(); - uint64_t i = 0; - - uint32_t bsz_rx_rd = app.burst_size_io_rx_read; - uint32_t bsz_rx_wr = app.burst_size_io_rx_write; - uint32_t bsz_tx_rd = app.burst_size_io_tx_read; - uint32_t bsz_tx_wr = app.burst_size_io_tx_write; - - uint8_t pos_lb = app.pos_lb; - - for ( ; ; ) { - if (APP_LCORE_IO_FLUSH && (unlikely(i == APP_LCORE_IO_FLUSH))) { - if (likely(lp->rx.n_nic_queues > 0)) { - app_lcore_io_rx_flush(lp, n_workers); - } - - if (likely(lp->tx.n_nic_ports > 0)) { - app_lcore_io_tx_flush(lp); - } - - i = 0; - } - - if (likely(lp->rx.n_nic_queues > 0)) { - app_lcore_io_rx(lp, n_workers, bsz_rx_rd, bsz_rx_wr, pos_lb); - } - - if (likely(lp->tx.n_nic_ports > 0)) { - app_lcore_io_tx(lp, n_workers, bsz_tx_rd, bsz_tx_wr); - } - - i ++; - } -} - -static inline void -app_lcore_worker( - struct app_lcore_params_worker *lp, - uint32_t bsz_rd, - uint32_t bsz_wr) -{ - uint32_t i; - - for (i = 0; i < lp->n_rings_in; i ++) { - struct rte_ring *ring_in = lp->rings_in[i]; - uint32_t j; - int ret; - - ret = rte_ring_sc_dequeue_bulk( - ring_in, - (void **) lp->mbuf_in.array, - bsz_rd, - NULL); - - if (unlikely(ret == 0)) - continue; - -#if APP_WORKER_DROP_ALL_PACKETS - for (j = 0; j < bsz_rd; j ++) { - struct rte_mbuf *pkt = lp->mbuf_in.array[j]; - rte_pktmbuf_free(pkt); - } - - continue; -#endif - - APP_WORKER_PREFETCH1(rte_pktmbuf_mtod(lp->mbuf_in.array[0], unsigned char *)); - APP_WORKER_PREFETCH0(lp->mbuf_in.array[1]); - - for (j = 0; j < bsz_rd; j ++) { - struct rte_mbuf *pkt; - struct rte_ipv4_hdr *ipv4_hdr; - uint32_t ipv4_dst, pos; - uint32_t port; - - if (likely(j < bsz_rd - 1)) { - APP_WORKER_PREFETCH1(rte_pktmbuf_mtod(lp->mbuf_in.array[j+1], unsigned char *)); - } - if (likely(j < bsz_rd - 2)) { - APP_WORKER_PREFETCH0(lp->mbuf_in.array[j+2]); - } - - pkt = lp->mbuf_in.array[j]; - ipv4_hdr = rte_pktmbuf_mtod_offset( - pkt, struct rte_ipv4_hdr *, - sizeof(struct rte_ether_hdr)); - ipv4_dst = rte_be_to_cpu_32(ipv4_hdr->dst_addr); - - if (unlikely(rte_lpm_lookup(lp->lpm_table, ipv4_dst, &port) != 0)) { - port = pkt->port; - } - - pos = lp->mbuf_out[port].n_mbufs; - - lp->mbuf_out[port].array[pos ++] = pkt; - if (likely(pos < bsz_wr)) { - lp->mbuf_out[port].n_mbufs = pos; - continue; - } - - ret = rte_ring_sp_enqueue_bulk( - lp->rings_out[port], - (void **) lp->mbuf_out[port].array, - bsz_wr, - NULL); - -#if APP_STATS - lp->rings_out_iters[port] ++; - if (ret > 0) { - lp->rings_out_count[port] += 1; - } - if (lp->rings_out_iters[port] == APP_STATS){ - printf("\t\tWorker %u out (NIC port %u): enq success rate = %.2f\n", - (unsigned) lp->worker_id, - port, - ((double) lp->rings_out_count[port]) / ((double) lp->rings_out_iters[port])); - lp->rings_out_iters[port] = 0; - lp->rings_out_count[port] = 0; - } -#endif - - if (unlikely(ret == 0)) { - uint32_t k; - for (k = 0; k < bsz_wr; k ++) { - struct rte_mbuf *pkt_to_free = lp->mbuf_out[port].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - - lp->mbuf_out[port].n_mbufs = 0; - lp->mbuf_out_flush[port] = 0; - } - } -} - -static inline void -app_lcore_worker_flush(struct app_lcore_params_worker *lp) -{ - uint32_t port; - - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - int ret; - - if (unlikely(lp->rings_out[port] == NULL)) { - continue; - } - - if (likely((lp->mbuf_out_flush[port] == 0) || - (lp->mbuf_out[port].n_mbufs == 0))) { - lp->mbuf_out_flush[port] = 1; - continue; - } - - ret = rte_ring_sp_enqueue_bulk( - lp->rings_out[port], - (void **) lp->mbuf_out[port].array, - lp->mbuf_out[port].n_mbufs, - NULL); - - if (unlikely(ret == 0)) { - uint32_t k; - for (k = 0; k < lp->mbuf_out[port].n_mbufs; k ++) { - struct rte_mbuf *pkt_to_free = lp->mbuf_out[port].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - - lp->mbuf_out[port].n_mbufs = 0; - lp->mbuf_out_flush[port] = 1; - } -} - -static void -app_lcore_main_loop_worker(void) { - uint32_t lcore = rte_lcore_id(); - struct app_lcore_params_worker *lp = &app.lcore_params[lcore].worker; - uint64_t i = 0; - - uint32_t bsz_rd = app.burst_size_worker_read; - uint32_t bsz_wr = app.burst_size_worker_write; - - for ( ; ; ) { - if (APP_LCORE_WORKER_FLUSH && (unlikely(i == APP_LCORE_WORKER_FLUSH))) { - app_lcore_worker_flush(lp); - i = 0; - } - - app_lcore_worker(lp, bsz_rd, bsz_wr); - - i ++; - } -} - -int -app_lcore_main_loop(__attribute__((unused)) void *arg) -{ - struct app_lcore_params *lp; - unsigned lcore; - - lcore = rte_lcore_id(); - lp = &app.lcore_params[lcore]; - - if (lp->type == e_APP_LCORE_IO) { - printf("Logical core %u (I/O) main loop.\n", lcore); - app_lcore_main_loop_io(); - } - - if (lp->type == e_APP_LCORE_WORKER) { - printf("Logical core %u (worker %u) main loop.\n", - lcore, - (unsigned) lp->worker.worker_id); - app_lcore_main_loop_worker(); - } - - return 0; -} diff --git a/examples/meson.build b/examples/meson.build index f0356f2a1..e4580f74a 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -24,7 +24,6 @@ all_examples = [ 'l2fwd-keepalive', 'l3fwd', 'l3fwd-acl', 'l3fwd-power', 'link_status_interrupt', - 'load_balancer', 'multi_process/client_server_mp/mp_client', 'multi_process/client_server_mp/mp_server', 'multi_process/hotplug_mp', -- 2.17.1 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/6] remove a few example applications 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 " Ciara Power ` (5 preceding siblings ...) 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 6/6] examples/load_balancer: " Ciara Power @ 2019-10-24 14:12 ` David Marchand 6 siblings, 0 replies; 27+ messages in thread From: David Marchand @ 2019-10-24 14:12 UTC (permalink / raw) To: Ciara Power; +Cc: dev, techboard On Thu, Oct 24, 2019 at 3:35 PM Ciara Power <ciara.power@intel.com> wrote: > As discussed by the DPDK technical board e.g. [1][2] and on the DPDK > mailing list [3], we have a lot of example applications shipped with > DPDK - a number which increases with each DPDK release, and not all of > which are probably needed any more. Therefore, this set removes 5 > example applications from the repository. > > v2: Remove the table listing sample applications > > [1] https://mails.dpdk.org/archives/dev/2019-May/132288.html > [2] https://mails.dpdk.org/archives/dev/2019-June/135847.html > [3] https://mails.dpdk.org/archives/dev/2019-July/138676.html > > > Bruce Richardson (2): > examples/exception_path: remove example from DPDK > examples/l3fwd-vf: remove example from DPDK > > Ciara Power (4): > doc: remove unnecessary sample app guide table > examples/quota-watermark: remove example from DPDK > examples/netmap-compat: remove example from DPDK > examples/load_balancer: remove example from DPDK - No need to repeat "from DPDK" in the patch title. - The conflicts are trivial but please, rebase this series on master. - Can you add an entry in the release notes for each removal? Thanks. -- David Marchand ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v3 0/6] remove a few example applications 2019-10-03 13:19 [dpdk-dev] [PATCH 0/6] remove a few example applications Bruce Richardson ` (7 preceding siblings ...) 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 " Ciara Power @ 2019-10-25 9:56 ` Ciara Power 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 1/6] doc: remove unnecessary sample app guide table Ciara Power ` (6 more replies) 8 siblings, 7 replies; 27+ messages in thread From: Ciara Power @ 2019-10-25 9:56 UTC (permalink / raw) To: dev; +Cc: techboard, Ciara Power As discussed by the DPDK technical board e.g. [1][2] and on the DPDK mailing list [3], we have a lot of example applications shipped with DPDK - a number which increases with each DPDK release, and not all of which are probably needed any more. Therefore, this set removes 5 example applications from the repository. v3: - Document removed applications in release notes. - Removed "from DPDK" in patch titles. v2: Remove the table listing sample applications [1] https://mails.dpdk.org/archives/dev/2019-May/132288.html [2] https://mails.dpdk.org/archives/dev/2019-June/135847.html [3] https://mails.dpdk.org/archives/dev/2019-July/138676.html Bruce Richardson (2): examples/exception_path: remove example examples/l3fwd-vf: remove example Ciara Power (4): doc: remove unnecessary sample app guide table examples/quota-watermark: remove example examples/netmap-compat: remove example examples/load_balancer: remove example MAINTAINERS | 15 - doc/guides/rel_notes/release_19_11.rst | 12 + doc/guides/sample_app_ug/exception_path.rst | 281 ----- doc/guides/sample_app_ug/index.rst | 5 - doc/guides/sample_app_ug/intro.rst | 44 +- .../sample_app_ug/l3_forward_virtual.rst | 98 -- doc/guides/sample_app_ug/load_balancer.rst | 201 --- .../sample_app_ug/netmap_compatibility.rst | 130 -- doc/guides/sample_app_ug/quota_watermark.rst | 465 ------- examples/Makefile | 5 - examples/exception_path/Makefile | 57 - examples/exception_path/main.c | 605 --------- examples/exception_path/meson.build | 11 - examples/l3fwd-vf/Makefile | 62 - examples/l3fwd-vf/main.c | 1077 ----------------- examples/l3fwd-vf/meson.build | 12 - examples/load_balancer/Makefile | 62 - examples/load_balancer/config.c | 1030 ---------------- examples/load_balancer/init.c | 537 -------- examples/load_balancer/main.c | 76 -- examples/load_balancer/main.h | 351 ------ examples/load_balancer/meson.build | 12 - examples/load_balancer/runtime.c | 642 ---------- examples/meson.build | 9 +- examples/netmap_compat/Makefile | 22 - examples/netmap_compat/bridge/Makefile | 35 - examples/netmap_compat/bridge/bridge.c | 347 ------ examples/netmap_compat/lib/compat_netmap.c | 906 -------------- 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 -- examples/quota_watermark/Makefile | 16 - examples/quota_watermark/include/conf.h | 19 - examples/quota_watermark/meson.build | 10 - examples/quota_watermark/qw/Makefile | 22 - examples/quota_watermark/qw/args.c | 78 -- examples/quota_watermark/qw/args.h | 12 - examples/quota_watermark/qw/init.c | 168 --- examples/quota_watermark/qw/init.h | 14 - examples/quota_watermark/qw/main.c | 373 ------ examples/quota_watermark/qw/main.h | 31 - examples/quota_watermark/qwctl/Makefile | 22 - examples/quota_watermark/qwctl/commands.c | 196 --- examples/quota_watermark/qwctl/commands.h | 12 - examples/quota_watermark/qwctl/qwctl.c | 67 - examples/quota_watermark/qwctl/qwctl.h | 12 - 47 files changed, 17 insertions(+), 8589 deletions(-) delete mode 100644 doc/guides/sample_app_ug/exception_path.rst delete mode 100644 doc/guides/sample_app_ug/l3_forward_virtual.rst delete mode 100644 doc/guides/sample_app_ug/load_balancer.rst delete mode 100644 doc/guides/sample_app_ug/netmap_compatibility.rst delete mode 100644 doc/guides/sample_app_ug/quota_watermark.rst delete mode 100644 examples/exception_path/Makefile delete mode 100644 examples/exception_path/main.c delete mode 100644 examples/exception_path/meson.build delete mode 100644 examples/l3fwd-vf/Makefile delete mode 100644 examples/l3fwd-vf/main.c delete mode 100644 examples/l3fwd-vf/meson.build delete mode 100644 examples/load_balancer/Makefile delete mode 100644 examples/load_balancer/config.c delete mode 100644 examples/load_balancer/init.c delete mode 100644 examples/load_balancer/main.c delete mode 100644 examples/load_balancer/main.h delete mode 100644 examples/load_balancer/meson.build delete mode 100644 examples/load_balancer/runtime.c 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 delete mode 100644 examples/quota_watermark/Makefile delete mode 100644 examples/quota_watermark/include/conf.h delete mode 100644 examples/quota_watermark/meson.build delete mode 100644 examples/quota_watermark/qw/Makefile delete mode 100644 examples/quota_watermark/qw/args.c delete mode 100644 examples/quota_watermark/qw/args.h delete mode 100644 examples/quota_watermark/qw/init.c delete mode 100644 examples/quota_watermark/qw/init.h delete mode 100644 examples/quota_watermark/qw/main.c delete mode 100644 examples/quota_watermark/qw/main.h delete mode 100644 examples/quota_watermark/qwctl/Makefile delete mode 100644 examples/quota_watermark/qwctl/commands.c delete mode 100644 examples/quota_watermark/qwctl/commands.h delete mode 100644 examples/quota_watermark/qwctl/qwctl.c delete mode 100644 examples/quota_watermark/qwctl/qwctl.h -- 2.17.1 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v3 1/6] doc: remove unnecessary sample app guide table 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 " Ciara Power @ 2019-10-25 9:56 ` Ciara Power 2019-10-25 10:26 ` [dpdk-dev] [dpdk-techboard] " Bruce Richardson 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 2/6] examples/exception_path: remove example Ciara Power ` (5 subsequent siblings) 6 siblings, 1 reply; 27+ messages in thread From: Ciara Power @ 2019-10-25 9:56 UTC (permalink / raw) To: dev; +Cc: techboard, Ciara Power The table of examples in the sample application guide is now removed, as it was unnecessary and difficult to update when adding/removing examples. Signed-off-by: Ciara Power <ciara.power@intel.com> --- v2: Remove the table listing sample applications --- doc/guides/sample_app_ug/intro.rst | 44 +----------------------------- 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/doc/guides/sample_app_ug/intro.rst b/doc/guides/sample_app_ug/intro.rst index 90704194a..a7576837c 100644 --- a/doc/guides/sample_app_ug/intro.rst +++ b/doc/guides/sample_app_ug/intro.rst @@ -23,49 +23,7 @@ command-line options. The DPDK Sample Applications ---------------------------- -Table :numref:`table_sample_apps` shows a list of some of the main sample -applications that are available in the examples directory of DPDK: - - .. _table_sample_apps: - - .. table:: **Some of the DPDK Sample applications** - - +---------------------------------------+--------------------------------------+ - | Bonding | Netmap Compatibility | - +---------------------------------------+--------------------------------------+ - | Command Line | Packet Ordering | - +---------------------------------------+--------------------------------------+ - | Distributor | Performance Thread | - +---------------------------------------+--------------------------------------+ - | Ethtool | Precision Time Protocol (PTP) Client | - +---------------------------------------+--------------------------------------+ - | Exception Path | Quality of Service (QoS) Metering | - +---------------------------------------+--------------------------------------+ - | Hello World | QoS Scheduler | - +---------------------------------------+--------------------------------------+ - | Internet Protocol (IP) Fragmentation | Quota and Watermark | - +---------------------------------------+--------------------------------------+ - | IP Pipeline | RX/TX Callbacks | - +---------------------------------------+--------------------------------------+ - | IP Reassembly | Server node EFD | - +---------------------------------------+--------------------------------------+ - | IPsec Security Gateway | Basic Forwarding/Skeleton App | - +---------------------------------------+--------------------------------------+ - | IPv4 multicast | Tunnel End Point (TEP) termination | - +---------------------------------------+--------------------------------------+ - | Kernel NIC Interface | Timer | - +---------------------------------------+--------------------------------------+ - | Network Layer 2 Forwarding + variants | Vhost | - +---------------------------------------+--------------------------------------+ - | Network Layer 3 Forwarding + variants | Vhost Xen | - +---------------------------------------+--------------------------------------+ - | Link Status Interrupt | VMDQ Forwarding | - +---------------------------------------+--------------------------------------+ - | Load Balancer | VMDQ and DCB Forwarding | - +---------------------------------------+--------------------------------------+ - | Multi-process | VM Power Management | - +---------------------------------------+--------------------------------------+ - +There are many sample applications available in the examples directory of DPDK. These examples range from simple to reasonably complex but most are designed to demonstrate one particular feature of DPDK. Some of the more interesting examples are highlighted below. -- 2.17.1 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [dpdk-dev] [dpdk-techboard] [PATCH v3 1/6] doc: remove unnecessary sample app guide table 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 1/6] doc: remove unnecessary sample app guide table Ciara Power @ 2019-10-25 10:26 ` Bruce Richardson 0 siblings, 0 replies; 27+ messages in thread From: Bruce Richardson @ 2019-10-25 10:26 UTC (permalink / raw) To: Ciara Power; +Cc: dev, techboard On Fri, Oct 25, 2019 at 10:56:03AM +0100, Ciara Power wrote: > The table of examples in the sample application guide is now removed, > as it was unnecessary and difficult to update when adding/removing > examples. > > Signed-off-by: Ciara Power <ciara.power@intel.com> > > --- > > v2: Remove the table listing sample applications > --- > doc/guides/sample_app_ug/intro.rst | 44 +----------------------------- > 1 file changed, 1 insertion(+), 43 deletions(-) > > diff --git a/doc/guides/sample_app_ug/intro.rst b/doc/guides/sample_app_ug/intro.rst > index 90704194a..a7576837c 100644 > --- a/doc/guides/sample_app_ug/intro.rst > +++ b/doc/guides/sample_app_ug/intro.rst > @@ -23,49 +23,7 @@ command-line options. > The DPDK Sample Applications > ---------------------------- > > -Table :numref:`table_sample_apps` shows a list of some of the main sample > -applications that are available in the examples directory of DPDK: > - > - .. _table_sample_apps: > - > - .. table:: **Some of the DPDK Sample applications** > - > - +---------------------------------------+--------------------------------------+ > - | Bonding | Netmap Compatibility | > - +---------------------------------------+--------------------------------------+ > - | Command Line | Packet Ordering | > - +---------------------------------------+--------------------------------------+ > - | Distributor | Performance Thread | > - +---------------------------------------+--------------------------------------+ > - | Ethtool | Precision Time Protocol (PTP) Client | > - +---------------------------------------+--------------------------------------+ > - | Exception Path | Quality of Service (QoS) Metering | > - +---------------------------------------+--------------------------------------+ > - | Hello World | QoS Scheduler | > - +---------------------------------------+--------------------------------------+ > - | Internet Protocol (IP) Fragmentation | Quota and Watermark | > - +---------------------------------------+--------------------------------------+ > - | IP Pipeline | RX/TX Callbacks | > - +---------------------------------------+--------------------------------------+ > - | IP Reassembly | Server node EFD | > - +---------------------------------------+--------------------------------------+ > - | IPsec Security Gateway | Basic Forwarding/Skeleton App | > - +---------------------------------------+--------------------------------------+ > - | IPv4 multicast | Tunnel End Point (TEP) termination | > - +---------------------------------------+--------------------------------------+ > - | Kernel NIC Interface | Timer | > - +---------------------------------------+--------------------------------------+ > - | Network Layer 2 Forwarding + variants | Vhost | > - +---------------------------------------+--------------------------------------+ > - | Network Layer 3 Forwarding + variants | Vhost Xen | > - +---------------------------------------+--------------------------------------+ > - | Link Status Interrupt | VMDQ Forwarding | > - +---------------------------------------+--------------------------------------+ > - | Load Balancer | VMDQ and DCB Forwarding | > - +---------------------------------------+--------------------------------------+ > - | Multi-process | VM Power Management | > - +---------------------------------------+--------------------------------------+ > - > +There are many sample applications available in the examples directory of DPDK. > These examples range from simple to reasonably complex but most are designed > to demonstrate one particular feature of DPDK. Some of the more interesting > examples are highlighted below. > -- > 2.17.1 > This table was pointless anyway, since the index gives a list of all the apps, and a select are already called out below this in the doc. Acked-by: Bruce Richardson <bruce.richardson@intel.com> ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v3 2/6] examples/exception_path: remove example 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 " Ciara Power 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 1/6] doc: remove unnecessary sample app guide table Ciara Power @ 2019-10-25 9:56 ` Ciara Power 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 3/6] examples/l3fwd-vf: " Ciara Power ` (4 subsequent siblings) 6 siblings, 0 replies; 27+ messages in thread From: Ciara Power @ 2019-10-25 9:56 UTC (permalink / raw) To: dev; +Cc: techboard, Bruce Richardson From: Bruce Richardson <bruce.richardson@intel.com> The example app shows the use of TUN/TAP with DPDK, but DPDK has a built-in TAP PMD, so this example is obsolete and so can be removed. Signed-off-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com> --- v3: Document removed application in release notes. --- MAINTAINERS | 3 - doc/guides/rel_notes/release_19_11.rst | 4 + doc/guides/sample_app_ug/exception_path.rst | 281 --------- doc/guides/sample_app_ug/index.rst | 1 - examples/Makefile | 1 - examples/exception_path/Makefile | 57 -- examples/exception_path/main.c | 605 -------------------- examples/exception_path/meson.build | 11 - examples/meson.build | 2 +- 9 files changed, 5 insertions(+), 960 deletions(-) delete mode 100644 doc/guides/sample_app_ug/exception_path.rst delete mode 100644 examples/exception_path/Makefile delete mode 100644 examples/exception_path/main.c delete mode 100644 examples/exception_path/meson.build diff --git a/MAINTAINERS b/MAINTAINERS index f0f555b37..e8f3cd787 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1454,9 +1454,6 @@ Other Example Applications F: examples/ethtool/ F: doc/guides/sample_app_ug/ethtool.rst -F: examples/exception_path/ -F: doc/guides/sample_app_ug/exception_path.rst - M: Marko Kovacevic <marko.kovacevic@intel.com> F: examples/fips_validation/ F: doc/guides/sample_app_ug/fips_validation.rst diff --git a/doc/guides/rel_notes/release_19_11.rst b/doc/guides/rel_notes/release_19_11.rst index f59a28307..a313d75bf 100644 --- a/doc/guides/rel_notes/release_19_11.rst +++ b/doc/guides/rel_notes/release_19_11.rst @@ -183,6 +183,10 @@ Removed Items ipv4_cksum|udp_cksum|tcp_cksum|timestamp| vlan_strip|vlan_filter|vlan_extend on|off +* The following sample applications have been removed in this release: + + * Exception Path + API Changes ----------- diff --git a/doc/guides/sample_app_ug/exception_path.rst b/doc/guides/sample_app_ug/exception_path.rst deleted file mode 100644 index a5590870c..000000000 --- a/doc/guides/sample_app_ug/exception_path.rst +++ /dev/null @@ -1,281 +0,0 @@ -.. SPDX-License-Identifier: BSD-3-Clause - Copyright(c) 2010-2014 Intel Corporation. - -Exception Path Sample Application -================================= - -The Exception Path sample application is a simple example that demonstrates the use of the DPDK -to set up an exception path for packets to go through the Linux* kernel. -This is done by using virtual TAP network interfaces. -These can be read from and written to by the DPDK application and -appear to the kernel as a standard network interface. - -Overview --------- - -The application creates two threads for each NIC port being used. -One thread reads from the port and writes the data unmodified to a thread-specific TAP interface. -The second thread reads from a TAP interface and writes the data unmodified to the NIC port. - -The packet flow through the exception path application is as shown in the following figure. - -.. _figure_exception_path_example: - -.. figure:: img/exception_path_example.* - - Packet Flow - - -To make throughput measurements, kernel bridges must be setup to forward data between the bridges appropriately. - -Compiling the Application -------------------------- - -To compile the sample application see :doc:`compiling`. - -The application is located in the ``exception_path`` sub-directory. - -Running the Application ------------------------ - -The application requires a number of command line options: - -.. code-block:: console - - .build/exception_path [EAL options] -- -p PORTMASK -i IN_CORES -o OUT_CORES - -where: - -* -p PORTMASK: A hex bitmask of ports to use - -* -i IN_CORES: A hex bitmask of cores which read from NIC - -* -o OUT_CORES: A hex bitmask of cores which write to NIC - -Refer to the *DPDK Getting Started Guide* for general information on running applications -and the Environment Abstraction Layer (EAL) options. - -The number of bits set in each bitmask must be the same. -The coremask -c or the corelist -l parameter of the EAL options should include IN_CORES and OUT_CORES. -The same bit must not be set in IN_CORES and OUT_CORES. -The affinities between ports and cores are set beginning with the least significant bit of each mask, that is, -the port represented by the lowest bit in PORTMASK is read from by the core represented by the lowest bit in IN_CORES, -and written to by the core represented by the lowest bit in OUT_CORES. - -For example to run the application with two ports and four cores: - -.. code-block:: console - - ./build/exception_path -l 0-3 -n 4 -- -p 3 -i 3 -o c - -Getting Statistics -~~~~~~~~~~~~~~~~~~ - -While the application is running, statistics on packets sent and -received can be displayed by sending the SIGUSR1 signal to the application from another terminal: - -.. code-block:: console - - killall -USR1 exception_path - -The statistics can be reset by sending a SIGUSR2 signal in a similar way. - -Explanation ------------ - -The following sections provide some explanation of the code. - -Initialization -~~~~~~~~~~~~~~ - -Setup of the mbuf pool, driver and queues is similar to the setup done in the :ref:`l2_fwd_app_real_and_virtual`. -In addition, the TAP interfaces must also be created. -A TAP interface is created for each lcore that is being used. -The code for creating the TAP interface is as follows: - -.. code-block:: c - - /* - * Create a tap network interface, or use existing one with same name. - * If name[0]='\0' then a name is automatically assigned and returned in name. - */ - - static int tap_create(char *name) - { - struct ifreq ifr; - int fd, ret; - - fd = open("/dev/net/tun", O_RDWR); - if (fd < 0) - return fd; - - memset(&ifr, 0, sizeof(ifr)); - - /* TAP device without packet information */ - - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - if (name && *name) - rte_snprinf(ifr.ifr_name, IFNAMSIZ, name); - - ret = ioctl(fd, TUNSETIFF, (void *) &ifr); - - if (ret < 0) { - close(fd); - return ret; - - } - - if (name) - snprintf(name, IFNAMSIZ, ifr.ifr_name); - - return fd; - } - -The other step in the initialization process that is unique to this sample application -is the association of each port with two cores: - -* One core to read from the port and write to a TAP interface - -* A second core to read from a TAP interface and write to the port - -This is done using an array called port_ids[], which is indexed by the lcore IDs. -The population of this array is shown below: - -.. code-block:: c - - tx_port = 0; - rx_port = 0; - - RTE_LCORE_FOREACH(i) { - if (input_cores_mask & (1ULL << i)) { - /* Skip ports that are not enabled */ - while ((ports_mask & (1 << rx_port)) == 0) { - rx_port++; - if (rx_port > (sizeof(ports_mask) * 8)) - goto fail; /* not enough ports */ - } - port_ids[i] = rx_port++; - } else if (output_cores_mask & (1ULL << i)) { - /* Skip ports that are not enabled */ - while ((ports_mask & (1 << tx_port)) == 0) { - tx_port++; - if (tx_port > (sizeof(ports_mask) * 8)) - goto fail; /* not enough ports */ - } - port_ids[i] = tx_port++; - } - } - -Packet Forwarding -~~~~~~~~~~~~~~~~~ - -After the initialization steps are complete, the main_loop() function is run on each lcore. -This function first checks the lcore_id against the user provided input_cores_mask and output_cores_mask to see -if this core is reading from or writing to a TAP interface. - -For the case that reads from a NIC port, the packet reception is the same as in the L2 Forwarding sample application -(see :ref:`l2_fwd_app_rx_tx_packets`). -The packet transmission is done by calling write() with the file descriptor of the appropriate TAP interface -and then explicitly freeing the mbuf back to the pool. - -.. code-block:: c - - /* Loop forever reading from NIC and writing to tap */ - - for (;;) { - struct rte_mbuf *pkts_burst[PKT_BURST_SZ]; - unsigned i; - - const unsigned nb_rx = rte_eth_rx_burst(port_ids[lcore_id], 0, pkts_burst, PKT_BURST_SZ); - - lcore_stats[lcore_id].rx += nb_rx; - - for (i = 0; likely(i < nb_rx); i++) { - struct rte_mbuf *m = pkts_burst[i]; - int ret = write(tap_fd, rte_pktmbuf_mtod(m, void*), - - rte_pktmbuf_data_len(m)); - rte_pktmbuf_free(m); - if (unlikely(ret<0)) - lcore_stats[lcore_id].dropped++; - else - lcore_stats[lcore_id].tx++; - } - } - -For the other case that reads from a TAP interface and writes to a NIC port, -packets are retrieved by doing a read() from the file descriptor of the appropriate TAP interface. -This fills in the data into the mbuf, then other fields are set manually. -The packet can then be transmitted as normal. - -.. code-block:: c - - /* Loop forever reading from tap and writing to NIC */ - - for (;;) { - int ret; - struct rte_mbuf *m = rte_pktmbuf_alloc(pktmbuf_pool); - - if (m == NULL) - continue; - - ret = read(tap_fd, m->pkt.data, MAX_PACKET_SZ); lcore_stats[lcore_id].rx++; - if (unlikely(ret < 0)) { - FATAL_ERROR("Reading from %s interface failed", tap_name); - } - - m->pkt.nb_segs = 1; - m->pkt.next = NULL; - m->pkt.data_len = (uint16_t)ret; - - ret = rte_eth_tx_burst(port_ids[lcore_id], 0, &m, 1); - if (unlikely(ret < 1)) { - rte_pktmuf_free(m); - lcore_stats[lcore_id].dropped++; - } - else { - lcore_stats[lcore_id].tx++; - } - } - -To set up loops for measuring throughput, TAP interfaces can be connected using bridging. -The steps to do this are described in the section that follows. - -Managing TAP Interfaces and Bridges -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The Exception Path sample application creates TAP interfaces with names of the format tap_dpdk_nn, -where nn is the lcore ID. These TAP interfaces need to be configured for use: - -.. code-block:: console - - ifconfig tap_dpdk_00 up - -To set up a bridge between two interfaces so that packets sent to one interface can be read from another, -use the brctl tool: - -.. code-block:: console - - brctl addbr "br0" - brctl addif br0 tap_dpdk_00 - brctl addif br0 tap_dpdk_03 - ifconfig br0 up - -The TAP interfaces created by this application exist only when the application is running, -so the steps above need to be repeated each time the application is run. -To avoid this, persistent TAP interfaces can be created using openvpn: - -.. code-block:: console - - openvpn --mktun --dev tap_dpdk_00 - -If this method is used, then the steps above have to be done only once and -the same TAP interfaces can be reused each time the application is run. -To remove bridges and persistent TAP interfaces, the following commands are used: - -.. code-block:: console - - ifconfig br0 down - brctl delbr br0 - openvpn --rmtun --dev tap_dpdk_00 - diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst index f23f8f59e..076346a60 100644 --- a/doc/guides/sample_app_ug/index.rst +++ b/doc/guides/sample_app_ug/index.rst @@ -12,7 +12,6 @@ Sample Applications User Guides compiling cmd_line ethtool - exception_path hello_world skeleton rxtx_callbacks diff --git a/examples/Makefile b/examples/Makefile index de11dd487..c756497d1 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -17,7 +17,6 @@ ifeq ($(CONFIG_RTE_LIBRTE_POWER),y) DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += distributor endif DIRS-y += ethtool -DIRS-y += exception_path DIRS-$(CONFIG_RTE_LIBRTE_EFD) += server_node_efd DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += fips_validation DIRS-$(CONFIG_RTE_LIBRTE_FLOW_CLASSIFY) += flow_classify diff --git a/examples/exception_path/Makefile b/examples/exception_path/Makefile deleted file mode 100644 index 90c7f133a..000000000 --- a/examples/exception_path/Makefile +++ /dev/null @@ -1,57 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2010-2014 Intel Corporation - -# binary name -APP = exception_path - -# all source are stored in SRCS-y -SRCS-y := main.c - -# Build using pkg-config variables if possible -ifeq ($(shell pkg-config --exists libdpdk && echo 0),0) - -all: shared -.PHONY: shared static -shared: build/$(APP)-shared - ln -sf $(APP)-shared build/$(APP) -static: build/$(APP)-static - ln -sf $(APP)-static build/$(APP) - -PKGCONF=pkg-config --define-prefix - -PC_FILE := $(shell $(PKGCONF) --path libdpdk) -CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) -LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk) -LDFLAGS_STATIC = -Wl,-Bstatic $(shell $(PKGCONF) --static --libs libdpdk) - -build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) - -build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC) - -build: - @mkdir -p $@ - -.PHONY: clean -clean: - rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared - test -d build && rmdir -p build || true - -else - -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 - -CFLAGS += -O3 -CFLAGS += $(WERROR_FLAGS) - -include $(RTE_SDK)/mk/rte.extapp.mk - -endif diff --git a/examples/exception_path/main.c b/examples/exception_path/main.c deleted file mode 100644 index 85dbd7ec7..000000000 --- a/examples/exception_path/main.c +++ /dev/null @@ -1,605 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> - -#include <netinet/in.h> -#include <net/if.h> -#ifdef RTE_EXEC_ENV_LINUX -#include <linux/if_tun.h> -#endif -#include <fcntl.h> -#include <sys/ioctl.h> -#include <unistd.h> -#include <signal.h> - -#include <rte_common.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_per_lcore.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_string_fns.h> -#include <rte_cycles.h> - -#ifndef APP_MAX_LCORE -#if (RTE_MAX_LCORE > 64) -#define APP_MAX_LCORE 64 -#else -#define APP_MAX_LCORE RTE_MAX_LCORE -#endif -#endif - -/* Macros for printing using RTE_LOG */ -#define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1 -#define FATAL_ERROR(fmt, args...) rte_exit(EXIT_FAILURE, fmt "\n", ##args) -#define PRINT_INFO(fmt, args...) RTE_LOG(INFO, APP, fmt "\n", ##args) - -/* Max ports than can be used (each port is associated with two lcores) */ -#define MAX_PORTS (APP_MAX_LCORE / 2) - -/* Max size of a single packet */ -#define MAX_PACKET_SZ (2048) - -/* Size of the data buffer in each mbuf */ -#define MBUF_DATA_SZ (MAX_PACKET_SZ + RTE_PKTMBUF_HEADROOM) - -/* Number of mbufs in mempool that is created */ -#define NB_MBUF 8192 - -/* How many packets to attempt to read from NIC in one go */ -#define PKT_BURST_SZ 32 - -/* How many objects (mbufs) to keep in per-lcore mempool cache */ -#define MEMPOOL_CACHE_SZ PKT_BURST_SZ - -/* Number of RX ring descriptors */ -#define NB_RXD 1024 - -/* Number of TX ring descriptors */ -#define NB_TXD 1024 - -/* - * RX and TX Prefetch, Host, and Write-back threshold values should be - * carefully set for optimal performance. Consult the network - * controller's datasheet and supporting DPDK documentation for guidance - * on how these parameters should be set. - */ - -/* Options for configuring ethernet port */ -static struct rte_eth_conf port_conf = { - .txmode = { - .mq_mode = ETH_MQ_TX_NONE, - }, -}; - -/* Mempool for mbufs */ -static struct rte_mempool * pktmbuf_pool = NULL; - -/* Mask of enabled ports */ -static uint32_t ports_mask = 0; - -/* Mask of cores that read from NIC and write to tap */ -static uint64_t input_cores_mask = 0; - -/* Mask of cores that read from tap and write to NIC */ -static uint64_t output_cores_mask = 0; - -/* Array storing port_id that is associated with each lcore */ -static uint16_t port_ids[APP_MAX_LCORE]; - -/* Structure type for recording lcore-specific stats */ -struct stats { - uint64_t rx; - uint64_t tx; - uint64_t dropped; -} __rte_cache_aligned; - -/* Array of lcore-specific stats */ -static struct stats lcore_stats[APP_MAX_LCORE]; - -/* Print out statistics on packets handled */ -static void -print_stats(void) -{ - unsigned i; - - printf("\n**Exception-Path example application statistics**\n" - "======= ====== ============ ============ ===============\n" - " Lcore Port RX TX Dropped on TX\n" - "------- ------ ------------ ------------ ---------------\n"); - RTE_LCORE_FOREACH(i) { - /* limit ourselves to application supported cores only */ - if (i >= APP_MAX_LCORE) - break; - printf("%6u %7u %13"PRIu64" %13"PRIu64" %16"PRIu64"\n", - i, (unsigned)port_ids[i], - lcore_stats[i].rx, lcore_stats[i].tx, - lcore_stats[i].dropped); - } - printf("======= ====== ============ ============ ===============\n"); -} - -/* Custom handling of signals to handle stats */ -static void -signal_handler(int signum) -{ - /* When we receive a USR1 signal, print stats */ - if (signum == SIGUSR1) { - print_stats(); - } - - /* When we receive a USR2 signal, reset stats */ - if (signum == SIGUSR2) { - memset(&lcore_stats, 0, sizeof(lcore_stats)); - printf("\n**Statistics have been reset**\n"); - return; - } -} - -#ifdef RTE_EXEC_ENV_LINUX -/* - * Create a tap network interface, or use existing one with same name. - * If name[0]='\0' then a name is automatically assigned and returned in name. - */ -static int tap_create(char *name) -{ - struct ifreq ifr; - int fd, ret; - - fd = open("/dev/net/tun", O_RDWR); - if (fd < 0) - return fd; - - memset(&ifr, 0, sizeof(ifr)); - - /* TAP device without packet information */ - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - - if (name && *name) - strlcpy(ifr.ifr_name, name, IFNAMSIZ); - - ret = ioctl(fd, TUNSETIFF, (void *) &ifr); - if (ret < 0) { - close(fd); - return ret; - } - - if (name) - strlcpy(name, ifr.ifr_name, IFNAMSIZ); - - return fd; -} -#else -/* - * Find a free tap network interface, or create a new one. - * The name is automatically assigned and returned in name. - */ -static int tap_create(char *name) -{ - int i, fd = -1; - char devname[PATH_MAX]; - - for (i = 0; i < 255; i++) { - snprintf(devname, sizeof(devname), "/dev/tap%d", i); - fd = open(devname, O_RDWR); - if (fd >= 0 || errno != EBUSY) - break; - } - - if (name) - snprintf(name, IFNAMSIZ, "tap%d", i); - - return fd; -} -#endif - -/* Main processing loop */ -static int -main_loop(__attribute__((unused)) void *arg) -{ - const unsigned lcore_id = rte_lcore_id(); - char tap_name[IFNAMSIZ]; - int tap_fd; - - if ((1ULL << lcore_id) & input_cores_mask) { - /* Create new tap interface */ - snprintf(tap_name, IFNAMSIZ, "tap_dpdk_%.2u", lcore_id); - tap_fd = tap_create(tap_name); - if (tap_fd < 0) - FATAL_ERROR("Could not create tap interface \"%s\" (%d)", - tap_name, tap_fd); - - PRINT_INFO("Lcore %u is reading from port %u and writing to %s", - lcore_id, (unsigned)port_ids[lcore_id], tap_name); - fflush(stdout); - /* Loop forever reading from NIC and writing to tap */ - for (;;) { - struct rte_mbuf *pkts_burst[PKT_BURST_SZ]; - unsigned i; - const unsigned nb_rx = - rte_eth_rx_burst(port_ids[lcore_id], 0, - pkts_burst, PKT_BURST_SZ); - lcore_stats[lcore_id].rx += nb_rx; - for (i = 0; likely(i < nb_rx); i++) { - struct rte_mbuf *m = pkts_burst[i]; - /* Ignore return val from write() */ - int ret = write(tap_fd, - rte_pktmbuf_mtod(m, void*), - rte_pktmbuf_data_len(m)); - rte_pktmbuf_free(m); - if (unlikely(ret < 0)) - lcore_stats[lcore_id].dropped++; - else - lcore_stats[lcore_id].tx++; - } - } - } - else if ((1ULL << lcore_id) & output_cores_mask) { - /* Create new tap interface */ - snprintf(tap_name, IFNAMSIZ, "tap_dpdk_%.2u", lcore_id); - tap_fd = tap_create(tap_name); - if (tap_fd < 0) - FATAL_ERROR("Could not create tap interface \"%s\" (%d)", - tap_name, tap_fd); - - PRINT_INFO("Lcore %u is reading from %s and writing to port %u", - lcore_id, tap_name, (unsigned)port_ids[lcore_id]); - fflush(stdout); - /* Loop forever reading from tap and writing to NIC */ - for (;;) { - int ret; - struct rte_mbuf *m = rte_pktmbuf_alloc(pktmbuf_pool); - if (m == NULL) - continue; - - ret = read(tap_fd, rte_pktmbuf_mtod(m, void *), - MAX_PACKET_SZ); - lcore_stats[lcore_id].rx++; - if (unlikely(ret < 0)) { - FATAL_ERROR("Reading from %s interface failed", - tap_name); - } - m->nb_segs = 1; - m->next = NULL; - m->pkt_len = (uint16_t)ret; - m->data_len = (uint16_t)ret; - ret = rte_eth_tx_burst(port_ids[lcore_id], 0, &m, 1); - if (unlikely(ret < 1)) { - rte_pktmbuf_free(m); - lcore_stats[lcore_id].dropped++; - } - else { - lcore_stats[lcore_id].tx++; - } - } - } - else { - PRINT_INFO("Lcore %u has nothing to do", lcore_id); - return 0; - } - /* - * Tap file is closed automatically when program exits. Putting close() - * here will cause the compiler to give an error about unreachable code. - */ -} - -/* Display usage instructions */ -static void -print_usage(const char *prgname) -{ - PRINT_INFO("\nUsage: %s [EAL options] -- -p PORTMASK -i IN_CORES -o OUT_CORES\n" - " -p PORTMASK: hex bitmask of ports to use\n" - " -i IN_CORES: hex bitmask of cores which read from NIC\n" - " -o OUT_CORES: hex bitmask of cores which write to NIC", - prgname); -} - -/* Convert string to unsigned number. 0 is returned if error occurs */ -static uint64_t -parse_unsigned(const char *portmask) -{ - char *end = NULL; - uint64_t num; - - num = strtoull(portmask, &end, 16); - if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) - return 0; - - return (uint64_t)num; -} - -/* Record affinities between ports and lcores in global port_ids[] array */ -static void -setup_port_lcore_affinities(void) -{ - unsigned long i; - uint16_t tx_port = 0; - uint16_t rx_port = 0; - - /* Setup port_ids[] array, and check masks were ok */ - for (i = 0; i < APP_MAX_LCORE; i++) { - if (!rte_lcore_is_enabled(i)) - continue; - if (input_cores_mask & (1ULL << i)) { - /* Skip ports that are not enabled */ - while ((ports_mask & (1 << rx_port)) == 0) { - rx_port++; - if (rx_port > (sizeof(ports_mask) * 8)) - goto fail; /* not enough ports */ - } - - port_ids[i] = rx_port++; - } else if (output_cores_mask & (1ULL << (i & 0x3f))) { - /* Skip ports that are not enabled */ - while ((ports_mask & (1 << tx_port)) == 0) { - tx_port++; - if (tx_port > (sizeof(ports_mask) * 8)) - goto fail; /* not enough ports */ - } - - port_ids[i] = tx_port++; - } - } - - if (rx_port != tx_port) - goto fail; /* uneven number of cores in masks */ - - if (ports_mask & (~((1 << rx_port) - 1))) - goto fail; /* unused ports */ - - return; -fail: - FATAL_ERROR("Invalid core/port masks specified on command line"); -} - -/* Parse the arguments given in the command line of the application */ -static void -parse_args(int argc, char **argv) -{ - int opt; - const char *prgname = argv[0]; - - /* Disable printing messages within getopt() */ - opterr = 0; - - /* Parse command line */ - while ((opt = getopt(argc, argv, "i:o:p:")) != EOF) { - switch (opt) { - case 'i': - input_cores_mask = parse_unsigned(optarg); - break; - case 'o': - output_cores_mask = parse_unsigned(optarg); - break; - case 'p': - ports_mask = parse_unsigned(optarg); - break; - default: - print_usage(prgname); - FATAL_ERROR("Invalid option specified"); - } - } - - /* Check that options were parsed ok */ - if (input_cores_mask == 0) { - print_usage(prgname); - FATAL_ERROR("IN_CORES not specified correctly"); - } - if (output_cores_mask == 0) { - print_usage(prgname); - FATAL_ERROR("OUT_CORES not specified correctly"); - } - if (ports_mask == 0) { - print_usage(prgname); - FATAL_ERROR("PORTMASK not specified correctly"); - } - - setup_port_lcore_affinities(); -} - -/* Initialise a single port on an Ethernet device */ -static void -init_port(uint16_t port) -{ - int ret; - uint16_t nb_rxd = NB_RXD; - uint16_t nb_txd = NB_TXD; - struct rte_eth_dev_info dev_info; - struct rte_eth_rxconf rxq_conf; - struct rte_eth_txconf txq_conf; - struct rte_eth_conf local_port_conf = port_conf; - - /* Initialise device and RX/TX queues */ - PRINT_INFO("Initialising port %u ...", port); - fflush(stdout); - - ret = rte_eth_dev_info_get(port, &dev_info); - if (ret != 0) - FATAL_ERROR("Error during getting device (port %u) info: %s\n", - port, strerror(-ret)); - - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - ret = rte_eth_dev_configure(port, 1, 1, &local_port_conf); - if (ret < 0) - FATAL_ERROR("Could not configure port%u (%d)", port, ret); - - ret = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd); - if (ret < 0) - FATAL_ERROR("Could not adjust number of descriptors for port%u (%d)", - port, ret); - - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = local_port_conf.rxmode.offloads; - ret = rte_eth_rx_queue_setup(port, 0, nb_rxd, - rte_eth_dev_socket_id(port), - &rxq_conf, - pktmbuf_pool); - if (ret < 0) - FATAL_ERROR("Could not setup up RX queue for port%u (%d)", - port, ret); - - txq_conf = dev_info.default_txconf; - txq_conf.offloads = local_port_conf.txmode.offloads; - ret = rte_eth_tx_queue_setup(port, 0, nb_txd, - rte_eth_dev_socket_id(port), - &txq_conf); - if (ret < 0) - FATAL_ERROR("Could not setup up TX queue for port%u (%d)", - port, ret); - - ret = rte_eth_dev_start(port); - if (ret < 0) - FATAL_ERROR("Could not start port%u (%d)", port, ret); - - ret = rte_eth_promiscuous_enable(port); - if (ret != 0) - FATAL_ERROR("Could not enable promiscuous mode for port%u (%s)", - port, rte_strerror(-ret)); -} - -/* Check the link status of all ports in up to 9s, and print them finally */ -static void -check_all_ports_link_status(uint32_t port_mask) -{ -#define CHECK_INTERVAL 100 /* 100ms */ -#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ - uint16_t portid; - uint8_t count, all_ports_up, print_flag = 0; - struct rte_eth_link link; - int ret; - - printf("\nChecking link status"); - fflush(stdout); - for (count = 0; count <= MAX_CHECK_TIME; count++) { - all_ports_up = 1; - RTE_ETH_FOREACH_DEV(portid) { - if ((port_mask & (1 << portid)) == 0) - continue; - memset(&link, 0, sizeof(link)); - ret = rte_eth_link_get_nowait(portid, &link); - if (ret < 0) { - all_ports_up = 0; - if (print_flag == 1) - printf("Port %u link get failed: %s\n", - portid, rte_strerror(-ret)); - continue; - } - /* print link status if flag set */ - if (print_flag == 1) { - if (link.link_status) - printf( - "Port%d Link Up. Speed %u Mbps - %s\n", - portid, link.link_speed, - (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? - ("full-duplex") : ("half-duplex\n")); - else - printf("Port %d Link Down\n", portid); - continue; - } - /* clear all_ports_up flag if any link down */ - if (link.link_status == ETH_LINK_DOWN) { - all_ports_up = 0; - break; - } - } - /* after finally printing all link status, get out */ - if (print_flag == 1) - break; - - if (all_ports_up == 0) { - printf("."); - fflush(stdout); - rte_delay_ms(CHECK_INTERVAL); - } - - /* set the print_flag if all ports up or timeout */ - if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { - print_flag = 1; - printf("done\n"); - } - } -} - -/* Initialise ports/queues etc. and start main loop on each core */ -int -main(int argc, char** argv) -{ - int ret; - unsigned i,high_port; - uint16_t nb_sys_ports, port; - - /* Associate signal_hanlder function with USR signals */ - signal(SIGUSR1, signal_handler); - signal(SIGUSR2, signal_handler); - - /* Initialise EAL */ - ret = rte_eal_init(argc, argv); - if (ret < 0) - FATAL_ERROR("Could not initialise EAL (%d)", ret); - argc -= ret; - argv += ret; - - /* Parse application arguments (after the EAL ones) */ - parse_args(argc, argv); - - /* Create the mbuf pool */ - pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, - MEMPOOL_CACHE_SZ, 0, MBUF_DATA_SZ, rte_socket_id()); - if (pktmbuf_pool == NULL) { - FATAL_ERROR("Could not initialise mbuf pool"); - return -1; - } - - /* Get number of ports found in scan */ - nb_sys_ports = rte_eth_dev_count_avail(); - if (nb_sys_ports == 0) - FATAL_ERROR("No supported Ethernet device found"); - /* Find highest port set in portmask */ - for (high_port = (sizeof(ports_mask) * 8) - 1; - (high_port != 0) && !(ports_mask & (1 << high_port)); - high_port--) - ; /* empty body */ - if (high_port > nb_sys_ports) - FATAL_ERROR("Port mask requires more ports than available"); - - /* Initialise each port */ - RTE_ETH_FOREACH_DEV(port) { - /* Skip ports that are not enabled */ - if ((ports_mask & (1 << port)) == 0) { - continue; - } - init_port(port); - } - check_all_ports_link_status(ports_mask); - - /* Launch per-lcore function on every lcore */ - rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER); - RTE_LCORE_FOREACH_SLAVE(i) { - if (rte_eal_wait_lcore(i) < 0) - return -1; - } - - return 0; -} diff --git a/examples/exception_path/meson.build b/examples/exception_path/meson.build deleted file mode 100644 index c34e11e36..000000000 --- a/examples/exception_path/meson.build +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2017 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' - -sources = files( - 'main.c' -) diff --git a/examples/meson.build b/examples/meson.build index a046b74ad..4663d9dea 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -13,7 +13,7 @@ all_examples = [ 'bbdev_app', 'bond', 'bpf', 'cmdline', 'distributor', 'ethtool', - 'eventdev_pipeline', 'exception_path', + 'eventdev_pipeline', 'fips_validation', 'flow_classify', 'flow_filtering', 'helloworld', 'ip_fragmentation', 'ip_pipeline', -- 2.17.1 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v3 3/6] examples/l3fwd-vf: remove example 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 " Ciara Power 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 1/6] doc: remove unnecessary sample app guide table Ciara Power 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 2/6] examples/exception_path: remove example Ciara Power @ 2019-10-25 9:56 ` Ciara Power 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 4/6] examples/quota-watermark: " Ciara Power ` (3 subsequent siblings) 6 siblings, 0 replies; 27+ messages in thread From: Ciara Power @ 2019-10-25 9:56 UTC (permalink / raw) To: dev; +Cc: techboard, Bruce Richardson From: Bruce Richardson <bruce.richardson@intel.com> The main l3fwd app should work with both PF and VF devices, so remove the VF-only l3fwd example. Signed-off-by: Bruce Richardson <bruce.richardson@intel.com> Acked-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com> --- v3: Document removed application in release notes. --- MAINTAINERS | 3 - doc/guides/rel_notes/release_19_11.rst | 2 + doc/guides/sample_app_ug/index.rst | 1 - .../sample_app_ug/l3_forward_virtual.rst | 98 -- examples/Makefile | 1 - examples/l3fwd-vf/Makefile | 62 - examples/l3fwd-vf/main.c | 1077 ----------------- examples/l3fwd-vf/meson.build | 12 - examples/meson.build | 2 +- 9 files changed, 3 insertions(+), 1255 deletions(-) delete mode 100644 doc/guides/sample_app_ug/l3_forward_virtual.rst delete mode 100644 examples/l3fwd-vf/Makefile delete mode 100644 examples/l3fwd-vf/main.c delete mode 100644 examples/l3fwd-vf/meson.build diff --git a/MAINTAINERS b/MAINTAINERS index e8f3cd787..aa9cfd9fc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1485,9 +1485,6 @@ F: examples/l2fwd-cat/ F: examples/l3fwd/ F: doc/guides/sample_app_ug/l3_forward.rst -F: examples/l3fwd-vf/ -F: doc/guides/sample_app_ug/l3_forward_virtual.rst - F: examples/link_status_interrupt/ F: doc/guides/sample_app_ug/link_status_intr.rst diff --git a/doc/guides/rel_notes/release_19_11.rst b/doc/guides/rel_notes/release_19_11.rst index a313d75bf..52bb8ba08 100644 --- a/doc/guides/rel_notes/release_19_11.rst +++ b/doc/guides/rel_notes/release_19_11.rst @@ -187,6 +187,8 @@ Removed Items * Exception Path + * L3 Forwarding in a Virtualization Environment + API Changes ----------- diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst index 076346a60..d212f81fe 100644 --- a/doc/guides/sample_app_ug/index.rst +++ b/doc/guides/sample_app_ug/index.rst @@ -29,7 +29,6 @@ Sample Applications User Guides l3_forward l3_forward_power_man l3_forward_access_ctrl - l3_forward_virtual link_status_intr load_balancer server_node_efd diff --git a/doc/guides/sample_app_ug/l3_forward_virtual.rst b/doc/guides/sample_app_ug/l3_forward_virtual.rst deleted file mode 100644 index 21eab8da3..000000000 --- a/doc/guides/sample_app_ug/l3_forward_virtual.rst +++ /dev/null @@ -1,98 +0,0 @@ -.. SPDX-License-Identifier: BSD-3-Clause - Copyright(c) 2010-2014 Intel Corporation. - -L3 Forwarding in a Virtualization Environment Sample Application -================================================================ - -The L3 Forwarding in a Virtualization Environment sample application is a simple example of packet processing using the DPDK. -The application performs L3 forwarding that takes advantage of Single Root I/O Virtualization (SR-IOV) features -in a virtualized environment. - -Overview --------- - -The application demonstrates the use of the hash and LPM libraries in the DPDK to implement packet forwarding. -The initialization and run-time paths are very similar to those of the :doc:`l3_forward`. -The forwarding decision is taken based on information read from the input packet. - -The lookup method is either hash-based or LPM-based and is selected at compile time. -When the selected lookup method is hash-based, a hash object is used to emulate the flow classification stage. -The hash object is used in correlation with the flow table to map each input packet to its flow at runtime. - -The hash lookup key is represented by the DiffServ 5-tuple composed of the following fields read from the input packet: -Source IP Address, Destination IP Address, Protocol, Source Port and Destination Port. -The ID of the output interface for the input packet is read from the identified flow table entry. -The set of flows used by the application is statically configured and loaded into the hash at initialization time. -When the selected lookup method is LPM based, an LPM object is used to emulate the forwarding stage for IPv4 packets. -The LPM object is used as the routing table to identify the next hop for each input packet at runtime. - -The LPM lookup key is represented by the Destination IP Address field read from the input packet. -The ID of the output interface for the input packet is the next hop returned by the LPM lookup. -The set of LPM rules used by the application is statically configured and loaded into the LPM object at the initialization time. - -.. note:: - - Please refer to :ref:`l2_fwd_vf_setup` for virtualized test case setup. - -Compiling the Application -------------------------- - -To compile the sample application see :doc:`compiling`. - -The application is located in the ``l3fwd-vf`` sub-directory. - -Running the Application ------------------------ - -The application has a number of command line options: - -.. code-block:: console - - ./build/l3fwd-vf [EAL options] -- -p PORTMASK --config(port,queue,lcore)[,(port,queue,lcore)] [--no-numa] - -where, - -* --p PORTMASK: Hexadecimal bitmask of ports to configure - -* --config (port,queue,lcore)[,(port,queue,lcore]: determines which queues from which ports are mapped to which cores - -* --no-numa: optional, disables numa awareness - -For example, consider a dual processor socket platform with 8 physical cores, where cores 0-7 and 16-23 appear on socket 0, -while cores 8-15 and 24-31 appear on socket 1. - -To enable L3 forwarding between two ports, assuming that both ports are in the same socket, using two cores, cores 1 and 2, -(which are in the same socket too), use the following command: - -.. code-block:: console - - ./build/l3fwd-vf -l 1,2 -n 4 -- -p 0x3 --config="(0,0,1),(1,0,2)" - -In this command: - -* The -l option enables cores 1 and 2 - -* The -p option enables ports 0 and 1 - -* The --config option enables one queue on each port and maps each (port,queue) pair to a specific core. - The following table shows the mapping in this example: - - +----------+-----------+-----------+------------------------------------+ - | **Port** | **Queue** | **lcore** | **Description** | - | | | | | - +==========+===========+===========+====================================+ - | 0 | 0 | 1 | Map queue 0 from port 0 to lcore 1 | - | | | | | - +----------+-----------+-----------+------------------------------------+ - | 1 | 0 | 2 | Map queue 0 from port 1 to lcore 2 | - | | | | | - +----------+-----------+-----------+------------------------------------+ - -Refer to the *DPDK Getting Started Guide* for general information on running applications -and the Environment Abstraction Layer (EAL) options. - -Explanation ------------ - -The operation of this application is similar to that of the basic L3 Forwarding Sample Application. -See :ref:`l3_fwd_explanation` for more information. diff --git a/examples/Makefile b/examples/Makefile index c756497d1..5dd8a72e5 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -46,7 +46,6 @@ endif DIRS-$(CONFIG_RTE_LIBRTE_ACL) += l3fwd-acl ifeq ($(CONFIG_RTE_LIBRTE_LPM)$(CONFIG_RTE_LIBRTE_HASH),yy) DIRS-$(CONFIG_RTE_LIBRTE_POWER) += l3fwd-power -DIRS-y += l3fwd-vf endif DIRS-y += link_status_interrupt DIRS-$(CONFIG_RTE_LIBRTE_LPM) += load_balancer diff --git a/examples/l3fwd-vf/Makefile b/examples/l3fwd-vf/Makefile deleted file mode 100644 index 7b186a23c..000000000 --- a/examples/l3fwd-vf/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2010-2014 Intel Corporation - -# binary name -APP = l3fwd-vf - -# all source are stored in SRCS-y -SRCS-y := main.c - -# Build using pkg-config variables if possible -ifeq ($(shell pkg-config --exists libdpdk && echo 0),0) - -all: shared -.PHONY: shared static -shared: build/$(APP)-shared - ln -sf $(APP)-shared build/$(APP) -static: build/$(APP)-static - ln -sf $(APP)-static build/$(APP) - -PKGCONF=pkg-config --define-prefix - -PC_FILE := $(shell $(PKGCONF) --path libdpdk) -CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) -LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk) -LDFLAGS_STATIC = -Wl,-Bstatic $(shell $(PKGCONF) --static --libs libdpdk) - -build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) - -build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC) - -build: - @mkdir -p $@ - -.PHONY: clean -clean: - rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared - test -d build && rmdir -p build || true - -else # Build using legacy build system - -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 - -CFLAGS += -O3 $(USER_FLAGS) -CFLAGS += $(WERROR_FLAGS) - -# workaround for a gcc bug with noreturn attribute -# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603 -ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y) -CFLAGS_main.o += -Wno-return-type -endif - -include $(RTE_SDK)/mk/rte.extapp.mk -endif diff --git a/examples/l3fwd-vf/main.c b/examples/l3fwd-vf/main.c deleted file mode 100644 index ff6c9e2f1..000000000 --- a/examples/l3fwd-vf/main.c +++ /dev/null @@ -1,1077 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> -#include <signal.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_spinlock.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_udp.h> -#include <rte_string_fns.h> - -#define APP_LOOKUP_EXACT_MATCH 0 -#define APP_LOOKUP_LPM 1 -#define DO_RFC_1812_CHECKS - -//#define APP_LOOKUP_METHOD APP_LOOKUP_EXACT_MATCH -#ifndef APP_LOOKUP_METHOD -#define APP_LOOKUP_METHOD APP_LOOKUP_LPM -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH) -#include <rte_hash.h> -#elif (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) -#include <rte_lpm.h> -#else -#error "APP_LOOKUP_METHOD set to incorrect value" -#endif - -#define RTE_LOGTYPE_L3FWD RTE_LOGTYPE_USER1 - -#define MEMPOOL_CACHE_SIZE 256 - -/* - * This expression is used to calculate the number of mbufs needed depending on user input, taking - * into account memory for rx and tx hardware rings, cache per lcore and mtable per port per lcore. - * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum value of 8192 - */ - -#define NB_MBUF RTE_MAX ( \ - (nb_ports*nb_rx_queue*nb_rxd + \ - nb_ports*nb_lcores*MAX_PKT_BURST + \ - nb_ports*n_tx_queue*nb_txd + \ - nb_lcores*MEMPOOL_CACHE_SIZE), \ - (unsigned)8192) - -#define MAX_PKT_BURST 32 -#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */ - -#define NB_SOCKETS 8 - -#define SOCKET0 0 - -/* Configure how many packets ahead to prefetch, when reading packets */ -#define PREFETCH_OFFSET 3 - -/* - * Configurable number of RX/TX ring descriptors - */ -#define RTE_TEST_RX_DESC_DEFAULT 1024 -#define RTE_TEST_TX_DESC_DEFAULT 1024 -static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; -static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; - -/* ethernet addresses of ports */ -static struct rte_ether_addr ports_eth_addr[RTE_MAX_ETHPORTS]; - -/* mask of enabled ports */ -static uint32_t enabled_port_mask = 0; -static int numa_on = 1; /**< NUMA is enabled by default. */ - -struct mbuf_table { - uint16_t len; - struct rte_mbuf *m_table[MAX_PKT_BURST]; -}; - -struct lcore_rx_queue { - uint16_t port_id; - uint8_t queue_id; -} __rte_cache_aligned; - -#define MAX_RX_QUEUE_PER_LCORE 16 -#define MAX_TX_QUEUE_PER_PORT 1 -#define MAX_RX_QUEUE_PER_PORT 1 - -#define MAX_LCORE_PARAMS 1024 -struct lcore_params { - uint16_t port_id; - uint8_t queue_id; - uint8_t lcore_id; -} __rte_cache_aligned; - -static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS]; -static struct lcore_params lcore_params_array_default[] = { - {0, 0, 2}, - {0, 1, 2}, - {0, 2, 2}, - {1, 0, 2}, - {1, 1, 2}, - {1, 2, 2}, - {2, 0, 2}, - {3, 0, 3}, - {3, 1, 3}, -}; - -static struct lcore_params * lcore_params = lcore_params_array_default; -static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) / - sizeof(lcore_params_array_default[0]); - -static struct rte_eth_conf port_conf = { - .rxmode = { - .mq_mode = ETH_MQ_RX_RSS, - .max_rx_pkt_len = RTE_ETHER_MAX_LEN, - .split_hdr_size = 0, - .offloads = DEV_RX_OFFLOAD_CHECKSUM, - }, - .rx_adv_conf = { - .rss_conf = { - .rss_key = NULL, - .rss_hf = ETH_RSS_IP, - }, - }, - .txmode = { - .mq_mode = ETH_MQ_TX_NONE, - }, -}; - -static struct rte_mempool * pktmbuf_pool[NB_SOCKETS]; - - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH) - -#ifdef RTE_ARCH_X86 -#include <rte_hash_crc.h> -#define DEFAULT_HASH_FUNC rte_hash_crc -#else -#include <rte_jhash.h> -#define DEFAULT_HASH_FUNC rte_jhash -#endif - -struct ipv4_5tuple { - uint32_t ip_dst; - uint32_t ip_src; - uint16_t port_dst; - uint16_t port_src; - uint8_t proto; -} __attribute__((__packed__)); - -struct l3fwd_route { - struct ipv4_5tuple key; - uint8_t if_out; -}; - -static struct l3fwd_route l3fwd_route_array[] = { - {{RTE_IPV4(100,10,0,1), RTE_IPV4(200,10,0,1), 101, 11, IPPROTO_TCP}, 0}, - {{RTE_IPV4(100,20,0,2), RTE_IPV4(200,20,0,2), 102, 12, IPPROTO_TCP}, 1}, - {{RTE_IPV4(100,30,0,3), RTE_IPV4(200,30,0,3), 103, 13, IPPROTO_TCP}, 2}, - {{RTE_IPV4(100,40,0,4), RTE_IPV4(200,40,0,4), 104, 14, IPPROTO_TCP}, 3}, -}; - -typedef struct rte_hash lookup_struct_t; -static lookup_struct_t *l3fwd_lookup_struct[NB_SOCKETS]; - -#define L3FWD_HASH_ENTRIES 1024 -struct rte_hash_parameters l3fwd_hash_params = { - .name = "l3fwd_hash_0", - .entries = L3FWD_HASH_ENTRIES, - .key_len = sizeof(struct ipv4_5tuple), - .hash_func = DEFAULT_HASH_FUNC, - .hash_func_init_val = 0, - .socket_id = SOCKET0, -}; - -#define L3FWD_NUM_ROUTES \ - (sizeof(l3fwd_route_array) / sizeof(l3fwd_route_array[0])) - -static uint8_t l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned; -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) -struct l3fwd_route { - uint32_t ip; - uint8_t depth; - uint8_t if_out; -}; - -static struct l3fwd_route l3fwd_route_array[] = { - {RTE_IPV4(1,1,1,0), 24, 0}, - {RTE_IPV4(2,1,1,0), 24, 1}, - {RTE_IPV4(3,1,1,0), 24, 2}, - {RTE_IPV4(4,1,1,0), 24, 3}, - {RTE_IPV4(5,1,1,0), 24, 4}, - {RTE_IPV4(6,1,1,0), 24, 5}, - {RTE_IPV4(7,1,1,0), 24, 6}, - {RTE_IPV4(8,1,1,0), 24, 7}, -}; - -#define L3FWD_NUM_ROUTES \ - (sizeof(l3fwd_route_array) / sizeof(l3fwd_route_array[0])) - -#define L3FWD_LPM_MAX_RULES 1024 - -typedef struct rte_lpm lookup_struct_t; -static lookup_struct_t *l3fwd_lookup_struct[NB_SOCKETS]; -#endif - -struct lcore_conf { - uint16_t n_rx_queue; - struct lcore_rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE]; - uint16_t tx_queue_id; - struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS]; - lookup_struct_t * lookup_struct; -} __rte_cache_aligned; - -static struct lcore_conf lcore_conf[RTE_MAX_LCORE]; -static rte_spinlock_t spinlock_conf[RTE_MAX_ETHPORTS] = {RTE_SPINLOCK_INITIALIZER}; -/* Send burst of packets on an output interface */ -static inline int -send_burst(struct lcore_conf *qconf, uint16_t n, uint16_t port) -{ - struct rte_mbuf **m_table; - int ret; - uint16_t queueid; - - queueid = qconf->tx_queue_id; - m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table; - - rte_spinlock_lock(&spinlock_conf[port]); - ret = rte_eth_tx_burst(port, queueid, m_table, n); - rte_spinlock_unlock(&spinlock_conf[port]); - - if (unlikely(ret < n)) { - do { - rte_pktmbuf_free(m_table[ret]); - } while (++ret < n); - } - - return 0; -} - -/* Enqueue a single packet, and send burst if queue is filled */ -static inline int -send_single_packet(struct rte_mbuf *m, uint16_t port) -{ - uint32_t lcore_id; - uint16_t len; - struct lcore_conf *qconf; - - lcore_id = rte_lcore_id(); - - qconf = &lcore_conf[lcore_id]; - len = qconf->tx_mbufs[port].len; - qconf->tx_mbufs[port].m_table[len] = m; - len++; - - /* enough pkts to be sent */ - if (unlikely(len == MAX_PKT_BURST)) { - send_burst(qconf, MAX_PKT_BURST, port); - len = 0; - } - - qconf->tx_mbufs[port].len = len; - return 0; -} - -#ifdef DO_RFC_1812_CHECKS -static inline int -is_valid_ipv4_pkt(struct rte_ipv4_hdr *pkt, uint32_t link_len) -{ - /* From http://www.rfc-editor.org/rfc/rfc1812.txt section 5.2.2 */ - /* - * 1. The packet length reported by the Link Layer must be large - * enough to hold the minimum length legal IP datagram (20 bytes). - */ - if (link_len < sizeof(struct rte_ipv4_hdr)) - return -1; - - /* 2. The IP checksum must be correct. */ - /* this is checked in H/W */ - - /* - * 3. The IP version number must be 4. If the version number is not 4 - * then the packet may be another version of IP, such as IPng or - * ST-II. - */ - if (((pkt->version_ihl) >> 4) != 4) - return -3; - /* - * 4. The IP header length field must be large enough to hold the - * minimum length legal IP datagram (20 bytes = 5 words). - */ - if ((pkt->version_ihl & 0xf) < 5) - return -4; - - /* - * 5. The IP total length field must be large enough to hold the IP - * datagram header, whose length is specified in the IP header length - * field. - */ - if (rte_cpu_to_be_16(pkt->total_length) < sizeof(struct rte_ipv4_hdr)) - return -5; - - return 0; -} -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH) -static void -print_key(struct ipv4_5tuple key) -{ - printf("IP dst = %08x, IP src = %08x, port dst = %d, port src = %d, proto = %d\n", - (unsigned)key.ip_dst, (unsigned)key.ip_src, key.port_dst, key.port_src, key.proto); -} - -static inline uint16_t -get_dst_port(struct rte_ipv4_hdr *ipv4_hdr, uint16_t portid, - lookup_struct_t *l3fwd_lookup_struct) -{ - struct ipv4_5tuple key; - struct rte_tcp_hdr *tcp; - struct rte_udp_hdr *udp; - int ret = 0; - - key.ip_dst = rte_be_to_cpu_32(ipv4_hdr->dst_addr); - key.ip_src = rte_be_to_cpu_32(ipv4_hdr->src_addr); - key.proto = ipv4_hdr->next_proto_id; - - switch (ipv4_hdr->next_proto_id) { - case IPPROTO_TCP: - tcp = (struct rte_tcp_hdr *)((unsigned char *) ipv4_hdr + - sizeof(struct rte_ipv4_hdr)); - key.port_dst = rte_be_to_cpu_16(tcp->dst_port); - key.port_src = rte_be_to_cpu_16(tcp->src_port); - break; - - case IPPROTO_UDP: - udp = (struct rte_udp_hdr *)((unsigned char *) ipv4_hdr + - sizeof(struct rte_ipv4_hdr)); - key.port_dst = rte_be_to_cpu_16(udp->dst_port); - key.port_src = rte_be_to_cpu_16(udp->src_port); - break; - - default: - key.port_dst = 0; - key.port_src = 0; - } - - /* Find destination port */ - ret = rte_hash_lookup(l3fwd_lookup_struct, (const void *)&key); - return ((ret < 0) ? portid : l3fwd_out_if[ret]); -} -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) -static inline uint32_t -get_dst_port(struct rte_ipv4_hdr *ipv4_hdr, uint16_t portid, - lookup_struct_t *l3fwd_lookup_struct) -{ - uint32_t next_hop; - - return ((rte_lpm_lookup(l3fwd_lookup_struct, - rte_be_to_cpu_32(ipv4_hdr->dst_addr), &next_hop) == 0) ? - next_hop : portid); -} -#endif - -static inline void -l3fwd_simple_forward(struct rte_mbuf *m, uint16_t portid, - lookup_struct_t *l3fwd_lookup_struct) -{ - struct rte_ether_hdr *eth_hdr; - struct rte_ipv4_hdr *ipv4_hdr; - void *tmp; - uint16_t dst_port; - - eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *); - - ipv4_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *, - sizeof(struct rte_ether_hdr)); - -#ifdef DO_RFC_1812_CHECKS - /* Check to make sure the packet is valid (RFC1812) */ - if (is_valid_ipv4_pkt(ipv4_hdr, m->pkt_len) < 0) { - rte_pktmbuf_free(m); - return; - } -#endif - - dst_port = get_dst_port(ipv4_hdr, portid, l3fwd_lookup_struct); - if (dst_port >= RTE_MAX_ETHPORTS || (enabled_port_mask & 1 << dst_port) == 0) - dst_port = portid; - - /* 02:00:00:00:00:xx */ - tmp = ð_hdr->d_addr.addr_bytes[0]; - *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40); - -#ifdef DO_RFC_1812_CHECKS - /* Update time to live and header checksum */ - --(ipv4_hdr->time_to_live); - ++(ipv4_hdr->hdr_checksum); -#endif - - /* src addr */ - rte_ether_addr_copy(&ports_eth_addr[dst_port], ð_hdr->s_addr); - - send_single_packet(m, dst_port); - -} - -/* main processing loop */ -static int -main_loop(__attribute__((unused)) void *dummy) -{ - struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; - unsigned lcore_id; - uint64_t prev_tsc, diff_tsc, cur_tsc; - int i, j, nb_rx; - uint8_t queueid; - uint16_t portid; - struct lcore_conf *qconf; - const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US; - - prev_tsc = 0; - - lcore_id = rte_lcore_id(); - qconf = &lcore_conf[lcore_id]; - - if (qconf->n_rx_queue == 0) { - RTE_LOG(INFO, L3FWD, "lcore %u has nothing to do\n", lcore_id); - return 0; - } - - RTE_LOG(INFO, L3FWD, "entering main loop on lcore %u\n", lcore_id); - - for (i = 0; i < qconf->n_rx_queue; i++) { - - portid = qconf->rx_queue_list[i].port_id; - queueid = qconf->rx_queue_list[i].queue_id; - RTE_LOG(INFO, L3FWD, " --lcoreid=%u portid=%u rxqueueid=%hhu\n", - lcore_id, portid, queueid); - } - - while (1) { - - cur_tsc = rte_rdtsc(); - - /* - * TX burst queue drain - */ - diff_tsc = cur_tsc - prev_tsc; - if (unlikely(diff_tsc > drain_tsc)) { - - /* - * This could be optimized (use queueid instead of - * portid), but it is not called so often - */ - for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { - if (qconf->tx_mbufs[portid].len == 0) - continue; - send_burst(&lcore_conf[lcore_id], - qconf->tx_mbufs[portid].len, - portid); - qconf->tx_mbufs[portid].len = 0; - } - - prev_tsc = cur_tsc; - } - - /* - * Read packet from RX queues - */ - for (i = 0; i < qconf->n_rx_queue; ++i) { - - portid = qconf->rx_queue_list[i].port_id; - queueid = qconf->rx_queue_list[i].queue_id; - nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst, MAX_PKT_BURST); - - /* Prefetch first packets */ - for (j = 0; j < PREFETCH_OFFSET && j < nb_rx; j++) { - rte_prefetch0(rte_pktmbuf_mtod( - pkts_burst[j], void *)); - } - - /* Prefetch and forward already prefetched packets */ - for (j = 0; j < (nb_rx - PREFETCH_OFFSET); j++) { - rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[ - j + PREFETCH_OFFSET], void *)); - l3fwd_simple_forward(pkts_burst[j], portid, qconf->lookup_struct); - } - - /* Forward remaining prefetched packets */ - for (; j < nb_rx; j++) { - l3fwd_simple_forward(pkts_burst[j], portid, qconf->lookup_struct); - } - } - } -} - -static int -check_lcore_params(void) -{ - uint8_t queue, lcore; - uint16_t i; - int socketid; - - for (i = 0; i < nb_lcore_params; ++i) { - queue = lcore_params[i].queue_id; - if (queue >= MAX_RX_QUEUE_PER_PORT) { - printf("invalid queue number: %hhu\n", queue); - return -1; - } - lcore = lcore_params[i].lcore_id; - if (!rte_lcore_is_enabled(lcore)) { - printf("error: lcore %hhu is not enabled in lcore mask\n", lcore); - return -1; - } - if ((socketid = rte_lcore_to_socket_id(lcore) != 0) && - (numa_on == 0)) { - printf("warning: lcore %hhu is on socket %d with numa off \n", - lcore, socketid); - } - } - return 0; -} - -static int -check_port_config(void) -{ - unsigned portid; - uint16_t i; - - for (i = 0; i < nb_lcore_params; ++i) { - portid = lcore_params[i].port_id; - if ((enabled_port_mask & (1 << portid)) == 0) { - printf("port %u is not enabled in port mask\n", portid); - return -1; - } - if (!rte_eth_dev_is_valid_port(portid)) { - printf("port %u is not present on the board\n", portid); - return -1; - } - } - return 0; -} - -static uint8_t -get_port_n_rx_queues(const uint16_t port) -{ - int queue = -1; - uint16_t i; - - for (i = 0; i < nb_lcore_params; ++i) { - if (lcore_params[i].port_id == port && lcore_params[i].queue_id > queue) - queue = lcore_params[i].queue_id; - } - return (uint8_t)(++queue); -} - -static int -init_lcore_rx_queues(void) -{ - uint16_t i, nb_rx_queue; - uint8_t lcore; - - for (i = 0; i < nb_lcore_params; ++i) { - lcore = lcore_params[i].lcore_id; - nb_rx_queue = lcore_conf[lcore].n_rx_queue; - if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) { - printf("error: too many queues (%u) for lcore: %u\n", - (unsigned)nb_rx_queue + 1, (unsigned)lcore); - return -1; - } else { - lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id = - lcore_params[i].port_id; - lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id = - lcore_params[i].queue_id; - lcore_conf[lcore].n_rx_queue++; - } - } - return 0; -} - -/* display usage */ -static void -print_usage(const char *prgname) -{ - printf ("%s [EAL options] -- -p PORTMASK" - " [--config (port,queue,lcore)[,(port,queue,lcore]]\n" - " -p PORTMASK: hexadecimal bitmask of ports to configure\n" - " --config (port,queue,lcore): rx queues configuration\n" - " --no-numa: optional, disable numa awareness\n", - prgname); -} - -/* Custom handling of signals to handle process terminal */ -static void -signal_handler(int signum) -{ - uint16_t portid; - - /* When we receive a SIGINT signal */ - if (signum == SIGINT) { - RTE_ETH_FOREACH_DEV(portid) { - /* skip ports that are not enabled */ - if ((enabled_port_mask & (1 << portid)) == 0) - continue; - rte_eth_dev_close(portid); - } - } - rte_exit(EXIT_SUCCESS, "\n User forced exit\n"); -} -static int -parse_portmask(const char *portmask) -{ - char *end = NULL; - unsigned long pm; - - /* parse hexadecimal string */ - pm = strtoul(portmask, &end, 16); - if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) - return -1; - - if (pm == 0) - return -1; - - return pm; -} - -static int -parse_config(const char *q_arg) -{ - char s[256]; - const char *p, *p0 = q_arg; - char *end; - enum fieldnames { - FLD_PORT = 0, - FLD_QUEUE, - FLD_LCORE, - _NUM_FLD - }; - unsigned long int_fld[_NUM_FLD]; - char *str_fld[_NUM_FLD]; - int i; - unsigned size; - - nb_lcore_params = 0; - - while ((p = strchr(p0,'(')) != NULL) { - ++p; - if((p0 = strchr(p,')')) == NULL) - return -1; - - size = p0 - p; - if(size >= sizeof(s)) - return -1; - - snprintf(s, sizeof(s), "%.*s", size, p); - if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != _NUM_FLD) - return -1; - for (i = 0; i < _NUM_FLD; i++){ - errno = 0; - int_fld[i] = strtoul(str_fld[i], &end, 0); - if (errno != 0 || end == str_fld[i] || int_fld[i] > 255) - return -1; - } - if (nb_lcore_params >= MAX_LCORE_PARAMS) { - printf("exceeded max number of lcore params: %hu\n", - nb_lcore_params); - return -1; - } - lcore_params_array[nb_lcore_params].port_id = int_fld[FLD_PORT]; - lcore_params_array[nb_lcore_params].queue_id = (uint8_t)int_fld[FLD_QUEUE]; - lcore_params_array[nb_lcore_params].lcore_id = (uint8_t)int_fld[FLD_LCORE]; - ++nb_lcore_params; - } - lcore_params = lcore_params_array; - return 0; -} - -/* Parse the argument given in the command line of the application */ -static int -parse_args(int argc, char **argv) -{ - int opt, ret; - char **argvopt; - int option_index; - char *prgname = argv[0]; - static struct option lgopts[] = { - {"config", 1, 0, 0}, - {"no-numa", 0, 0, 0}, - {NULL, 0, 0, 0} - }; - - argvopt = argv; - - while ((opt = getopt_long(argc, argvopt, "p:", - lgopts, &option_index)) != EOF) { - - switch (opt) { - /* portmask */ - case 'p': - enabled_port_mask = parse_portmask(optarg); - if (enabled_port_mask == 0) { - printf("invalid portmask\n"); - print_usage(prgname); - return -1; - } - break; - - /* long options */ - case 0: - if (!strcmp(lgopts[option_index].name, "config")) { - ret = parse_config(optarg); - if (ret) { - printf("invalid config\n"); - print_usage(prgname); - return -1; - } - } - - if (!strcmp(lgopts[option_index].name, "no-numa")) { - printf("numa is disabled \n"); - numa_on = 0; - } - break; - - default: - print_usage(prgname); - return -1; - } - } - - if (optind >= 0) - argv[optind-1] = prgname; - - ret = optind-1; - optind = 1; /* reset getopt lib */ - return ret; -} - -static void -print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr) -{ - char buf[RTE_ETHER_ADDR_FMT_SIZE]; - rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr); - printf("%s%s", name, buf); -} - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_EXACT_MATCH) -static void -setup_hash(int socketid) -{ - unsigned i; - int ret; - char s[64]; - - /* create hashes */ - snprintf(s, sizeof(s), "l3fwd_hash_%d", socketid); - l3fwd_hash_params.name = s; - l3fwd_hash_params.socket_id = socketid; - l3fwd_lookup_struct[socketid] = rte_hash_create(&l3fwd_hash_params); - if (l3fwd_lookup_struct[socketid] == NULL) - rte_exit(EXIT_FAILURE, "Unable to create the l3fwd hash on " - "socket %d\n", socketid); - - /* populate the hash */ - for (i = 0; i < L3FWD_NUM_ROUTES; i++) { - ret = rte_hash_add_key (l3fwd_lookup_struct[socketid], - (void *) &l3fwd_route_array[i].key); - if (ret < 0) { - rte_exit(EXIT_FAILURE, "Unable to add entry %u to the" - "l3fwd hash on socket %d\n", i, socketid); - } - l3fwd_out_if[ret] = l3fwd_route_array[i].if_out; - printf("Hash: Adding key\n"); - print_key(l3fwd_route_array[i].key); - } -} -#endif - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) -static void -setup_lpm(int socketid) -{ - unsigned i; - int ret; - char s[64]; - - struct rte_lpm_config lpm_ipv4_config; - - lpm_ipv4_config.max_rules = L3FWD_LPM_MAX_RULES; - lpm_ipv4_config.number_tbl8s = 256; - lpm_ipv4_config.flags = 0; - - /* create the LPM table */ - snprintf(s, sizeof(s), "L3FWD_LPM_%d", socketid); - l3fwd_lookup_struct[socketid] = - rte_lpm_create(s, socketid, &lpm_ipv4_config); - if (l3fwd_lookup_struct[socketid] == NULL) - rte_exit(EXIT_FAILURE, "Unable to create the l3fwd LPM table" - " on socket %d\n", socketid); - - /* populate the LPM table */ - for (i = 0; i < L3FWD_NUM_ROUTES; i++) { - ret = rte_lpm_add(l3fwd_lookup_struct[socketid], - l3fwd_route_array[i].ip, - l3fwd_route_array[i].depth, - l3fwd_route_array[i].if_out); - - if (ret < 0) { - rte_exit(EXIT_FAILURE, "Unable to add entry %u to the " - "l3fwd LPM table on socket %d\n", - i, socketid); - } - - printf("LPM: Adding route 0x%08x / %d (%d)\n", - (unsigned)l3fwd_route_array[i].ip, - l3fwd_route_array[i].depth, - l3fwd_route_array[i].if_out); - } -} -#endif - -static int -init_mem(unsigned nb_mbuf) -{ - struct lcore_conf *qconf; - int socketid; - unsigned lcore_id; - char s[64]; - - for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { - if (rte_lcore_is_enabled(lcore_id) == 0) - continue; - - if (numa_on) - socketid = rte_lcore_to_socket_id(lcore_id); - else - socketid = 0; - - if (socketid >= NB_SOCKETS) { - rte_exit(EXIT_FAILURE, "Socket %d of lcore %u is out of range %d\n", - socketid, lcore_id, NB_SOCKETS); - } - if (pktmbuf_pool[socketid] == NULL) { - snprintf(s, sizeof(s), "mbuf_pool_%d", socketid); - pktmbuf_pool[socketid] = rte_pktmbuf_pool_create(s, - nb_mbuf, MEMPOOL_CACHE_SIZE, 0, - RTE_MBUF_DEFAULT_BUF_SIZE, socketid); - if (pktmbuf_pool[socketid] == NULL) - rte_exit(EXIT_FAILURE, "Cannot init mbuf pool on socket %d\n", socketid); - else - printf("Allocated mbuf pool on socket %d\n", socketid); - -#if (APP_LOOKUP_METHOD == APP_LOOKUP_LPM) - setup_lpm(socketid); -#else - setup_hash(socketid); -#endif - } - qconf = &lcore_conf[lcore_id]; - qconf->lookup_struct = l3fwd_lookup_struct[socketid]; - } - return 0; -} - -int -main(int argc, char **argv) -{ - struct lcore_conf *qconf; - struct rte_eth_dev_info dev_info; - struct rte_eth_txconf *txconf; - int ret; - unsigned nb_ports; - uint16_t queueid, portid; - unsigned lcore_id; - uint32_t nb_lcores; - uint16_t n_tx_queue; - uint8_t nb_rx_queue, queue, socketid; - - signal(SIGINT, signal_handler); - /* init EAL */ - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n"); - argc -= ret; - argv += ret; - - /* parse application arguments (after the EAL ones) */ - ret = parse_args(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid L3FWD-VF parameters\n"); - - if (check_lcore_params() < 0) - rte_exit(EXIT_FAILURE, "check_lcore_params failed\n"); - - ret = init_lcore_rx_queues(); - if (ret < 0) - rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n"); - - nb_ports = rte_eth_dev_count_avail(); - - if (check_port_config() < 0) - rte_exit(EXIT_FAILURE, "check_port_config failed\n"); - - nb_lcores = rte_lcore_count(); - - /* initialize all ports */ - RTE_ETH_FOREACH_DEV(portid) { - struct rte_eth_conf local_port_conf = port_conf; - - /* skip ports that are not enabled */ - if ((enabled_port_mask & (1 << portid)) == 0) { - printf("\nSkipping disabled port %d\n", portid); - continue; - } - - /* init port */ - printf("Initializing port %d ... ", portid ); - fflush(stdout); - - /* must always equal(=1) */ - nb_rx_queue = get_port_n_rx_queues(portid); - n_tx_queue = MAX_TX_QUEUE_PER_PORT; - - printf("Creating queues: nb_rxq=%d nb_txq=%u... ", - nb_rx_queue, (unsigned)1 ); - - rte_eth_dev_info_get(portid, &dev_info); - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - - local_port_conf.rx_adv_conf.rss_conf.rss_hf &= - dev_info.flow_type_rss_offloads; - if (local_port_conf.rx_adv_conf.rss_conf.rss_hf != - port_conf.rx_adv_conf.rss_conf.rss_hf) { - printf("Port %u modified RSS hash function based on hardware support," - "requested:%#"PRIx64" configured:%#"PRIx64"\n", - portid, - port_conf.rx_adv_conf.rss_conf.rss_hf, - local_port_conf.rx_adv_conf.rss_conf.rss_hf); - } - - ret = rte_eth_dev_configure(portid, nb_rx_queue, - n_tx_queue, &local_port_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%d\n", - ret, portid); - - ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, - &nb_txd); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Cannot adjust number of descriptors: err=%d, port=%d\n", - ret, portid); - - ret = rte_eth_macaddr_get(portid, &ports_eth_addr[portid]); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Cannot get MAC address: err=%d, port=%d\n", - ret, portid); - - print_ethaddr(" Address:", &ports_eth_addr[portid]); - printf(", "); - - ret = init_mem(NB_MBUF); - if (ret < 0) - rte_exit(EXIT_FAILURE, "init_mem failed\n"); - - /* init one TX queue */ - socketid = (uint8_t)rte_lcore_to_socket_id(rte_get_master_lcore()); - - printf("txq=%d,%d,%d ", portid, 0, socketid); - fflush(stdout); - - txconf = &dev_info.default_txconf; - txconf->offloads = local_port_conf.txmode.offloads; - ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, - socketid, txconf); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: err=%d, " - "port=%d\n", ret, portid); - - printf("\n"); - } - - for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { - struct rte_eth_rxconf rxq_conf; - - if (rte_lcore_is_enabled(lcore_id) == 0) - continue; - qconf = &lcore_conf[lcore_id]; - qconf->tx_queue_id = 0; - - printf("\nInitializing rx queues on lcore %u ... ", lcore_id ); - fflush(stdout); - /* init RX queues */ - for(queue = 0; queue < qconf->n_rx_queue; ++queue) { - portid = qconf->rx_queue_list[queue].port_id; - queueid = qconf->rx_queue_list[queue].queue_id; - - if (numa_on) - socketid = (uint8_t)rte_lcore_to_socket_id(lcore_id); - else - socketid = 0; - - printf("rxq=%d,%d,%d ", portid, queueid, socketid); - fflush(stdout); - - rte_eth_dev_info_get(portid, &dev_info); - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = port_conf.rxmode.offloads; - ret = rte_eth_rx_queue_setup(portid, queueid, nb_rxd, - socketid, &rxq_conf, - pktmbuf_pool[socketid]); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup: err=%d," - "port=%d\n", ret, portid); - } - } - printf("\n"); - - /* start ports */ - RTE_ETH_FOREACH_DEV(portid) { - if ((enabled_port_mask & (1 << portid)) == 0) { - continue; - } - /* Start device */ - ret = rte_eth_dev_start(portid); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, port=%d\n", - ret, portid); - - printf("done: Port %d\n", portid); - - } - - /* launch per-lcore init on every lcore */ - rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER); - RTE_LCORE_FOREACH_SLAVE(lcore_id) { - if (rte_eal_wait_lcore(lcore_id) < 0) - return -1; - } - - return 0; -} diff --git a/examples/l3fwd-vf/meson.build b/examples/l3fwd-vf/meson.build deleted file mode 100644 index 226286e74..000000000 --- a/examples/l3fwd-vf/meson.build +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2017 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' - -deps += ['lpm', 'hash'] -sources = files( - 'main.c' -) diff --git a/examples/meson.build b/examples/meson.build index 4663d9dea..81ac8199a 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -23,7 +23,7 @@ all_examples = [ 'l2fwd-crypto', 'l2fwd-jobstats', 'l2fwd-keepalive', 'l3fwd', 'l3fwd-acl', 'l3fwd-power', - 'l3fwd-vf', 'link_status_interrupt', + 'link_status_interrupt', 'load_balancer', 'multi_process/client_server_mp/mp_client', 'multi_process/client_server_mp/mp_server', -- 2.17.1 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v3 4/6] examples/quota-watermark: remove example 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 " Ciara Power ` (2 preceding siblings ...) 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 3/6] examples/l3fwd-vf: " Ciara Power @ 2019-10-25 9:56 ` Ciara Power 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 5/6] examples/netmap-compat: " Ciara Power ` (2 subsequent siblings) 6 siblings, 0 replies; 27+ messages in thread From: Ciara Power @ 2019-10-25 9:56 UTC (permalink / raw) To: dev; +Cc: techboard, Ciara Power Original DPDK rings code had explicit support for a single watermark per-ring, but more recent releases of DPDK had a more general mechanism where each enqueue or dequeue call could return the remaining elements/free-slots in the ring. Therefore, this example is not as relevant as before and can be removed. Signed-off-by: Ciara Power <ciara.power@intel.com> Acked-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com> --- v3: Document removed application in release notes. --- MAINTAINERS | 3 - doc/guides/rel_notes/release_19_11.rst | 2 + doc/guides/sample_app_ug/index.rst | 1 - doc/guides/sample_app_ug/quota_watermark.rst | 465 ------------------- examples/Makefile | 1 - examples/meson.build | 2 +- examples/quota_watermark/Makefile | 16 - examples/quota_watermark/include/conf.h | 19 - examples/quota_watermark/meson.build | 10 - examples/quota_watermark/qw/Makefile | 22 - examples/quota_watermark/qw/args.c | 78 ---- examples/quota_watermark/qw/args.h | 12 - examples/quota_watermark/qw/init.c | 168 ------- examples/quota_watermark/qw/init.h | 14 - examples/quota_watermark/qw/main.c | 373 --------------- examples/quota_watermark/qw/main.h | 31 -- examples/quota_watermark/qwctl/Makefile | 22 - examples/quota_watermark/qwctl/commands.c | 196 -------- examples/quota_watermark/qwctl/commands.h | 12 - examples/quota_watermark/qwctl/qwctl.c | 67 --- examples/quota_watermark/qwctl/qwctl.h | 12 - 21 files changed, 3 insertions(+), 1523 deletions(-) delete mode 100644 doc/guides/sample_app_ug/quota_watermark.rst delete mode 100644 examples/quota_watermark/Makefile delete mode 100644 examples/quota_watermark/include/conf.h delete mode 100644 examples/quota_watermark/meson.build delete mode 100644 examples/quota_watermark/qw/Makefile delete mode 100644 examples/quota_watermark/qw/args.c delete mode 100644 examples/quota_watermark/qw/args.h delete mode 100644 examples/quota_watermark/qw/init.c delete mode 100644 examples/quota_watermark/qw/init.h delete mode 100644 examples/quota_watermark/qw/main.c delete mode 100644 examples/quota_watermark/qw/main.h delete mode 100644 examples/quota_watermark/qwctl/Makefile delete mode 100644 examples/quota_watermark/qwctl/commands.c delete mode 100644 examples/quota_watermark/qwctl/commands.h delete mode 100644 examples/quota_watermark/qwctl/qwctl.c delete mode 100644 examples/quota_watermark/qwctl/qwctl.h diff --git a/MAINTAINERS b/MAINTAINERS index aa9cfd9fc..85e7b433f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1501,9 +1501,6 @@ F: doc/guides/sample_app_ug/performance_thread.rst F: examples/ptpclient/ -F: examples/quota_watermark/ -F: doc/guides/sample_app_ug/quota_watermark.rst - M: Bruce Richardson <bruce.richardson@intel.com> M: John McNamara <john.mcnamara@intel.com> F: examples/rxtx_callbacks/ diff --git a/doc/guides/rel_notes/release_19_11.rst b/doc/guides/rel_notes/release_19_11.rst index 52bb8ba08..c07763ce9 100644 --- a/doc/guides/rel_notes/release_19_11.rst +++ b/doc/guides/rel_notes/release_19_11.rst @@ -189,6 +189,8 @@ Removed Items * L3 Forwarding in a Virtualization Environment + * Quota and Watermark + API Changes ----------- diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst index d212f81fe..dafe8553f 100644 --- a/doc/guides/sample_app_ug/index.rst +++ b/doc/guides/sample_app_ug/index.rst @@ -36,7 +36,6 @@ Sample Applications User Guides multi_process qos_metering qos_scheduler - quota_watermark timer packet_ordering vmdq_dcb_forwarding diff --git a/doc/guides/sample_app_ug/quota_watermark.rst b/doc/guides/sample_app_ug/quota_watermark.rst deleted file mode 100644 index 125e6fb73..000000000 --- a/doc/guides/sample_app_ug/quota_watermark.rst +++ /dev/null @@ -1,465 +0,0 @@ -.. SPDX-License-Identifier: BSD-3-Clause - Copyright(c) 2010-2017 Intel Corporation. - -Quota and Watermark Sample Application -====================================== - -The Quota and Watermark sample application is a simple example of packet -processing using Data Plane Development Kit (DPDK) that showcases the use -of a quota as the maximum number of packets enqueue/dequeue at a time and -low and high thresholds, or watermarks, to signal low and high ring usage -respectively. - -Additionally, it shows how the thresholds can be used to feedback congestion notifications to data producers by -temporarily stopping processing overloaded rings and sending Ethernet flow control frames. - -This sample application is split in two parts: - -* qw - The core quota and watermark sample application - -* qwctl - A command line tool to alter quota and watermarks while qw is running - -Overview --------- - -The Quota and Watermark sample application performs forwarding for each packet that is received on a given port. -The destination port is the adjacent port from the enabled port mask, that is, -if the first four ports are enabled (port mask 0xf), ports 0 and 1 forward into each other, -and ports 2 and 3 forward into each other. -The MAC addresses of the forwarded Ethernet frames are not affected. - -Internally, packets are pulled from the ports by the master logical core and put on a variable length processing pipeline, -each stage of which being connected by rings, as shown in :numref:`figure_pipeline_overview`. - -.. _figure_pipeline_overview: - -.. figure:: img/pipeline_overview.* - - Pipeline Overview - - -An adjustable quota value controls how many packets are being moved through the pipeline per enqueue and dequeue. -Adjustable threshold values associated with the rings control a back-off mechanism that -tries to prevent the pipeline from being overloaded by: - -* Stopping enqueuing on rings for which the usage has crossed the high watermark threshold - -* Sending Ethernet pause frames - -* Only resuming enqueuing on a ring once its usage goes below a global low watermark threshold - -This mechanism allows congestion notifications to go up the ring pipeline and -eventually lead to an Ethernet flow control frame being send to the source. - -On top of serving as an example of quota and watermark usage, -this application can be used to benchmark ring based processing pipelines performance using a traffic- generator, -as shown in :numref:`figure_ring_pipeline_perf_setup`. - -.. _figure_ring_pipeline_perf_setup: - -.. figure:: img/ring_pipeline_perf_setup.* - - Ring-based Processing Pipeline Performance Setup - -Compiling the Application -------------------------- - -To compile the sample application see :doc:`compiling`. - -The application is located in the ``quota_watermark`` sub-directory. - -Running the Application ------------------------ - -The core application, qw, has to be started first. - -Once it is up and running, one can alter quota and watermarks while it runs using the control application, qwctl. - -Running the Core Application -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The application requires a single command line option: - -.. code-block:: console - - ./qw/build/qw [EAL options] -- -p PORTMASK - -where, - --p PORTMASK: A hexadecimal bitmask of the ports to configure - -To run the application in a linux environment with four logical cores and ports 0 and 2, -issue the following command: - -.. code-block:: console - - ./qw/build/qw -l 0-3 -n 4 -- -p 5 - -Refer to the *DPDK Getting Started Guide* for general information on running applications and -the Environment Abstraction Layer (EAL) options. - -Running the Control Application -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The control application requires a number of command line options: - -.. code-block:: console - - ./qwctl/build/qwctl [EAL options] --proc-type=secondary - -The --proc-type=secondary option is necessary for the EAL to properly initialize the control application to -use the same huge pages as the core application and thus be able to access its rings. - -To run the application in a linux environment on logical core 0, issue the following command: - -.. code-block:: console - - ./qwctl/build/qwctl -l 0 -n 4 --proc-type=secondary - -Refer to the *DPDK Getting Started* Guide for general information on running applications and -the Environment Abstraction Layer (EAL) options. - -qwctl is an interactive command line that let the user change variables in a running instance of qw. -The help command gives a list of available commands: - -.. code-block:: console - - $ qwctl > help - -Code Overview -------------- - -The following sections provide a quick guide to the application's source code. - -Core Application - qw -~~~~~~~~~~~~~~~~~~~~~ - -EAL and Drivers Setup -^^^^^^^^^^^^^^^^^^^^^ - -The EAL arguments are parsed at the beginning of the main() function: - -.. code-block:: c - - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot initialize EAL\n"); - - argc -= ret; - argv += ret; - -Then, a call to init_dpdk(), defined in init.c, is made to initialize the poll mode drivers: - -.. code-block:: c - - void - init_dpdk(void) - { - int ret; - - /* Bind the drivers to usable devices */ - - ret = rte_pci_probe(); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_pci_probe(): error %d\n", ret); - - if (rte_eth_dev_count_avail() < 2) - rte_exit(EXIT_FAILURE, "Not enough Ethernet port available\n"); - } - -To fully understand this code, it is recommended to study the chapters that relate to the *Poll Mode Driver* -in the *DPDK Getting Started Guide* and the *DPDK API Reference*. - -Shared Variables Setup -^^^^^^^^^^^^^^^^^^^^^^ - -The quota and high and low watermark shared variables are put into an rte_memzone using a call to setup_shared_variables(): - -.. code-block:: c - - void - setup_shared_variables(void) - { - const struct rte_memzone *qw_memzone; - - qw_memzone = rte_memzone_reserve(QUOTA_WATERMARK_MEMZONE_NAME, - 3 * sizeof(int), rte_socket_id(), 0); - if (qw_memzone == NULL) - rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno)); - - quota = qw_memzone->addr; - low_watermark = (unsigned int *) qw_memzone->addr + 1; - high_watermark = (unsigned int *) qw_memzone->addr + 2; - } - -These three variables are initialized to a default value in main() and -can be changed while qw is running using the qwctl control program. - -Application Arguments -^^^^^^^^^^^^^^^^^^^^^ - -The qw application only takes one argument: a port mask that specifies which ports should be used by the application. -At least two ports are needed to run the application and there should be an even number of ports given in the port mask. - -The port mask parsing is done in parse_qw_args(), defined in args.c. - -Mbuf Pool Initialization -^^^^^^^^^^^^^^^^^^^^^^^^ - -Once the application's arguments are parsed, an mbuf pool is created. -It contains a set of mbuf objects that are used by the driver and the application to store network packets: - -.. code-block:: c - - /* Create a pool of mbuf to store packets */ - mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", MBUF_PER_POOL, 32, 0, - MBUF_DATA_SIZE, rte_socket_id()); - - if (mbuf_pool == NULL) - rte_panic("%s\n", rte_strerror(rte_errno)); - -The rte_mempool is a generic structure used to handle pools of objects. -In this case, it is necessary to create a pool that will be used by the driver. - -The number of allocated pkt mbufs is MBUF_PER_POOL, with a data room size -of MBUF_DATA_SIZE each. -A per-lcore cache of 32 mbufs is kept. -The memory is allocated in on the master lcore's socket, but it is possible to extend this code to allocate one mbuf pool per socket. - -The rte_pktmbuf_pool_create() function uses the default mbuf pool and mbuf -initializers, respectively rte_pktmbuf_pool_init() and rte_pktmbuf_init(). -An advanced application may want to use the mempool API to create the -mbuf pool with more control. - -Ports Configuration and Pairing -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Each port in the port mask is configured and a corresponding ring is created in the master lcore's array of rings. -This ring is the first in the pipeline and will hold the packets directly coming from the port. - -.. code-block:: c - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) - if (is_bit_set(port_id, portmask)) { - configure_eth_port(port_id); - init_ring(master_lcore_id, port_id); - } - - pair_ports(); - -The configure_eth_port() and init_ring() functions are used to configure a port and a ring respectively and are defined in init.c. -They make use of the DPDK APIs defined in rte_eth.h and rte_ring.h. - -pair_ports() builds the port_pairs[] array so that its key-value pairs are a mapping between reception and transmission ports. -It is defined in init.c. - -Logical Cores Assignment -^^^^^^^^^^^^^^^^^^^^^^^^ - -The application uses the master logical core to poll all the ports for new packets and enqueue them on a ring associated with the port. - -Each logical core except the last runs pipeline_stage() after a ring for each used port is initialized on that core. -pipeline_stage() on core X dequeues packets from core X-1's rings and enqueue them on its own rings. See :numref:`figure_threads_pipelines`. - -.. code-block:: c - - /* Start pipeline_stage() on all the available slave lcore but the last */ - - for (lcore_id = 0 ; lcore_id < last_lcore_id; lcore_id++) { - if (rte_lcore_is_enabled(lcore_id) && lcore_id != master_lcore_id) { - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) - if (is_bit_set(port_id, portmask)) - init_ring(lcore_id, port_id); - - rte_eal_remote_launch(pipeline_stage, NULL, lcore_id); - } - } - -The last available logical core runs send_stage(), -which is the last stage of the pipeline dequeuing packets from the last ring in the pipeline and -sending them out on the destination port setup by pair_ports(). - -.. code-block:: c - - /* Start send_stage() on the last slave core */ - - rte_eal_remote_launch(send_stage, NULL, last_lcore_id); - -Receive, Process and Transmit Packets -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. _figure_threads_pipelines: - -.. figure:: img/threads_pipelines.* - - Threads and Pipelines - - -In the receive_stage() function running on the master logical core, -the main task is to read ingress packets from the RX ports and enqueue them -on the port's corresponding first ring in the pipeline. -This is done using the following code: - -.. code-block:: c - - lcore_id = rte_lcore_id(); - - /* Process each port round robin style */ - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - if (!is_bit_set(port_id, portmask)) - continue; - - ring = rings[lcore_id][port_id]; - - if (ring_state[port_id] != RING_READY) { - if (rte_ring_count(ring) > *low_watermark) - continue; - else - ring_state[port_id] = RING_READY; - } - - /* Enqueue received packets on the RX ring */ - nb_rx_pkts = rte_eth_rx_burst(port_id, 0, pkts, - (uint16_t) *quota); - ret = rte_ring_enqueue_bulk(ring, (void *) pkts, - nb_rx_pkts, &free); - if (RING_SIZE - free > *high_watermark) { - ring_state[port_id] = RING_OVERLOADED; - send_pause_frame(port_id, 1337); - } - - if (ret == 0) { - - /* - * Return mbufs to the pool, - * effectively dropping packets - */ - for (i = 0; i < nb_rx_pkts; i++) - rte_pktmbuf_free(pkts[i]); - } - } - -For each port in the port mask, the corresponding ring's pointer is fetched into ring and that ring's state is checked: - -* If it is in the RING_READY state, \*quota packets are grabbed from the port and put on the ring. - Should this operation make the ring's usage cross its high watermark, - the ring is marked as overloaded and an Ethernet flow control frame is sent to the source. - -* If it is not in the RING_READY state, this port is ignored until the ring's usage crosses the \*low_watermark value. - -The pipeline_stage() function's task is to process and move packets from the preceding pipeline stage. -This thread is running on most of the logical cores to create and arbitrarily long pipeline. - -.. code-block:: c - - lcore_id = rte_lcore_id(); - - previous_lcore_id = get_previous_lcore_id(lcore_id); - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - if (!is_bit_set(port_id, portmask)) - continue; - - tx = rings[lcore_id][port_id]; - rx = rings[previous_lcore_id][port_id]; - - if (ring_state[port_id] != RING_READY) { - if (rte_ring_count(tx) > *low_watermark) - continue; - else - ring_state[port_id] = RING_READY; - } - - /* Dequeue up to quota mbuf from rx */ - nb_dq_pkts = rte_ring_dequeue_burst(rx, pkts, - *quota, NULL); - if (unlikely(nb_dq_pkts < 0)) - continue; - - /* Enqueue them on tx */ - ret = rte_ring_enqueue_bulk(tx, pkts, - nb_dq_pkts, &free); - if (RING_SIZE - free > *high_watermark) - ring_state[port_id] = RING_OVERLOADED; - - if (ret == 0) { - - /* - * Return mbufs to the pool, - * effectively dropping packets - */ - for (i = 0; i < nb_dq_pkts; i++) - rte_pktmbuf_free(pkts[i]); - } - } - -The thread's logic works mostly like receive_stage(), -except that packets are moved from ring to ring instead of port to ring. - -In this example, no actual processing is done on the packets, -but pipeline_stage() is an ideal place to perform any processing required by the application. - -Finally, the send_stage() function's task is to read packets from the last ring in a pipeline and -send them on the destination port defined in the port_pairs[] array. -It is running on the last available logical core only. - -.. code-block:: c - - lcore_id = rte_lcore_id(); - - previous_lcore_id = get_previous_lcore_id(lcore_id); - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - if (!is_bit_set(port_id, portmask)) continue; - - dest_port_id = port_pairs[port_id]; - tx = rings[previous_lcore_id][port_id]; - - if (rte_ring_empty(tx)) continue; - - /* Dequeue packets from tx and send them */ - - nb_dq_pkts = rte_ring_dequeue_burst(tx, (void *) tx_pkts, *quota); - nb_tx_pkts = rte_eth_tx_burst(dest_port_id, 0, tx_pkts, nb_dq_pkts); - } - -For each port in the port mask, up to \*quota packets are pulled from the last ring in its pipeline and -sent on the destination port paired with the current port. - -Control Application - qwctl -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The qwctl application uses the rte_cmdline library to provide the user with an interactive command line that -can be used to modify and inspect parameters in a running qw application. -Those parameters are the global quota and low_watermark value as well as each ring's built-in high watermark. - -Command Definitions -^^^^^^^^^^^^^^^^^^^ - -The available commands are defined in commands.c. - -It is advised to use the cmdline sample application user guide as a reference for everything related to the rte_cmdline library. - -Accessing Shared Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The setup_shared_variables() function retrieves the shared variables quota and -low_watermark from the rte_memzone previously created by qw. - -.. code-block:: c - - static void - setup_shared_variables(void) - { - const struct rte_memzone *qw_memzone; - - qw_memzone = rte_memzone_lookup(QUOTA_WATERMARK_MEMZONE_NAME); - if (qw_memzone == NULL) - rte_exit(EXIT_FAILURE, "Couldn't find memzone\n"); - - quota = qw_memzone->addr; - - low_watermark = (unsigned int *) qw_memzone->addr + 1; - high_watermark = (unsigned int *) qw_memzone->addr + 2; - } diff --git a/examples/Makefile b/examples/Makefile index 5dd8a72e5..02ff86534 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -59,7 +59,6 @@ endif DIRS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ptpclient DIRS-$(CONFIG_RTE_LIBRTE_METER) += qos_meter DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += qos_sched -DIRS-y += quota_watermark DIRS-$(CONFIG_RTE_ETHDEV_RXTX_CALLBACKS) += rxtx_callbacks DIRS-y += service_cores DIRS-y += skeleton diff --git a/examples/meson.build b/examples/meson.build index 81ac8199a..6c26fffb4 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -33,7 +33,7 @@ all_examples = [ 'netmap_compat', 'ntb', 'packet_ordering', 'performance-thread', 'ptpclient', 'qos_meter', 'qos_sched', - 'quota_watermark', 'rxtx_callbacks', + 'rxtx_callbacks', 'server_node_efd', 'service_cores', 'skeleton', 'tep_termination', 'timer', 'vdpa', diff --git a/examples/quota_watermark/Makefile b/examples/quota_watermark/Makefile deleted file mode 100644 index 8ef053198..000000000 --- a/examples/quota_watermark/Makefile +++ /dev/null @@ -1,16 +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 - -DIRS-$(CONFIG_RTE_EXEC_ENV_LINUX) += qw -DIRS-$(CONFIG_RTE_EXEC_ENV_LINUX) += qwctl - -include $(RTE_SDK)/mk/rte.extsubdir.mk diff --git a/examples/quota_watermark/include/conf.h b/examples/quota_watermark/include/conf.h deleted file mode 100644 index 4f29aa64b..000000000 --- a/examples/quota_watermark/include/conf.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _CONF_H_ -#define _CONF_H_ - -#define RING_SIZE 1024 -#define MAX_PKT_QUOTA 64 - -#define RX_DESC_PER_QUEUE 1024 -#define TX_DESC_PER_QUEUE 1024 - -#define MBUF_DATA_SIZE RTE_MBUF_DEFAULT_BUF_SIZE -#define MBUF_PER_POOL 8192 - -#define QUOTA_WATERMARK_MEMZONE_NAME "qw_global_vars" - -#endif /* _CONF_H_ */ diff --git a/examples/quota_watermark/meson.build b/examples/quota_watermark/meson.build deleted file mode 100644 index c370d7476..000000000 --- a/examples/quota_watermark/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/quota_watermark/qw/Makefile b/examples/quota_watermark/qw/Makefile deleted file mode 100644 index 3f10f01c3..000000000 --- a/examples/quota_watermark/qw/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 - -# binary name -APP = qw - -# all source are stored in SRCS-y -SRCS-y := args.c init.c main.c - -CFLAGS += -O3 -DQW_SOFTWARE_FC -CFLAGS += $(WERROR_FLAGS) - -include $(RTE_SDK)/mk/rte.extapp.mk diff --git a/examples/quota_watermark/qw/args.c b/examples/quota_watermark/qw/args.c deleted file mode 100644 index a750ec258..000000000 --- a/examples/quota_watermark/qw/args.c +++ /dev/null @@ -1,78 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include <rte_common.h> -#include <rte_lcore.h> - -#include "args.h" - - -unsigned int portmask = 0; - - -static void -usage(const char *prgname) -{ - fprintf(stderr, "Usage: %s [EAL args] -- -p <portmask>\n" - "-p PORTMASK: hexadecimal bitmask of NIC ports to configure\n", - prgname); -} - -static unsigned long -parse_portmask(const char *portmask_str) -{ - return strtoul(portmask_str, NULL, 16); -} - -static void -check_core_count(void) -{ - if (rte_lcore_count() < 3) - rte_exit(EXIT_FAILURE, - "At least 3 cores need to be passed in the coremask\n"); -} - -static void -check_portmask_value(unsigned int portmask) -{ - unsigned int port_nb = 0; - - port_nb = __builtin_popcount(portmask); - - if (port_nb == 0) - rte_exit(EXIT_FAILURE, - "At least 2 ports need to be passed in the portmask\n"); - - if (port_nb % 2 != 0) - rte_exit(EXIT_FAILURE, - "An even number of ports is required in the portmask\n"); -} - -int -parse_qw_args(int argc, char **argv) -{ - int opt; - - while ((opt = getopt(argc, argv, "h:p:")) != -1) { - switch (opt) { - case 'h': - usage(argv[0]); - break; - case 'p': - portmask = parse_portmask(optarg); - break; - default: - usage(argv[0]); - } - } - - check_core_count(); - check_portmask_value(portmask); - - return 0; -} diff --git a/examples/quota_watermark/qw/args.h b/examples/quota_watermark/qw/args.h deleted file mode 100644 index ab777db01..000000000 --- a/examples/quota_watermark/qw/args.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _ARGS_H_ -#define _ARGS_H_ - -extern unsigned int portmask; - -int parse_qw_args(int argc, char **argv); - -#endif /* _ARGS_H_ */ diff --git a/examples/quota_watermark/qw/init.c b/examples/quota_watermark/qw/init.c deleted file mode 100644 index 5ebcc83ac..000000000 --- a/examples/quota_watermark/qw/init.c +++ /dev/null @@ -1,168 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <fcntl.h> -#include <unistd.h> -#include <sys/mman.h> - -#include <rte_eal.h> - -#include <rte_common.h> -#include <rte_errno.h> -#include <rte_ethdev.h> -#include <rte_memzone.h> -#include <rte_ring.h> -#include <rte_string_fns.h> - -#include "args.h" -#include "init.h" -#include "main.h" -#include "../include/conf.h" - - -static struct rte_eth_conf port_conf = { - .rxmode = { - .split_hdr_size = 0, - }, - .txmode = { - .mq_mode = ETH_DCB_NONE, - }, -}; - -static struct rte_eth_fc_conf fc_conf = { - .mode = RTE_FC_TX_PAUSE, - .high_water = 80 * 510 / 100, - .low_water = 60 * 510 / 100, - .pause_time = 1337, - .send_xon = 0, -}; - - -void configure_eth_port(uint16_t port_id) -{ - int ret; - uint16_t nb_rxd = RX_DESC_PER_QUEUE; - uint16_t nb_txd = TX_DESC_PER_QUEUE; - struct rte_eth_rxconf rxq_conf; - struct rte_eth_txconf txq_conf; - struct rte_eth_dev_info dev_info; - struct rte_eth_conf local_port_conf = port_conf; - - rte_eth_dev_stop(port_id); - - rte_eth_dev_info_get(port_id, &dev_info); - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - ret = rte_eth_dev_configure(port_id, 1, 1, &local_port_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot configure port %u (error %d)\n", - (unsigned int) port_id, ret); - - ret = rte_eth_dev_adjust_nb_rx_tx_desc(port_id, &nb_rxd, &nb_txd); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Cannot adjust number of descriptors for port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Initialize the port's RX queue */ - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = local_port_conf.rxmode.offloads; - ret = rte_eth_rx_queue_setup(port_id, 0, nb_rxd, - rte_eth_dev_socket_id(port_id), - &rxq_conf, - mbuf_pool); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Failed to setup RX queue on port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Initialize the port's TX queue */ - txq_conf = dev_info.default_txconf; - txq_conf.offloads = local_port_conf.txmode.offloads; - ret = rte_eth_tx_queue_setup(port_id, 0, nb_txd, - rte_eth_dev_socket_id(port_id), - &txq_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Failed to setup TX queue on port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Initialize the port's flow control */ - ret = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Failed to setup hardware flow control on port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Start the port */ - ret = rte_eth_dev_start(port_id); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Failed to start port %u (error %d)\n", - (unsigned int) port_id, ret); - - /* Put it in promiscuous mode */ - ret = rte_eth_promiscuous_enable(port_id); - if (ret != 0) - rte_exit(EXIT_FAILURE, - "Failed to enable promiscuous mode for port %u: %s\n", - port_id, rte_strerror(-ret)); -} - -void -init_dpdk(void) -{ - if (rte_eth_dev_count_avail() < 2) - rte_exit(EXIT_FAILURE, "Not enough ethernet port available\n"); -} - -void init_ring(int lcore_id, uint16_t port_id) -{ - struct rte_ring *ring; - char ring_name[RTE_RING_NAMESIZE]; - - snprintf(ring_name, RTE_RING_NAMESIZE, - "core%d_port%d", lcore_id, port_id); - ring = rte_ring_create(ring_name, RING_SIZE, rte_socket_id(), - RING_F_SP_ENQ | RING_F_SC_DEQ); - - if (ring == NULL) - rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno)); - - *high_watermark = 80 * RING_SIZE / 100; - - rings[lcore_id][port_id] = ring; -} - -void -pair_ports(void) -{ - uint16_t i, j; - - /* Pair ports with their "closest neighbour" in the portmask */ - for (i = 0; i < RTE_MAX_ETHPORTS; i++) - if (is_bit_set(i, portmask)) - for (j = i + 1; j < RTE_MAX_ETHPORTS; j++) - if (is_bit_set(j, portmask)) { - port_pairs[i] = j; - port_pairs[j] = i; - i = j; - break; - } -} - -void -setup_shared_variables(void) -{ - const struct rte_memzone *qw_memzone; - - qw_memzone = rte_memzone_reserve(QUOTA_WATERMARK_MEMZONE_NAME, - 3 * sizeof(int), rte_socket_id(), 0); - if (qw_memzone == NULL) - rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno)); - - quota = qw_memzone->addr; - low_watermark = (unsigned int *) qw_memzone->addr + 1; - high_watermark = (unsigned int *) qw_memzone->addr + 2; -} diff --git a/examples/quota_watermark/qw/init.h b/examples/quota_watermark/qw/init.h deleted file mode 100644 index e0c90df72..000000000 --- a/examples/quota_watermark/qw/init.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _INIT_H_ -#define _INIT_H_ - -void configure_eth_port(uint16_t port_id); -void init_dpdk(void); -void init_ring(int lcore_id, uint16_t port_id); -void pair_ports(void); -void setup_shared_variables(void); - -#endif /* _INIT_H_ */ diff --git a/examples/quota_watermark/qw/main.c b/examples/quota_watermark/qw/main.c deleted file mode 100644 index c985eed24..000000000 --- a/examples/quota_watermark/qw/main.c +++ /dev/null @@ -1,373 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <rte_eal.h> - -#include <rte_common.h> -#include <rte_debug.h> -#include <rte_errno.h> -#include <rte_ethdev.h> -#include <rte_launch.h> -#include <rte_lcore.h> -#include <rte_log.h> -#include <rte_mbuf.h> -#include <rte_ring.h> - -#include <rte_byteorder.h> - -#include "args.h" -#include "main.h" -#include "init.h" -#include "../include/conf.h" - - -#ifdef QW_SOFTWARE_FC -#define SEND_PAUSE_FRAME(port_id, duration) send_pause_frame(port_id, duration) -#else -#define SEND_PAUSE_FRAME(port_id, duration) do { } while(0) -#endif - -#define ETHER_TYPE_FLOW_CONTROL 0x8808 - -struct ether_fc_frame { - uint16_t opcode; - uint16_t param; -} __attribute__((__packed__)); - - -int *quota; -unsigned int *low_watermark; -unsigned int *high_watermark; - -uint16_t port_pairs[RTE_MAX_ETHPORTS]; - -struct rte_ring *rings[RTE_MAX_LCORE][RTE_MAX_ETHPORTS]; -struct rte_mempool *mbuf_pool; - - -static void send_pause_frame(uint16_t port_id, uint16_t duration) -{ - struct rte_mbuf *mbuf; - struct ether_fc_frame *pause_frame; - struct rte_ether_hdr *hdr; - struct rte_ether_addr mac_addr; - int ret; - - RTE_LOG_DP(DEBUG, USER1, - "Sending PAUSE frame (duration=%d) on port %d\n", - duration, port_id); - - ret = rte_eth_macaddr_get(port_id, &mac_addr); - if (ret != 0) { - RTE_LOG_DP(ERR, USER1, - "Failed to get MAC address (port %u): %s\n", - port_id, rte_strerror(-ret)); - return; - } - - /* Get a mbuf from the pool */ - mbuf = rte_pktmbuf_alloc(mbuf_pool); - if (unlikely(mbuf == NULL)) - return; - - /* Prepare a PAUSE frame */ - hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr *); - pause_frame = (struct ether_fc_frame *) &hdr[1]; - - rte_ether_addr_copy(&mac_addr, &hdr->s_addr); - - void *tmp = &hdr->d_addr.addr_bytes[0]; - *((uint64_t *)tmp) = 0x010000C28001ULL; - - hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_FLOW_CONTROL); - - pause_frame->opcode = rte_cpu_to_be_16(0x0001); - pause_frame->param = rte_cpu_to_be_16(duration); - - mbuf->pkt_len = 60; - mbuf->data_len = 60; - - rte_eth_tx_burst(port_id, 0, &mbuf, 1); -} - -/** - * Get the previous enabled lcore ID - * - * @param lcore_id - * The current lcore ID. - * @return - * The previous enabled lcore_id or -1 if not found. - */ -static unsigned int -get_previous_lcore_id(unsigned int lcore_id) -{ - int i; - - for (i = lcore_id - 1; i >= 0; i--) - if (rte_lcore_is_enabled(i)) - return i; - - return -1; -} - -/** - * Get the last enabled lcore ID - * - * @return - * The last enabled lcore_id. - */ -static unsigned int -get_last_lcore_id(void) -{ - int i; - - for (i = RTE_MAX_LCORE; i >= 0; i--) - if (rte_lcore_is_enabled(i)) - return i; - - return 0; -} - -static void -receive_stage(__attribute__((unused)) void *args) -{ - int i, ret; - - uint16_t port_id; - uint16_t nb_rx_pkts; - - unsigned int lcore_id; - unsigned int free; - - struct rte_mbuf *pkts[MAX_PKT_QUOTA]; - struct rte_ring *ring; - enum ring_state ring_state[RTE_MAX_ETHPORTS] = { RING_READY }; - - lcore_id = rte_lcore_id(); - - RTE_LOG(INFO, USER1, - "%s() started on core %u\n", __func__, lcore_id); - - while (1) { - - /* Process each port round robin style */ - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - - if (!is_bit_set(port_id, portmask)) - continue; - - ring = rings[lcore_id][port_id]; - - if (ring_state[port_id] != RING_READY) { - if (rte_ring_count(ring) > *low_watermark) - continue; - else - ring_state[port_id] = RING_READY; - } - - /* Enqueue received packets on the RX ring */ - nb_rx_pkts = rte_eth_rx_burst(port_id, 0, pkts, - (uint16_t) *quota); - ret = rte_ring_enqueue_bulk(ring, (void *) pkts, - nb_rx_pkts, &free); - if (RING_SIZE - free > *high_watermark) { - ring_state[port_id] = RING_OVERLOADED; - send_pause_frame(port_id, 1337); - } - - if (ret == 0) { - - /* - * Return mbufs to the pool, - * effectively dropping packets - */ - for (i = 0; i < nb_rx_pkts; i++) - rte_pktmbuf_free(pkts[i]); - } - } - } -} - -static int -pipeline_stage(__attribute__((unused)) void *args) -{ - int i, ret; - int nb_dq_pkts; - - uint16_t port_id; - - unsigned int lcore_id, previous_lcore_id; - unsigned int free; - - void *pkts[MAX_PKT_QUOTA]; - struct rte_ring *rx, *tx; - enum ring_state ring_state[RTE_MAX_ETHPORTS] = { RING_READY }; - - lcore_id = rte_lcore_id(); - previous_lcore_id = get_previous_lcore_id(lcore_id); - - RTE_LOG(INFO, USER1, - "%s() started on core %u - processing packets from core %u\n", - __func__, lcore_id, previous_lcore_id); - - while (1) { - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - - if (!is_bit_set(port_id, portmask)) - continue; - - tx = rings[lcore_id][port_id]; - rx = rings[previous_lcore_id][port_id]; - - if (ring_state[port_id] != RING_READY) { - if (rte_ring_count(tx) > *low_watermark) - continue; - else - ring_state[port_id] = RING_READY; - } - - /* Dequeue up to quota mbuf from rx */ - nb_dq_pkts = rte_ring_dequeue_burst(rx, pkts, - *quota, NULL); - if (unlikely(nb_dq_pkts < 0)) - continue; - - /* Enqueue them on tx */ - ret = rte_ring_enqueue_bulk(tx, pkts, - nb_dq_pkts, &free); - if (RING_SIZE - free > *high_watermark) - ring_state[port_id] = RING_OVERLOADED; - - if (ret == 0) { - - /* - * Return mbufs to the pool, - * effectively dropping packets - */ - for (i = 0; i < nb_dq_pkts; i++) - rte_pktmbuf_free(pkts[i]); - } - } - } - - return 0; -} - -static int -send_stage(__attribute__((unused)) void *args) -{ - uint16_t nb_dq_pkts; - - uint16_t port_id; - uint16_t dest_port_id; - - unsigned int lcore_id, previous_lcore_id; - - struct rte_ring *tx; - struct rte_mbuf *tx_pkts[MAX_PKT_QUOTA]; - - lcore_id = rte_lcore_id(); - previous_lcore_id = get_previous_lcore_id(lcore_id); - - RTE_LOG(INFO, USER1, - "%s() started on core %u - processing packets from core %u\n", - __func__, lcore_id, previous_lcore_id); - - while (1) { - - /* Process each ring round robin style */ - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) { - - if (!is_bit_set(port_id, portmask)) - continue; - - dest_port_id = port_pairs[port_id]; - tx = rings[previous_lcore_id][port_id]; - - if (rte_ring_empty(tx)) - continue; - - /* Dequeue packets from tx and send them */ - nb_dq_pkts = (uint16_t) rte_ring_dequeue_burst(tx, - (void *) tx_pkts, *quota, NULL); - rte_eth_tx_burst(dest_port_id, 0, tx_pkts, nb_dq_pkts); - - /* TODO: Check if nb_dq_pkts == nb_tx_pkts? */ - } - } - - return 0; -} - -int -main(int argc, char **argv) -{ - int ret; - unsigned int lcore_id, master_lcore_id, last_lcore_id; - - uint16_t port_id; - - rte_log_set_global_level(RTE_LOG_INFO); - - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot initialize EAL\n"); - - argc -= ret; - argv += ret; - - init_dpdk(); - setup_shared_variables(); - - *quota = 32; - *low_watermark = 60 * RING_SIZE / 100; - - last_lcore_id = get_last_lcore_id(); - master_lcore_id = rte_get_master_lcore(); - - /* Parse the application's arguments */ - ret = parse_qw_args(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid quota/watermark argument(s)\n"); - - /* Create a pool of mbuf to store packets */ - mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", MBUF_PER_POOL, 32, 0, - MBUF_DATA_SIZE, rte_socket_id()); - if (mbuf_pool == NULL) - rte_panic("%s\n", rte_strerror(rte_errno)); - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) - if (is_bit_set(port_id, portmask)) { - configure_eth_port(port_id); - init_ring(master_lcore_id, port_id); - } - - pair_ports(); - - /* - * Start pipeline_connect() on all the available slave lcores - * but the last - */ - for (lcore_id = 0 ; lcore_id < last_lcore_id; lcore_id++) { - if (rte_lcore_is_enabled(lcore_id) && - lcore_id != master_lcore_id) { - - for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) - if (is_bit_set(port_id, portmask)) - init_ring(lcore_id, port_id); - - rte_eal_remote_launch(pipeline_stage, - NULL, lcore_id); - } - } - - /* Start send_stage() on the last slave core */ - rte_eal_remote_launch(send_stage, NULL, last_lcore_id); - - /* Start receive_stage() on the master core */ - receive_stage(NULL); - - return 0; -} diff --git a/examples/quota_watermark/qw/main.h b/examples/quota_watermark/qw/main.h deleted file mode 100644 index 9903ddc8c..000000000 --- a/examples/quota_watermark/qw/main.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _MAIN_H_ -#define _MAIN_H_ - -#include "../include/conf.h" - -enum ring_state { - RING_READY, - RING_OVERLOADED, -}; - -extern int *quota; -extern unsigned int *low_watermark; -extern unsigned int *high_watermark; - -extern uint16_t port_pairs[RTE_MAX_ETHPORTS]; - -extern struct rte_ring *rings[RTE_MAX_LCORE][RTE_MAX_ETHPORTS]; -extern struct rte_mempool *mbuf_pool; - - -static inline int -is_bit_set(int i, unsigned int mask) -{ - return (1 << i) & mask; -} - -#endif /* _MAIN_H_ */ diff --git a/examples/quota_watermark/qwctl/Makefile b/examples/quota_watermark/qwctl/Makefile deleted file mode 100644 index a40f28025..000000000 --- a/examples/quota_watermark/qwctl/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 - -# binary name -APP = qwctl - -# all source are stored in SRCS-y -SRCS-y := commands.c qwctl.c - -CFLAGS += -O3 -CFLAGS += $(WERROR_FLAGS) - -include $(RTE_SDK)/mk/rte.extapp.mk diff --git a/examples/quota_watermark/qwctl/commands.c b/examples/quota_watermark/qwctl/commands.c deleted file mode 100644 index a1c646b9f..000000000 --- a/examples/quota_watermark/qwctl/commands.c +++ /dev/null @@ -1,196 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <termios.h> - -#include <cmdline_rdline.h> -#include <cmdline_parse.h> -#include <cmdline_parse_num.h> -#include <cmdline_parse_string.h> -#include <cmdline.h> - -#include <rte_ring.h> - -#include "qwctl.h" -#include "../include/conf.h" - - -/** - * help command - */ - -struct cmd_help_tokens { - cmdline_fixed_string_t verb; -}; - -cmdline_parse_token_string_t cmd_help_verb = - TOKEN_STRING_INITIALIZER(struct cmd_help_tokens, verb, "help"); - -static void -cmd_help_handler(__attribute__((unused)) void *parsed_result, - struct cmdline *cl, - __attribute__((unused)) void *data) -{ - cmdline_printf(cl, "Available commands:\n" - "- help\n" - "- set [ring_name|variable] <value>\n" - "- show [ring_name|variable]\n" - "\n" - "Available variables:\n" - "- low_watermark\n" - "- quota\n" - "- ring names follow the core%%u_port%%u format\n"); -} - -cmdline_parse_inst_t cmd_help = { - .f = cmd_help_handler, - .data = NULL, - .help_str = "show help", - .tokens = { - (void *) &cmd_help_verb, - NULL, - }, -}; - - -/** - * set command - */ - -struct cmd_set_tokens { - cmdline_fixed_string_t verb; - cmdline_fixed_string_t variable; - uint32_t value; -}; - -cmdline_parse_token_string_t cmd_set_verb = - TOKEN_STRING_INITIALIZER(struct cmd_set_tokens, verb, "set"); - -cmdline_parse_token_string_t cmd_set_variable = - TOKEN_STRING_INITIALIZER(struct cmd_set_tokens, variable, NULL); - -cmdline_parse_token_num_t cmd_set_value = - TOKEN_NUM_INITIALIZER(struct cmd_set_tokens, value, UINT32); - -static void -cmd_set_handler(__attribute__((unused)) void *parsed_result, - struct cmdline *cl, - __attribute__((unused)) void *data) -{ - struct cmd_set_tokens *tokens = parsed_result; - struct rte_ring *ring; - - if (!strcmp(tokens->variable, "quota")) { - - if (tokens->value > 0 && tokens->value <= MAX_PKT_QUOTA) - *quota = tokens->value; - else - cmdline_printf(cl, "quota must be between 1 and %u\n", - MAX_PKT_QUOTA); - } - - else if (!strcmp(tokens->variable, "low_watermark")) { - - if (tokens->value <= 100) - *low_watermark = tokens->value * RING_SIZE / 100; - else - cmdline_printf(cl, - "low_watermark must be between 0%% and 100%%\n"); - } - - else { - - ring = rte_ring_lookup(tokens->variable); - if (ring == NULL) - cmdline_printf(cl, "Cannot find ring \"%s\"\n", - tokens->variable); - else - if (tokens->value >= *low_watermark * 100 / RING_SIZE - && tokens->value <= 100) - *high_watermark = tokens->value * - RING_SIZE / 100; - else - cmdline_printf(cl, - "ring high watermark must be between %u%% and 100%%\n", - *low_watermark * 100 / RING_SIZE); - } -} - -cmdline_parse_inst_t cmd_set = { - .f = cmd_set_handler, - .data = NULL, - .help_str = "Set a variable value", - .tokens = { - (void *) &cmd_set_verb, - (void *) &cmd_set_variable, - (void *) &cmd_set_value, - NULL, - }, -}; - - -/** - * show command - */ - -struct cmd_show_tokens { - cmdline_fixed_string_t verb; - cmdline_fixed_string_t variable; -}; - -cmdline_parse_token_string_t cmd_show_verb = - TOKEN_STRING_INITIALIZER(struct cmd_show_tokens, verb, "show"); - -cmdline_parse_token_string_t cmd_show_variable = - TOKEN_STRING_INITIALIZER(struct cmd_show_tokens, - variable, NULL); - - -static void -cmd_show_handler(__attribute__((unused)) void *parsed_result, - struct cmdline *cl, - __attribute__((unused)) void *data) -{ - struct cmd_show_tokens *tokens = parsed_result; - struct rte_ring *ring; - - if (!strcmp(tokens->variable, "quota")) - cmdline_printf(cl, "Global quota: %d\n", *quota); - - else if (!strcmp(tokens->variable, "low_watermark")) - cmdline_printf(cl, "Global low_watermark: %u\n", - *low_watermark); - - else { - - ring = rte_ring_lookup(tokens->variable); - if (ring == NULL) - cmdline_printf(cl, "Cannot find ring \"%s\"\n", - tokens->variable); - else - rte_ring_dump(stdout, ring); - } -} - -cmdline_parse_inst_t cmd_show = { - .f = cmd_show_handler, - .data = NULL, - .help_str = "Show a variable value", - .tokens = { - (void *) &cmd_show_verb, - (void *) &cmd_show_variable, - NULL, - }, -}; - - -cmdline_parse_ctx_t qwctl_ctx[] = { - (cmdline_parse_inst_t *)&cmd_help, - (cmdline_parse_inst_t *)&cmd_set, - (cmdline_parse_inst_t *)&cmd_show, - NULL, -}; diff --git a/examples/quota_watermark/qwctl/commands.h b/examples/quota_watermark/qwctl/commands.h deleted file mode 100644 index 4a4e97475..000000000 --- a/examples/quota_watermark/qwctl/commands.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _COMMANDS_H_ -#define _COMMANDS_H_ - -#include <cmdline_parse.h> - -extern cmdline_parse_ctx_t qwctl_ctx[]; - -#endif /* _COMMANDS_H_ */ diff --git a/examples/quota_watermark/qwctl/qwctl.c b/examples/quota_watermark/qwctl/qwctl.c deleted file mode 100644 index 2f7914c80..000000000 --- a/examples/quota_watermark/qwctl/qwctl.c +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <fcntl.h> -#include <stdio.h> -#include <termios.h> -#include <unistd.h> -#include <sys/mman.h> - -#include <rte_eal.h> - -#include <rte_log.h> -#include <rte_memzone.h> - -#include <cmdline_rdline.h> -#include <cmdline_parse.h> -#include <cmdline_socket.h> -#include <cmdline.h> - - -#include "qwctl.h" -#include "commands.h" -#include "../include/conf.h" - - -int *quota; -unsigned int *low_watermark; -unsigned int *high_watermark; - - -static void -setup_shared_variables(void) -{ - const struct rte_memzone *qw_memzone; - - qw_memzone = rte_memzone_lookup(QUOTA_WATERMARK_MEMZONE_NAME); - if (qw_memzone == NULL) - rte_exit(EXIT_FAILURE, "Couldn't find memzone\n"); - - quota = qw_memzone->addr; - low_watermark = (unsigned int *) qw_memzone->addr + 1; - high_watermark = (unsigned int *) qw_memzone->addr + 2; -} - -int main(int argc, char **argv) -{ - int ret; - struct cmdline *cl; - - rte_log_set_global_level(RTE_LOG_INFO); - - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot initialize EAL\n"); - - setup_shared_variables(); - - cl = cmdline_stdin_new(qwctl_ctx, "qwctl> "); - if (cl == NULL) - rte_exit(EXIT_FAILURE, "Cannot create cmdline instance\n"); - - cmdline_interact(cl); - cmdline_stdin_exit(cl); - - return 0; -} diff --git a/examples/quota_watermark/qwctl/qwctl.h b/examples/quota_watermark/qwctl/qwctl.h deleted file mode 100644 index 2a4559388..000000000 --- a/examples/quota_watermark/qwctl/qwctl.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _MAIN_H_ -#define _MAIN_H_ - -extern int *quota; -extern unsigned int *low_watermark; -extern unsigned int *high_watermark; - -#endif /* _MAIN_H_ */ -- 2.17.1 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v3 5/6] examples/netmap-compat: remove example 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 " Ciara Power ` (3 preceding siblings ...) 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 4/6] examples/quota-watermark: " Ciara Power @ 2019-10-25 9:56 ` Ciara Power 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 6/6] examples/load_balancer: " Ciara Power 2019-10-26 20:35 ` [dpdk-dev] [PATCH v3 0/6] remove a few example applications David Marchand 6 siblings, 0 replies; 27+ messages in thread From: Ciara Power @ 2019-10-25 9:56 UTC (permalink / raw) To: dev; +Cc: techboard, 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 <ciara.power@intel.com> Acked-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com> --- v3: Document removed application in release notes. --- MAINTAINERS | 3 - doc/guides/rel_notes/release_19_11.rst | 2 + doc/guides/sample_app_ug/index.rst | 1 - .../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 | 347 ------- examples/netmap_compat/lib/compat_netmap.c | 906 ------------------ 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, 3 insertions(+), 1891 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 85e7b433f..dfe9355a5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1491,9 +1491,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 <john.mcnamara@intel.com> F: examples/performance-thread/ diff --git a/doc/guides/rel_notes/release_19_11.rst b/doc/guides/rel_notes/release_19_11.rst index c07763ce9..83ec7ef59 100644 --- a/doc/guides/rel_notes/release_19_11.rst +++ b/doc/guides/rel_notes/release_19_11.rst @@ -191,6 +191,8 @@ Removed Items * Quota and Watermark + * Netmap Compatibility + API Changes ----------- 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/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 f3819d222..000000000 --- a/examples/netmap_compat/bridge/bridge.c +++ /dev/null @@ -1,347 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <fcntl.h> -#include <getopt.h> -#include <inttypes.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/mman.h> - -#include <rte_eal.h> -#include <rte_ethdev.h> -#include <rte_mbuf.h> -#include <rte_mempool.h> -#include <rte_string_fns.h> -#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); - - err = rte_eth_promiscuous_enable(ports.p[i].id); - if (err != 0) - rte_exit(EXIT_FAILURE, - "Couldn't enable promiscuous mode on port %u: %s\n", - ports.p[i].id, rte_strerror(-err)); - } - - 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 c25cc093d..000000000 --- a/examples/netmap_compat/lib/compat_netmap.c +++ /dev/null @@ -1,906 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <errno.h> -#include <inttypes.h> -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <net/if.h> -#include <sys/types.h> -#include <sys/resource.h> -#include <sys/mman.h> - -#include <rte_common.h> -#include <rte_errno.h> -#include <rte_ethdev.h> -#include <rte_log.h> -#include <rte_malloc.h> -#include <rte_mbuf.h> -#include <rte_spinlock.h> -#include <rte_string_fns.h> - -#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; - } - - ret = rte_eth_dev_info_get(portid, &dev_info); - if (ret != 0) { - RTE_LOG(ERR, USER1, - "Error during getting device (port %u) info: %s\n", - portid, strerror(-ret)); - return ret; - } - - 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 <poll.h> -#include <linux/ioctl.h> -#include <net/if.h> - -#include <rte_ethdev.h> -#include <rte_mempool.h> - -#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_ */ -- 2.17.1 ^ permalink raw reply [flat|nested] 27+ messages in thread
* [dpdk-dev] [PATCH v3 6/6] examples/load_balancer: remove example 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 " Ciara Power ` (4 preceding siblings ...) 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 5/6] examples/netmap-compat: " Ciara Power @ 2019-10-25 9:56 ` Ciara Power 2019-10-26 20:35 ` [dpdk-dev] [PATCH v3 0/6] remove a few example applications David Marchand 6 siblings, 0 replies; 27+ messages in thread From: Ciara Power @ 2019-10-25 9:56 UTC (permalink / raw) To: dev; +Cc: techboard, Ciara Power This example can be removed because DPDK now has a range of libraries, especially rte_eventdev, that did not exist previously for load balancing, making this less relevant. Also, modern NIC cards have greater ability to do load balancing, e.g. using RSS, over a wider range of fields than earlier cards did. Signed-off-by: Ciara Power <ciara.power@intel.com> Acked-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com> --- v3: Document removed applications in release notes. --- MAINTAINERS | 3 - doc/guides/rel_notes/release_19_11.rst | 2 + doc/guides/sample_app_ug/index.rst | 1 - doc/guides/sample_app_ug/load_balancer.rst | 201 ---- examples/Makefile | 1 - examples/load_balancer/Makefile | 62 -- examples/load_balancer/config.c | 1030 -------------------- examples/load_balancer/init.c | 537 ---------- examples/load_balancer/main.c | 76 -- examples/load_balancer/main.h | 351 ------- examples/load_balancer/meson.build | 12 - examples/load_balancer/runtime.c | 642 ------------ examples/meson.build | 1 - 13 files changed, 2 insertions(+), 2917 deletions(-) delete mode 100644 doc/guides/sample_app_ug/load_balancer.rst delete mode 100644 examples/load_balancer/Makefile delete mode 100644 examples/load_balancer/config.c delete mode 100644 examples/load_balancer/init.c delete mode 100644 examples/load_balancer/main.c delete mode 100644 examples/load_balancer/main.h delete mode 100644 examples/load_balancer/meson.build delete mode 100644 examples/load_balancer/runtime.c diff --git a/MAINTAINERS b/MAINTAINERS index dfe9355a5..40f3c7257 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1488,9 +1488,6 @@ F: doc/guides/sample_app_ug/l3_forward.rst F: examples/link_status_interrupt/ F: doc/guides/sample_app_ug/link_status_intr.rst -F: examples/load_balancer/ -F: doc/guides/sample_app_ug/load_balancer.rst - L-threads - EXPERIMENTAL M: John McNamara <john.mcnamara@intel.com> F: examples/performance-thread/ diff --git a/doc/guides/rel_notes/release_19_11.rst b/doc/guides/rel_notes/release_19_11.rst index 83ec7ef59..7c807d554 100644 --- a/doc/guides/rel_notes/release_19_11.rst +++ b/doc/guides/rel_notes/release_19_11.rst @@ -193,6 +193,8 @@ Removed Items * Netmap Compatibility + * Load Balancer + API Changes ----------- diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst index 5f4924df6..191eebb56 100644 --- a/doc/guides/sample_app_ug/index.rst +++ b/doc/guides/sample_app_ug/index.rst @@ -30,7 +30,6 @@ Sample Applications User Guides l3_forward_power_man l3_forward_access_ctrl link_status_intr - load_balancer server_node_efd service_cores multi_process diff --git a/doc/guides/sample_app_ug/load_balancer.rst b/doc/guides/sample_app_ug/load_balancer.rst deleted file mode 100644 index 8f2abdfb8..000000000 --- a/doc/guides/sample_app_ug/load_balancer.rst +++ /dev/null @@ -1,201 +0,0 @@ -.. SPDX-License-Identifier: BSD-3-Clause - Copyright(c) 2010-2014 Intel Corporation. - -Load Balancer Sample Application -================================ - -The Load Balancer sample application demonstrates the concept of isolating the packet I/O task -from the application-specific workload. -Depending on the performance target, -a number of logical cores (lcores) are dedicated to handle the interaction with the NIC ports (I/O lcores), -while the rest of the lcores are dedicated to performing the application processing (worker lcores). -The worker lcores are totally oblivious to the intricacies of the packet I/O activity and -use the NIC-agnostic interface provided by software rings to exchange packets with the I/O cores. - -Overview --------- - -The architecture of the Load Balance application is presented in the following figure. - -.. _figure_load_bal_app_arch: - -.. figure:: img/load_bal_app_arch.* - - Load Balancer Application Architecture - - -For the sake of simplicity, the diagram illustrates a specific case of two I/O RX and two I/O TX lcores off loading the packet I/O -overhead incurred by four NIC ports from four worker cores, with each I/O lcore handling RX/TX for two NIC ports. - -I/O RX Logical Cores -~~~~~~~~~~~~~~~~~~~~ - -Each I/O RX lcore performs packet RX from its assigned NIC RX rings and then distributes the received packets to the worker threads. -The application allows each I/O RX lcore to communicate with any of the worker threads, -therefore each (I/O RX lcore, worker lcore) pair is connected through a dedicated single producer - single consumer software ring. - -The worker lcore to handle the current packet is determined by reading a predefined 1-byte field from the input packet: - -worker_id = packet[load_balancing_field] % n_workers - -Since all the packets that are part of the same traffic flow are expected to have the same value for the load balancing field, -this scheme also ensures that all the packets that are part of the same traffic flow are directed to the same worker lcore (flow affinity) -in the same order they enter the system (packet ordering). - -I/O TX Logical Cores -~~~~~~~~~~~~~~~~~~~~ - -Each I/O lcore owns the packet TX for a predefined set of NIC ports. To enable each worker thread to send packets to any NIC TX port, -the application creates a software ring for each (worker lcore, NIC TX port) pair, -with each I/O TX core handling those software rings that are associated with NIC ports that it handles. - -Worker Logical Cores -~~~~~~~~~~~~~~~~~~~~ - -Each worker lcore reads packets from its set of input software rings and -routes them to the NIC ports for transmission by dispatching them to output software rings. -The routing logic is LPM based, with all the worker threads sharing the same LPM rules. - -Compiling the Application -------------------------- - -To compile the sample application see :doc:`compiling`. - -The application is located in the ``load_balancer`` sub-directory. - -Running the Application ------------------------ - -To successfully run the application, -the command line used to start the application has to be in sync with the traffic flows configured on the traffic generator side. - -For examples of application command lines and traffic generator flows, please refer to the DPDK Test Report. -For more details on how to set up and run the sample applications provided with DPDK package, -please refer to the *DPDK Getting Started Guide*. - -Explanation ------------ - -Application Configuration -~~~~~~~~~~~~~~~~~~~~~~~~~ - -The application run-time configuration is done through the application command line parameters. -Any parameter that is not specified as mandatory is optional, -with the default value hard-coded in the main.h header file from the application folder. - -The list of application command line parameters is listed below: - -#. --rx "(PORT, QUEUE, LCORE), ...": The list of NIC RX ports and queues handled by the I/O RX lcores. - This parameter also implicitly defines the list of I/O RX lcores. This is a mandatory parameter. - -#. --tx "(PORT, LCORE), ... ": The list of NIC TX ports handled by the I/O TX lcores. - This parameter also implicitly defines the list of I/O TX lcores. - This is a mandatory parameter. - -#. --w "LCORE, ...": The list of the worker lcores. This is a mandatory parameter. - -#. --lpm "IP / PREFIX => PORT; ...": The list of LPM rules used by the worker lcores for packet forwarding. - This is a mandatory parameter. - -#. --rsz "A, B, C, D": Ring sizes: - - #. A = The size (in number of buffer descriptors) of each of the NIC RX rings read by the I/O RX lcores. - - #. B = The size (in number of elements) of each of the software rings used by the I/O RX lcores to send packets to worker lcores. - - #. C = The size (in number of elements) of each of the software rings used by the worker lcores to send packets to I/O TX lcores. - - #. D = The size (in number of buffer descriptors) of each of the NIC TX rings written by I/O TX lcores. - -#. --bsz "(A, B), (C, D), (E, F)": Burst sizes: - - #. A = The I/O RX lcore read burst size from NIC RX. - - #. B = The I/O RX lcore write burst size to the output software rings. - - #. C = The worker lcore read burst size from the input software rings. - - #. D = The worker lcore write burst size to the output software rings. - - #. E = The I/O TX lcore read burst size from the input software rings. - - #. F = The I/O TX lcore write burst size to the NIC TX. - -#. --pos-lb POS: The position of the 1-byte field within the input packet used by the I/O RX lcores - to identify the worker lcore for the current packet. - This field needs to be within the first 64 bytes of the input packet. - -The infrastructure of software rings connecting I/O lcores and worker lcores is built by the application -as a result of the application configuration provided by the user through the application command line parameters. - -A specific lcore performing the I/O RX role for a specific set of NIC ports can also perform the I/O TX role -for the same or a different set of NIC ports. -A specific lcore cannot perform both the I/O role (either RX or TX) and the worker role during the same session. - -Example: - -.. code-block:: console - - ./load_balancer -l 3-7 -n 4 -- --rx "(0,0,3),(1,0,3)" --tx "(0,3),(1,3)" --w "4,5,6,7" --lpm "1.0.0.0/24=>0; 1.0.1.0/24=>1;" --pos-lb 29 - -There is a single I/O lcore (lcore 3) that handles RX and TX for two NIC ports (ports 0 and 1) that -handles packets to/from four worker lcores (lcores 4, 5, 6 and 7) that -are assigned worker IDs 0 to 3 (worker ID for lcore 4 is 0, for lcore 5 is 1, for lcore 6 is 2 and for lcore 7 is 3). - -Assuming that all the input packets are IPv4 packets with no VLAN label and the source IP address of the current packet is A.B.C.D, -the worker lcore for the current packet is determined by byte D (which is byte 29). -There are two LPM rules that are used by each worker lcore to route packets to the output NIC ports. - -The following table illustrates the packet flow through the system for several possible traffic flows: - -+------------+----------------+-----------------+------------------------------+--------------+ -| **Flow #** | **Source** | **Destination** | **Worker ID (Worker lcore)** | **Output** | -| | **IP Address** | **IP Address** | | **NIC Port** | -| | | | | | -+============+================+=================+==============================+==============+ -| 1 | 0.0.0.0 | 1.0.0.1 | 0 (4) | 0 | -| | | | | | -+------------+----------------+-----------------+------------------------------+--------------+ -| 2 | 0.0.0.1 | 1.0.1.2 | 1 (5) | 1 | -| | | | | | -+------------+----------------+-----------------+------------------------------+--------------+ -| 3 | 0.0.0.14 | 1.0.0.3 | 2 (6) | 0 | -| | | | | | -+------------+----------------+-----------------+------------------------------+--------------+ -| 4 | 0.0.0.15 | 1.0.1.4 | 3 (7) | 1 | -| | | | | | -+------------+----------------+-----------------+------------------------------+--------------+ - -NUMA Support -~~~~~~~~~~~~ - -The application has built-in performance enhancements for the NUMA case: - -#. One buffer pool per each CPU socket. - -#. One LPM table per each CPU socket. - -#. Memory for the NIC RX or TX rings is allocated on the same socket with the lcore handling the respective ring. - -In the case where multiple CPU sockets are used in the system, -it is recommended to enable at least one lcore to fulfill the I/O role for the NIC ports that -are directly attached to that CPU socket through the PCI Express* bus. -It is always recommended to handle the packet I/O with lcores from the same CPU socket as the NICs. - -Depending on whether the I/O RX lcore (same CPU socket as NIC RX), -the worker lcore and the I/O TX lcore (same CPU socket as NIC TX) handling a specific input packet, -are on the same or different CPU sockets, the following run-time scenarios are possible: - -#. AAA: The packet is received, processed and transmitted without going across CPU sockets. - -#. AAB: The packet is received and processed on socket A, - but as it has to be transmitted on a NIC port connected to socket B, - the packet is sent to socket B through software rings. - -#. ABB: The packet is received on socket A, but as it has to be processed by a worker lcore on socket B, - the packet is sent to socket B through software rings. - The packet is transmitted by a NIC port connected to the same CPU socket as the worker lcore that processed it. - -#. ABC: The packet is received on socket A, it is processed by an lcore on socket B, - then it has to be transmitted out by a NIC connected to socket C. - The performance price for crossing the CPU socket boundary is paid twice for this packet. diff --git a/examples/Makefile b/examples/Makefile index 6bba09ce9..62d0865c5 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -48,7 +48,6 @@ ifeq ($(CONFIG_RTE_LIBRTE_LPM)$(CONFIG_RTE_LIBRTE_HASH),yy) DIRS-$(CONFIG_RTE_LIBRTE_POWER) += l3fwd-power endif DIRS-y += link_status_interrupt -DIRS-$(CONFIG_RTE_LIBRTE_LPM) += load_balancer DIRS-y += multi_process DIRS-y += ntb DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += packet_ordering diff --git a/examples/load_balancer/Makefile b/examples/load_balancer/Makefile deleted file mode 100644 index caae8a107..000000000 --- a/examples/load_balancer/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2010-2014 Intel Corporation - -# binary name -APP = load_balancer - -# all source are stored in SRCS-y -SRCS-y := main.c config.c init.c runtime.c - -# Build using pkg-config variables if possible -ifeq ($(shell pkg-config --exists libdpdk && echo 0),0) - -all: shared -.PHONY: shared static -shared: build/$(APP)-shared - ln -sf $(APP)-shared build/$(APP) -static: build/$(APP)-static - ln -sf $(APP)-static build/$(APP) - -PKGCONF=pkg-config --define-prefix - -PC_FILE := $(shell $(PKGCONF) --path libdpdk) -CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) -LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk) -LDFLAGS_STATIC = -Wl,-Bstatic $(shell $(PKGCONF) --static --libs libdpdk) - -build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) - -build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build - $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC) - -build: - @mkdir -p $@ - -.PHONY: clean -clean: - rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared - test -d build && rmdir -p build || true - -else # Build using legacy build system - -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 - -CFLAGS += -O3 -g -CFLAGS += $(WERROR_FLAGS) - -# workaround for a gcc bug with noreturn attribute -# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603 -ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y) -CFLAGS_main.o += -Wno-return-type -endif - -include $(RTE_SDK)/mk/rte.extapp.mk -endif diff --git a/examples/load_balancer/config.c b/examples/load_balancer/config.c deleted file mode 100644 index 972c85c5b..000000000 --- a/examples/load_balancer/config.c +++ /dev/null @@ -1,1030 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_lpm.h> -#include <rte_string_fns.h> - -#include "main.h" - -struct app_params app; - -static const char usage[] = -" \n" -" load_balancer <EAL PARAMS> -- <APP PARAMS> \n" -" \n" -"Application manadatory parameters: \n" -" --rx \"(PORT, QUEUE, LCORE), ...\" : List of NIC RX ports and queues \n" -" handled by the I/O RX lcores \n" -" --tx \"(PORT, LCORE), ...\" : List of NIC TX ports handled by the I/O TX \n" -" lcores \n" -" --w \"LCORE, ...\" : List of the worker lcores \n" -" --lpm \"IP / PREFIX => PORT; ...\" : List of LPM rules used by the worker \n" -" lcores for packet forwarding \n" -" \n" -"Application optional parameters: \n" -" --rsz \"A, B, C, D\" : Ring sizes \n" -" A = Size (in number of buffer descriptors) of each of the NIC RX \n" -" rings read by the I/O RX lcores (default value is %u) \n" -" B = Size (in number of elements) of each of the SW rings used by the\n" -" I/O RX lcores to send packets to worker lcores (default value is\n" -" %u) \n" -" C = Size (in number of elements) of each of the SW rings used by the\n" -" worker lcores to send packets to I/O TX lcores (default value is\n" -" %u) \n" -" D = Size (in number of buffer descriptors) of each of the NIC TX \n" -" rings written by I/O TX lcores (default value is %u) \n" -" --bsz \"(A, B), (C, D), (E, F)\" : Burst sizes \n" -" A = I/O RX lcore read burst size from NIC RX (default value is %u) \n" -" B = I/O RX lcore write burst size to output SW rings (default value \n" -" is %u) \n" -" C = Worker lcore read burst size from input SW rings (default value \n" -" is %u) \n" -" D = Worker lcore write burst size to output SW rings (default value \n" -" is %u) \n" -" E = I/O TX lcore read burst size from input SW rings (default value \n" -" is %u) \n" -" F = I/O TX lcore write burst size to NIC TX (default value is %u) \n" -" --pos-lb POS : Position of the 1-byte field within the input packet used by\n" -" the I/O RX lcores to identify the worker lcore for the current \n" -" packet (default value is %u) \n"; - -void -app_print_usage(void) -{ - printf(usage, - APP_DEFAULT_NIC_RX_RING_SIZE, - APP_DEFAULT_RING_RX_SIZE, - APP_DEFAULT_RING_TX_SIZE, - APP_DEFAULT_NIC_TX_RING_SIZE, - APP_DEFAULT_BURST_SIZE_IO_RX_READ, - APP_DEFAULT_BURST_SIZE_IO_RX_WRITE, - APP_DEFAULT_BURST_SIZE_WORKER_READ, - APP_DEFAULT_BURST_SIZE_WORKER_WRITE, - APP_DEFAULT_BURST_SIZE_IO_TX_READ, - APP_DEFAULT_BURST_SIZE_IO_TX_WRITE, - APP_DEFAULT_IO_RX_LB_POS - ); -} - -#ifndef APP_ARG_RX_MAX_CHARS -#define APP_ARG_RX_MAX_CHARS 4096 -#endif - -#ifndef APP_ARG_RX_MAX_TUPLES -#define APP_ARG_RX_MAX_TUPLES 128 -#endif - -static int -str_to_unsigned_array( - const char *s, size_t sbuflen, - char separator, - unsigned num_vals, - unsigned *vals) -{ - char str[sbuflen+1]; - char *splits[num_vals]; - char *endptr = NULL; - int i, num_splits = 0; - - /* copy s so we don't modify original string */ - strlcpy(str, s, sizeof(str)); - num_splits = rte_strsplit(str, sizeof(str), splits, num_vals, separator); - - errno = 0; - for (i = 0; i < num_splits; i++) { - vals[i] = strtoul(splits[i], &endptr, 0); - if (errno != 0 || *endptr != '\0') - return -1; - } - - return num_splits; -} - -static int -str_to_unsigned_vals( - const char *s, - size_t sbuflen, - char separator, - unsigned num_vals, ...) -{ - unsigned i, vals[num_vals]; - va_list ap; - - num_vals = str_to_unsigned_array(s, sbuflen, separator, num_vals, vals); - - va_start(ap, num_vals); - for (i = 0; i < num_vals; i++) { - unsigned *u = va_arg(ap, unsigned *); - *u = vals[i]; - } - va_end(ap); - return num_vals; -} - -static int -parse_arg_rx(const char *arg) -{ - const char *p0 = arg, *p = arg; - uint32_t n_tuples; - - if (strnlen(arg, APP_ARG_RX_MAX_CHARS + 1) == APP_ARG_RX_MAX_CHARS + 1) { - return -1; - } - - n_tuples = 0; - while ((p = strchr(p0,'(')) != NULL) { - struct app_lcore_params *lp; - uint32_t port, queue, lcore, i; - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 3, &port, &queue, &lcore) != 3)) { - return -2; - } - - /* Enable port and queue for later initialization */ - if ((port >= APP_MAX_NIC_PORTS) || (queue >= APP_MAX_RX_QUEUES_PER_NIC_PORT)) { - return -3; - } - if (app.nic_rx_queue_mask[port][queue] != 0) { - return -4; - } - app.nic_rx_queue_mask[port][queue] = 1; - - /* Check and assign (port, queue) to I/O lcore */ - if (rte_lcore_is_enabled(lcore) == 0) { - return -5; - } - - if (lcore >= APP_MAX_LCORES) { - return -6; - } - lp = &app.lcore_params[lcore]; - if (lp->type == e_APP_LCORE_WORKER) { - return -7; - } - lp->type = e_APP_LCORE_IO; - const size_t n_queues = RTE_MIN(lp->io.rx.n_nic_queues, - RTE_DIM(lp->io.rx.nic_queues)); - for (i = 0; i < n_queues; i ++) { - if ((lp->io.rx.nic_queues[i].port == port) && - (lp->io.rx.nic_queues[i].queue == queue)) { - return -8; - } - } - if (lp->io.rx.n_nic_queues >= APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE) { - return -9; - } - lp->io.rx.nic_queues[lp->io.rx.n_nic_queues].port = port; - lp->io.rx.nic_queues[lp->io.rx.n_nic_queues].queue = (uint8_t) queue; - lp->io.rx.n_nic_queues ++; - - n_tuples ++; - if (n_tuples > APP_ARG_RX_MAX_TUPLES) { - return -10; - } - } - - if (n_tuples == 0) { - return -11; - } - - return 0; -} - -#ifndef APP_ARG_TX_MAX_CHARS -#define APP_ARG_TX_MAX_CHARS 4096 -#endif - -#ifndef APP_ARG_TX_MAX_TUPLES -#define APP_ARG_TX_MAX_TUPLES 128 -#endif - -static int -parse_arg_tx(const char *arg) -{ - const char *p0 = arg, *p = arg; - uint32_t n_tuples; - - if (strnlen(arg, APP_ARG_TX_MAX_CHARS + 1) == APP_ARG_TX_MAX_CHARS + 1) { - return -1; - } - - n_tuples = 0; - while ((p = strchr(p0,'(')) != NULL) { - struct app_lcore_params *lp; - uint32_t port, lcore, i; - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 2, &port, &lcore) != 2)) { - return -2; - } - - /* Enable port and queue for later initialization */ - if (port >= APP_MAX_NIC_PORTS) { - return -3; - } - if (app.nic_tx_port_mask[port] != 0) { - return -4; - } - app.nic_tx_port_mask[port] = 1; - - /* Check and assign (port, queue) to I/O lcore */ - if (rte_lcore_is_enabled(lcore) == 0) { - return -5; - } - - if (lcore >= APP_MAX_LCORES) { - return -6; - } - lp = &app.lcore_params[lcore]; - if (lp->type == e_APP_LCORE_WORKER) { - return -7; - } - lp->type = e_APP_LCORE_IO; - const size_t n_ports = RTE_MIN(lp->io.tx.n_nic_ports, - RTE_DIM(lp->io.tx.nic_ports)); - for (i = 0; i < n_ports; i ++) { - if (lp->io.tx.nic_ports[i] == port) { - return -8; - } - } - if (lp->io.tx.n_nic_ports >= APP_MAX_NIC_TX_PORTS_PER_IO_LCORE) { - return -9; - } - lp->io.tx.nic_ports[lp->io.tx.n_nic_ports] = port; - lp->io.tx.n_nic_ports ++; - - n_tuples ++; - if (n_tuples > APP_ARG_TX_MAX_TUPLES) { - return -10; - } - } - - if (n_tuples == 0) { - return -11; - } - - return 0; -} - -#ifndef APP_ARG_W_MAX_CHARS -#define APP_ARG_W_MAX_CHARS 4096 -#endif - -#ifndef APP_ARG_W_MAX_TUPLES -#define APP_ARG_W_MAX_TUPLES APP_MAX_WORKER_LCORES -#endif - -static int -parse_arg_w(const char *arg) -{ - const char *p = arg; - uint32_t n_tuples; - - if (strnlen(arg, APP_ARG_W_MAX_CHARS + 1) == APP_ARG_W_MAX_CHARS + 1) { - return -1; - } - - n_tuples = 0; - while (*p != 0) { - struct app_lcore_params *lp; - uint32_t lcore; - - errno = 0; - lcore = strtoul(p, NULL, 0); - if (errno != 0) { - return -2; - } - - /* Check and enable worker lcore */ - if (rte_lcore_is_enabled(lcore) == 0) { - return -3; - } - - if (lcore >= APP_MAX_LCORES) { - return -4; - } - lp = &app.lcore_params[lcore]; - if (lp->type == e_APP_LCORE_IO) { - return -5; - } - lp->type = e_APP_LCORE_WORKER; - - n_tuples ++; - if (n_tuples > APP_ARG_W_MAX_TUPLES) { - return -6; - } - - p = strchr(p, ','); - if (p == NULL) { - break; - } - p ++; - } - - if (n_tuples == 0) { - return -7; - } - - if ((n_tuples & (n_tuples - 1)) != 0) { - return -8; - } - - return 0; -} - -#ifndef APP_ARG_LPM_MAX_CHARS -#define APP_ARG_LPM_MAX_CHARS 4096 -#endif - -static int -parse_arg_lpm(const char *arg) -{ - const char *p = arg, *p0; - - if (strnlen(arg, APP_ARG_LPM_MAX_CHARS + 1) == APP_ARG_TX_MAX_CHARS + 1) { - return -1; - } - - while (*p != 0) { - uint32_t ip_a, ip_b, ip_c, ip_d, ip, depth, if_out; - char *endptr; - - p0 = strchr(p, '/'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, '.', 4, &ip_a, &ip_b, &ip_c, &ip_d) != 4)) { - return -2; - } - - p = p0 + 1; - errno = 0; - depth = strtoul(p, &endptr, 0); - if (errno != 0 || *endptr != '=') { - return -3; - } - p = strchr(p, '>'); - if (p == NULL) { - return -4; - } - if_out = strtoul(++p, &endptr, 0); - if (errno != 0 || (*endptr != '\0' && *endptr != ';')) { - return -5; - } - - if ((ip_a >= 256) || (ip_b >= 256) || (ip_c >= 256) || (ip_d >= 256) || - (depth == 0) || (depth >= 32) || - (if_out >= APP_MAX_NIC_PORTS)) { - return -6; - } - ip = (ip_a << 24) | (ip_b << 16) | (ip_c << 8) | ip_d; - - if (app.n_lpm_rules >= APP_MAX_LPM_RULES) { - return -7; - } - app.lpm_rules[app.n_lpm_rules].ip = ip; - app.lpm_rules[app.n_lpm_rules].depth = (uint8_t) depth; - app.lpm_rules[app.n_lpm_rules].if_out = (uint8_t) if_out; - app.n_lpm_rules ++; - - p = strchr(p, ';'); - if (p == NULL) { - return -8; - } - p ++; - } - - if (app.n_lpm_rules == 0) { - return -9; - } - - return 0; -} - -static int -app_check_lpm_table(void) -{ - uint32_t rule; - - /* For each rule, check that the output I/F is enabled */ - for (rule = 0; rule < app.n_lpm_rules; rule ++) - { - uint32_t port = app.lpm_rules[rule].if_out; - - if (app.nic_tx_port_mask[port] == 0) { - return -1; - } - } - - return 0; -} - -static int -app_check_every_rx_port_is_tx_enabled(void) -{ - uint16_t port; - - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - if ((app_get_nic_rx_queues_per_port(port) > 0) && (app.nic_tx_port_mask[port] == 0)) { - return -1; - } - } - - return 0; -} - -#ifndef APP_ARG_RSZ_CHARS -#define APP_ARG_RSZ_CHARS 63 -#endif - -static int -parse_arg_rsz(const char *arg) -{ - if (strnlen(arg, APP_ARG_RSZ_CHARS + 1) == APP_ARG_RSZ_CHARS + 1) { - return -1; - } - - if (str_to_unsigned_vals(arg, APP_ARG_RSZ_CHARS, ',', 4, - &app.nic_rx_ring_size, - &app.ring_rx_size, - &app.ring_tx_size, - &app.nic_tx_ring_size) != 4) - return -2; - - - if ((app.nic_rx_ring_size == 0) || - (app.nic_tx_ring_size == 0) || - (app.ring_rx_size == 0) || - (app.ring_tx_size == 0)) { - return -3; - } - - return 0; -} - -#ifndef APP_ARG_BSZ_CHARS -#define APP_ARG_BSZ_CHARS 63 -#endif - -static int -parse_arg_bsz(const char *arg) -{ - const char *p = arg, *p0; - if (strnlen(arg, APP_ARG_BSZ_CHARS + 1) == APP_ARG_BSZ_CHARS + 1) { - return -1; - } - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 2, &app.burst_size_io_rx_read, &app.burst_size_io_rx_write) != 2)) { - return -2; - } - - p = strchr(p0, '('); - if (p == NULL) { - return -3; - } - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 2, &app.burst_size_worker_read, &app.burst_size_worker_write) != 2)) { - return -4; - } - - p = strchr(p0, '('); - if (p == NULL) { - return -5; - } - - p0 = strchr(p++, ')'); - if ((p0 == NULL) || - (str_to_unsigned_vals(p, p0 - p, ',', 2, &app.burst_size_io_tx_read, &app.burst_size_io_tx_write) != 2)) { - return -6; - } - - if ((app.burst_size_io_rx_read == 0) || - (app.burst_size_io_rx_write == 0) || - (app.burst_size_worker_read == 0) || - (app.burst_size_worker_write == 0) || - (app.burst_size_io_tx_read == 0) || - (app.burst_size_io_tx_write == 0)) { - return -7; - } - - if ((app.burst_size_io_rx_read > APP_MBUF_ARRAY_SIZE) || - (app.burst_size_io_rx_write > APP_MBUF_ARRAY_SIZE) || - (app.burst_size_worker_read > APP_MBUF_ARRAY_SIZE) || - (app.burst_size_worker_write > APP_MBUF_ARRAY_SIZE) || - ((2 * app.burst_size_io_tx_read) > APP_MBUF_ARRAY_SIZE) || - (app.burst_size_io_tx_write > APP_MBUF_ARRAY_SIZE)) { - return -8; - } - - return 0; -} - -#ifndef APP_ARG_NUMERICAL_SIZE_CHARS -#define APP_ARG_NUMERICAL_SIZE_CHARS 15 -#endif - -static int -parse_arg_pos_lb(const char *arg) -{ - uint32_t x; - char *endpt; - - if (strnlen(arg, APP_ARG_NUMERICAL_SIZE_CHARS + 1) == APP_ARG_NUMERICAL_SIZE_CHARS + 1) { - return -1; - } - - errno = 0; - x = strtoul(arg, &endpt, 10); - if (errno != 0 || endpt == arg || *endpt != '\0'){ - return -2; - } - - if (x >= 64) { - return -3; - } - - app.pos_lb = (uint8_t) x; - - return 0; -} - -/* Parse the argument given in the command line of the application */ -int -app_parse_args(int argc, char **argv) -{ - int opt, ret; - char **argvopt; - int option_index; - char *prgname = argv[0]; - static struct option lgopts[] = { - {"rx", 1, 0, 0}, - {"tx", 1, 0, 0}, - {"w", 1, 0, 0}, - {"lpm", 1, 0, 0}, - {"rsz", 1, 0, 0}, - {"bsz", 1, 0, 0}, - {"pos-lb", 1, 0, 0}, - {NULL, 0, 0, 0} - }; - uint32_t arg_w = 0; - uint32_t arg_rx = 0; - uint32_t arg_tx = 0; - uint32_t arg_lpm = 0; - uint32_t arg_rsz = 0; - uint32_t arg_bsz = 0; - uint32_t arg_pos_lb = 0; - - argvopt = argv; - - while ((opt = getopt_long(argc, argvopt, "", - lgopts, &option_index)) != EOF) { - - switch (opt) { - /* long options */ - case 0: - if (!strcmp(lgopts[option_index].name, "rx")) { - arg_rx = 1; - ret = parse_arg_rx(optarg); - if (ret) { - printf("Incorrect value for --rx argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "tx")) { - arg_tx = 1; - ret = parse_arg_tx(optarg); - if (ret) { - printf("Incorrect value for --tx argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "w")) { - arg_w = 1; - ret = parse_arg_w(optarg); - if (ret) { - printf("Incorrect value for --w argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "lpm")) { - arg_lpm = 1; - ret = parse_arg_lpm(optarg); - if (ret) { - printf("Incorrect value for --lpm argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "rsz")) { - arg_rsz = 1; - ret = parse_arg_rsz(optarg); - if (ret) { - printf("Incorrect value for --rsz argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "bsz")) { - arg_bsz = 1; - ret = parse_arg_bsz(optarg); - if (ret) { - printf("Incorrect value for --bsz argument (%d)\n", ret); - return -1; - } - } - if (!strcmp(lgopts[option_index].name, "pos-lb")) { - arg_pos_lb = 1; - ret = parse_arg_pos_lb(optarg); - if (ret) { - printf("Incorrect value for --pos-lb argument (%d)\n", ret); - return -1; - } - } - break; - - default: - return -1; - } - } - - /* Check that all mandatory arguments are provided */ - if ((arg_rx == 0) || (arg_tx == 0) || (arg_w == 0) || (arg_lpm == 0)){ - printf("Not all mandatory arguments are present\n"); - return -1; - } - - /* Assign default values for the optional arguments not provided */ - if (arg_rsz == 0) { - app.nic_rx_ring_size = APP_DEFAULT_NIC_RX_RING_SIZE; - app.nic_tx_ring_size = APP_DEFAULT_NIC_TX_RING_SIZE; - app.ring_rx_size = APP_DEFAULT_RING_RX_SIZE; - app.ring_tx_size = APP_DEFAULT_RING_TX_SIZE; - } - - if (arg_bsz == 0) { - app.burst_size_io_rx_read = APP_DEFAULT_BURST_SIZE_IO_RX_READ; - app.burst_size_io_rx_write = APP_DEFAULT_BURST_SIZE_IO_RX_WRITE; - app.burst_size_io_tx_read = APP_DEFAULT_BURST_SIZE_IO_TX_READ; - app.burst_size_io_tx_write = APP_DEFAULT_BURST_SIZE_IO_TX_WRITE; - app.burst_size_worker_read = APP_DEFAULT_BURST_SIZE_WORKER_READ; - app.burst_size_worker_write = APP_DEFAULT_BURST_SIZE_WORKER_WRITE; - } - - if (arg_pos_lb == 0) { - app.pos_lb = APP_DEFAULT_IO_RX_LB_POS; - } - - /* Check cross-consistency of arguments */ - if ((ret = app_check_lpm_table()) < 0) { - printf("At least one LPM rule is inconsistent (%d)\n", ret); - return -1; - } - if (app_check_every_rx_port_is_tx_enabled() < 0) { - printf("On LPM lookup miss, packet is sent back on the input port.\n"); - printf("At least one RX port is not enabled for TX.\n"); - return -2; - } - - if (optind >= 0) - argv[optind - 1] = prgname; - - ret = optind - 1; - optind = 1; /* reset getopt lib */ - return ret; -} - -int -app_get_nic_rx_queues_per_port(uint16_t port) -{ - uint32_t i, count; - - if (port >= APP_MAX_NIC_PORTS) { - return -1; - } - - count = 0; - for (i = 0; i < APP_MAX_RX_QUEUES_PER_NIC_PORT; i ++) { - if (app.nic_rx_queue_mask[port][i] == 1) { - count ++; - } - } - - return count; -} - -int -app_get_lcore_for_nic_rx(uint16_t port, uint8_t queue, uint32_t *lcore_out) -{ - uint32_t lcore; - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - uint32_t i; - - if (app.lcore_params[lcore].type != e_APP_LCORE_IO) { - continue; - } - - const size_t n_queues = RTE_MIN(lp->rx.n_nic_queues, - RTE_DIM(lp->rx.nic_queues)); - for (i = 0; i < n_queues; i ++) { - if ((lp->rx.nic_queues[i].port == port) && - (lp->rx.nic_queues[i].queue == queue)) { - *lcore_out = lcore; - return 0; - } - } - } - - return -1; -} - -int -app_get_lcore_for_nic_tx(uint16_t port, uint32_t *lcore_out) -{ - uint32_t lcore; - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - uint32_t i; - - if (app.lcore_params[lcore].type != e_APP_LCORE_IO) { - continue; - } - - const size_t n_ports = RTE_MIN(lp->tx.n_nic_ports, - RTE_DIM(lp->tx.nic_ports)); - for (i = 0; i < n_ports; i ++) { - if (lp->tx.nic_ports[i] == port) { - *lcore_out = lcore; - return 0; - } - } - } - - return -1; -} - -int -app_is_socket_used(uint32_t socket) -{ - uint32_t lcore; - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - if (app.lcore_params[lcore].type == e_APP_LCORE_DISABLED) { - continue; - } - - if (socket == rte_lcore_to_socket_id(lcore)) { - return 1; - } - } - - return 0; -} - -uint32_t -app_get_lcores_io_rx(void) -{ - uint32_t lcore, count; - - count = 0; - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp_io = &app.lcore_params[lcore].io; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp_io->rx.n_nic_queues == 0)) { - continue; - } - - count ++; - } - - return count; -} - -uint32_t -app_get_lcores_worker(void) -{ - uint32_t lcore, count; - - count = 0; - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - count ++; - } - - if (count > APP_MAX_WORKER_LCORES) { - rte_panic("Algorithmic error (too many worker lcores)\n"); - return 0; - } - - return count; -} - -void -app_print_params(void) -{ - unsigned port, queue, lcore, rule, i, j; - - /* Print NIC RX configuration */ - printf("NIC RX ports: "); - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - uint32_t n_rx_queues = app_get_nic_rx_queues_per_port(port); - - if (n_rx_queues == 0) { - continue; - } - - printf("%u (", port); - for (queue = 0; queue < APP_MAX_RX_QUEUES_PER_NIC_PORT; queue ++) { - if (app.nic_rx_queue_mask[port][queue] == 1) { - printf("%u ", queue); - } - } - printf(") "); - } - printf(";\n"); - - /* Print I/O lcore RX params */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp->rx.n_nic_queues == 0)) { - continue; - } - - printf("I/O lcore %u (socket %u): ", lcore, rte_lcore_to_socket_id(lcore)); - - printf("RX ports "); - for (i = 0; i < lp->rx.n_nic_queues; i ++) { - printf("(%u, %u) ", - (unsigned) lp->rx.nic_queues[i].port, - (unsigned) lp->rx.nic_queues[i].queue); - } - printf("; "); - - printf("Output rings "); - for (i = 0; i < lp->rx.n_rings; i ++) { - printf("%p ", lp->rx.rings[i]); - } - printf(";\n"); - } - - /* Print worker lcore RX params */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp = &app.lcore_params[lcore].worker; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - printf("Worker lcore %u (socket %u) ID %u: ", - lcore, - rte_lcore_to_socket_id(lcore), - (unsigned)lp->worker_id); - - printf("Input rings "); - for (i = 0; i < lp->n_rings_in; i ++) { - printf("%p ", lp->rings_in[i]); - } - - printf(";\n"); - } - - printf("\n"); - - /* Print NIC TX configuration */ - printf("NIC TX ports: "); - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - if (app.nic_tx_port_mask[port] == 1) { - printf("%u ", port); - } - } - printf(";\n"); - - /* Print I/O TX lcore params */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - uint32_t n_workers = app_get_lcores_worker(); - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp->tx.n_nic_ports == 0)) { - continue; - } - - printf("I/O lcore %u (socket %u): ", lcore, rte_lcore_to_socket_id(lcore)); - - printf("Input rings per TX port "); - for (i = 0; i < lp->tx.n_nic_ports; i ++) { - port = lp->tx.nic_ports[i]; - - printf("%u (", port); - for (j = 0; j < n_workers; j ++) { - printf("%p ", lp->tx.rings[port][j]); - } - printf(") "); - - } - - printf(";\n"); - } - - /* Print worker lcore TX params */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp = &app.lcore_params[lcore].worker; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - printf("Worker lcore %u (socket %u) ID %u: \n", - lcore, - rte_lcore_to_socket_id(lcore), - (unsigned)lp->worker_id); - - printf("Output rings per TX port "); - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - if (lp->rings_out[port] != NULL) { - printf("%u (%p) ", port, lp->rings_out[port]); - } - } - - printf(";\n"); - } - - /* Print LPM rules */ - printf("LPM rules: \n"); - for (rule = 0; rule < app.n_lpm_rules; rule ++) { - uint32_t ip = app.lpm_rules[rule].ip; - uint8_t depth = app.lpm_rules[rule].depth; - uint8_t if_out = app.lpm_rules[rule].if_out; - - printf("\t%u: %u.%u.%u.%u/%u => %u;\n", - rule, - (unsigned) (ip & 0xFF000000) >> 24, - (unsigned) (ip & 0x00FF0000) >> 16, - (unsigned) (ip & 0x0000FF00) >> 8, - (unsigned) ip & 0x000000FF, - (unsigned) depth, - (unsigned) if_out - ); - } - - /* Rings */ - printf("Ring sizes: NIC RX = %u; Worker in = %u; Worker out = %u; NIC TX = %u;\n", - (unsigned) app.nic_rx_ring_size, - (unsigned) app.ring_rx_size, - (unsigned) app.ring_tx_size, - (unsigned) app.nic_tx_ring_size); - - /* Bursts */ - printf("Burst sizes: I/O RX (rd = %u, wr = %u); Worker (rd = %u, wr = %u); I/O TX (rd = %u, wr = %u)\n", - (unsigned) app.burst_size_io_rx_read, - (unsigned) app.burst_size_io_rx_write, - (unsigned) app.burst_size_worker_read, - (unsigned) app.burst_size_worker_write, - (unsigned) app.burst_size_io_tx_read, - (unsigned) app.burst_size_io_tx_write); -} diff --git a/examples/load_balancer/init.c b/examples/load_balancer/init.c deleted file mode 100644 index 762226754..000000000 --- a/examples/load_balancer/init.c +++ /dev/null @@ -1,537 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_ring.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_string_fns.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_lpm.h> - -#include "main.h" - -static struct rte_eth_conf port_conf = { - .rxmode = { - .mq_mode = ETH_MQ_RX_RSS, - .split_hdr_size = 0, - .offloads = DEV_RX_OFFLOAD_CHECKSUM, - }, - .rx_adv_conf = { - .rss_conf = { - .rss_key = NULL, - .rss_hf = ETH_RSS_IP, - }, - }, - .txmode = { - .mq_mode = ETH_MQ_TX_NONE, - }, -}; - -static void -app_assign_worker_ids(void) -{ - uint32_t lcore, worker_id; - - /* Assign ID for each worker */ - worker_id = 0; - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp_worker = &app.lcore_params[lcore].worker; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - lp_worker->worker_id = worker_id; - worker_id ++; - } -} - -static void -app_init_mbuf_pools(void) -{ - unsigned socket, lcore; - - /* Init the buffer pools */ - for (socket = 0; socket < APP_MAX_SOCKETS; socket ++) { - char name[32]; - if (app_is_socket_used(socket) == 0) { - continue; - } - - snprintf(name, sizeof(name), "mbuf_pool_%u", socket); - printf("Creating the mbuf pool for socket %u ...\n", socket); - app.pools[socket] = rte_pktmbuf_pool_create( - name, APP_DEFAULT_MEMPOOL_BUFFERS, - APP_DEFAULT_MEMPOOL_CACHE_SIZE, - 0, APP_DEFAULT_MBUF_DATA_SIZE, socket); - if (app.pools[socket] == NULL) { - rte_panic("Cannot create mbuf pool on socket %u\n", socket); - } - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - if (app.lcore_params[lcore].type == e_APP_LCORE_DISABLED) { - continue; - } - - socket = rte_lcore_to_socket_id(lcore); - app.lcore_params[lcore].pool = app.pools[socket]; - } -} - -static void -app_init_lpm_tables(void) -{ - unsigned socket, lcore; - - /* Init the LPM tables */ - for (socket = 0; socket < APP_MAX_SOCKETS; socket ++) { - char name[32]; - uint32_t rule; - - if (app_is_socket_used(socket) == 0) { - continue; - } - - struct rte_lpm_config lpm_config; - - lpm_config.max_rules = APP_MAX_LPM_RULES; - lpm_config.number_tbl8s = 256; - lpm_config.flags = 0; - snprintf(name, sizeof(name), "lpm_table_%u", socket); - printf("Creating the LPM table for socket %u ...\n", socket); - app.lpm_tables[socket] = rte_lpm_create( - name, - socket, - &lpm_config); - if (app.lpm_tables[socket] == NULL) { - rte_panic("Unable to create LPM table on socket %u\n", socket); - } - - for (rule = 0; rule < app.n_lpm_rules; rule ++) { - int ret; - - ret = rte_lpm_add(app.lpm_tables[socket], - app.lpm_rules[rule].ip, - app.lpm_rules[rule].depth, - app.lpm_rules[rule].if_out); - - if (ret < 0) { - rte_panic("Unable to add entry %u (%x/%u => %u) to the LPM table on socket %u (%d)\n", - (unsigned) rule, - (unsigned) app.lpm_rules[rule].ip, - (unsigned) app.lpm_rules[rule].depth, - (unsigned) app.lpm_rules[rule].if_out, - socket, - ret); - } - } - - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - socket = rte_lcore_to_socket_id(lcore); - app.lcore_params[lcore].worker.lpm_table = app.lpm_tables[socket]; - } -} - -static void -app_init_rings_rx(void) -{ - unsigned lcore; - - /* Initialize the rings for the RX side */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp_io = &app.lcore_params[lcore].io; - unsigned socket_io, lcore_worker; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp_io->rx.n_nic_queues == 0)) { - continue; - } - - socket_io = rte_lcore_to_socket_id(lcore); - - for (lcore_worker = 0; lcore_worker < APP_MAX_LCORES; lcore_worker ++) { - char name[32]; - struct app_lcore_params_worker *lp_worker = &app.lcore_params[lcore_worker].worker; - struct rte_ring *ring = NULL; - - if (app.lcore_params[lcore_worker].type != e_APP_LCORE_WORKER) { - continue; - } - - printf("Creating ring to connect I/O lcore %u (socket %u) with worker lcore %u ...\n", - lcore, - socket_io, - lcore_worker); - snprintf(name, sizeof(name), "app_ring_rx_s%u_io%u_w%u", - socket_io, - lcore, - lcore_worker); - ring = rte_ring_create( - name, - app.ring_rx_size, - socket_io, - RING_F_SP_ENQ | RING_F_SC_DEQ); - if (ring == NULL) { - rte_panic("Cannot create ring to connect I/O core %u with worker core %u\n", - lcore, - lcore_worker); - } - - lp_io->rx.rings[lp_io->rx.n_rings] = ring; - lp_io->rx.n_rings ++; - - lp_worker->rings_in[lp_worker->n_rings_in] = ring; - lp_worker->n_rings_in ++; - } - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp_io = &app.lcore_params[lcore].io; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp_io->rx.n_nic_queues == 0)) { - continue; - } - - if (lp_io->rx.n_rings != app_get_lcores_worker()) { - rte_panic("Algorithmic error (I/O RX rings)\n"); - } - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp_worker = &app.lcore_params[lcore].worker; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - if (lp_worker->n_rings_in != app_get_lcores_io_rx()) { - rte_panic("Algorithmic error (worker input rings)\n"); - } - } -} - -static void -app_init_rings_tx(void) -{ - unsigned lcore; - - /* Initialize the rings for the TX side */ - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_worker *lp_worker = &app.lcore_params[lcore].worker; - unsigned port; - - if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { - continue; - } - - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - char name[32]; - struct app_lcore_params_io *lp_io = NULL; - struct rte_ring *ring; - uint32_t socket_io, lcore_io; - - if (app.nic_tx_port_mask[port] == 0) { - continue; - } - - if (app_get_lcore_for_nic_tx(port, &lcore_io) < 0) { - rte_panic("Algorithmic error (no I/O core to handle TX of port %u)\n", - port); - } - - lp_io = &app.lcore_params[lcore_io].io; - socket_io = rte_lcore_to_socket_id(lcore_io); - - printf("Creating ring to connect worker lcore %u with TX port %u (through I/O lcore %u) (socket %u) ...\n", - lcore, port, (unsigned)lcore_io, (unsigned)socket_io); - snprintf(name, sizeof(name), "app_ring_tx_s%u_w%u_p%u", socket_io, lcore, port); - ring = rte_ring_create( - name, - app.ring_tx_size, - socket_io, - RING_F_SP_ENQ | RING_F_SC_DEQ); - if (ring == NULL) { - rte_panic("Cannot create ring to connect worker core %u with TX port %u\n", - lcore, - port); - } - - lp_worker->rings_out[port] = ring; - lp_io->tx.rings[port][lp_worker->worker_id] = ring; - } - } - - for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { - struct app_lcore_params_io *lp_io = &app.lcore_params[lcore].io; - unsigned i; - - if ((app.lcore_params[lcore].type != e_APP_LCORE_IO) || - (lp_io->tx.n_nic_ports == 0)) { - continue; - } - - for (i = 0; i < lp_io->tx.n_nic_ports; i ++){ - unsigned port, j; - - port = lp_io->tx.nic_ports[i]; - for (j = 0; j < app_get_lcores_worker(); j ++) { - if (lp_io->tx.rings[port][j] == NULL) { - rte_panic("Algorithmic error (I/O TX rings)\n"); - } - } - } - } -} - -/* Check the link status of all ports in up to 9s, and print them finally */ -static void -check_all_ports_link_status(uint16_t port_num, uint32_t port_mask) -{ -#define CHECK_INTERVAL 100 /* 100ms */ -#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ - uint16_t portid; - uint8_t count, all_ports_up, print_flag = 0; - struct rte_eth_link link; - int ret; - uint32_t n_rx_queues, n_tx_queues; - - printf("\nChecking link status"); - fflush(stdout); - for (count = 0; count <= MAX_CHECK_TIME; count++) { - all_ports_up = 1; - for (portid = 0; portid < port_num; portid++) { - if ((port_mask & (1 << portid)) == 0) - continue; - n_rx_queues = app_get_nic_rx_queues_per_port(portid); - n_tx_queues = app.nic_tx_port_mask[portid]; - if ((n_rx_queues == 0) && (n_tx_queues == 0)) - continue; - memset(&link, 0, sizeof(link)); - ret = rte_eth_link_get_nowait(portid, &link); - if (ret < 0) { - all_ports_up = 0; - if (print_flag == 1) - printf("Port %u link get failed: %s\n", - portid, rte_strerror(-ret)); - continue; - } - /* print link status if flag set */ - if (print_flag == 1) { - if (link.link_status) - printf( - "Port%d Link Up - speed %uMbps - %s\n", - portid, link.link_speed, - (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? - ("full-duplex") : ("half-duplex\n")); - else - printf("Port %d Link Down\n", portid); - continue; - } - /* clear all_ports_up flag if any link down */ - if (link.link_status == ETH_LINK_DOWN) { - all_ports_up = 0; - break; - } - } - /* after finally printing all link status, get out */ - if (print_flag == 1) - break; - - if (all_ports_up == 0) { - printf("."); - fflush(stdout); - rte_delay_ms(CHECK_INTERVAL); - } - - /* set the print_flag if all ports up or timeout */ - if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { - print_flag = 1; - printf("done\n"); - } - } -} - -static void -app_init_nics(void) -{ - unsigned socket; - uint32_t lcore; - uint16_t port; - uint8_t queue; - int ret; - uint32_t n_rx_queues, n_tx_queues; - - /* Init NIC ports and queues, then start the ports */ - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - struct rte_mempool *pool; - uint16_t nic_rx_ring_size; - uint16_t nic_tx_ring_size; - struct rte_eth_rxconf rxq_conf; - struct rte_eth_txconf txq_conf; - struct rte_eth_dev_info dev_info; - struct rte_eth_conf local_port_conf = port_conf; - - n_rx_queues = app_get_nic_rx_queues_per_port(port); - n_tx_queues = app.nic_tx_port_mask[port]; - - if ((n_rx_queues == 0) && (n_tx_queues == 0)) { - continue; - } - - /* Init port */ - printf("Initializing NIC port %u ...\n", port); - - ret = rte_eth_dev_info_get(port, &dev_info); - if (ret != 0) - rte_panic("Error during getting device (port %u) info: %s\n", - port, strerror(-ret)); - - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - - local_port_conf.rx_adv_conf.rss_conf.rss_hf &= - dev_info.flow_type_rss_offloads; - if (local_port_conf.rx_adv_conf.rss_conf.rss_hf != - port_conf.rx_adv_conf.rss_conf.rss_hf) { - printf("Port %u modified RSS hash function based on hardware support," - "requested:%#"PRIx64" configured:%#"PRIx64"\n", - port, - port_conf.rx_adv_conf.rss_conf.rss_hf, - local_port_conf.rx_adv_conf.rss_conf.rss_hf); - } - - ret = rte_eth_dev_configure( - port, - (uint8_t) n_rx_queues, - (uint8_t) n_tx_queues, - &local_port_conf); - if (ret < 0) { - rte_panic("Cannot init NIC port %u (%d)\n", port, ret); - } - - ret = rte_eth_promiscuous_enable(port); - if (ret != 0) - rte_panic("Cannot enable promiscuous mode on port %u (%s)\n", - port, rte_strerror(-ret)); - - nic_rx_ring_size = app.nic_rx_ring_size; - nic_tx_ring_size = app.nic_tx_ring_size; - ret = rte_eth_dev_adjust_nb_rx_tx_desc( - port, &nic_rx_ring_size, &nic_tx_ring_size); - if (ret < 0) { - rte_panic("Cannot adjust number of descriptors for port %u (%d)\n", - port, ret); - } - app.nic_rx_ring_size = nic_rx_ring_size; - app.nic_tx_ring_size = nic_tx_ring_size; - - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = local_port_conf.rxmode.offloads; - /* Init RX queues */ - for (queue = 0; queue < APP_MAX_RX_QUEUES_PER_NIC_PORT; queue ++) { - if (app.nic_rx_queue_mask[port][queue] == 0) { - continue; - } - - app_get_lcore_for_nic_rx(port, queue, &lcore); - socket = rte_lcore_to_socket_id(lcore); - pool = app.lcore_params[lcore].pool; - - printf("Initializing NIC port %u RX queue %u ...\n", - port, queue); - ret = rte_eth_rx_queue_setup( - port, - queue, - (uint16_t) app.nic_rx_ring_size, - socket, - &rxq_conf, - pool); - if (ret < 0) { - rte_panic("Cannot init RX queue %u for port %u (%d)\n", - queue, port, ret); - } - } - - txq_conf = dev_info.default_txconf; - txq_conf.offloads = local_port_conf.txmode.offloads; - /* Init TX queues */ - if (app.nic_tx_port_mask[port] == 1) { - app_get_lcore_for_nic_tx(port, &lcore); - socket = rte_lcore_to_socket_id(lcore); - printf("Initializing NIC port %u TX queue 0 ...\n", - port); - ret = rte_eth_tx_queue_setup( - port, - 0, - (uint16_t) app.nic_tx_ring_size, - socket, - &txq_conf); - if (ret < 0) { - rte_panic("Cannot init TX queue 0 for port %d (%d)\n", - port, - ret); - } - } - - /* Start port */ - ret = rte_eth_dev_start(port); - if (ret < 0) { - rte_panic("Cannot start port %d (%d)\n", port, ret); - } - } - - check_all_ports_link_status(APP_MAX_NIC_PORTS, (~0x0)); -} - -void -app_init(void) -{ - app_assign_worker_ids(); - app_init_mbuf_pools(); - app_init_lpm_tables(); - app_init_rings_rx(); - app_init_rings_tx(); - app_init_nics(); - - printf("Initialization completed.\n"); -} diff --git a/examples/load_balancer/main.c b/examples/load_balancer/main.c deleted file mode 100644 index d3dcb235d..000000000 --- a/examples/load_balancer/main.c +++ /dev/null @@ -1,76 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> -#include <unistd.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_lpm.h> - -#include "main.h" - -int -main(int argc, char **argv) -{ - uint32_t lcore; - int ret; - - /* Init EAL */ - ret = rte_eal_init(argc, argv); - if (ret < 0) - return -1; - argc -= ret; - argv += ret; - - /* Parse application arguments (after the EAL ones) */ - ret = app_parse_args(argc, argv); - if (ret < 0) { - app_print_usage(); - return -1; - } - - /* Init */ - app_init(); - app_print_params(); - - /* Launch per-lcore init on every lcore */ - rte_eal_mp_remote_launch(app_lcore_main_loop, NULL, CALL_MASTER); - RTE_LCORE_FOREACH_SLAVE(lcore) { - if (rte_eal_wait_lcore(lcore) < 0) { - return -1; - } - } - - return 0; -} diff --git a/examples/load_balancer/main.h b/examples/load_balancer/main.h deleted file mode 100644 index 9fefb62ed..000000000 --- a/examples/load_balancer/main.h +++ /dev/null @@ -1,351 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifndef _MAIN_H_ -#define _MAIN_H_ - -/* Logical cores */ -#ifndef APP_MAX_SOCKETS -#define APP_MAX_SOCKETS 2 -#endif - -#ifndef APP_MAX_LCORES -#define APP_MAX_LCORES RTE_MAX_LCORE -#endif - -#ifndef APP_MAX_NIC_PORTS -#define APP_MAX_NIC_PORTS RTE_MAX_ETHPORTS -#endif - -#ifndef APP_MAX_RX_QUEUES_PER_NIC_PORT -#define APP_MAX_RX_QUEUES_PER_NIC_PORT 128 -#endif - -#ifndef APP_MAX_TX_QUEUES_PER_NIC_PORT -#define APP_MAX_TX_QUEUES_PER_NIC_PORT 128 -#endif - -#ifndef APP_MAX_IO_LCORES -#if (APP_MAX_LCORES > 16) -#define APP_MAX_IO_LCORES 16 -#else -#define APP_MAX_IO_LCORES APP_MAX_LCORES -#endif -#endif -#if (APP_MAX_IO_LCORES > APP_MAX_LCORES) -#error "APP_MAX_IO_LCORES is too big" -#endif - -#ifndef APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE -#define APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE 16 -#endif - -#ifndef APP_MAX_NIC_TX_PORTS_PER_IO_LCORE -#define APP_MAX_NIC_TX_PORTS_PER_IO_LCORE 16 -#endif -#if (APP_MAX_NIC_TX_PORTS_PER_IO_LCORE > APP_MAX_NIC_PORTS) -#error "APP_MAX_NIC_TX_PORTS_PER_IO_LCORE too big" -#endif - -#ifndef APP_MAX_WORKER_LCORES -#if (APP_MAX_LCORES > 16) -#define APP_MAX_WORKER_LCORES 16 -#else -#define APP_MAX_WORKER_LCORES APP_MAX_LCORES -#endif -#endif -#if (APP_MAX_WORKER_LCORES > APP_MAX_LCORES) -#error "APP_MAX_WORKER_LCORES is too big" -#endif - - -/* Mempools */ -#ifndef APP_DEFAULT_MBUF_DATA_SIZE -#define APP_DEFAULT_MBUF_DATA_SIZE RTE_MBUF_DEFAULT_BUF_SIZE -#endif - -#ifndef APP_DEFAULT_MEMPOOL_BUFFERS -#define APP_DEFAULT_MEMPOOL_BUFFERS 8192 * 4 -#endif - -#ifndef APP_DEFAULT_MEMPOOL_CACHE_SIZE -#define APP_DEFAULT_MEMPOOL_CACHE_SIZE 256 -#endif - -/* LPM Tables */ -#ifndef APP_MAX_LPM_RULES -#define APP_MAX_LPM_RULES 1024 -#endif - -/* NIC RX */ -#ifndef APP_DEFAULT_NIC_RX_RING_SIZE -#define APP_DEFAULT_NIC_RX_RING_SIZE 1024 -#endif - -/* - * RX and TX Prefetch, Host, and Write-back threshold values should be - * carefully set for optimal performance. Consult the network - * controller's datasheet and supporting DPDK documentation for guidance - * on how these parameters should be set. - */ -#ifndef APP_DEFAULT_NIC_RX_PTHRESH -#define APP_DEFAULT_NIC_RX_PTHRESH 8 -#endif - -#ifndef APP_DEFAULT_NIC_RX_HTHRESH -#define APP_DEFAULT_NIC_RX_HTHRESH 8 -#endif - -#ifndef APP_DEFAULT_NIC_RX_WTHRESH -#define APP_DEFAULT_NIC_RX_WTHRESH 4 -#endif - -#ifndef APP_DEFAULT_NIC_RX_FREE_THRESH -#define APP_DEFAULT_NIC_RX_FREE_THRESH 64 -#endif - -#ifndef APP_DEFAULT_NIC_RX_DROP_EN -#define APP_DEFAULT_NIC_RX_DROP_EN 0 -#endif - -/* NIC TX */ -#ifndef APP_DEFAULT_NIC_TX_RING_SIZE -#define APP_DEFAULT_NIC_TX_RING_SIZE 1024 -#endif - -/* - * These default values are optimized for use with the Intel(R) 82599 10 GbE - * Controller and the DPDK ixgbe PMD. Consider using other values for other - * network controllers and/or network drivers. - */ -#ifndef APP_DEFAULT_NIC_TX_PTHRESH -#define APP_DEFAULT_NIC_TX_PTHRESH 36 -#endif - -#ifndef APP_DEFAULT_NIC_TX_HTHRESH -#define APP_DEFAULT_NIC_TX_HTHRESH 0 -#endif - -#ifndef APP_DEFAULT_NIC_TX_WTHRESH -#define APP_DEFAULT_NIC_TX_WTHRESH 0 -#endif - -#ifndef APP_DEFAULT_NIC_TX_FREE_THRESH -#define APP_DEFAULT_NIC_TX_FREE_THRESH 0 -#endif - -#ifndef APP_DEFAULT_NIC_TX_RS_THRESH -#define APP_DEFAULT_NIC_TX_RS_THRESH 0 -#endif - -/* Software Rings */ -#ifndef APP_DEFAULT_RING_RX_SIZE -#define APP_DEFAULT_RING_RX_SIZE 1024 -#endif - -#ifndef APP_DEFAULT_RING_TX_SIZE -#define APP_DEFAULT_RING_TX_SIZE 1024 -#endif - -/* Bursts */ -#ifndef APP_MBUF_ARRAY_SIZE -#define APP_MBUF_ARRAY_SIZE 512 -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_IO_RX_READ -#define APP_DEFAULT_BURST_SIZE_IO_RX_READ 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_IO_RX_READ > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_IO_RX_READ is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_IO_RX_WRITE -#define APP_DEFAULT_BURST_SIZE_IO_RX_WRITE 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_IO_RX_WRITE > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_IO_RX_WRITE is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_IO_TX_READ -#define APP_DEFAULT_BURST_SIZE_IO_TX_READ 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_IO_TX_READ > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_IO_TX_READ is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_IO_TX_WRITE -#define APP_DEFAULT_BURST_SIZE_IO_TX_WRITE 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_IO_TX_WRITE > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_IO_TX_WRITE is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_WORKER_READ -#define APP_DEFAULT_BURST_SIZE_WORKER_READ 144 -#endif -#if ((2 * APP_DEFAULT_BURST_SIZE_WORKER_READ) > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_WORKER_READ is too big" -#endif - -#ifndef APP_DEFAULT_BURST_SIZE_WORKER_WRITE -#define APP_DEFAULT_BURST_SIZE_WORKER_WRITE 144 -#endif -#if (APP_DEFAULT_BURST_SIZE_WORKER_WRITE > APP_MBUF_ARRAY_SIZE) -#error "APP_DEFAULT_BURST_SIZE_WORKER_WRITE is too big" -#endif - -/* Load balancing logic */ -#ifndef APP_DEFAULT_IO_RX_LB_POS -#define APP_DEFAULT_IO_RX_LB_POS 29 -#endif -#if (APP_DEFAULT_IO_RX_LB_POS >= 64) -#error "APP_DEFAULT_IO_RX_LB_POS is too big" -#endif - -struct app_mbuf_array { - struct rte_mbuf *array[APP_MBUF_ARRAY_SIZE]; - uint32_t n_mbufs; -}; - -enum app_lcore_type { - e_APP_LCORE_DISABLED = 0, - e_APP_LCORE_IO, - e_APP_LCORE_WORKER -}; - -struct app_lcore_params_io { - /* I/O RX */ - struct { - /* NIC */ - struct { - uint16_t port; - uint8_t queue; - } nic_queues[APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE]; - uint32_t n_nic_queues; - - /* Rings */ - struct rte_ring *rings[APP_MAX_WORKER_LCORES]; - uint32_t n_rings; - - /* Internal buffers */ - struct app_mbuf_array mbuf_in; - struct app_mbuf_array mbuf_out[APP_MAX_WORKER_LCORES]; - uint8_t mbuf_out_flush[APP_MAX_WORKER_LCORES]; - - /* Stats */ - uint32_t nic_queues_count[APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE]; - uint32_t nic_queues_iters[APP_MAX_NIC_RX_QUEUES_PER_IO_LCORE]; - uint32_t rings_count[APP_MAX_WORKER_LCORES]; - uint32_t rings_iters[APP_MAX_WORKER_LCORES]; - } rx; - - /* I/O TX */ - struct { - /* Rings */ - struct rte_ring *rings[APP_MAX_NIC_PORTS][APP_MAX_WORKER_LCORES]; - - /* NIC */ - uint16_t nic_ports[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - uint32_t n_nic_ports; - - /* Internal buffers */ - struct app_mbuf_array mbuf_out[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - uint8_t mbuf_out_flush[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - - /* Stats */ - uint32_t rings_count[APP_MAX_NIC_PORTS][APP_MAX_WORKER_LCORES]; - uint32_t rings_iters[APP_MAX_NIC_PORTS][APP_MAX_WORKER_LCORES]; - uint32_t nic_ports_count[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - uint32_t nic_ports_iters[APP_MAX_NIC_TX_PORTS_PER_IO_LCORE]; - } tx; -}; - -struct app_lcore_params_worker { - /* Rings */ - struct rte_ring *rings_in[APP_MAX_IO_LCORES]; - uint32_t n_rings_in; - struct rte_ring *rings_out[APP_MAX_NIC_PORTS]; - - /* LPM table */ - struct rte_lpm *lpm_table; - uint32_t worker_id; - - /* Internal buffers */ - struct app_mbuf_array mbuf_in; - struct app_mbuf_array mbuf_out[APP_MAX_NIC_PORTS]; - uint8_t mbuf_out_flush[APP_MAX_NIC_PORTS]; - - /* Stats */ - uint32_t rings_in_count[APP_MAX_IO_LCORES]; - uint32_t rings_in_iters[APP_MAX_IO_LCORES]; - uint32_t rings_out_count[APP_MAX_NIC_PORTS]; - uint32_t rings_out_iters[APP_MAX_NIC_PORTS]; -}; - -struct app_lcore_params { - union { - struct app_lcore_params_io io; - struct app_lcore_params_worker worker; - }; - enum app_lcore_type type; - struct rte_mempool *pool; -} __rte_cache_aligned; - -struct app_lpm_rule { - uint32_t ip; - uint8_t depth; - uint8_t if_out; -}; - -struct app_params { - /* lcore */ - struct app_lcore_params lcore_params[APP_MAX_LCORES]; - - /* NIC */ - uint8_t nic_rx_queue_mask[APP_MAX_NIC_PORTS][APP_MAX_RX_QUEUES_PER_NIC_PORT]; - uint8_t nic_tx_port_mask[APP_MAX_NIC_PORTS]; - - /* mbuf pools */ - struct rte_mempool *pools[APP_MAX_SOCKETS]; - - /* LPM tables */ - struct rte_lpm *lpm_tables[APP_MAX_SOCKETS]; - struct app_lpm_rule lpm_rules[APP_MAX_LPM_RULES]; - uint32_t n_lpm_rules; - - /* rings */ - uint32_t nic_rx_ring_size; - uint32_t nic_tx_ring_size; - uint32_t ring_rx_size; - uint32_t ring_tx_size; - - /* burst size */ - uint32_t burst_size_io_rx_read; - uint32_t burst_size_io_rx_write; - uint32_t burst_size_io_tx_read; - uint32_t burst_size_io_tx_write; - uint32_t burst_size_worker_read; - uint32_t burst_size_worker_write; - - /* load balancing */ - uint8_t pos_lb; -} __rte_cache_aligned; - -extern struct app_params app; - -int app_parse_args(int argc, char **argv); -void app_print_usage(void); -void app_init(void); -int app_lcore_main_loop(void *arg); - -int app_get_nic_rx_queues_per_port(uint16_t port); -int app_get_lcore_for_nic_rx(uint16_t port, uint8_t queue, - uint32_t *lcore_out); -int app_get_lcore_for_nic_tx(uint16_t port, uint32_t *lcore_out); -int app_is_socket_used(uint32_t socket); -uint32_t app_get_lcores_io_rx(void); -uint32_t app_get_lcores_worker(void); -void app_print_params(void); - -#endif /* _MAIN_H_ */ diff --git a/examples/load_balancer/meson.build b/examples/load_balancer/meson.build deleted file mode 100644 index 4f7ac3999..000000000 --- a/examples/load_balancer/meson.build +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright(c) 2017 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' - -deps += 'lpm' -sources = files( - 'config.c', 'init.c', 'main.c', 'runtime.c' -) diff --git a/examples/load_balancer/runtime.c b/examples/load_balancer/runtime.c deleted file mode 100644 index f0aad1513..000000000 --- a/examples/load_balancer/runtime.c +++ /dev/null @@ -1,642 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.h> -#include <sys/types.h> -#include <string.h> -#include <sys/queue.h> -#include <stdarg.h> -#include <errno.h> -#include <getopt.h> - -#include <rte_common.h> -#include <rte_byteorder.h> -#include <rte_log.h> -#include <rte_memory.h> -#include <rte_memcpy.h> -#include <rte_eal.h> -#include <rte_launch.h> -#include <rte_atomic.h> -#include <rte_cycles.h> -#include <rte_prefetch.h> -#include <rte_lcore.h> -#include <rte_per_lcore.h> -#include <rte_branch_prediction.h> -#include <rte_interrupts.h> -#include <rte_random.h> -#include <rte_debug.h> -#include <rte_ether.h> -#include <rte_ethdev.h> -#include <rte_ring.h> -#include <rte_mempool.h> -#include <rte_mbuf.h> -#include <rte_ip.h> -#include <rte_tcp.h> -#include <rte_lpm.h> - -#include "main.h" - -#ifndef APP_LCORE_IO_FLUSH -#define APP_LCORE_IO_FLUSH 1000000 -#endif - -#ifndef APP_LCORE_WORKER_FLUSH -#define APP_LCORE_WORKER_FLUSH 1000000 -#endif - -#ifndef APP_STATS -#define APP_STATS 1000000 -#endif - -#define APP_IO_RX_DROP_ALL_PACKETS 0 -#define APP_WORKER_DROP_ALL_PACKETS 0 -#define APP_IO_TX_DROP_ALL_PACKETS 0 - -#ifndef APP_IO_RX_PREFETCH_ENABLE -#define APP_IO_RX_PREFETCH_ENABLE 1 -#endif - -#ifndef APP_WORKER_PREFETCH_ENABLE -#define APP_WORKER_PREFETCH_ENABLE 1 -#endif - -#ifndef APP_IO_TX_PREFETCH_ENABLE -#define APP_IO_TX_PREFETCH_ENABLE 1 -#endif - -#if APP_IO_RX_PREFETCH_ENABLE -#define APP_IO_RX_PREFETCH0(p) rte_prefetch0(p) -#define APP_IO_RX_PREFETCH1(p) rte_prefetch1(p) -#else -#define APP_IO_RX_PREFETCH0(p) -#define APP_IO_RX_PREFETCH1(p) -#endif - -#if APP_WORKER_PREFETCH_ENABLE -#define APP_WORKER_PREFETCH0(p) rte_prefetch0(p) -#define APP_WORKER_PREFETCH1(p) rte_prefetch1(p) -#else -#define APP_WORKER_PREFETCH0(p) -#define APP_WORKER_PREFETCH1(p) -#endif - -#if APP_IO_TX_PREFETCH_ENABLE -#define APP_IO_TX_PREFETCH0(p) rte_prefetch0(p) -#define APP_IO_TX_PREFETCH1(p) rte_prefetch1(p) -#else -#define APP_IO_TX_PREFETCH0(p) -#define APP_IO_TX_PREFETCH1(p) -#endif - -static inline void -app_lcore_io_rx_buffer_to_send ( - struct app_lcore_params_io *lp, - uint32_t worker, - struct rte_mbuf *mbuf, - uint32_t bsz) -{ - uint32_t pos; - int ret; - - pos = lp->rx.mbuf_out[worker].n_mbufs; - lp->rx.mbuf_out[worker].array[pos ++] = mbuf; - if (likely(pos < bsz)) { - lp->rx.mbuf_out[worker].n_mbufs = pos; - return; - } - - ret = rte_ring_sp_enqueue_bulk( - lp->rx.rings[worker], - (void **) lp->rx.mbuf_out[worker].array, - bsz, - NULL); - - if (unlikely(ret == 0)) { - uint32_t k; - for (k = 0; k < bsz; k ++) { - struct rte_mbuf *m = lp->rx.mbuf_out[worker].array[k]; - rte_pktmbuf_free(m); - } - } - - lp->rx.mbuf_out[worker].n_mbufs = 0; - lp->rx.mbuf_out_flush[worker] = 0; - -#if APP_STATS - lp->rx.rings_iters[worker] ++; - if (likely(ret == 0)) { - lp->rx.rings_count[worker] ++; - } - if (unlikely(lp->rx.rings_iters[worker] == APP_STATS)) { - unsigned lcore = rte_lcore_id(); - - printf("\tI/O RX %u out (worker %u): enq success rate = %.2f\n", - lcore, - (unsigned)worker, - ((double) lp->rx.rings_count[worker]) / ((double) lp->rx.rings_iters[worker])); - lp->rx.rings_iters[worker] = 0; - lp->rx.rings_count[worker] = 0; - } -#endif -} - -static inline void -app_lcore_io_rx( - struct app_lcore_params_io *lp, - uint32_t n_workers, - uint32_t bsz_rd, - uint32_t bsz_wr, - uint8_t pos_lb) -{ - struct rte_mbuf *mbuf_1_0, *mbuf_1_1, *mbuf_2_0, *mbuf_2_1; - uint8_t *data_1_0, *data_1_1 = NULL; - uint32_t i; - - for (i = 0; i < lp->rx.n_nic_queues; i ++) { - uint16_t port = lp->rx.nic_queues[i].port; - uint8_t queue = lp->rx.nic_queues[i].queue; - uint32_t n_mbufs, j; - - n_mbufs = rte_eth_rx_burst( - port, - queue, - lp->rx.mbuf_in.array, - (uint16_t) bsz_rd); - - if (unlikely(n_mbufs == 0)) { - continue; - } - -#if APP_STATS - lp->rx.nic_queues_iters[i] ++; - lp->rx.nic_queues_count[i] += n_mbufs; - if (unlikely(lp->rx.nic_queues_iters[i] == APP_STATS)) { - struct rte_eth_stats stats; - unsigned lcore = rte_lcore_id(); - - rte_eth_stats_get(port, &stats); - - printf("I/O RX %u in (NIC port %u): NIC drop ratio = %.2f avg burst size = %.2f\n", - lcore, - port, - (double) stats.imissed / (double) (stats.imissed + stats.ipackets), - ((double) lp->rx.nic_queues_count[i]) / ((double) lp->rx.nic_queues_iters[i])); - lp->rx.nic_queues_iters[i] = 0; - lp->rx.nic_queues_count[i] = 0; - } -#endif - -#if APP_IO_RX_DROP_ALL_PACKETS - for (j = 0; j < n_mbufs; j ++) { - struct rte_mbuf *pkt = lp->rx.mbuf_in.array[j]; - rte_pktmbuf_free(pkt); - } - - continue; -#endif - - mbuf_1_0 = lp->rx.mbuf_in.array[0]; - mbuf_1_1 = lp->rx.mbuf_in.array[1]; - data_1_0 = rte_pktmbuf_mtod(mbuf_1_0, uint8_t *); - if (likely(n_mbufs > 1)) { - data_1_1 = rte_pktmbuf_mtod(mbuf_1_1, uint8_t *); - } - - mbuf_2_0 = lp->rx.mbuf_in.array[2]; - mbuf_2_1 = lp->rx.mbuf_in.array[3]; - APP_IO_RX_PREFETCH0(mbuf_2_0); - APP_IO_RX_PREFETCH0(mbuf_2_1); - - for (j = 0; j + 3 < n_mbufs; j += 2) { - struct rte_mbuf *mbuf_0_0, *mbuf_0_1; - uint8_t *data_0_0, *data_0_1; - uint32_t worker_0, worker_1; - - mbuf_0_0 = mbuf_1_0; - mbuf_0_1 = mbuf_1_1; - data_0_0 = data_1_0; - data_0_1 = data_1_1; - - mbuf_1_0 = mbuf_2_0; - mbuf_1_1 = mbuf_2_1; - data_1_0 = rte_pktmbuf_mtod(mbuf_2_0, uint8_t *); - data_1_1 = rte_pktmbuf_mtod(mbuf_2_1, uint8_t *); - APP_IO_RX_PREFETCH0(data_1_0); - APP_IO_RX_PREFETCH0(data_1_1); - - mbuf_2_0 = lp->rx.mbuf_in.array[j+4]; - mbuf_2_1 = lp->rx.mbuf_in.array[j+5]; - APP_IO_RX_PREFETCH0(mbuf_2_0); - APP_IO_RX_PREFETCH0(mbuf_2_1); - - worker_0 = data_0_0[pos_lb] & (n_workers - 1); - worker_1 = data_0_1[pos_lb] & (n_workers - 1); - - app_lcore_io_rx_buffer_to_send(lp, worker_0, mbuf_0_0, bsz_wr); - app_lcore_io_rx_buffer_to_send(lp, worker_1, mbuf_0_1, bsz_wr); - } - - /* Handle the last 1, 2 (when n_mbufs is even) or 3 (when n_mbufs is odd) packets */ - for ( ; j < n_mbufs; j += 1) { - struct rte_mbuf *mbuf; - uint8_t *data; - uint32_t worker; - - mbuf = mbuf_1_0; - mbuf_1_0 = mbuf_1_1; - mbuf_1_1 = mbuf_2_0; - mbuf_2_0 = mbuf_2_1; - - data = rte_pktmbuf_mtod(mbuf, uint8_t *); - - APP_IO_RX_PREFETCH0(mbuf_1_0); - - worker = data[pos_lb] & (n_workers - 1); - - app_lcore_io_rx_buffer_to_send(lp, worker, mbuf, bsz_wr); - } - } -} - -static inline void -app_lcore_io_rx_flush(struct app_lcore_params_io *lp, uint32_t n_workers) -{ - uint32_t worker; - - for (worker = 0; worker < n_workers; worker ++) { - int ret; - - if (likely((lp->rx.mbuf_out_flush[worker] == 0) || - (lp->rx.mbuf_out[worker].n_mbufs == 0))) { - lp->rx.mbuf_out_flush[worker] = 1; - continue; - } - - ret = rte_ring_sp_enqueue_bulk( - lp->rx.rings[worker], - (void **) lp->rx.mbuf_out[worker].array, - lp->rx.mbuf_out[worker].n_mbufs, - NULL); - - if (unlikely(ret == 0)) { - uint32_t k; - for (k = 0; k < lp->rx.mbuf_out[worker].n_mbufs; k ++) { - struct rte_mbuf *pkt_to_free = lp->rx.mbuf_out[worker].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - - lp->rx.mbuf_out[worker].n_mbufs = 0; - lp->rx.mbuf_out_flush[worker] = 1; - } -} - -static inline void -app_lcore_io_tx( - struct app_lcore_params_io *lp, - uint32_t n_workers, - uint32_t bsz_rd, - uint32_t bsz_wr) -{ - uint32_t worker; - - for (worker = 0; worker < n_workers; worker ++) { - uint32_t i; - - for (i = 0; i < lp->tx.n_nic_ports; i ++) { - uint16_t port = lp->tx.nic_ports[i]; - struct rte_ring *ring = lp->tx.rings[port][worker]; - uint32_t n_mbufs, n_pkts; - int ret; - - n_mbufs = lp->tx.mbuf_out[port].n_mbufs; - ret = rte_ring_sc_dequeue_bulk( - ring, - (void **) &lp->tx.mbuf_out[port].array[n_mbufs], - bsz_rd, - NULL); - - if (unlikely(ret == 0)) - continue; - - n_mbufs += bsz_rd; - -#if APP_IO_TX_DROP_ALL_PACKETS - { - uint32_t j; - APP_IO_TX_PREFETCH0(lp->tx.mbuf_out[port].array[0]); - APP_IO_TX_PREFETCH0(lp->tx.mbuf_out[port].array[1]); - - for (j = 0; j < n_mbufs; j ++) { - if (likely(j < n_mbufs - 2)) { - APP_IO_TX_PREFETCH0(lp->tx.mbuf_out[port].array[j + 2]); - } - - rte_pktmbuf_free(lp->tx.mbuf_out[port].array[j]); - } - - lp->tx.mbuf_out[port].n_mbufs = 0; - - continue; - } -#endif - - if (unlikely(n_mbufs < bsz_wr)) { - lp->tx.mbuf_out[port].n_mbufs = n_mbufs; - continue; - } - - n_pkts = rte_eth_tx_burst( - port, - 0, - lp->tx.mbuf_out[port].array, - (uint16_t) n_mbufs); - -#if APP_STATS - lp->tx.nic_ports_iters[port] ++; - lp->tx.nic_ports_count[port] += n_pkts; - if (unlikely(lp->tx.nic_ports_iters[port] == APP_STATS)) { - unsigned lcore = rte_lcore_id(); - - printf("\t\t\tI/O TX %u out (port %u): avg burst size = %.2f\n", - lcore, - port, - ((double) lp->tx.nic_ports_count[port]) / ((double) lp->tx.nic_ports_iters[port])); - lp->tx.nic_ports_iters[port] = 0; - lp->tx.nic_ports_count[port] = 0; - } -#endif - - if (unlikely(n_pkts < n_mbufs)) { - uint32_t k; - for (k = n_pkts; k < n_mbufs; k ++) { - struct rte_mbuf *pkt_to_free = lp->tx.mbuf_out[port].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - lp->tx.mbuf_out[port].n_mbufs = 0; - lp->tx.mbuf_out_flush[port] = 0; - } - } -} - -static inline void -app_lcore_io_tx_flush(struct app_lcore_params_io *lp) -{ - uint16_t port; - uint32_t i; - - for (i = 0; i < lp->tx.n_nic_ports; i++) { - uint32_t n_pkts; - - port = lp->tx.nic_ports[i]; - if (likely((lp->tx.mbuf_out_flush[port] == 0) || - (lp->tx.mbuf_out[port].n_mbufs == 0))) { - lp->tx.mbuf_out_flush[port] = 1; - continue; - } - - n_pkts = rte_eth_tx_burst( - port, - 0, - lp->tx.mbuf_out[port].array, - (uint16_t) lp->tx.mbuf_out[port].n_mbufs); - - if (unlikely(n_pkts < lp->tx.mbuf_out[port].n_mbufs)) { - uint32_t k; - for (k = n_pkts; k < lp->tx.mbuf_out[port].n_mbufs; k ++) { - struct rte_mbuf *pkt_to_free = lp->tx.mbuf_out[port].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - - lp->tx.mbuf_out[port].n_mbufs = 0; - lp->tx.mbuf_out_flush[port] = 1; - } -} - -static void -app_lcore_main_loop_io(void) -{ - uint32_t lcore = rte_lcore_id(); - struct app_lcore_params_io *lp = &app.lcore_params[lcore].io; - uint32_t n_workers = app_get_lcores_worker(); - uint64_t i = 0; - - uint32_t bsz_rx_rd = app.burst_size_io_rx_read; - uint32_t bsz_rx_wr = app.burst_size_io_rx_write; - uint32_t bsz_tx_rd = app.burst_size_io_tx_read; - uint32_t bsz_tx_wr = app.burst_size_io_tx_write; - - uint8_t pos_lb = app.pos_lb; - - for ( ; ; ) { - if (APP_LCORE_IO_FLUSH && (unlikely(i == APP_LCORE_IO_FLUSH))) { - if (likely(lp->rx.n_nic_queues > 0)) { - app_lcore_io_rx_flush(lp, n_workers); - } - - if (likely(lp->tx.n_nic_ports > 0)) { - app_lcore_io_tx_flush(lp); - } - - i = 0; - } - - if (likely(lp->rx.n_nic_queues > 0)) { - app_lcore_io_rx(lp, n_workers, bsz_rx_rd, bsz_rx_wr, pos_lb); - } - - if (likely(lp->tx.n_nic_ports > 0)) { - app_lcore_io_tx(lp, n_workers, bsz_tx_rd, bsz_tx_wr); - } - - i ++; - } -} - -static inline void -app_lcore_worker( - struct app_lcore_params_worker *lp, - uint32_t bsz_rd, - uint32_t bsz_wr) -{ - uint32_t i; - - for (i = 0; i < lp->n_rings_in; i ++) { - struct rte_ring *ring_in = lp->rings_in[i]; - uint32_t j; - int ret; - - ret = rte_ring_sc_dequeue_bulk( - ring_in, - (void **) lp->mbuf_in.array, - bsz_rd, - NULL); - - if (unlikely(ret == 0)) - continue; - -#if APP_WORKER_DROP_ALL_PACKETS - for (j = 0; j < bsz_rd; j ++) { - struct rte_mbuf *pkt = lp->mbuf_in.array[j]; - rte_pktmbuf_free(pkt); - } - - continue; -#endif - - APP_WORKER_PREFETCH1(rte_pktmbuf_mtod(lp->mbuf_in.array[0], unsigned char *)); - APP_WORKER_PREFETCH0(lp->mbuf_in.array[1]); - - for (j = 0; j < bsz_rd; j ++) { - struct rte_mbuf *pkt; - struct rte_ipv4_hdr *ipv4_hdr; - uint32_t ipv4_dst, pos; - uint32_t port; - - if (likely(j < bsz_rd - 1)) { - APP_WORKER_PREFETCH1(rte_pktmbuf_mtod(lp->mbuf_in.array[j+1], unsigned char *)); - } - if (likely(j < bsz_rd - 2)) { - APP_WORKER_PREFETCH0(lp->mbuf_in.array[j+2]); - } - - pkt = lp->mbuf_in.array[j]; - ipv4_hdr = rte_pktmbuf_mtod_offset( - pkt, struct rte_ipv4_hdr *, - sizeof(struct rte_ether_hdr)); - ipv4_dst = rte_be_to_cpu_32(ipv4_hdr->dst_addr); - - if (unlikely(rte_lpm_lookup(lp->lpm_table, ipv4_dst, &port) != 0)) { - port = pkt->port; - } - - pos = lp->mbuf_out[port].n_mbufs; - - lp->mbuf_out[port].array[pos ++] = pkt; - if (likely(pos < bsz_wr)) { - lp->mbuf_out[port].n_mbufs = pos; - continue; - } - - ret = rte_ring_sp_enqueue_bulk( - lp->rings_out[port], - (void **) lp->mbuf_out[port].array, - bsz_wr, - NULL); - -#if APP_STATS - lp->rings_out_iters[port] ++; - if (ret > 0) { - lp->rings_out_count[port] += 1; - } - if (lp->rings_out_iters[port] == APP_STATS){ - printf("\t\tWorker %u out (NIC port %u): enq success rate = %.2f\n", - (unsigned) lp->worker_id, - port, - ((double) lp->rings_out_count[port]) / ((double) lp->rings_out_iters[port])); - lp->rings_out_iters[port] = 0; - lp->rings_out_count[port] = 0; - } -#endif - - if (unlikely(ret == 0)) { - uint32_t k; - for (k = 0; k < bsz_wr; k ++) { - struct rte_mbuf *pkt_to_free = lp->mbuf_out[port].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - - lp->mbuf_out[port].n_mbufs = 0; - lp->mbuf_out_flush[port] = 0; - } - } -} - -static inline void -app_lcore_worker_flush(struct app_lcore_params_worker *lp) -{ - uint32_t port; - - for (port = 0; port < APP_MAX_NIC_PORTS; port ++) { - int ret; - - if (unlikely(lp->rings_out[port] == NULL)) { - continue; - } - - if (likely((lp->mbuf_out_flush[port] == 0) || - (lp->mbuf_out[port].n_mbufs == 0))) { - lp->mbuf_out_flush[port] = 1; - continue; - } - - ret = rte_ring_sp_enqueue_bulk( - lp->rings_out[port], - (void **) lp->mbuf_out[port].array, - lp->mbuf_out[port].n_mbufs, - NULL); - - if (unlikely(ret == 0)) { - uint32_t k; - for (k = 0; k < lp->mbuf_out[port].n_mbufs; k ++) { - struct rte_mbuf *pkt_to_free = lp->mbuf_out[port].array[k]; - rte_pktmbuf_free(pkt_to_free); - } - } - - lp->mbuf_out[port].n_mbufs = 0; - lp->mbuf_out_flush[port] = 1; - } -} - -static void -app_lcore_main_loop_worker(void) { - uint32_t lcore = rte_lcore_id(); - struct app_lcore_params_worker *lp = &app.lcore_params[lcore].worker; - uint64_t i = 0; - - uint32_t bsz_rd = app.burst_size_worker_read; - uint32_t bsz_wr = app.burst_size_worker_write; - - for ( ; ; ) { - if (APP_LCORE_WORKER_FLUSH && (unlikely(i == APP_LCORE_WORKER_FLUSH))) { - app_lcore_worker_flush(lp); - i = 0; - } - - app_lcore_worker(lp, bsz_rd, bsz_wr); - - i ++; - } -} - -int -app_lcore_main_loop(__attribute__((unused)) void *arg) -{ - struct app_lcore_params *lp; - unsigned lcore; - - lcore = rte_lcore_id(); - lp = &app.lcore_params[lcore]; - - if (lp->type == e_APP_LCORE_IO) { - printf("Logical core %u (I/O) main loop.\n", lcore); - app_lcore_main_loop_io(); - } - - if (lp->type == e_APP_LCORE_WORKER) { - printf("Logical core %u (worker %u) main loop.\n", - lcore, - (unsigned) lp->worker.worker_id); - app_lcore_main_loop_worker(); - } - - return 0; -} diff --git a/examples/meson.build b/examples/meson.build index f0356f2a1..e4580f74a 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -24,7 +24,6 @@ all_examples = [ 'l2fwd-keepalive', 'l3fwd', 'l3fwd-acl', 'l3fwd-power', 'link_status_interrupt', - 'load_balancer', 'multi_process/client_server_mp/mp_client', 'multi_process/client_server_mp/mp_server', 'multi_process/hotplug_mp', -- 2.17.1 ^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [dpdk-dev] [PATCH v3 0/6] remove a few example applications 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 " Ciara Power ` (5 preceding siblings ...) 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 6/6] examples/load_balancer: " Ciara Power @ 2019-10-26 20:35 ` David Marchand 6 siblings, 0 replies; 27+ messages in thread From: David Marchand @ 2019-10-26 20:35 UTC (permalink / raw) To: Ciara Power; +Cc: dev, techboard On Fri, Oct 25, 2019 at 11:59 AM Ciara Power <ciara.power@intel.com> wrote: > > As discussed by the DPDK technical board e.g. [1][2] and on the DPDK > mailing list [3], we have a lot of example applications shipped with > DPDK - a number which increases with each DPDK release, and not all of > which are probably needed any more. Therefore, this set removes 5 > example applications from the repository. > > v3: > - Document removed applications in release notes. > - Removed "from DPDK" in patch titles. > > v2: Remove the table listing sample applications > > [1] https://mails.dpdk.org/archives/dev/2019-May/132288.html > [2] https://mails.dpdk.org/archives/dev/2019-June/135847.html > [3] https://mails.dpdk.org/archives/dev/2019-July/138676.html > > > Bruce Richardson (2): > examples/exception_path: remove example > examples/l3fwd-vf: remove example > > Ciara Power (4): > doc: remove unnecessary sample app guide table > examples/quota-watermark: remove example > examples/netmap-compat: remove example > examples/load_balancer: remove example > > MAINTAINERS | 15 - > doc/guides/rel_notes/release_19_11.rst | 12 + > doc/guides/sample_app_ug/exception_path.rst | 281 ----- > doc/guides/sample_app_ug/index.rst | 5 - > doc/guides/sample_app_ug/intro.rst | 44 +- > .../sample_app_ug/l3_forward_virtual.rst | 98 -- > doc/guides/sample_app_ug/load_balancer.rst | 201 --- > .../sample_app_ug/netmap_compatibility.rst | 130 -- > doc/guides/sample_app_ug/quota_watermark.rst | 465 ------- > examples/Makefile | 5 - > examples/exception_path/Makefile | 57 - > examples/exception_path/main.c | 605 --------- > examples/exception_path/meson.build | 11 - > examples/l3fwd-vf/Makefile | 62 - > examples/l3fwd-vf/main.c | 1077 ----------------- > examples/l3fwd-vf/meson.build | 12 - > examples/load_balancer/Makefile | 62 - > examples/load_balancer/config.c | 1030 ---------------- > examples/load_balancer/init.c | 537 -------- > examples/load_balancer/main.c | 76 -- > examples/load_balancer/main.h | 351 ------ > examples/load_balancer/meson.build | 12 - > examples/load_balancer/runtime.c | 642 ---------- > examples/meson.build | 9 +- > examples/netmap_compat/Makefile | 22 - > examples/netmap_compat/bridge/Makefile | 35 - > examples/netmap_compat/bridge/bridge.c | 347 ------ > examples/netmap_compat/lib/compat_netmap.c | 906 -------------- > 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 -- > examples/quota_watermark/Makefile | 16 - > examples/quota_watermark/include/conf.h | 19 - > examples/quota_watermark/meson.build | 10 - > examples/quota_watermark/qw/Makefile | 22 - > examples/quota_watermark/qw/args.c | 78 -- > examples/quota_watermark/qw/args.h | 12 - > examples/quota_watermark/qw/init.c | 168 --- > examples/quota_watermark/qw/init.h | 14 - > examples/quota_watermark/qw/main.c | 373 ------ > examples/quota_watermark/qw/main.h | 31 - > examples/quota_watermark/qwctl/Makefile | 22 - > examples/quota_watermark/qwctl/commands.c | 196 --- > examples/quota_watermark/qwctl/commands.h | 12 - > examples/quota_watermark/qwctl/qwctl.c | 67 - > examples/quota_watermark/qwctl/qwctl.h | 12 - > 47 files changed, 17 insertions(+), 8589 deletions(-) > delete mode 100644 doc/guides/sample_app_ug/exception_path.rst > delete mode 100644 doc/guides/sample_app_ug/l3_forward_virtual.rst > delete mode 100644 doc/guides/sample_app_ug/load_balancer.rst > delete mode 100644 doc/guides/sample_app_ug/netmap_compatibility.rst > delete mode 100644 doc/guides/sample_app_ug/quota_watermark.rst > delete mode 100644 examples/exception_path/Makefile > delete mode 100644 examples/exception_path/main.c > delete mode 100644 examples/exception_path/meson.build > delete mode 100644 examples/l3fwd-vf/Makefile > delete mode 100644 examples/l3fwd-vf/main.c > delete mode 100644 examples/l3fwd-vf/meson.build > delete mode 100644 examples/load_balancer/Makefile > delete mode 100644 examples/load_balancer/config.c > delete mode 100644 examples/load_balancer/init.c > delete mode 100644 examples/load_balancer/main.c > delete mode 100644 examples/load_balancer/main.h > delete mode 100644 examples/load_balancer/meson.build > delete mode 100644 examples/load_balancer/runtime.c > 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 > delete mode 100644 examples/quota_watermark/Makefile > delete mode 100644 examples/quota_watermark/include/conf.h > delete mode 100644 examples/quota_watermark/meson.build > delete mode 100644 examples/quota_watermark/qw/Makefile > delete mode 100644 examples/quota_watermark/qw/args.c > delete mode 100644 examples/quota_watermark/qw/args.h > delete mode 100644 examples/quota_watermark/qw/init.c > delete mode 100644 examples/quota_watermark/qw/init.h > delete mode 100644 examples/quota_watermark/qw/main.c > delete mode 100644 examples/quota_watermark/qw/main.h > delete mode 100644 examples/quota_watermark/qwctl/Makefile > delete mode 100644 examples/quota_watermark/qwctl/commands.c > delete mode 100644 examples/quota_watermark/qwctl/commands.h > delete mode 100644 examples/quota_watermark/qwctl/qwctl.c > delete mode 100644 examples/quota_watermark/qwctl/qwctl.h > > -- > 2.17.1 > Moved vhost-scsi removal notice into the list of removed example introduced by this patchset. Sorted this list alphabetically. Applied, thanks. -- David Marchand ^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2019-10-26 20:35 UTC | newest] Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2019-10-03 13:19 [dpdk-dev] [PATCH 0/6] remove a few example applications Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 1/6] examples/exception_path: remove example from DPDK Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 2/6] examples/l3fwd-vf: " Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 3/6] examples/quota-watermark: " Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 4/6] examples/netmap-compat: " Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 5/6] examples/load_balancer: " Bruce Richardson 2019-10-03 13:19 ` [dpdk-dev] [PATCH 6/6] doc: close up gaps in sample app guide table Bruce Richardson 2019-10-23 15:19 ` Thomas Monjalon 2019-10-23 15:21 ` [dpdk-dev] [dpdk-techboard] [PATCH 0/6] remove a few example applications Stephen Hemminger 2019-10-23 15:53 ` Hemant Agrawal 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 " Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 1/6] doc: remove unnecessary sample app guide table Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 2/6] examples/exception_path: remove example from DPDK Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 3/6] examples/l3fwd-vf: " Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 4/6] examples/quota-watermark: " Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 5/6] examples/netmap-compat: " Ciara Power 2019-10-24 13:31 ` [dpdk-dev] [PATCH v2 6/6] examples/load_balancer: " Ciara Power 2019-10-24 14:12 ` [dpdk-dev] [PATCH v2 0/6] remove a few example applications David Marchand 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 " Ciara Power 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 1/6] doc: remove unnecessary sample app guide table Ciara Power 2019-10-25 10:26 ` [dpdk-dev] [dpdk-techboard] " Bruce Richardson 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 2/6] examples/exception_path: remove example Ciara Power 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 3/6] examples/l3fwd-vf: " Ciara Power 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 4/6] examples/quota-watermark: " Ciara Power 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 5/6] examples/netmap-compat: " Ciara Power 2019-10-25 9:56 ` [dpdk-dev] [PATCH v3 6/6] examples/load_balancer: " Ciara Power 2019-10-26 20:35 ` [dpdk-dev] [PATCH v3 0/6] remove a few example applications David Marchand
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).