diff options
author | Matias Elo <matias.elo@nokia.com> | 2023-03-10 10:16:35 +0200 |
---|---|---|
committer | Petri Savolainen <petri.savolainen@nokia.com> | 2023-03-17 16:17:54 +0200 |
commit | 8be77b5634878ffc1bbad16e13938b3d7468fdcb (patch) | |
tree | b42d2fc720af40d4e276e9894a4b3e929a4bafac | |
parent | 3f9ab770e1d622c82d3a718a86d1a13d2d4d0603 (diff) |
linux-gen: pktio: remove netmap pktio
Remove rarely used Netmap pktio device to ease code maintenance and reduce
CI runtime. Netmap pktio can be replaced for example by socket_xdp pktio,
which provides better performance with standard Linux APIs.
Signed-off-by: Matias Elo <matias.elo@nokia.com>
Reviewed-by: Jere Leppänen <jere.leppanen@nokia.com>
-rw-r--r-- | .github/workflows/ci-pipeline.yml | 29 | ||||
-rw-r--r-- | DEPENDENCIES | 100 | ||||
-rw-r--r-- | config/odp-linux-generic.conf | 9 | ||||
-rw-r--r-- | doc/process-guide/faq.adoc | 3 | ||||
-rw-r--r-- | include/odp/autoheader_internal.h.in | 3 | ||||
-rw-r--r-- | platform/linux-generic/Makefile.am | 2 | ||||
-rw-r--r-- | platform/linux-generic/README | 4 | ||||
-rw-r--r-- | platform/linux-generic/include/odp_packet_io_internal.h | 5 | ||||
-rw-r--r-- | platform/linux-generic/m4/configure.m4 | 1 | ||||
-rw-r--r-- | platform/linux-generic/m4/odp_netmap.m4 | 49 | ||||
-rw-r--r-- | platform/linux-generic/pktio/io_ops.c | 3 | ||||
-rw-r--r-- | platform/linux-generic/pktio/netmap.c | 1347 | ||||
-rw-r--r-- | platform/linux-generic/pktio/socket_common.c | 5 | ||||
-rw-r--r-- | platform/linux-generic/test/Makefile.am | 3 | ||||
-rw-r--r-- | platform/linux-generic/test/validation/api/pktio/Makefile.am | 3 | ||||
-rwxr-xr-x | platform/linux-generic/test/validation/api/pktio/pktio_run.sh | 3 | ||||
-rwxr-xr-x | platform/linux-generic/test/validation/api/pktio/pktio_run_netmap.sh | 123 |
17 files changed, 14 insertions, 1678 deletions
diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index a51bfc9ae..da09fe020 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -462,32 +462,3 @@ jobs: - name: Failure log if: ${{ failure() }} run: find . -name "*.trs" | xargs grep -l '^.test-result. FAIL' | while read trs ; do echo FAILURE detected at $trs; cat ${trs%%.trs}.log ; done - - Run_netmap: - runs-on: ubuntu-20.04 - env: - NETMAP_TAG: a315cf3f - strategy: - fail-fast: false - matrix: - cc: [gcc, clang] - conf: ['--with-netmap-path=/odp/netmap', - '--with-netmap-path=/odp/netmap --disable-static-applications'] - steps: - - uses: actions/checkout@v3 - - name: Install dependencies - run: | - sudo apt-get install linux-headers-`uname -r` - CDIR=`pwd` - git clone --single-branch --branch=master https://github.com/luigirizzo/netmap.git - pushd netmap/LINUX - git checkout ${NETMAP_TAG} - ./configure --drivers= - make -j $(nproc) - popd - sudo insmod ./netmap/LINUX/netmap.ko - - run: sudo docker run -i -v `pwd`:/odp --privileged --shm-size 8g -e CC="${{matrix.cc}}" -e ARCH="${ARCH}" - -e CONF="${{matrix.conf}}" $CONTAINER_NAMESPACE/odp-ci-${OS}-${ARCH} /odp/scripts/ci/check.sh - - name: Failure log - if: ${{ failure() }} - run: find . -name "*.trs" | xargs grep -l '^.test-result. FAIL' | while read trs ; do echo FAILURE detected at $trs; cat ${trs%%.trs}.log ; done diff --git a/DEPENDENCIES b/DEPENDENCIES index d7af53dff..bb51bc2e0 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -152,86 +152,8 @@ Prerequisites for building the OpenDataPlane (ODP) API $ ./configure --with-crypto=ipsecmb $ make -3.5 Netmap packet I/O support (optional) - Netmap accelerated ODP packet I/O. - -3.5.1 Building netmap kernel modules - - ODP works at least with the latest release version of netmap, which is - currently v13.0. However, if possible one should try to use the latest netmap - master branch commit for the best performance and the latest bug fixes. - - # Checkout netmap code - $ git clone https://github.com/luigirizzo/netmap.git - $ cd netmap - $ git checkout v13.0 (optional) - - This is enough to build ODP. If you don't want to build netmap kernel - modules you can jump to section 3.3.2. - - Netmap consists of a core kernel module (netmap.ko), optional modified - device drivers and user space API headers to access the netmap - functionality. It is recommended to build both the core module and modified - device drivers for optimal performance. - - Netmap builds as an out-of-tree kernel module, you need matching kernel - sources to compile it. General build instructions can be found in the packet - README: https://github.com/luigirizzo/netmap/blob/master/LINUX/README. - - If you are running Ubuntu/Debian with the stock kernel and you want to - compile both netmap.ko and modified drivers, these steps will guide you - through it. - - # Download kernel headers - $ sudo apt-get install linux-headers-$(uname -r) - - # Download kernel source matching to the headers - $ sudo apt-get install linux-source - # or - $ apt-get source linux-image-$(uname -r) - - The source archive will be placed in /usr/src/linux-source-<kernel-version> - (or in the current directory if using apt-get source). You will need to - locate it and extract it to a convenient place. - - # Compile netmap - $ cd <netmap_dir>/LINUX - $ ./configure --kernel-sources=<path_to_kernel_src> - $ make - -3.5.2 Building ODP - - $ cd <odp_dir> - $ ./bootstrap - $ ./configure --with-netmap-path=<netmap_dir> - $ make - -3.5.3 Inserting netmap kernel modules - - In order to use netmap I/O you need to insert at least the core netmap - kernel module. - - $ cd <netmap_dir>/LINUX - $ sudo insmod netmap.ko - - To insert the optional modified drivers you first need to remove the - original drivers, if loaded (and if not linked into the kernel). For - example, if using ixgbe: - - $ cd <netmap_path>/LINUX - $ sudo rmmod ixgbe - $ sudo insmod ixgbe/ixgbe.ko - - To restore the original drivers you should be able to use modprobe. - -3.5.4 Running ODP with netmap I/O - - ODP applications will use netmap for packet I/O by default as long as the - netmap kernel module is loaded. If socket I/O is desired instead, it can be - activated by setting the environment variable ODP_PKTIO_DISABLE_NETMAP. - -3.6 DPDK packet I/O support (optional) +3.5 DPDK packet I/O support (optional) Use DPDK for ODP packet I/O. Currently supported DPDK versions are v19.11, v20.11 (recommended), v21.11, and v22.11. @@ -240,7 +162,7 @@ Prerequisites for building the OpenDataPlane (ODP) API https://github.com/OpenDataPlane/odp-dpdk.git for a full DPDK based ODP implementation. -3.6.1 DPDK pktio requirements +3.5.1 DPDK pktio requirements DPDK pktio adds a dependency to NUMA library. # Debian/Ubuntu @@ -249,11 +171,11 @@ Prerequisites for building the OpenDataPlane (ODP) API # CentOS/RedHat/Fedora $ sudo yum install numactl-devel -3.6.2 Native DPDK install +3.5.2 Native DPDK install # Debian/Ubuntu starting from 20.04 $ sudo apt-get install dpdk-dev -3.6.3 Build DPDK v19.11 from source +3.5.3 Build DPDK v19.11 from source $ git clone https://dpdk.org/git/dpdk-stable --branch 19.11 --depth 1 ./<dpdk-dir> # Make and edit DPDK configuration @@ -271,7 +193,7 @@ Prerequisites for building the OpenDataPlane (ODP) API # Configure ODP $ ./configure --with-dpdk-path=<dpdk-dir> -3.6.4 Build DPDK v20.11 and onwards from source +3.5.4 Build DPDK v20.11 and onwards from source $ git clone https://dpdk.org/git/dpdk-stable --branch <version, e.g. 21.11> --depth 1 ./<dpdk-dir> # Prepare the build directory @@ -291,7 +213,7 @@ Prerequisites for building the OpenDataPlane (ODP) API # Or, if DPDK was not installed to the default location, set PKG_CONFIG_PATH: $ PKG_CONFIG_PATH=<dpdk-dir>/install/lib/x86_64-linux-gnu/pkgconfig ./configure --enable-dpdk -3.6.5 Setup system +3.5.5 Setup system # Load DPDK modules $ sudo modprobe uio @@ -303,7 +225,7 @@ Prerequisites for building the OpenDataPlane (ODP) API 512 x 2MB huge pages. All this can be done with the DPDK setup script (<dpdk-dir>/usertools/dpdk-setup.sh). -3.6.6 Running ODP with DPDK pktio +3.5.6 Running ODP with DPDK pktio ODP applications will try use DPDK for packet I/O by default. If some other I/O type is desired instead, DPDK I/O can be disabled by setting the @@ -319,7 +241,7 @@ Prerequisites for building the OpenDataPlane (ODP) API 1024MB of memory: $ sudo ODP_PKTIO_DPDK_PARAMS="-m 1024" ./test/performance/odp_l2fwd -i 0 -c 1 -3.7 AF_XDP socket based packet I/O support (optional) +3.6 AF_XDP socket based packet I/O support (optional) Use AF_XDP socket for packet I/O. At the moment, only zero-copy variant is supported, requiring a kernel version 5.4 or higher. Additionally, if packet @@ -336,7 +258,7 @@ Prerequisites for building the OpenDataPlane (ODP) API Note that, currently, AF_XDP socket packet I/O cannot be instantiated if DPDK zero-copy is enabled. -3.7.1 AF_XDP socket packet I/O requirements +3.6.1 AF_XDP socket packet I/O requirements AF_XDP socket packet I/O implementation requires libxdp and libbpf libraries. They can be fetched from XDP-project in GitHub: @@ -358,14 +280,14 @@ Prerequisites for building the OpenDataPlane (ODP) API $ cd <path to built libbpf> $ make install -3.7.2 Build ODP with AF_XDP socket packet I/O support +3.6.2 Build ODP with AF_XDP socket packet I/O support After building and installing libxdp and libbpf, ODP can be configured to be built with AF_XDP support (pass PKG_CONFIG_PATH if needed). $ ./configure --enable-xdp -3.7.3 Running ODP with AF_XDP socket packet I/O +3.6.3 Running ODP with AF_XDP socket packet I/O AF_XDP socket packet I/Os bind to TRX-combined queues. Based on the packet prosessing needs, NIC(s) of the environment should be configured diff --git a/config/odp-linux-generic.conf b/config/odp-linux-generic.conf index 142a205d0..89bdecc4b 100644 --- a/config/odp-linux-generic.conf +++ b/config/odp-linux-generic.conf @@ -140,15 +140,6 @@ pktio_dpdk: { } } -# netmap pktio options -pktio_netmap: { - # Interface specific options - virt: { - nr_rx_slots = 0 - nr_tx_slots = 0 - } -} - # XDP pktio options pktio_xdp: { # Number of RX and TX descriptors to be reserved for AF_XDP socket diff --git a/doc/process-guide/faq.adoc b/doc/process-guide/faq.adoc index cbdd05757..8b3de4de7 100644 --- a/doc/process-guide/faq.adoc +++ b/doc/process-guide/faq.adoc @@ -219,9 +219,6 @@ vendors package this capability as a NIC + ODP library. The ODP project also supports its own ODP-DPDK [1] implementation to help migrations from the lower level DPDK API to the ODPs abstraction. -But traditional NICs are supported odp-linux has PKTIO support for Netmap and -DPDK. - == Does ODP support polling mode? ODP does not dictate a model, although the majority of current contributors see diff --git a/include/odp/autoheader_internal.h.in b/include/odp/autoheader_internal.h.in index a42b34ad0..87cefa131 100644 --- a/include/odp/autoheader_internal.h.in +++ b/include/odp/autoheader_internal.h.in @@ -17,9 +17,6 @@ /* Define to 1 to enable DPDK zero copy support */ #undef _ODP_DPDK_ZERO_COPY -/* Define to 1 to enable netmap packet I/O support */ -#undef _ODP_PKTIO_NETMAP - /* Define to 1 to enable pcap packet I/O support */ #undef _ODP_PKTIO_PCAP diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index d49a2138b..324507ee5 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -12,7 +12,6 @@ AM_CPPFLAGS += -I$(top_srcdir)/platform/$(with_platform)/arch/@ARCH_DIR@ AM_CPPFLAGS += -I$(top_srcdir)/platform/$(with_platform)/arch/default AM_CPPFLAGS += $(OPENSSL_CPPFLAGS) -AM_CPPFLAGS += $(NETMAP_CPPFLAGS) AM_CFLAGS += $(AARCH64CRYPTO_CFLAGS) AM_CFLAGS += $(DPDK_CFLAGS) @@ -270,7 +269,6 @@ __LIB__libodp_linux_la_SOURCES = \ pktio/io_ops.c \ pktio/ipc.c \ pktio/loop.c \ - pktio/netmap.c \ pktio/null.c \ pktio/pktio_common.c \ pktio/socket.c \ diff --git a/platform/linux-generic/README b/platform/linux-generic/README index 138e6040c..8fa50c127 100644 --- a/platform/linux-generic/README +++ b/platform/linux-generic/README @@ -29,17 +29,17 @@ SPDX-License-Identifier: BSD-3-Clause E.g. socket:eth1 - netmap:eth2 + socket_xdp:eth2 The supported pktio types are: dpdk ipc loop - netmap null pcap socket socket_mmap + socket_xdp tap 5. Random data diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h index 187a3a76f..9caf3c2e9 100644 --- a/platform/linux-generic/include/odp_packet_io_internal.h +++ b/platform/linux-generic/include/odp_packet_io_internal.h @@ -62,9 +62,7 @@ ODP_STATIC_ASSERT(PKTIO_LSO_PROFILES < UINT8_MAX, "PKTIO_LSO_PROFILES_ERROR"); /* Forward declaration */ struct pktio_if_ops; -#if defined(_ODP_PKTIO_NETMAP) -#define PKTIO_PRIVATE_SIZE 74752 -#elif defined(_ODP_PKTIO_XDP) && ODP_CACHE_LINE_SIZE == 128 +#if defined(_ODP_PKTIO_XDP) && ODP_CACHE_LINE_SIZE == 128 #define PKTIO_PRIVATE_SIZE 33792 #elif defined(_ODP_PKTIO_XDP) #define PKTIO_PRIVATE_SIZE 29696 @@ -292,7 +290,6 @@ static inline void _odp_pktio_tx_ts_set(pktio_entry_t *entry) odp_atomic_store_u64(&entry->tx_ts, ts_val.u64); } -extern const pktio_if_ops_t _odp_netmap_pktio_ops; extern const pktio_if_ops_t _odp_dpdk_pktio_ops; extern const pktio_if_ops_t _odp_sock_xdp_pktio_ops; extern const pktio_if_ops_t _odp_sock_mmsg_pktio_ops; diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4 index f018d2b24..00ee3683b 100644 --- a/platform/linux-generic/m4/configure.m4 +++ b/platform/linux-generic/m4/configure.m4 @@ -28,7 +28,6 @@ m4_include([platform/linux-generic/m4/odp_openssl.m4]) m4_include([platform/linux-generic/m4/odp_crypto.m4]) m4_include([platform/linux-generic/m4/odp_ipsec_mb.m4]) m4_include([platform/linux-generic/m4/odp_pcapng.m4]) -m4_include([platform/linux-generic/m4/odp_netmap.m4]) m4_include([platform/linux-generic/m4/odp_dpdk.m4]) m4_include([platform/linux-generic/m4/odp_xdp.m4]) ODP_EVENT_VALIDATION diff --git a/platform/linux-generic/m4/odp_netmap.m4 b/platform/linux-generic/m4/odp_netmap.m4 deleted file mode 100644 index 7688c080e..000000000 --- a/platform/linux-generic/m4/odp_netmap.m4 +++ /dev/null @@ -1,49 +0,0 @@ -########################################################################## -# Enable netmap support -########################################################################## -netmap_support=no -AC_ARG_ENABLE([netmap_support], - [AS_HELP_STRING([--enable-netmap-support], [include netmap IO support] - [[default=disabled] (linux-generic)])], - [if test x$enableval = xyes; then - netmap_support=yes - fi]) - -########################################################################## -# Set optional netmap path -########################################################################## -AC_ARG_WITH([netmap-path], -AS_HELP_STRING([--with-netmap-path=DIR], [path to netmap root directory] - [[default=system] (linux-generic)]), - [NETMAP_PATH=$withval - NETMAP_CPPFLAGS="-isystem $NETMAP_PATH/sys" - netmap_support=yes],[]) - -########################################################################## -# Save and set temporary compilation flags -########################################################################## -OLD_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$NETMAP_CPPFLAGS $CPPFLAGS" - -########################################################################## -# Check for netmap availability -########################################################################## -if test x$netmap_support = xyes -then - AC_CHECK_HEADERS([net/netmap_user.h], [], - [AC_MSG_FAILURE(["can't find netmap header"])]) - AC_DEFINE([_ODP_PKTIO_NETMAP], [1], - [Define to 1 to enable netmap packet I/O support]) - AC_SUBST([NETMAP_CPPFLAGS]) -else - netmap_support=no -fi - -########################################################################## -# Restore old saved variables -########################################################################## -CPPFLAGS=$OLD_CPPFLAGS - -AC_CONFIG_COMMANDS_PRE([dnl -AM_CONDITIONAL([netmap_support], [test x$netmap_support = xyes ]) -]) diff --git a/platform/linux-generic/pktio/io_ops.c b/platform/linux-generic/pktio/io_ops.c index f9ea89f71..141b881e3 100644 --- a/platform/linux-generic/pktio/io_ops.c +++ b/platform/linux-generic/pktio/io_ops.c @@ -19,9 +19,6 @@ const pktio_if_ops_t * const _odp_pktio_if_ops[] = { #ifdef _ODP_PKTIO_XDP &_odp_sock_xdp_pktio_ops, #endif -#ifdef _ODP_PKTIO_NETMAP - &_odp_netmap_pktio_ops, -#endif #ifdef _ODP_PKTIO_PCAP &_odp_pcap_pktio_ops, #endif diff --git a/platform/linux-generic/pktio/netmap.c b/platform/linux-generic/pktio/netmap.c deleted file mode 100644 index 0352e33f7..000000000 --- a/platform/linux-generic/pktio/netmap.c +++ /dev/null @@ -1,1347 +0,0 @@ -/* Copyright (c) 2015-2018, Linaro Limited - * Copyright (c) 2019-2022, Nokia - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <odp/autoheader_internal.h> - -#ifdef _ODP_PKTIO_NETMAP - -#include <odp_posix_extensions.h> - -#include <odp/api/packet.h> -#include <odp/api/plat/packet_inlines.h> -#include <odp/api/time.h> -#include <odp/api/plat/time_inlines.h> - -#include <odp_parse_internal.h> -#include <odp_packet_io_internal.h> -#include <odp_packet_io_stats.h> -#include <odp_ethtool_stats.h> -#include <odp_ethtool_rss.h> -#include <odp_socket_common.h> -#include <odp_debug_internal.h> -#include <odp_errno_define.h> -#include <odp_classification_datamodel.h> -#include <odp_classification_internal.h> -#include <odp_libconfig_internal.h> -#include <odp_macros_internal.h> - -#include <protocols/eth.h> -#include <sys/ioctl.h> -#include <sys/syscall.h> -#include <poll.h> -#include <linux/ethtool.h> -#include <linux/sockios.h> -#include <inttypes.h> - -/* Disable netmap debug prints */ -#ifndef ND -#define ND(_fmt, ...) do {} while (0) -#define D(_fmt, ...) do {} while (0) -#define RD(lps, format, ...) do {} while (0) -#endif - -#define NETMAP_WITH_LIBS -#include <net/netmap_user.h> - -#define NM_WAIT_TIMEOUT 10 /* netmap_wait_for_link() timeout in seconds */ -#define NM_INJECT_RETRIES 10 - -#define NM_MAX_DESC 64 - -#define NM_BUF_SIZE "/sys/module/netmap/parameters/buf_size" - -/** netmap runtime configuration options */ -typedef struct { - int nr_rx_slots; - int nr_tx_slots; -} netmap_opt_t; - -/** Ring for mapping pktin/pktout queues to netmap descriptors */ -typedef struct ODP_ALIGNED_CACHE { - unsigned int first; /**< Index of first netmap descriptor */ - unsigned int last; /**< Index of last netmap descriptor */ - unsigned int num; /**< Number of netmap descriptors */ - /** Netmap metadata for the device */ - struct nm_desc *desc[NM_MAX_DESC]; - unsigned int cur; /**< Index of current netmap descriptor */ - odp_ticketlock_t lock; /**< Queue lock */ -} netmap_ring_t; - -/** Netmap ring slot */ -typedef struct { - char *buf; /**< Slot buffer pointer */ - uint16_t len; /**< Slot length */ -} netmap_slot_t; - -/** Packet socket using netmap mmaped rings for both Rx and Tx */ -typedef struct { - odp_pool_t pool; /**< pool to alloc packets from */ - uint32_t if_flags; /**< interface flags */ - uint32_t mtu; /**< maximum transmission unit */ - uint32_t mtu_max; /**< maximum supported MTU value */ - int sockfd; /**< control socket */ - unsigned char if_mac[ETH_ALEN]; /**< eth mac address */ - char nm_name[IF_NAMESIZE + 7]; /**< netmap:<ifname> */ - char if_name[IF_NAMESIZE]; /**< interface name used in ioctl */ - odp_bool_t is_virtual; /**< nm virtual port (VALE/pipe) */ - uint32_t num_rx_rings; /**< number of nm rx rings */ - uint32_t num_tx_rings; /**< number of nm tx rings */ - unsigned int num_rx_desc_rings; /**< number of rx descriptor rings */ - unsigned int num_tx_desc_rings; /**< number of tx descriptor rings */ - odp_bool_t lockless_rx; /**< no locking for rx */ - odp_bool_t lockless_tx; /**< no locking for tx */ - /** mapping of pktin queues to netmap rx descriptors */ - netmap_ring_t rx_desc_ring[ODP_PKTIN_MAX_QUEUES]; - /** mapping of pktout queues to netmap tx descriptors */ - netmap_ring_t tx_desc_ring[ODP_PKTOUT_MAX_QUEUES]; - netmap_opt_t opt; /**< options */ -} pkt_netmap_t; - -ODP_STATIC_ASSERT(PKTIO_PRIVATE_SIZE >= sizeof(pkt_netmap_t), - "PKTIO_PRIVATE_SIZE too small"); - -static inline pkt_netmap_t *pkt_priv(pktio_entry_t *pktio_entry) -{ - return (pkt_netmap_t *)(uintptr_t)(pktio_entry->pkt_priv); -} - -static int disable_pktio; /** !0 this pktio disabled, 0 enabled */ -static int netmap_stats_reset(pktio_entry_t *pktio_entry); - -static int read_netmap_buf_size(void) -{ - FILE *file; - char str[128]; - int size = 0; - - file = fopen(NM_BUF_SIZE, "rt"); - if (file == NULL) { - /* File not found */ - return 0; - } - - if (fgets(str, sizeof(str), file) != NULL) { - /* Read netmap buffer size */ - if (sscanf(str, "%i", &size) != 1) - size = 0; - } - - fclose(file); - - return size; -} - -static int lookup_opt(const char *opt_name, const char *drv_name, int *val) -{ - const char *base = "pktio_netmap"; - int ret; - - ret = _odp_libconfig_lookup_ext_int(base, drv_name, opt_name, val); - if (ret == 0) - _ODP_ERR("Unable to find netmap configuration option: %s\n", opt_name); - - return ret; -} - -static int init_options(pktio_entry_t *pktio_entry) -{ - netmap_opt_t *opt = &pkt_priv(pktio_entry)->opt; - - if (!lookup_opt("nr_rx_slots", "virt", - &opt->nr_rx_slots)) - return -1; - if (opt->nr_rx_slots < 0 || - opt->nr_rx_slots > 4096) { - _ODP_ERR("Invalid number of RX slots\n"); - return -1; - } - - if (!lookup_opt("nr_tx_slots", "virt", - &opt->nr_tx_slots)) - return -1; - if (opt->nr_tx_slots < 0 || - opt->nr_tx_slots > 4096) { - _ODP_ERR("Invalid number of TX slots\n"); - return -1; - } - - _ODP_DBG("netmap interface: %s\n", pkt_priv(pktio_entry)->if_name); - _ODP_DBG(" num_rx_desc: %d\n", opt->nr_rx_slots); - _ODP_DBG(" num_tx_desc: %d\n", opt->nr_tx_slots); - - return 0; -} - -static int netmap_do_ioctl(pktio_entry_t *pktio_entry, unsigned long cmd, - int subcmd) -{ - pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); - struct ethtool_value eval; - struct ifreq ifr; - int err; - int fd = pkt_nm->sockfd; - - memset(&ifr, 0, sizeof(ifr)); - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", - pkt_priv(pktio_entry)->if_name); - - switch (cmd) { - case SIOCSIFFLAGS: - ifr.ifr_flags = pkt_nm->if_flags & 0xffff; - break; - case SIOCETHTOOL: - eval.cmd = subcmd; - eval.data = 0; - ifr.ifr_data = (caddr_t)&eval; - break; - default: - break; - } - err = ioctl(fd, cmd, &ifr); - if (err) - goto done; - - switch (cmd) { - case SIOCGIFFLAGS: - pkt_nm->if_flags = (ifr.ifr_flags << 16) | - (0xffff & ifr.ifr_flags); - break; - case SIOCETHTOOL: - if (subcmd == ETHTOOL_GLINK) - return eval.data; - break; - default: - break; - } -done: - if (err) - _ODP_ERR("ioctl err %d %lu: %s\n", err, cmd, strerror(errno)); - - return err; -} - -/** - * Map netmap rings to pktin/pktout queues - * - * @param rings Array of netmap descriptor rings - * @param num_queues Number of pktin/pktout queues - * @param num_rings Number of matching netmap rings - */ -static inline void map_netmap_rings(netmap_ring_t *rings, - unsigned int num_queues, unsigned int num_rings) -{ - netmap_ring_t *desc_ring; - unsigned int rings_per_queue; - unsigned int remainder; - unsigned int mapped_rings; - unsigned int i; - unsigned int desc_id = 0; - - rings_per_queue = num_rings / num_queues; - remainder = num_rings % num_queues; - - if (remainder) - _ODP_DBG("WARNING: Netmap rings mapped unevenly to queues\n"); - - for (i = 0; i < num_queues; i++) { - desc_ring = &rings[i]; - if (i < remainder) - mapped_rings = rings_per_queue + 1; - else - mapped_rings = rings_per_queue; - - desc_ring->first = desc_id; - desc_ring->cur = desc_id; - desc_ring->last = desc_ring->first + mapped_rings - 1; - desc_ring->num = mapped_rings; - - desc_id = desc_ring->last + 1; - } -} - -static int netmap_input_queues_config(pktio_entry_t *pktio_entry, - const odp_pktin_queue_param_t *p) -{ - pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); - odp_pktin_mode_t mode = pktio_entry->param.in_mode; - unsigned int num_queues = p->num_queues; - odp_bool_t lockless; - - /* Scheduler synchronizes input queue polls. Only single thread - * at a time polls a queue */ - if (mode == ODP_PKTIN_MODE_SCHED) - lockless = 1; - else - lockless = (p->op_mode == ODP_PKTIO_OP_MT_UNSAFE); - - if (p->hash_enable && num_queues > 1) { - if (_odp_rss_conf_set_fd(pkt_priv(pktio_entry)->sockfd, - pkt_priv(pktio_entry)->if_name, - &p->hash_proto)) { - _ODP_ERR("Failed to configure input hash\n"); - return -1; - } - } - - pkt_nm->lockless_rx = lockless; - - return 0; -} - -static int netmap_output_queues_config(pktio_entry_t *pktio_entry, - const odp_pktout_queue_param_t *p) -{ - pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); - - pkt_nm->lockless_tx = (p->op_mode == ODP_PKTIO_OP_MT_UNSAFE); - - return 0; -} - -/** - * Close netmap descriptors - * - * Can be reopened using netmap_start() function. - * - * @param pktio_entry Packet IO entry - */ -static inline void netmap_close_descriptors(pktio_entry_t *pktio_entry) -{ - int i, j; - pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); - - for (i = 0; i < ODP_PKTIN_MAX_QUEUES; i++) { - for (j = 0; j < NM_MAX_DESC; j++) { - if (pkt_nm->rx_desc_ring[i].desc[j] != NULL) { - nm_close(pkt_nm->rx_desc_ring[i].desc[j]); - pkt_nm->rx_desc_ring[i].desc[j] = NULL; - } - } - } - for (i = 0; i < ODP_PKTOUT_MAX_QUEUES; i++) { - for (j = 0; j < NM_MAX_DESC; j++) { - if (pkt_nm->tx_desc_ring[i].desc[j] != NULL) { - nm_close(pkt_nm->tx_desc_ring[i].desc[j]); - pkt_nm->tx_desc_ring[i].desc[j] = NULL; - } - } - } - - pkt_nm->num_rx_desc_rings = 0; - pkt_nm->num_tx_desc_rings = 0; -} - -static int netmap_close(pktio_entry_t *pktio_entry) -{ - pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); - - netmap_close_descriptors(pktio_entry); - - if (pkt_nm->sockfd != -1 && close(pkt_nm->sockfd) != 0) { - _odp_errno = errno; - _ODP_ERR("close(sockfd): %s\n", strerror(errno)); - return -1; - } - return 0; -} - -static int netmap_link_status(pktio_entry_t *pktio_entry) -{ - if (pkt_priv(pktio_entry)->is_virtual) - return ODP_PKTIO_LINK_STATUS_UP; - - return _odp_link_status_fd(pkt_priv(pktio_entry)->sockfd, - pkt_priv(pktio_entry)->if_name); -} - -static int netmap_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *info) -{ - pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); - - if (pkt_nm->is_virtual) { - memset(info, 0, sizeof(odp_pktio_link_info_t)); - - info->autoneg = ODP_PKTIO_LINK_AUTONEG_OFF; - info->duplex = ODP_PKTIO_LINK_DUPLEX_FULL; - info->media = "virtual"; - info->pause_rx = ODP_PKTIO_LINK_PAUSE_OFF; - info->pause_tx = ODP_PKTIO_LINK_PAUSE_OFF; - info->speed = ODP_PKTIO_LINK_SPEED_UNKNOWN; - info->status = ODP_PKTIO_LINK_STATUS_UP; - - return 0; - } - - return _odp_link_info_fd(pkt_nm->sockfd, pkt_nm->if_name, info); -} - -/** - * Wait for netmap link to come up - * - * @param pktio_entry Packet IO entry - * - * @retval 1 link is up - * @retval 0 link is down - * @retval <0 on failure - */ -static inline int netmap_wait_for_link(pktio_entry_t *pktio_entry) -{ - int i; - int ret; - - /* Wait for the link to come up */ - for (i = 0; i <= NM_WAIT_TIMEOUT; i++) { - ret = netmap_link_status(pktio_entry); - if (ret == -1) - return -1; - /* nm_open() causes the physical link to reset. When using a - * direct attached loopback cable there may be a small delay - * until the opposing end's interface comes back up again. In - * this case without the additional sleep pktio validation - * tests fail. */ - if (!pkt_priv(pktio_entry)->is_virtual) - sleep(1); - if (ret == 1) - return 1; - } - _ODP_DBG("%s link is down\n", pkt_priv(pktio_entry)->if_name); - return 0; -} - -/** - * Initialize netmap capability values - * - * @param pktio_entry Packet IO entry - */ -static void netmap_init_capability(pktio_entry_t *pktio_entry) -{ - pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); - odp_pktio_capability_t *capa = &pktio_entry->capa; - - memset(capa, 0, sizeof(odp_pktio_capability_t)); - - capa->max_input_queues = ODP_PKTIN_MAX_QUEUES; - if (pkt_nm->num_rx_rings < ODP_PKTIN_MAX_QUEUES) - capa->max_input_queues = pkt_nm->num_rx_rings; - if (capa->max_input_queues > NM_MAX_DESC) { - /* Have to use a single descriptor to fetch packets from all - * netmap rings */ - capa->max_input_queues = 1; - _ODP_DBG("Unable to store all %" PRIu32 " rx rings (max %d)\n" - " max input queues: %u\n", pkt_nm->num_rx_rings, - NM_MAX_DESC, capa->max_input_queues); - } - - capa->max_output_queues = ODP_PKTOUT_MAX_QUEUES; - if (pkt_nm->num_tx_rings < ODP_PKTOUT_MAX_QUEUES) - capa->max_output_queues = pkt_nm->num_tx_rings; - if (capa->max_output_queues > NM_MAX_DESC) { - capa->max_output_queues = NM_MAX_DESC; - _ODP_DBG("Unable to store all %" PRIu32 " tx rings (max %d)\n" - " max output queues: %u\n", pkt_nm->num_tx_rings, - NM_MAX_DESC, capa->max_output_queues); - } - - capa->set_op.op.promisc_mode = 1; - capa->set_op.op.maxlen = 1; - - capa->maxlen.equal = true; - capa->maxlen.min_input = _ODP_SOCKET_MTU_MIN; - capa->maxlen.max_input = pkt_nm->mtu_max; - capa->maxlen.min_output = _ODP_SOCKET_MTU_MIN; - capa->maxlen.max_output = pkt_nm->mtu_max; - - odp_pktio_config_init(&capa->config); - capa->config.pktin.bit.ts_all = 1; - capa->config.pktin.bit.ts_ptp = 1; - - capa->config.pktout.bit.ts_ena = 1; -} - -/** - * Open a netmap interface - * - * In addition to standard interfaces (with or without modified netmap drivers) - * virtual VALE and pipe interfaces are also supported. These can be used for - * example for testing packet IO functionality without any physical interfaces. - * - * To use virtual interfaces the 'netdev' device name has to begin with 'vale' - * prefix. A valid VALE device name would be e.g. 'vale0'. Pipe device names - * have to include also '{NN' (master) or '}NN' (slave) suffix. A valid pipe - * master would be e.g. 'vale0{0' and a slave to the same pipe 'vale0}0'. - * - * Netmap requires standard interface names to begin with 'netmap:' prefix. - * netmap_open() adds the prefix if it is missing. Virtual interfaces don't - * require the 'netmap:' prefix. - * - * @param id Packet IO handle - * @param pktio_entry Packet IO entry - * @param netdev Packet IO device name - * @param pool Default pool from which to allocate storage for packets - * - * @retval 0 on success - * @retval <0 on failure - */ -static int netmap_open(odp_pktio_t id ODP_UNUSED, pktio_entry_t *pktio_entry, - const char *netdev, odp_pool_t pool) -{ - int i; - int err; - int sockfd; - const char *prefix; - uint32_t mtu; - uint32_t nm_buf_size; - pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); - struct nm_desc *desc; - odp_pktin_hash_proto_t hash_proto; - odp_pktio_stats_t cur_stats; - - if (disable_pktio) - return -1; - - if (pool == ODP_POOL_INVALID) - return -1; - - /* Init pktio entry */ - memset(pkt_nm, 0, sizeof(*pkt_nm)); - pkt_nm->sockfd = -1; - pkt_nm->pool = pool; - - /* allow interface to be opened with or without the 'netmap:' prefix */ - prefix = "netmap:"; - if (strncmp(netdev, "netmap:", 7) == 0) - netdev += 7; - if (strncmp(netdev, "vale", 4) == 0) { - pkt_nm->is_virtual = 1; - prefix = ""; - } - - snprintf(pkt_nm->nm_name, sizeof(pkt_nm->nm_name), "%s%s", prefix, - netdev); - snprintf(pkt_nm->if_name, sizeof(pkt_nm->if_name), "%s", netdev); - - /* Initialize runtime options */ - if (init_options(pktio_entry)) { - _ODP_ERR("Initializing runtime options failed\n"); - return -1; - } - - /* Read netmap buffer size */ - nm_buf_size = read_netmap_buf_size(); - if (!nm_buf_size) { - _ODP_ERR("Unable to read netmap buf size\n"); - return -1; - } - pkt_nm->mtu_max = _ODP_SOCKET_MTU_MAX; - if (pkt_nm->mtu_max > nm_buf_size) - pkt_nm->mtu_max = nm_buf_size; - - if (!pkt_nm->is_virtual) { - sockfd = socket(AF_INET, SOCK_DGRAM, 0); - if (sockfd == -1) { - _ODP_ERR("Cannot get device control socket\n"); - return -1; - } - pkt_nm->sockfd = sockfd; - - /* Use either interface MTU or netmap buffer size as MTU, - * whichever is smaller. */ - mtu = _odp_mtu_get_fd(pkt_nm->sockfd, pkt_nm->if_name); - if (mtu == 0) { - _ODP_ERR("Unable to read interface MTU\n"); - goto error; - } - pkt_nm->mtu = (mtu < nm_buf_size) ? mtu : nm_buf_size; - - /* Netmap requires that interface MTU size <= nm buf size */ - if (mtu > nm_buf_size) { - if (_odp_mtu_set_fd(pkt_nm->sockfd, pkt_nm->if_name, - nm_buf_size)) { - _ODP_ERR("Unable to set interface MTU\n"); - goto error; - } - } - } - /* Dummy open here to check if netmap module is available and to read - * capability info. */ - desc = nm_open(pkt_nm->nm_name, NULL, 0, NULL); - if (desc == NULL) { - _ODP_ERR("nm_open(%s) failed\n", pkt_nm->nm_name); - goto error; - } - pkt_nm->num_rx_rings = desc->nifp->ni_rx_rings; - pkt_nm->num_tx_rings = desc->nifp->ni_tx_rings; - - netmap_init_capability(pktio_entry); - - nm_close(desc); - - for (i = 0; i < ODP_PKTIN_MAX_QUEUES; i++) - odp_ticketlock_init(&pkt_nm->rx_desc_ring[i].lock); - - for (i = 0; i < ODP_PKTOUT_MAX_QUEUES; i++) - odp_ticketlock_init(&pkt_nm->tx_desc_ring[i].lock); - - if (pkt_nm->is_virtual) { - static unsigned int mac; - uint32_t tid = syscall(SYS_gettid); - - if ((int)tid == -1) - _ODP_DBG("Unable to fetch thread ID. VALE port MAC " - "addresses may not be unique.\n"); - - pktio_entry->capa.max_input_queues = 1; - pktio_entry->capa.set_op.op.maxlen = 0; - pktio_entry->capa.set_op.op.promisc_mode = 0; - pkt_nm->mtu = nm_buf_size; - pktio_entry->stats_type = STATS_UNSUPPORTED; - /* Set MAC address for virtual interface */ - pkt_nm->if_mac[0] = 0x2; - pkt_nm->if_mac[1] = (tid >> 24) & 0xff; - pkt_nm->if_mac[2] = (tid >> 16) & 0xff; - pkt_nm->if_mac[3] = (tid >> 8) & 0xff; - pkt_nm->if_mac[4] = tid & 0xff; - pkt_nm->if_mac[5] = ++mac; - - return 0; - } - - /* Check if RSS is supported. If not, set 'max_input_queues' to 1. */ - if (_odp_rss_conf_get_supported_fd(pkt_nm->sockfd, netdev, - &hash_proto) == 0) { - _ODP_DBG("RSS not supported\n"); - pktio_entry->capa.max_input_queues = 1; - } - - err = netmap_do_ioctl(pktio_entry, SIOCGIFFLAGS, 0); - if (err) - goto error; - if ((pkt_nm->if_flags & IFF_UP) == 0) - _ODP_DBG("%s is down\n", pkt_nm->if_name); - - err = _odp_mac_addr_get_fd(pkt_nm->sockfd, netdev, pkt_nm->if_mac); - if (err) - goto error; - - /* netmap uses only ethtool to get statistics counters */ - err = _odp_ethtool_stats_get_fd(pkt_nm->sockfd, pkt_nm->if_name, &cur_stats); - if (err) { - _ODP_DBG("netmap pktio %s does not support statistics counters\n", - pkt_nm->if_name); - pktio_entry->stats_type = STATS_UNSUPPORTED; - } else { - pktio_entry->stats_type = STATS_ETHTOOL; - _odp_sock_stats_capa(pktio_entry, &pktio_entry->capa); - } - - (void)netmap_stats_reset(pktio_entry); - - return 0; - -error: - netmap_close(pktio_entry); - return -1; -} - -static int netmap_start(pktio_entry_t *pktio_entry) -{ - pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); - netmap_ring_t *desc_ring; - struct nm_desc *desc_ptr; - unsigned int i; - unsigned int j; - unsigned int num_rx_desc = 0; - uint64_t flags; - odp_pktin_mode_t in_mode = pktio_entry->param.in_mode; - odp_pktout_mode_t out_mode = pktio_entry->param.out_mode; - - /* If no pktin/pktout queues have been configured. Configure one - * for each direction. */ - if (!pktio_entry->num_in_queue && - in_mode != ODP_PKTIN_MODE_DISABLED) { - odp_pktin_queue_param_t param; - - odp_pktin_queue_param_init(¶m); - param.num_queues = 1; - if (odp_pktin_queue_config(pktio_entry->handle, ¶m)) - return -1; - } - if (!pktio_entry->num_out_queue && - out_mode == ODP_PKTOUT_MODE_DIRECT) { - odp_pktout_queue_param_t param; - - odp_pktout_queue_param_init(¶m); - param.num_queues = 1; - if (odp_pktout_queue_config(pktio_entry->handle, ¶m)) - return -1; - } - - if (pkt_nm->num_rx_desc_rings == pktio_entry->num_in_queue && - pkt_nm->num_tx_desc_rings == pktio_entry->num_out_queue) - return (netmap_wait_for_link(pktio_entry) == 1) ? 0 : -1; - - netmap_close_descriptors(pktio_entry); - - /* Map pktin/pktout queues to netmap rings */ - if (pktio_entry->num_in_queue) { - /* In single queue case only one netmap descriptor is - * required. */ - num_rx_desc = (pktio_entry->num_in_queue == 1) ? 1 : - pkt_nm->num_rx_rings; - - map_netmap_rings(pkt_nm->rx_desc_ring, - pktio_entry->num_in_queue, num_rx_desc); - } - if (pktio_entry->num_out_queue) - /* Enough to map only one netmap tx ring per pktout queue */ - map_netmap_rings(pkt_nm->tx_desc_ring, - pktio_entry->num_out_queue, - pktio_entry->num_out_queue); - - /* Use nm_open() to parse netmap flags from interface name */ - desc_ptr = nm_open(pkt_nm->nm_name, NULL, 0, NULL); - if (desc_ptr == NULL) { - _ODP_ERR("nm_start(%s) failed\n", pkt_nm->nm_name); - goto error; - } - struct nm_desc base_desc = *desc_ptr; - - nm_close(desc_ptr); - - base_desc.self = &base_desc; - base_desc.mem = NULL; - if (pkt_priv(pktio_entry)->is_virtual) { - base_desc.req.nr_rx_slots = - pkt_priv(pktio_entry)->opt.nr_rx_slots; - base_desc.req.nr_tx_slots = - pkt_priv(pktio_entry)->opt.nr_tx_slots; - } - base_desc.req.nr_ringid = 0; - if ((base_desc.req.nr_flags & NR_REG_MASK) == NR_REG_ALL_NIC || - (base_desc.req.nr_flags & NR_REG_MASK) == NR_REG_ONE_NIC) { - base_desc.req.nr_flags &= ~NR_REG_MASK; - if (num_rx_desc == 1) - base_desc.req.nr_flags |= NR_REG_ALL_NIC; - else - base_desc.req.nr_flags |= NR_REG_ONE_NIC; - } - - /* Only the first rx descriptor does mmap */ - desc_ring = pkt_nm->rx_desc_ring; - flags = NM_OPEN_IFNAME | NETMAP_NO_TX_POLL; - if (pkt_priv(pktio_entry)->is_virtual) - flags |= NM_OPEN_RING_CFG; - desc_ring[0].desc[0] = nm_open(pkt_nm->nm_name, NULL, flags, - &base_desc); - if (desc_ring[0].desc[0] == NULL) { - _ODP_ERR("nm_start(%s) failed\n", pkt_nm->nm_name); - goto error; - } - /* Open rest of the rx descriptors (one per netmap ring) */ - flags = NM_OPEN_IFNAME | NETMAP_NO_TX_POLL | NM_OPEN_NO_MMAP; - if (pkt_priv(pktio_entry)->is_virtual) - flags |= NM_OPEN_RING_CFG; - for (i = 0; i < pktio_entry->num_in_queue; i++) { - for (j = desc_ring[i].first; j <= desc_ring[i].last; j++) { - if (i == 0 && j == 0) { /* First already opened */ - if (num_rx_desc > 1) - continue; - else - break; - } - base_desc.req.nr_ringid = j; - desc_ring[i].desc[j] = nm_open(pkt_nm->nm_name, NULL, - flags, &base_desc); - if (desc_ring[i].desc[j] == NULL) { - _ODP_ERR("nm_start(%s) failed\n", pkt_nm->nm_name); - goto error; - } - } - } - /* Open tx descriptors */ - desc_ring = pkt_nm->tx_desc_ring; - flags = NM_OPEN_IFNAME | NM_OPEN_NO_MMAP; - if (pkt_priv(pktio_entry)->is_virtual) - flags |= NM_OPEN_RING_CFG; - - if ((base_desc.req.nr_flags & NR_REG_MASK) == NR_REG_ALL_NIC) { - base_desc.req.nr_flags &= ~NR_REG_ALL_NIC; - base_desc.req.nr_flags |= NR_REG_ONE_NIC; - } - - for (i = 0; i < pktio_entry->num_out_queue; i++) { - for (j = desc_ring[i].first; j <= desc_ring[i].last; j++) { - base_desc.req.nr_ringid = j; - desc_ring[i].desc[j] = nm_open(pkt_nm->nm_name, NULL, - flags, &base_desc); - if (desc_ring[i].desc[j] == NULL) { - _ODP_ERR("nm_start(%s) failed\n", pkt_nm->nm_name); - goto error; - } - } - } - pkt_nm->num_rx_desc_rings = pktio_entry->num_in_queue; - pkt_nm->num_tx_desc_rings = pktio_entry->num_out_queue; - /* Wait for the link to come up */ - return (netmap_wait_for_link(pktio_entry) == 1) ? 0 : -1; - -error: - netmap_close_descriptors(pktio_entry); - return -1; -} - -static int netmap_stop(pktio_entry_t *pktio_entry ODP_UNUSED) -{ - return 0; -} - -/** - * Create ODP packets from netmap packets - * - * @param pktio_entry Packet IO entry - * @param pkt_tbl Array for new ODP packet handles - * @param slot_tbl Array of netmap ring slots - * @param slot_num Number of netmap ring slots - * @param ts Pointer to pktin timestamp - * - * @retval Number of created packets - */ -static inline int netmap_pkt_to_odp(pktio_entry_t *pktio_entry, - odp_packet_t pkt_tbl[], - netmap_slot_t slot_tbl[], int16_t slot_num, - odp_time_t *ts) -{ - odp_packet_t pkt; - odp_pool_t pool = pkt_priv(pktio_entry)->pool; - odp_packet_hdr_t *pkt_hdr; - int i; - int num; - uint32_t max_len; - uint16_t frame_offset = pktio_entry->pktin_frame_offset; - int num_rx = 0; - const odp_proto_layer_t layer = pktio_entry->parse_layer; - const odp_pktin_config_opt_t opt = pktio_entry->config.pktin; - - /* Allocate maximum sized packets */ - max_len = pkt_priv(pktio_entry)->mtu; - - num = _odp_packet_alloc_multi(pool, max_len + frame_offset, - pkt_tbl, slot_num); - - for (i = 0; i < num; i++) { - netmap_slot_t slot; - uint16_t len; - const uint8_t *buf; - - slot = slot_tbl[i]; - len = slot.len; - buf = (const uint8_t *)slot.buf; - - odp_prefetch(slot.buf); - - pkt = pkt_tbl[i]; - pkt_hdr = packet_hdr(pkt); - - pull_tail(pkt_hdr, max_len - len); - if (frame_offset) - pull_head(pkt_hdr, frame_offset); - - if (odp_packet_copy_from_mem(pkt, 0, len, slot.buf) != 0) { - odp_packet_free(pkt); - continue; - } - - if (layer) { - int ret; - - ret = _odp_packet_parse_common(pkt_hdr, buf, len, len, - layer, opt); - if (ret) - odp_atomic_inc_u64(&pktio_entry->stats_extra.in_errors); - - if (ret < 0) { - odp_packet_free(pkt); - continue; - } - - if (pktio_cls_enabled(pktio_entry)) { - odp_pool_t new_pool; - - ret = _odp_cls_classify_packet(pktio_entry, buf, - &new_pool, pkt_hdr); - if (ret < 0) - odp_atomic_inc_u64(&pktio_entry->stats_extra.in_discards); - - if (ret) { - odp_packet_free(pkt); - continue; - } - - if (odp_unlikely(_odp_pktio_packet_to_pool( - &pkt, &pkt_hdr, new_pool))) { - odp_packet_free(pkt); - odp_atomic_inc_u64(&pktio_entry->stats_extra.in_discards); - continue; - } - } - } - - pkt_hdr->input = pktio_entry->handle; - packet_set_ts(pkt_hdr, ts); - - pkt_tbl[num_rx++] = pkt; - } - - return num_rx; -} - -static inline int netmap_recv_desc(pktio_entry_t *pktio_entry, - struct nm_desc *desc, - odp_packet_t pkt_table[], int num) -{ - struct netmap_ring *ring; - odp_time_t ts_val; - odp_time_t *ts = NULL; - netmap_slot_t slot_tbl[num]; - char *buf; - uint32_t slot_id; - uint32_t mtu = pkt_priv(pktio_entry)->mtu; - int i; - int ring_id = desc->cur_rx_ring; - int num_rx = 0; - int num_rings = desc->last_rx_ring - desc->first_rx_ring + 1; - - if (pktio_entry->config.pktin.bit.ts_all || - pktio_entry->config.pktin.bit.ts_ptp) - ts = &ts_val; - - for (i = 0; i < num_rings && num_rx != num; i++) { - if (ring_id > desc->last_rx_ring) - ring_id = desc->first_rx_ring; - - ring = NETMAP_RXRING(desc->nifp, ring_id); - - while (!nm_ring_empty(ring) && num_rx != num) { - slot_id = ring->cur; - buf = NETMAP_BUF(ring, ring->slot[slot_id].buf_idx); - - if (odp_likely(ring->slot[slot_id].len <= mtu)) { - slot_tbl[num_rx].buf = buf; - slot_tbl[num_rx].len = ring->slot[slot_id].len; - num_rx++; - } else { - _ODP_DBG("Dropped oversized packet: %" PRIu16 " " - "B\n", ring->slot[slot_id].len); - } - ring->cur = nm_ring_next(ring, slot_id); - ring->head = ring->cur; - } - ring_id++; - } - desc->cur_rx_ring = ring_id; - - if (num_rx) { - if (ts != NULL) - ts_val = odp_time_global(); - return netmap_pkt_to_odp(pktio_entry, pkt_table, slot_tbl, - num_rx, ts); - } - return 0; -} - -static int netmap_fd_set(pktio_entry_t *pktio_entry, int index, fd_set *readfds) -{ - struct nm_desc *desc; - pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); - unsigned int first_desc_id = pkt_nm->rx_desc_ring[index].first; - unsigned int last_desc_id = pkt_nm->rx_desc_ring[index].last; - unsigned int desc_id; - int num_desc = pkt_nm->rx_desc_ring[index].num; - int i; - int max_fd = 0; - - if (!pkt_nm->lockless_rx) - odp_ticketlock_lock(&pkt_nm->rx_desc_ring[index].lock); - - desc_id = pkt_nm->rx_desc_ring[index].cur; - - for (i = 0; i < num_desc; i++) { - if (desc_id > last_desc_id) - desc_id = first_desc_id; - - desc = pkt_nm->rx_desc_ring[index].desc[desc_id]; - - FD_SET(desc->fd, readfds); - if (desc->fd > max_fd) - max_fd = desc->fd; - desc_id++; - } - pkt_nm->rx_desc_ring[index].cur = desc_id; - - if (!pkt_nm->lockless_rx) - odp_ticketlock_unlock(&pkt_nm->rx_desc_ring[index].lock); - - return max_fd; -} - -static int netmap_recv(pktio_entry_t *pktio_entry, int index, - odp_packet_t pkt_table[], int num) -{ - struct nm_desc *desc; - pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); - unsigned int first_desc_id = pkt_nm->rx_desc_ring[index].first; - unsigned int last_desc_id = pkt_nm->rx_desc_ring[index].last; - unsigned int desc_id; - int num_desc = pkt_nm->rx_desc_ring[index].num; - int i; - int num_rx = 0; - int max_fd = 0; - fd_set empty_rings; - - FD_ZERO(&empty_rings); - - if (!pkt_nm->lockless_rx) - odp_ticketlock_lock(&pkt_nm->rx_desc_ring[index].lock); - - desc_id = pkt_nm->rx_desc_ring[index].cur; - - for (i = 0; i < num_desc && num_rx != num; i++) { - if (desc_id > last_desc_id) - desc_id = first_desc_id; - - desc = pkt_nm->rx_desc_ring[index].desc[desc_id]; - - num_rx += netmap_recv_desc(pktio_entry, desc, - &pkt_table[num_rx], num - num_rx); - - if (num_rx != num) { - FD_SET(desc->fd, &empty_rings); - if (desc->fd > max_fd) - max_fd = desc->fd; - } - desc_id++; - } - pkt_nm->rx_desc_ring[index].cur = desc_id; - - if (num_rx != num) { - struct timeval tout = {.tv_sec = 0, .tv_usec = 0}; - - if (select(max_fd + 1, &empty_rings, NULL, NULL, &tout) == -1) - _ODP_ERR("RX: select error\n"); - } - if (!pkt_nm->lockless_rx) - odp_ticketlock_unlock(&pkt_nm->rx_desc_ring[index].lock); - - return num_rx; -} - -static int netmap_recv_tmo(pktio_entry_t *pktio_entry, int index, - odp_packet_t pkt_table[], int num, uint64_t usecs) -{ - struct timeval timeout; - int ret; - int maxfd; - fd_set readfds; - - ret = netmap_recv(pktio_entry, index, pkt_table, num); - if (ret != 0) - return ret; - - timeout.tv_sec = usecs / (1000 * 1000); - timeout.tv_usec = usecs - timeout.tv_sec * (1000ULL * 1000ULL); - FD_ZERO(&readfds); - maxfd = netmap_fd_set(pktio_entry, index, &readfds); - - if (select(maxfd + 1, &readfds, NULL, NULL, &timeout) == 0) - return 0; - - return netmap_recv(pktio_entry, index, pkt_table, num); -} - -static int netmap_recv_mq_tmo(pktio_entry_t *pktio_entry[], int index[], - uint32_t num_q, odp_packet_t pkt_table[], int num, - uint32_t *from, uint64_t usecs) -{ - struct timeval timeout; - uint32_t i; - int ret; - int maxfd = -1, maxfd2; - fd_set readfds; - - for (i = 0; i < num_q; i++) { - ret = netmap_recv(pktio_entry[i], index[i], pkt_table, num); - - if (ret > 0 && from) - *from = i; - - if (ret != 0) - return ret; - } - - FD_ZERO(&readfds); - - for (i = 0; i < num_q; i++) { - maxfd2 = netmap_fd_set(pktio_entry[i], index[i], &readfds); - if (maxfd2 > maxfd) - maxfd = maxfd2; - } - - timeout.tv_sec = usecs / (1000 * 1000); - timeout.tv_usec = usecs - timeout.tv_sec * (1000ULL * 1000ULL); - - if (select(maxfd + 1, &readfds, NULL, NULL, &timeout) == 0) - return 0; - - for (i = 0; i < num_q; i++) { - ret = netmap_recv(pktio_entry[i], index[i], pkt_table, num); - - if (ret > 0 && from) - *from = i; - - if (ret != 0) - return ret; - } - - return 0; -} - -static int netmap_send(pktio_entry_t *pktio_entry, int index, - const odp_packet_t pkt_table[], int num) -{ - pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); - struct pollfd polld; - struct nm_desc *desc; - struct netmap_ring *ring; - int i; - int nb_tx; - int desc_id; - int tx_ts_idx = 0; - uint8_t tx_ts_enabled = _odp_pktio_tx_ts_enabled(pktio_entry); - odp_packet_t pkt; - uint32_t pkt_len; - unsigned int slot_id; - char *buf; - - /* Only one netmap tx ring per pktout queue */ - desc_id = pkt_nm->tx_desc_ring[index].cur; - desc = pkt_nm->tx_desc_ring[index].desc[desc_id]; - ring = NETMAP_TXRING(desc->nifp, desc->cur_tx_ring); - - if (!pkt_nm->lockless_tx) - odp_ticketlock_lock(&pkt_nm->tx_desc_ring[index].lock); - - polld.fd = desc->fd; - polld.events = POLLOUT; - - for (nb_tx = 0; nb_tx < num; nb_tx++) { - pkt = pkt_table[nb_tx]; - pkt_len = odp_packet_len(pkt); - - if (pkt_len > pkt_nm->mtu) { - if (nb_tx == 0) - _odp_errno = EMSGSIZE; - break; - } - for (i = 0; i < NM_INJECT_RETRIES; i++) { - if (nm_ring_empty(ring)) { - poll(&polld, 1, 0); - continue; - } - slot_id = ring->cur; - ring->slot[slot_id].flags = 0; - ring->slot[slot_id].len = pkt_len; - - buf = NETMAP_BUF(ring, ring->slot[slot_id].buf_idx); - - if (odp_packet_copy_to_mem(pkt, 0, pkt_len, buf)) { - i = NM_INJECT_RETRIES; - break; - } - ring->cur = nm_ring_next(ring, slot_id); - ring->head = ring->cur; - break; - } - if (i == NM_INJECT_RETRIES) - break; - - if (tx_ts_enabled && tx_ts_idx == 0) { - if (odp_unlikely(packet_hdr(pkt)->p.flags.ts_set)) - tx_ts_idx = i + 1; - } - } - /* Send pending packets */ - poll(&polld, 1, 0); - - if (!pkt_nm->lockless_tx) - odp_ticketlock_unlock(&pkt_nm->tx_desc_ring[index].lock); - - if (odp_unlikely(nb_tx == 0)) { - if (_odp_errno != 0) - return -1; - } else { - if (odp_unlikely(tx_ts_idx && nb_tx >= tx_ts_idx)) - _odp_pktio_tx_ts_set(pktio_entry); - - odp_packet_free_multi(pkt_table, nb_tx); - } - - return nb_tx; -} - -static int netmap_mac_addr_get(pktio_entry_t *pktio_entry, void *mac_addr) -{ - memcpy(mac_addr, pkt_priv(pktio_entry)->if_mac, ETH_ALEN); - return ETH_ALEN; -} - -static uint32_t netmap_mtu_get(pktio_entry_t *pktio_entry) -{ - return pkt_priv(pktio_entry)->mtu; -} - -static int netmap_mtu_set(pktio_entry_t *pktio_entry, uint32_t maxlen_input, - uint32_t maxlen_output ODP_UNUSED) -{ - pkt_netmap_t *pkt_nm = pkt_priv(pktio_entry); - int ret; - - ret = _odp_mtu_set_fd(pkt_nm->sockfd, pktio_entry->name, maxlen_input); - if (ret) - return ret; - - pkt_nm->mtu = maxlen_input; - - return 0; -} - -static int netmap_promisc_mode_set(pktio_entry_t *pktio_entry, - odp_bool_t enable) -{ - if (pkt_priv(pktio_entry)->is_virtual) { - _odp_errno = ENOTSUP; - return -1; - } - - return _odp_promisc_mode_set_fd(pkt_priv(pktio_entry)->sockfd, - pkt_priv(pktio_entry)->if_name, enable); -} - -static int netmap_promisc_mode_get(pktio_entry_t *pktio_entry) -{ - if (pkt_priv(pktio_entry)->is_virtual) - return 0; - - return _odp_promisc_mode_get_fd(pkt_priv(pktio_entry)->sockfd, - pkt_priv(pktio_entry)->if_name); -} - -static int netmap_capability(pktio_entry_t *pktio_entry, - odp_pktio_capability_t *capa) -{ - *capa = pktio_entry->capa; - return 0; -} - -static int netmap_stats(pktio_entry_t *pktio_entry, - odp_pktio_stats_t *stats) -{ - return _odp_sock_stats_fd(pktio_entry, - stats, - pkt_priv(pktio_entry)->sockfd); -} - -static int netmap_stats_reset(pktio_entry_t *pktio_entry) -{ - return _odp_sock_stats_reset_fd(pktio_entry, - pkt_priv(pktio_entry)->sockfd); -} - -static int netmap_extra_stat_info(pktio_entry_t *pktio_entry, - odp_pktio_extra_stat_info_t info[], int num) -{ - return _odp_sock_extra_stat_info(pktio_entry, info, num, - pkt_priv(pktio_entry)->sockfd); -} - -static int netmap_extra_stats(pktio_entry_t *pktio_entry, uint64_t stats[], - int num) -{ - return _odp_sock_extra_stats(pktio_entry, stats, num, - pkt_priv(pktio_entry)->sockfd); -} - -static int netmap_extra_stat_counter(pktio_entry_t *pktio_entry, uint32_t id, - uint64_t *stat) -{ - return _odp_sock_extra_stat_counter(pktio_entry, id, stat, - pkt_priv(pktio_entry)->sockfd); -} - -static void netmap_print(pktio_entry_t *pktio_entry) -{ - odp_pktin_hash_proto_t hash_proto; - - if (_odp_rss_conf_get_fd(pkt_priv(pktio_entry)->sockfd, - pkt_priv(pktio_entry)->if_name, &hash_proto)) - _odp_rss_conf_print(&hash_proto); -} - -static int netmap_init_global(void) -{ - if (getenv("ODP_PKTIO_DISABLE_NETMAP")) { - _ODP_PRINT("PKTIO: netmap pktio skipped," - " enabled export ODP_PKTIO_DISABLE_NETMAP=1.\n"); - disable_pktio = 1; - } else { - _ODP_PRINT("PKTIO: initialized netmap pktio," - " use export ODP_PKTIO_DISABLE_NETMAP=1 to disable.\n" - " Netmap prefixes are netmap:eth0 or vale:eth0. Refer to" - " Netmap documentation for usage information.\n"); - } - return 0; -} - -const pktio_if_ops_t _odp_netmap_pktio_ops = { - .name = "netmap", - .print = netmap_print, - .init_global = netmap_init_global, - .init_local = NULL, - .term = NULL, - .open = netmap_open, - .close = netmap_close, - .start = netmap_start, - .stop = netmap_stop, - .link_status = netmap_link_status, - .link_info = netmap_link_info, - .stats = netmap_stats, - .stats_reset = netmap_stats_reset, - .extra_stat_info = netmap_extra_stat_info, - .extra_stats = netmap_extra_stats, - .extra_stat_counter = netmap_extra_stat_counter, - .maxlen_get = netmap_mtu_get, - .maxlen_set = netmap_mtu_set, - .promisc_mode_set = netmap_promisc_mode_set, - .promisc_mode_get = netmap_promisc_mode_get, - .mac_get = netmap_mac_addr_get, - .mac_set = NULL, - .capability = netmap_capability, - .pktio_ts_res = NULL, - .pktio_ts_from_ns = NULL, - .pktio_time = NULL, - .config = NULL, - .input_queues_config = netmap_input_queues_config, - .output_queues_config = netmap_output_queues_config, - .recv = netmap_recv, - .recv_tmo = netmap_recv_tmo, - .recv_mq_tmo = netmap_recv_mq_tmo, - .send = netmap_send, - .fd_set = netmap_fd_set -}; -#else /* _ODP_PKTIO_NETMAP */ -/* Avoid warning about empty translation unit */ -typedef int _odp_dummy; -#endif diff --git a/platform/linux-generic/pktio/socket_common.c b/platform/linux-generic/pktio/socket_common.c index b6ae7b9ae..d7c320a54 100644 --- a/platform/linux-generic/pktio/socket_common.c +++ b/platform/linux-generic/pktio/socket_common.c @@ -46,7 +46,6 @@ struct ethtool_link_settings { /** * ODP_PACKET_SOCKET_MMSG: * ODP_PACKET_SOCKET_MMAP: - * ODP_PACKET_NETMAP: */ int _odp_mac_addr_get_fd(int fd, const char *name, unsigned char mac_dst[]) { @@ -70,7 +69,6 @@ int _odp_mac_addr_get_fd(int fd, const char *name, unsigned char mac_dst[]) /* * ODP_PACKET_SOCKET_MMSG: * ODP_PACKET_SOCKET_MMAP: - * ODP_PACKET_NETMAP: * ODP_PACKET_TAP: */ uint32_t _odp_mtu_get_fd(int fd, const char *name) @@ -91,7 +89,6 @@ uint32_t _odp_mtu_get_fd(int fd, const char *name) /* * ODP_PACKET_SOCKET_MMAP: * ODP_PACKET_SOCKET_MMSG: - * ODP_PACKET_NETMAP: * ODP_PACKET_TAP: */ int _odp_mtu_set_fd(int fd, const char *name, int mtu) @@ -114,7 +111,6 @@ int _odp_mtu_set_fd(int fd, const char *name, int mtu) /* * ODP_PACKET_SOCKET_MMSG: * ODP_PACKET_SOCKET_MMAP: - * ODP_PACKET_NETMAP: */ int _odp_promisc_mode_set_fd(int fd, const char *name, int enable) { @@ -146,7 +142,6 @@ int _odp_promisc_mode_set_fd(int fd, const char *name, int enable) /* * ODP_PACKET_SOCKET_MMSG: * ODP_PACKET_SOCKET_MMAP: - * ODP_PACKET_NETMAP: */ int _odp_promisc_mode_get_fd(int fd, const char *name) { diff --git a/platform/linux-generic/test/Makefile.am b/platform/linux-generic/test/Makefile.am index 06e5a3ba2..99d7199ad 100644 --- a/platform/linux-generic/test/Makefile.am +++ b/platform/linux-generic/test/Makefile.am @@ -23,9 +23,6 @@ SUBDIRS += validation/api/pktio\ if ODP_PKTIO_PCAP TESTS += validation/api/pktio/pktio_run_pcap.sh endif -if netmap_support -TESTS += validation/api/pktio/pktio_run_netmap.sh -endif if PKTIO_DPDK TESTS += validation/api/pktio/pktio_run_dpdk.sh endif diff --git a/platform/linux-generic/test/validation/api/pktio/Makefile.am b/platform/linux-generic/test/validation/api/pktio/Makefile.am index 98b8b233d..1646743fe 100644 --- a/platform/linux-generic/test/validation/api/pktio/Makefile.am +++ b/platform/linux-generic/test/validation/api/pktio/Makefile.am @@ -5,9 +5,6 @@ dist_check_SCRIPTS = pktio_env \ if ODP_PKTIO_PCAP dist_check_SCRIPTS += pktio_run_pcap.sh endif -if netmap_support -dist_check_SCRIPTS += pktio_run_netmap.sh -endif if PKTIO_DPDK dist_check_SCRIPTS += pktio_run_dpdk.sh endif diff --git a/platform/linux-generic/test/validation/api/pktio/pktio_run.sh b/platform/linux-generic/test/validation/api/pktio/pktio_run.sh index 9820ca339..cac297768 100755 --- a/platform/linux-generic/test/validation/api/pktio/pktio_run.sh +++ b/platform/linux-generic/test/validation/api/pktio/pktio_run.sh @@ -62,9 +62,6 @@ run_test() unset ODP_PKTIO_DISABLE_SOCKET_${distype} done - # this script doesn't support testing with netmap - export ODP_PKTIO_DISABLE_NETMAP=y - for distype in SKIP MMAP; do if [ "$disabletype" != "SKIP" ]; then export ODP_PKTIO_DISABLE_SOCKET_${distype}=y diff --git a/platform/linux-generic/test/validation/api/pktio/pktio_run_netmap.sh b/platform/linux-generic/test/validation/api/pktio/pktio_run_netmap.sh deleted file mode 100755 index f4851483b..000000000 --- a/platform/linux-generic/test/validation/api/pktio/pktio_run_netmap.sh +++ /dev/null @@ -1,123 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2016-2018, Linaro Limited -# All rights reserved. -# -# SPDX-License-Identifier: BSD-3-Clause -# - -# any parameter passed as arguments to this script is passed unchanged to -# the test itself (pktio_main) - -# directories where pktio_main binary can be found: -# -in the validation dir when running make check (intree or out of tree) -# -in the script directory, when running after 'make install', or -# -in the validation when running standalone (./pktio_run) intree. -# -in the current directory. -# running stand alone out of tree requires setting PATH -PATH=${TEST_DIR}/api/pktio:$PATH -PATH=$(dirname $0):$PATH -PATH=$(dirname $0)/../../../../../../test/validation/api/pktio:$PATH -PATH=.:$PATH - -pktio_main_path=$(which pktio_main${EXEEXT}) -if [ -x "$pktio_main_path" ] ; then - echo "running with pktio_main: $pktio_main_path" -else - echo "cannot find pktio_main: please set you PATH for it." -fi - -# directory where platform test sources are, including scripts -TEST_SRC_DIR=$(dirname $0) - -# exit codes expected by automake for skipped tests -TEST_SKIPPED=77 - -# Use installed pktio env or for make check take it from the test directory -if [ -f "./pktio_env" ]; then - . ./pktio_env -elif [ -f ${TEST_SRC_DIR}/pktio_env ]; then - . ${TEST_SRC_DIR}/pktio_env -else - echo "ERROR: unable to find pktio_env!" - echo "pktio_env has to be in current directory or in ${TEST_SRC_DIR}" - exit 1 -fi - -run_test() -{ - local ret=0 - - pktio_main${EXEEXT} $* - ret=$? - - if [ $ret -ne 0 ]; then - echo "!!! FAILED !!!" - fi - - return $ret -} - -run_test_vale() -{ - # use two vale ports on the same switch - export ODP_PKTIO_IF0=valetest:0 - export ODP_PKTIO_IF1=valetest:1 - run_test - return $? -} - -run_test_pipe() -{ - # use a netmap pipe - export ODP_PKTIO_IF0=valetest:0{0 - export ODP_PKTIO_IF1=valetest:0}0 - run_test - return $? -} - -run_test_veth() -{ - if [ "$(lsmod | grep veth)" = "" ]; then - echo "netmap enabled veth module not loaded, skipping test." - return 0 - fi - - setup_pktio_env clean - export ODP_PKTIO_IF0=netmap:$IF0 - export ODP_PKTIO_IF1=netmap:$IF1 - run_test - return $? -} - -run() -{ - local ret=0 - - # need to be root to run these tests - if [ "$(id -u)" != "0" ]; then - echo "netmap tests must be run as root, skipping test." - exit $TEST_SKIPPED - fi - - if [ "$(lsmod | grep netmap)" = "" ]; then - echo "netmap kernel module not loaded, skipping test." - exit $TEST_SKIPPED - fi - - if [ "$ODP_PKTIO_IF0" != "" ]; then - run_test - ret=$? - else - run_test_vale - r=$?; [ $ret = 0 ] && ret=$r - run_test_pipe - r=$?; [ $ret = 0 ] && ret=$r - run_test_veth - r=$?; [ $ret = 0 ] && ret=$r - fi - - exit $ret -} - -run |