summaryrefslogtreecommitdiffstats
path: root/src/spdk/dpdk/app/test-pmd
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
commit19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch)
tree42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/spdk/dpdk/app/test-pmd
parentInitial commit. (diff)
downloadceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.tar.xz
ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.zip
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/spdk/dpdk/app/test-pmd')
-rw-r--r--src/spdk/dpdk/app/test-pmd/Makefile76
-rw-r--r--src/spdk/dpdk/app/test-pmd/bpf_cmd.c198
-rw-r--r--src/spdk/dpdk/app/test-pmd/bpf_cmd.h16
-rw-r--r--src/spdk/dpdk/app/test-pmd/cmdline.c19763
-rw-r--r--src/spdk/dpdk/app/test-pmd/cmdline_flow.c6888
-rw-r--r--src/spdk/dpdk/app/test-pmd/cmdline_mtr.c1467
-rw-r--r--src/spdk/dpdk/app/test-pmd/cmdline_mtr.h24
-rw-r--r--src/spdk/dpdk/app/test-pmd/cmdline_tm.c2463
-rw-r--r--src/spdk/dpdk/app/test-pmd/cmdline_tm.h32
-rw-r--r--src/spdk/dpdk/app/test-pmd/config.c4318
-rw-r--r--src/spdk/dpdk/app/test-pmd/csumonly.c1112
-rw-r--r--src/spdk/dpdk/app/test-pmd/flowgen.c222
-rw-r--r--src/spdk/dpdk/app/test-pmd/icmpecho.c535
-rw-r--r--src/spdk/dpdk/app/test-pmd/ieee1588fwd.c218
-rw-r--r--src/spdk/dpdk/app/test-pmd/iofwd.c111
-rw-r--r--src/spdk/dpdk/app/test-pmd/macfwd.c141
-rw-r--r--src/spdk/dpdk/app/test-pmd/macswap.c120
-rw-r--r--src/spdk/dpdk/app/test-pmd/macswap.h40
-rw-r--r--src/spdk/dpdk/app/test-pmd/macswap_common.h46
-rw-r--r--src/spdk/dpdk/app/test-pmd/macswap_neon.h97
-rw-r--r--src/spdk/dpdk/app/test-pmd/macswap_sse.h94
-rw-r--r--src/spdk/dpdk/app/test-pmd/meson.build49
-rw-r--r--src/spdk/dpdk/app/test-pmd/noisy_vnf.c279
-rw-r--r--src/spdk/dpdk/app/test-pmd/parameters.c1413
-rw-r--r--src/spdk/dpdk/app/test-pmd/rxonly.c88
-rw-r--r--src/spdk/dpdk/app/test-pmd/softnicfwd.c686
-rw-r--r--src/spdk/dpdk/app/test-pmd/testpmd.c3859
-rw-r--r--src/spdk/dpdk/app/test-pmd/testpmd.h938
-rw-r--r--src/spdk/dpdk/app/test-pmd/txonly.c361
-rw-r--r--src/spdk/dpdk/app/test-pmd/util.c377
30 files changed, 46031 insertions, 0 deletions
diff --git a/src/spdk/dpdk/app/test-pmd/Makefile b/src/spdk/dpdk/app/test-pmd/Makefile
new file mode 100644
index 000000000..ea818de22
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/Makefile
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2015 Intel Corporation
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifeq ($(CONFIG_RTE_TEST_PMD),y)
+
+#
+# library name
+#
+APP = testpmd
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -Wno-deprecated-declarations
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-y := testpmd.c
+SRCS-y += parameters.c
+SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline.c
+SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_mtr.c
+SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_tm.c
+SRCS-y += config.c
+SRCS-y += iofwd.c
+SRCS-y += macfwd.c
+SRCS-y += macswap.c
+SRCS-y += flowgen.c
+SRCS-y += rxonly.c
+SRCS-y += txonly.c
+SRCS-y += csumonly.c
+SRCS-y += icmpecho.c
+SRCS-y += noisy_vnf.c
+SRCS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ieee1588fwd.c
+SRCS-$(CONFIG_RTE_LIBRTE_BPF) += bpf_cmd.c
+SRCS-y += util.c
+
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_SOFTNIC), y)
+SRCS-y += softnicfwd.c
+endif
+
+ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
+
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_BOND),y)
+LDLIBS += -lrte_pmd_bond
+endif
+
+ifeq ($(CONFIG_RTE_LIBRTE_DPAA_BUS)$(CONFIG_RTE_LIBRTE_DPAA_PMD),yy)
+LDLIBS += -lrte_pmd_dpaa
+LDLIBS += -lrte_bus_dpaa
+LDLIBS += -lrte_mempool_dpaa
+endif
+
+ifeq ($(CONFIG_RTE_LIBRTE_IXGBE_PMD),y)
+LDLIBS += -lrte_pmd_ixgbe
+endif
+
+ifeq ($(CONFIG_RTE_LIBRTE_I40E_PMD),y)
+LDLIBS += -lrte_pmd_i40e
+endif
+
+ifeq ($(CONFIG_RTE_LIBRTE_BNXT_PMD),y)
+LDLIBS += -lrte_pmd_bnxt
+endif
+
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_SOFTNIC),y)
+LDLIBS += -lrte_pmd_softnic
+endif
+
+endif
+
+include $(RTE_SDK)/mk/rte.app.mk
+
+endif
diff --git a/src/spdk/dpdk/app/test-pmd/bpf_cmd.c b/src/spdk/dpdk/app/test-pmd/bpf_cmd.c
new file mode 100644
index 000000000..0f984ccf4
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/bpf_cmd.c
@@ -0,0 +1,198 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <stdio.h>
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_bpf_ethdev.h>
+
+#include <cmdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+#include "testpmd.h"
+
+static const struct rte_bpf_xsym bpf_xsym[] = {
+ {
+ .name = RTE_STR(stdout),
+ .type = RTE_BPF_XTYPE_VAR,
+ .var = {
+ .val = &stdout,
+ .desc = {
+ .type = RTE_BPF_ARG_PTR,
+ .size = sizeof(stdout),
+ },
+ },
+ },
+ {
+ .name = RTE_STR(rte_pktmbuf_dump),
+ .type = RTE_BPF_XTYPE_FUNC,
+ .func = {
+ .val = (void *)rte_pktmbuf_dump,
+ .nb_args = 3,
+ .args = {
+ [0] = {
+ .type = RTE_BPF_ARG_RAW,
+ .size = sizeof(uintptr_t),
+ },
+ [1] = {
+ .type = RTE_BPF_ARG_PTR_MBUF,
+ .size = sizeof(struct rte_mbuf),
+ },
+ [2] = {
+ .type = RTE_BPF_ARG_RAW,
+ .size = sizeof(uint32_t),
+ },
+ },
+ },
+ },
+};
+
+/* *** load BPF program *** */
+struct cmd_bpf_ld_result {
+ cmdline_fixed_string_t bpf;
+ cmdline_fixed_string_t dir;
+ uint8_t port;
+ uint16_t queue;
+ cmdline_fixed_string_t op;
+ cmdline_fixed_string_t flags;
+ cmdline_fixed_string_t prm;
+};
+
+static void
+bpf_parse_flags(const char *str, struct rte_bpf_arg *arg, uint32_t *flags)
+{
+ uint32_t i, v;
+
+ *flags = RTE_BPF_ETH_F_NONE;
+ arg->type = RTE_BPF_ARG_PTR;
+ arg->size = mbuf_data_size;
+
+ for (i = 0; str[i] != 0; i++) {
+ v = toupper(str[i]);
+ if (v == 'J')
+ *flags |= RTE_BPF_ETH_F_JIT;
+ else if (v == 'M') {
+ arg->type = RTE_BPF_ARG_PTR_MBUF;
+ arg->size = sizeof(struct rte_mbuf);
+ arg->buf_size = mbuf_data_size;
+ } else if (v == '-')
+ continue;
+ else
+ printf("unknown flag: \'%c\'", v);
+ }
+}
+
+static void cmd_operate_bpf_ld_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ int32_t rc;
+ uint32_t flags;
+ struct cmd_bpf_ld_result *res;
+ struct rte_bpf_prm prm;
+ const char *fname, *sname;
+
+ res = parsed_result;
+ memset(&prm, 0, sizeof(prm));
+ prm.xsym = bpf_xsym;
+ prm.nb_xsym = RTE_DIM(bpf_xsym);
+
+ bpf_parse_flags(res->flags, &prm.prog_arg, &flags);
+ fname = res->prm;
+ sname = ".text";
+
+ if (strcmp(res->dir, "rx") == 0) {
+ rc = rte_bpf_eth_rx_elf_load(res->port, res->queue, &prm,
+ fname, sname, flags);
+ printf("%d:%s\n", rc, strerror(-rc));
+ } else if (strcmp(res->dir, "tx") == 0) {
+ rc = rte_bpf_eth_tx_elf_load(res->port, res->queue, &prm,
+ fname, sname, flags);
+ printf("%d:%s\n", rc, strerror(-rc));
+ } else
+ printf("invalid value: %s\n", res->dir);
+}
+
+cmdline_parse_token_string_t cmd_load_bpf_start =
+ TOKEN_STRING_INITIALIZER(struct cmd_bpf_ld_result,
+ bpf, "bpf-load");
+cmdline_parse_token_string_t cmd_load_bpf_dir =
+ TOKEN_STRING_INITIALIZER(struct cmd_bpf_ld_result,
+ dir, "rx#tx");
+cmdline_parse_token_num_t cmd_load_bpf_port =
+ TOKEN_NUM_INITIALIZER(struct cmd_bpf_ld_result, port, UINT8);
+cmdline_parse_token_num_t cmd_load_bpf_queue =
+ TOKEN_NUM_INITIALIZER(struct cmd_bpf_ld_result, queue, UINT16);
+cmdline_parse_token_string_t cmd_load_bpf_flags =
+ TOKEN_STRING_INITIALIZER(struct cmd_bpf_ld_result,
+ flags, NULL);
+cmdline_parse_token_string_t cmd_load_bpf_prm =
+ TOKEN_STRING_INITIALIZER(struct cmd_bpf_ld_result,
+ prm, NULL);
+
+cmdline_parse_inst_t cmd_operate_bpf_ld_parse = {
+ .f = cmd_operate_bpf_ld_parsed,
+ .data = NULL,
+ .help_str = "bpf-load rx|tx <port> <queue> <J|M|B> <file_name>",
+ .tokens = {
+ (void *)&cmd_load_bpf_start,
+ (void *)&cmd_load_bpf_dir,
+ (void *)&cmd_load_bpf_port,
+ (void *)&cmd_load_bpf_queue,
+ (void *)&cmd_load_bpf_flags,
+ (void *)&cmd_load_bpf_prm,
+ NULL,
+ },
+};
+
+/* *** unload BPF program *** */
+struct cmd_bpf_unld_result {
+ cmdline_fixed_string_t bpf;
+ cmdline_fixed_string_t dir;
+ uint8_t port;
+ uint16_t queue;
+};
+
+static void cmd_operate_bpf_unld_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_bpf_unld_result *res;
+
+ res = parsed_result;
+
+ if (strcmp(res->dir, "rx") == 0)
+ rte_bpf_eth_rx_unload(res->port, res->queue);
+ else if (strcmp(res->dir, "tx") == 0)
+ rte_bpf_eth_tx_unload(res->port, res->queue);
+ else
+ printf("invalid value: %s\n", res->dir);
+}
+
+cmdline_parse_token_string_t cmd_unload_bpf_start =
+ TOKEN_STRING_INITIALIZER(struct cmd_bpf_unld_result,
+ bpf, "bpf-unload");
+cmdline_parse_token_string_t cmd_unload_bpf_dir =
+ TOKEN_STRING_INITIALIZER(struct cmd_bpf_unld_result,
+ dir, "rx#tx");
+cmdline_parse_token_num_t cmd_unload_bpf_port =
+ TOKEN_NUM_INITIALIZER(struct cmd_bpf_unld_result, port, UINT8);
+cmdline_parse_token_num_t cmd_unload_bpf_queue =
+ TOKEN_NUM_INITIALIZER(struct cmd_bpf_unld_result, queue, UINT16);
+
+cmdline_parse_inst_t cmd_operate_bpf_unld_parse = {
+ .f = cmd_operate_bpf_unld_parsed,
+ .data = NULL,
+ .help_str = "bpf-unload rx|tx <port> <queue>",
+ .tokens = {
+ (void *)&cmd_unload_bpf_start,
+ (void *)&cmd_unload_bpf_dir,
+ (void *)&cmd_unload_bpf_port,
+ (void *)&cmd_unload_bpf_queue,
+ NULL,
+ },
+};
diff --git a/src/spdk/dpdk/app/test-pmd/bpf_cmd.h b/src/spdk/dpdk/app/test-pmd/bpf_cmd.h
new file mode 100644
index 000000000..5ee4c9f79
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/bpf_cmd.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef _BPF_CMD_H_
+#define _BPF_CMD_H_
+
+#ifdef RTE_LIBRTE_BPF
+
+ /* BPF CLI */
+extern cmdline_parse_inst_t cmd_operate_bpf_ld_parse;
+extern cmdline_parse_inst_t cmd_operate_bpf_unld_parse;
+
+#endif /* RTE_LIBRTE_BPF */
+
+#endif /* _BPF_CMD_H_ */
diff --git a/src/spdk/dpdk/app/test-pmd/cmdline.c b/src/spdk/dpdk/app/test-pmd/cmdline.c
new file mode 100644
index 000000000..996a49876
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/cmdline.c
@@ -0,0 +1,19763 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation.
+ * Copyright(c) 2014 6WIND S.A.
+ */
+
+#include <stdarg.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <sys/queue.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_malloc.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_string_fns.h>
+#include <rte_devargs.h>
+#include <rte_flow.h>
+#include <rte_gro.h>
+#include <rte_mbuf_dyn.h>
+
+#include <cmdline_rdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+#ifdef RTE_LIBRTE_PMD_BOND
+#include <rte_eth_bond.h>
+#include <rte_eth_bond_8023ad.h>
+#endif
+#if defined RTE_LIBRTE_DPAA_BUS && defined RTE_LIBRTE_DPAA_PMD
+#include <rte_pmd_dpaa.h>
+#endif
+#ifdef RTE_LIBRTE_IXGBE_PMD
+#include <rte_pmd_ixgbe.h>
+#endif
+#ifdef RTE_LIBRTE_I40E_PMD
+#include <rte_pmd_i40e.h>
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+#include <rte_pmd_bnxt.h>
+#endif
+#include "testpmd.h"
+#include "cmdline_mtr.h"
+#include "cmdline_tm.h"
+#include "bpf_cmd.h"
+
+static struct cmdline *testpmd_cl;
+
+static void cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue);
+
+/* *** Help command with introduction. *** */
+struct cmd_help_brief_result {
+ cmdline_fixed_string_t help;
+};
+
+static void cmd_help_brief_parsed(__rte_unused void *parsed_result,
+ struct cmdline *cl,
+ __rte_unused void *data)
+{
+ cmdline_printf(
+ cl,
+ "\n"
+ "Help is available for the following sections:\n\n"
+ " help control : Start and stop forwarding.\n"
+ " help display : Displaying port, stats and config "
+ "information.\n"
+ " help config : Configuration information.\n"
+ " help ports : Configuring ports.\n"
+ " help registers : Reading and setting port registers.\n"
+ " help filters : Filters configuration help.\n"
+ " help traffic_management : Traffic Management commands.\n"
+ " help devices : Device related cmds.\n"
+ " help all : All of the above sections.\n\n"
+ );
+
+}
+
+cmdline_parse_token_string_t cmd_help_brief_help =
+ TOKEN_STRING_INITIALIZER(struct cmd_help_brief_result, help, "help");
+
+cmdline_parse_inst_t cmd_help_brief = {
+ .f = cmd_help_brief_parsed,
+ .data = NULL,
+ .help_str = "help: Show help",
+ .tokens = {
+ (void *)&cmd_help_brief_help,
+ NULL,
+ },
+};
+
+/* *** Help command with help sections. *** */
+struct cmd_help_long_result {
+ cmdline_fixed_string_t help;
+ cmdline_fixed_string_t section;
+};
+
+static void cmd_help_long_parsed(void *parsed_result,
+ struct cmdline *cl,
+ __rte_unused void *data)
+{
+ int show_all = 0;
+ struct cmd_help_long_result *res = parsed_result;
+
+ if (!strcmp(res->section, "all"))
+ show_all = 1;
+
+ if (show_all || !strcmp(res->section, "control")) {
+
+ cmdline_printf(
+ cl,
+ "\n"
+ "Control forwarding:\n"
+ "-------------------\n\n"
+
+ "start\n"
+ " Start packet forwarding with current configuration.\n\n"
+
+ "start tx_first\n"
+ " Start packet forwarding with current config"
+ " after sending one burst of packets.\n\n"
+
+ "stop\n"
+ " Stop packet forwarding, and display accumulated"
+ " statistics.\n\n"
+
+ "quit\n"
+ " Quit to prompt.\n\n"
+ );
+ }
+
+ if (show_all || !strcmp(res->section, "display")) {
+
+ cmdline_printf(
+ cl,
+ "\n"
+ "Display:\n"
+ "--------\n\n"
+
+ "show port (info|stats|summary|xstats|fdir|stat_qmap|dcb_tc|cap) (port_id|all)\n"
+ " Display information for port_id, or all.\n\n"
+
+ "show port X rss reta (size) (mask0,mask1,...)\n"
+ " Display the rss redirection table entry indicated"
+ " by masks on port X. size is used to indicate the"
+ " hardware supported reta size\n\n"
+
+ "show port (port_id) rss-hash [key]\n"
+ " Display the RSS hash functions and RSS hash key of port\n\n"
+
+ "clear port (info|stats|xstats|fdir|stat_qmap) (port_id|all)\n"
+ " Clear information for port_id, or all.\n\n"
+
+ "show (rxq|txq) info (port_id) (queue_id)\n"
+ " Display information for configured RX/TX queue.\n\n"
+
+ "show config (rxtx|cores|fwd|txpkts)\n"
+ " Display the given configuration.\n\n"
+
+ "read rxd (port_id) (queue_id) (rxd_id)\n"
+ " Display an RX descriptor of a port RX queue.\n\n"
+
+ "read txd (port_id) (queue_id) (txd_id)\n"
+ " Display a TX descriptor of a port TX queue.\n\n"
+
+ "ddp get list (port_id)\n"
+ " Get ddp profile info list\n\n"
+
+ "ddp get info (profile_path)\n"
+ " Get ddp profile information.\n\n"
+
+ "show vf stats (port_id) (vf_id)\n"
+ " Display a VF's statistics.\n\n"
+
+ "clear vf stats (port_id) (vf_id)\n"
+ " Reset a VF's statistics.\n\n"
+
+ "show port (port_id) pctype mapping\n"
+ " Get flow ptype to pctype mapping on a port\n\n"
+
+ "show port meter stats (port_id) (meter_id) (clear)\n"
+ " Get meter stats on a port\n\n"
+
+ "show fwd stats all\n"
+ " Display statistics for all fwd engines.\n\n"
+
+ "clear fwd stats all\n"
+ " Clear statistics for all fwd engines.\n\n"
+
+ "show port (port_id) rx_offload capabilities\n"
+ " List all per queue and per port Rx offloading"
+ " capabilities of a port\n\n"
+
+ "show port (port_id) rx_offload configuration\n"
+ " List port level and all queue level"
+ " Rx offloading configuration\n\n"
+
+ "show port (port_id) tx_offload capabilities\n"
+ " List all per queue and per port"
+ " Tx offloading capabilities of a port\n\n"
+
+ "show port (port_id) tx_offload configuration\n"
+ " List port level and all queue level"
+ " Tx offloading configuration\n\n"
+
+ "show port (port_id) tx_metadata\n"
+ " Show Tx metadata value set"
+ " for a specific port\n\n"
+
+ "show port (port_id) ptypes\n"
+ " Show port supported ptypes"
+ " for a specific port\n\n"
+
+ "show device info (<identifier>|all)"
+ " Show general information about devices probed.\n\n"
+
+ "show port (port_id) rxq|txq (queue_id) desc (desc_id) status"
+ " Show status of rx|tx descriptor.\n\n"
+
+ "show port (port_id) macs|mcast_macs"
+ " Display list of mac addresses added to port.\n\n"
+ );
+ }
+
+ if (show_all || !strcmp(res->section, "config")) {
+ cmdline_printf(
+ cl,
+ "\n"
+ "Configuration:\n"
+ "--------------\n"
+ "Configuration changes only become active when"
+ " forwarding is started/restarted.\n\n"
+
+ "set default\n"
+ " Reset forwarding to the default configuration.\n\n"
+
+ "set verbose (level)\n"
+ " Set the debug verbosity level X.\n\n"
+
+ "set log global|(type) (level)\n"
+ " Set the log level.\n\n"
+
+ "set nbport (num)\n"
+ " Set number of ports.\n\n"
+
+ "set nbcore (num)\n"
+ " Set number of cores.\n\n"
+
+ "set coremask (mask)\n"
+ " Set the forwarding cores hexadecimal mask.\n\n"
+
+ "set portmask (mask)\n"
+ " Set the forwarding ports hexadecimal mask.\n\n"
+
+ "set burst (num)\n"
+ " Set number of packets per burst.\n\n"
+
+ "set burst tx delay (microseconds) retry (num)\n"
+ " Set the transmit delay time and number of retries,"
+ " effective when retry is enabled.\n\n"
+
+ "set txpkts (x[,y]*)\n"
+ " Set the length of each segment of TXONLY"
+ " and optionally CSUM packets.\n\n"
+
+ "set txsplit (off|on|rand)\n"
+ " Set the split policy for the TX packets."
+ " Right now only applicable for CSUM and TXONLY"
+ " modes\n\n"
+
+ "set corelist (x[,y]*)\n"
+ " Set the list of forwarding cores.\n\n"
+
+ "set portlist (x[,y]*)\n"
+ " Set the list of forwarding ports.\n\n"
+
+ "set port setup on (iterator|event)\n"
+ " Select how attached port is retrieved for setup.\n\n"
+
+ "set tx loopback (port_id) (on|off)\n"
+ " Enable or disable tx loopback.\n\n"
+
+ "set all queues drop (port_id) (on|off)\n"
+ " Set drop enable bit for all queues.\n\n"
+
+ "set vf split drop (port_id) (vf_id) (on|off)\n"
+ " Set split drop enable bit for a VF from the PF.\n\n"
+
+ "set vf mac antispoof (port_id) (vf_id) (on|off).\n"
+ " Set MAC antispoof for a VF from the PF.\n\n"
+
+ "set macsec offload (port_id) on encrypt (on|off) replay-protect (on|off)\n"
+ " Enable MACsec offload.\n\n"
+
+ "set macsec offload (port_id) off\n"
+ " Disable MACsec offload.\n\n"
+
+ "set macsec sc (tx|rx) (port_id) (mac) (pi)\n"
+ " Configure MACsec secure connection (SC).\n\n"
+
+ "set macsec sa (tx|rx) (port_id) (idx) (an) (pn) (key)\n"
+ " Configure MACsec secure association (SA).\n\n"
+
+ "set vf broadcast (port_id) (vf_id) (on|off)\n"
+ " Set VF broadcast for a VF from the PF.\n\n"
+
+ "vlan set stripq (on|off) (port_id,queue_id)\n"
+ " Set the VLAN strip for a queue on a port.\n\n"
+
+ "set vf vlan stripq (port_id) (vf_id) (on|off)\n"
+ " Set the VLAN strip for all queues in a pool for a VF from the PF.\n\n"
+
+ "set vf vlan insert (port_id) (vf_id) (vlan_id)\n"
+ " Set VLAN insert for a VF from the PF.\n\n"
+
+ "set vf vlan antispoof (port_id) (vf_id) (on|off)\n"
+ " Set VLAN antispoof for a VF from the PF.\n\n"
+
+ "set vf vlan tag (port_id) (vf_id) (on|off)\n"
+ " Set VLAN tag for a VF from the PF.\n\n"
+
+ "set vf tx max-bandwidth (port_id) (vf_id) (bandwidth)\n"
+ " Set a VF's max bandwidth(Mbps).\n\n"
+
+ "set vf tc tx min-bandwidth (port_id) (vf_id) (bw1, bw2, ...)\n"
+ " Set all TCs' min bandwidth(%%) on a VF.\n\n"
+
+ "set vf tc tx max-bandwidth (port_id) (vf_id) (tc_no) (bandwidth)\n"
+ " Set a TC's max bandwidth(Mbps) on a VF.\n\n"
+
+ "set tx strict-link-priority (port_id) (tc_bitmap)\n"
+ " Set some TCs' strict link priority mode on a physical port.\n\n"
+
+ "set tc tx min-bandwidth (port_id) (bw1, bw2, ...)\n"
+ " Set all TCs' min bandwidth(%%) for all PF and VFs.\n\n"
+
+ "vlan set (strip|filter|qinq_strip|extend) (on|off) (port_id)\n"
+ " Set the VLAN strip or filter or qinq strip or extend\n\n"
+
+ "vlan set (inner|outer) tpid (value) (port_id)\n"
+ " Set the VLAN TPID for Packet Filtering on"
+ " a port\n\n"
+
+ "rx_vlan add (vlan_id|all) (port_id)\n"
+ " Add a vlan_id, or all identifiers, to the set"
+ " of VLAN identifiers filtered by port_id.\n\n"
+
+ "rx_vlan rm (vlan_id|all) (port_id)\n"
+ " Remove a vlan_id, or all identifiers, from the set"
+ " of VLAN identifiers filtered by port_id.\n\n"
+
+ "rx_vlan add (vlan_id) port (port_id) vf (vf_mask)\n"
+ " Add a vlan_id, to the set of VLAN identifiers"
+ "filtered for VF(s) from port_id.\n\n"
+
+ "rx_vlan rm (vlan_id) port (port_id) vf (vf_mask)\n"
+ " Remove a vlan_id, to the set of VLAN identifiers"
+ "filtered for VF(s) from port_id.\n\n"
+
+ "tunnel_filter add (port_id) (outer_mac) (inner_mac) (ip_addr) "
+ "(inner_vlan) (vxlan|nvgre|ipingre|vxlan-gpe) (imac-ivlan|imac-ivlan-tenid|"
+ "imac-tenid|imac|omac-imac-tenid|oip|iip) (tenant_id) (queue_id)\n"
+ " add a tunnel filter of a port.\n\n"
+
+ "tunnel_filter rm (port_id) (outer_mac) (inner_mac) (ip_addr) "
+ "(inner_vlan) (vxlan|nvgre|ipingre|vxlan-gpe) (imac-ivlan|imac-ivlan-tenid|"
+ "imac-tenid|imac|omac-imac-tenid|oip|iip) (tenant_id) (queue_id)\n"
+ " remove a tunnel filter of a port.\n\n"
+
+ "rx_vxlan_port add (udp_port) (port_id)\n"
+ " Add an UDP port for VXLAN packet filter on a port\n\n"
+
+ "rx_vxlan_port rm (udp_port) (port_id)\n"
+ " Remove an UDP port for VXLAN packet filter on a port\n\n"
+
+ "tx_vlan set (port_id) vlan_id[, vlan_id_outer]\n"
+ " Set hardware insertion of VLAN IDs (single or double VLAN "
+ "depends on the number of VLAN IDs) in packets sent on a port.\n\n"
+
+ "tx_vlan set pvid port_id vlan_id (on|off)\n"
+ " Set port based TX VLAN insertion.\n\n"
+
+ "tx_vlan reset (port_id)\n"
+ " Disable hardware insertion of a VLAN header in"
+ " packets sent on a port.\n\n"
+
+ "csum set (ip|udp|tcp|sctp|outer-ip|outer-udp) (hw|sw) (port_id)\n"
+ " Select hardware or software calculation of the"
+ " checksum when transmitting a packet using the"
+ " csum forward engine.\n"
+ " ip|udp|tcp|sctp always concern the inner layer.\n"
+ " outer-ip concerns the outer IP layer in"
+ " outer-udp concerns the outer UDP layer in"
+ " case the packet is recognized as a tunnel packet by"
+ " the forward engine (vxlan, gre and ipip are supported)\n"
+ " Please check the NIC datasheet for HW limits.\n\n"
+
+ "csum parse-tunnel (on|off) (tx_port_id)\n"
+ " If disabled, treat tunnel packets as non-tunneled"
+ " packets (treat inner headers as payload). The port\n"
+ " argument is the port used for TX in csum forward"
+ " engine.\n\n"
+
+ "csum show (port_id)\n"
+ " Display tx checksum offload configuration\n\n"
+
+ "tso set (segsize) (portid)\n"
+ " Enable TCP Segmentation Offload in csum forward"
+ " engine.\n"
+ " Please check the NIC datasheet for HW limits.\n\n"
+
+ "tso show (portid)"
+ " Display the status of TCP Segmentation Offload.\n\n"
+
+ "set port (port_id) gro on|off\n"
+ " Enable or disable Generic Receive Offload in"
+ " csum forwarding engine.\n\n"
+
+ "show port (port_id) gro\n"
+ " Display GRO configuration.\n\n"
+
+ "set gro flush (cycles)\n"
+ " Set the cycle to flush GROed packets from"
+ " reassembly tables.\n\n"
+
+ "set port (port_id) gso (on|off)"
+ " Enable or disable Generic Segmentation Offload in"
+ " csum forwarding engine.\n\n"
+
+ "set gso segsz (length)\n"
+ " Set max packet length for output GSO segments,"
+ " including packet header and payload.\n\n"
+
+ "show port (port_id) gso\n"
+ " Show GSO configuration.\n\n"
+
+ "set fwd (%s)\n"
+ " Set packet forwarding mode.\n\n"
+
+ "mac_addr add (port_id) (XX:XX:XX:XX:XX:XX)\n"
+ " Add a MAC address on port_id.\n\n"
+
+ "mac_addr remove (port_id) (XX:XX:XX:XX:XX:XX)\n"
+ " Remove a MAC address from port_id.\n\n"
+
+ "mac_addr set (port_id) (XX:XX:XX:XX:XX:XX)\n"
+ " Set the default MAC address for port_id.\n\n"
+
+ "mac_addr add port (port_id) vf (vf_id) (mac_address)\n"
+ " Add a MAC address for a VF on the port.\n\n"
+
+ "set vf mac addr (port_id) (vf_id) (XX:XX:XX:XX:XX:XX)\n"
+ " Set the MAC address for a VF from the PF.\n\n"
+
+ "set eth-peer (port_id) (peer_addr)\n"
+ " set the peer address for certain port.\n\n"
+
+ "set port (port_id) uta (mac_address|all) (on|off)\n"
+ " Add/Remove a or all unicast hash filter(s)"
+ "from port X.\n\n"
+
+ "set promisc (port_id|all) (on|off)\n"
+ " Set the promiscuous mode on port_id, or all.\n\n"
+
+ "set allmulti (port_id|all) (on|off)\n"
+ " Set the allmulti mode on port_id, or all.\n\n"
+
+ "set vf promisc (port_id) (vf_id) (on|off)\n"
+ " Set unicast promiscuous mode for a VF from the PF.\n\n"
+
+ "set vf allmulti (port_id) (vf_id) (on|off)\n"
+ " Set multicast promiscuous mode for a VF from the PF.\n\n"
+
+ "set flow_ctrl rx (on|off) tx (on|off) (high_water)"
+ " (low_water) (pause_time) (send_xon) mac_ctrl_frame_fwd"
+ " (on|off) autoneg (on|off) (port_id)\n"
+ "set flow_ctrl rx (on|off) (portid)\n"
+ "set flow_ctrl tx (on|off) (portid)\n"
+ "set flow_ctrl high_water (high_water) (portid)\n"
+ "set flow_ctrl low_water (low_water) (portid)\n"
+ "set flow_ctrl pause_time (pause_time) (portid)\n"
+ "set flow_ctrl send_xon (send_xon) (portid)\n"
+ "set flow_ctrl mac_ctrl_frame_fwd (on|off) (portid)\n"
+ "set flow_ctrl autoneg (on|off) (port_id)\n"
+ " Set the link flow control parameter on a port.\n\n"
+
+ "set pfc_ctrl rx (on|off) tx (on|off) (high_water)"
+ " (low_water) (pause_time) (priority) (port_id)\n"
+ " Set the priority flow control parameter on a"
+ " port.\n\n"
+
+ "set stat_qmap (tx|rx) (port_id) (queue_id) (qmapping)\n"
+ " Set statistics mapping (qmapping 0..15) for RX/TX"
+ " queue on port.\n"
+ " e.g., 'set stat_qmap rx 0 2 5' sets rx queue 2"
+ " on port 0 to mapping 5.\n\n"
+
+ "set xstats-hide-zero on|off\n"
+ " Set the option to hide the zero values"
+ " for xstats display.\n"
+
+ "set port (port_id) vf (vf_id) rx|tx on|off\n"
+ " Enable/Disable a VF receive/tranmit from a port\n\n"
+
+ "set port (port_id) vf (vf_id) (mac_addr)"
+ " (exact-mac#exact-mac-vlan#hashmac|hashmac-vlan) on|off\n"
+ " Add/Remove unicast or multicast MAC addr filter"
+ " for a VF.\n\n"
+
+ "set port (port_id) vf (vf_id) rxmode (AUPE|ROPE|BAM"
+ "|MPE) (on|off)\n"
+ " AUPE:accepts untagged VLAN;"
+ "ROPE:accept unicast hash\n\n"
+ " BAM:accepts broadcast packets;"
+ "MPE:accepts all multicast packets\n\n"
+ " Enable/Disable a VF receive mode of a port\n\n"
+
+ "set port (port_id) queue (queue_id) rate (rate_num)\n"
+ " Set rate limit for a queue of a port\n\n"
+
+ "set port (port_id) vf (vf_id) rate (rate_num) "
+ "queue_mask (queue_mask_value)\n"
+ " Set rate limit for queues in VF of a port\n\n"
+
+ "set port (port_id) mirror-rule (rule_id)"
+ " (pool-mirror-up|pool-mirror-down|vlan-mirror)"
+ " (poolmask|vlanid[,vlanid]*) dst-pool (pool_id) (on|off)\n"
+ " Set pool or vlan type mirror rule on a port.\n"
+ " e.g., 'set port 0 mirror-rule 0 vlan-mirror 0,1"
+ " dst-pool 0 on' enable mirror traffic with vlan 0,1"
+ " to pool 0.\n\n"
+
+ "set port (port_id) mirror-rule (rule_id)"
+ " (uplink-mirror|downlink-mirror) dst-pool"
+ " (pool_id) (on|off)\n"
+ " Set uplink or downlink type mirror rule on a port.\n"
+ " e.g., 'set port 0 mirror-rule 0 uplink-mirror dst-pool"
+ " 0 on' enable mirror income traffic to pool 0.\n\n"
+
+ "reset port (port_id) mirror-rule (rule_id)\n"
+ " Reset a mirror rule.\n\n"
+
+ "set flush_rx (on|off)\n"
+ " Flush (default) or don't flush RX streams before"
+ " forwarding. Mainly used with PCAP drivers.\n\n"
+
+ "set bypass mode (normal|bypass|isolate) (port_id)\n"
+ " Set the bypass mode for the lowest port on bypass enabled"
+ " NIC.\n\n"
+
+ "set bypass event (timeout|os_on|os_off|power_on|power_off) "
+ "mode (normal|bypass|isolate) (port_id)\n"
+ " Set the event required to initiate specified bypass mode for"
+ " the lowest port on a bypass enabled NIC where:\n"
+ " timeout = enable bypass after watchdog timeout.\n"
+ " os_on = enable bypass when OS/board is powered on.\n"
+ " os_off = enable bypass when OS/board is powered off.\n"
+ " power_on = enable bypass when power supply is turned on.\n"
+ " power_off = enable bypass when power supply is turned off."
+ "\n\n"
+
+ "set bypass timeout (0|1.5|2|3|4|8|16|32)\n"
+ " Set the bypass watchdog timeout to 'n' seconds"
+ " where 0 = instant.\n\n"
+
+ "show bypass config (port_id)\n"
+ " Show the bypass configuration for a bypass enabled NIC"
+ " using the lowest port on the NIC.\n\n"
+
+#ifdef RTE_LIBRTE_PMD_BOND
+ "create bonded device (mode) (socket)\n"
+ " Create a new bonded device with specific bonding mode and socket.\n\n"
+
+ "add bonding slave (slave_id) (port_id)\n"
+ " Add a slave device to a bonded device.\n\n"
+
+ "remove bonding slave (slave_id) (port_id)\n"
+ " Remove a slave device from a bonded device.\n\n"
+
+ "set bonding mode (value) (port_id)\n"
+ " Set the bonding mode on a bonded device.\n\n"
+
+ "set bonding primary (slave_id) (port_id)\n"
+ " Set the primary slave for a bonded device.\n\n"
+
+ "show bonding config (port_id)\n"
+ " Show the bonding config for port_id.\n\n"
+
+ "set bonding mac_addr (port_id) (address)\n"
+ " Set the MAC address of a bonded device.\n\n"
+
+ "set bonding mode IEEE802.3AD aggregator policy (port_id) (agg_name)"
+ " Set Aggregation mode for IEEE802.3AD (mode 4)"
+
+ "set bonding xmit_balance_policy (port_id) (l2|l23|l34)\n"
+ " Set the transmit balance policy for bonded device running in balance mode.\n\n"
+
+ "set bonding mon_period (port_id) (value)\n"
+ " Set the bonding link status monitoring polling period in ms.\n\n"
+
+ "set bonding lacp dedicated_queues <port_id> (enable|disable)\n"
+ " Enable/disable dedicated queues for LACP control traffic.\n\n"
+
+#endif
+ "set link-up port (port_id)\n"
+ " Set link up for a port.\n\n"
+
+ "set link-down port (port_id)\n"
+ " Set link down for a port.\n\n"
+
+ "E-tag set insertion on port-tag-id (value)"
+ " port (port_id) vf (vf_id)\n"
+ " Enable E-tag insertion for a VF on a port\n\n"
+
+ "E-tag set insertion off port (port_id) vf (vf_id)\n"
+ " Disable E-tag insertion for a VF on a port\n\n"
+
+ "E-tag set stripping (on|off) port (port_id)\n"
+ " Enable/disable E-tag stripping on a port\n\n"
+
+ "E-tag set forwarding (on|off) port (port_id)\n"
+ " Enable/disable E-tag based forwarding"
+ " on a port\n\n"
+
+ "E-tag set filter add e-tag-id (value) dst-pool"
+ " (pool_id) port (port_id)\n"
+ " Add an E-tag forwarding filter on a port\n\n"
+
+ "E-tag set filter del e-tag-id (value) port (port_id)\n"
+ " Delete an E-tag forwarding filter on a port\n\n"
+
+ "ddp add (port_id) (profile_path[,backup_profile_path])\n"
+ " Load a profile package on a port\n\n"
+
+ "ddp del (port_id) (backup_profile_path)\n"
+ " Delete a profile package from a port\n\n"
+
+ "ptype mapping get (port_id) (valid_only)\n"
+ " Get ptype mapping on a port\n\n"
+
+ "ptype mapping replace (port_id) (target) (mask) (pky_type)\n"
+ " Replace target with the pkt_type in ptype mapping\n\n"
+
+ "ptype mapping reset (port_id)\n"
+ " Reset ptype mapping on a port\n\n"
+
+ "ptype mapping update (port_id) (hw_ptype) (sw_ptype)\n"
+ " Update a ptype mapping item on a port\n\n"
+
+ "set port (port_id) ptype_mask (ptype_mask)\n"
+ " set packet types classification for a specific port\n\n"
+
+ "set port (port_id) queue-region region_id (value) "
+ "queue_start_index (value) queue_num (value)\n"
+ " Set a queue region on a port\n\n"
+
+ "set port (port_id) queue-region region_id (value) "
+ "flowtype (value)\n"
+ " Set a flowtype region index on a port\n\n"
+
+ "set port (port_id) queue-region UP (value) region_id (value)\n"
+ " Set the mapping of User Priority to "
+ "queue region on a port\n\n"
+
+ "set port (port_id) queue-region flush (on|off)\n"
+ " flush all queue region related configuration\n\n"
+
+ "show port meter cap (port_id)\n"
+ " Show port meter capability information\n\n"
+
+ "add port meter profile srtcm_rfc2697 (port_id) (profile_id) (cir) (cbs) (ebs)\n"
+ " meter profile add - srtcm rfc 2697\n\n"
+
+ "add port meter profile trtcm_rfc2698 (port_id) (profile_id) (cir) (pir) (cbs) (pbs)\n"
+ " meter profile add - trtcm rfc 2698\n\n"
+
+ "add port meter profile trtcm_rfc4115 (port_id) (profile_id) (cir) (eir) (cbs) (ebs)\n"
+ " meter profile add - trtcm rfc 4115\n\n"
+
+ "del port meter profile (port_id) (profile_id)\n"
+ " meter profile delete\n\n"
+
+ "create port meter (port_id) (mtr_id) (profile_id) (meter_enable)\n"
+ "(g_action) (y_action) (r_action) (stats_mask) (shared)\n"
+ "(use_pre_meter_color) [(dscp_tbl_entry0) (dscp_tbl_entry1)...\n"
+ "(dscp_tbl_entry63)]\n"
+ " meter create\n\n"
+
+ "enable port meter (port_id) (mtr_id)\n"
+ " meter enable\n\n"
+
+ "disable port meter (port_id) (mtr_id)\n"
+ " meter disable\n\n"
+
+ "del port meter (port_id) (mtr_id)\n"
+ " meter delete\n\n"
+
+ "set port meter profile (port_id) (mtr_id) (profile_id)\n"
+ " meter update meter profile\n\n"
+
+ "set port meter dscp table (port_id) (mtr_id) [(dscp_tbl_entry0)\n"
+ "(dscp_tbl_entry1)...(dscp_tbl_entry63)]\n"
+ " update meter dscp table entries\n\n"
+
+ "set port meter policer action (port_id) (mtr_id) (action_mask)\n"
+ "(action0) [(action1) (action2)]\n"
+ " meter update policer action\n\n"
+
+ "set port meter stats mask (port_id) (mtr_id) (stats_mask)\n"
+ " meter update stats\n\n"
+
+ "show port (port_id) queue-region\n"
+ " show all queue region related configuration info\n\n"
+
+ , list_pkt_forwarding_modes()
+ );
+ }
+
+ if (show_all || !strcmp(res->section, "ports")) {
+
+ cmdline_printf(
+ cl,
+ "\n"
+ "Port Operations:\n"
+ "----------------\n\n"
+
+ "port start (port_id|all)\n"
+ " Start all ports or port_id.\n\n"
+
+ "port stop (port_id|all)\n"
+ " Stop all ports or port_id.\n\n"
+
+ "port close (port_id|all)\n"
+ " Close all ports or port_id.\n\n"
+
+ "port reset (port_id|all)\n"
+ " Reset all ports or port_id.\n\n"
+
+ "port attach (ident)\n"
+ " Attach physical or virtual dev by pci address or virtual device name\n\n"
+
+ "port detach (port_id)\n"
+ " Detach physical or virtual dev by port_id\n\n"
+
+ "port config (port_id|all)"
+ " speed (10|100|1000|10000|25000|40000|50000|100000|200000|auto)"
+ " duplex (half|full|auto)\n"
+ " Set speed and duplex for all ports or port_id\n\n"
+
+ "port config (port_id|all) loopback (mode)\n"
+ " Set loopback mode for all ports or port_id\n\n"
+
+ "port config all (rxq|txq|rxd|txd) (value)\n"
+ " Set number for rxq/txq/rxd/txd.\n\n"
+
+ "port config all max-pkt-len (value)\n"
+ " Set the max packet length.\n\n"
+
+ "port config all max-lro-pkt-size (value)\n"
+ " Set the max LRO aggregated packet size.\n\n"
+
+ "port config all drop-en (on|off)\n"
+ " Enable or disable packet drop on all RX queues of all ports when no "
+ "receive buffers available.\n\n"
+
+ "port config all rss (all|default|ip|tcp|udp|sctp|"
+ "ether|port|vxlan|geneve|nvgre|vxlan-gpe|none|<flowtype_id>)\n"
+ " Set the RSS mode.\n\n"
+
+ "port config port-id rss reta (hash,queue)[,(hash,queue)]\n"
+ " Set the RSS redirection table.\n\n"
+
+ "port config (port_id) dcb vt (on|off) (traffic_class)"
+ " pfc (on|off)\n"
+ " Set the DCB mode.\n\n"
+
+ "port config all burst (value)\n"
+ " Set the number of packets per burst.\n\n"
+
+ "port config all (txpt|txht|txwt|rxpt|rxht|rxwt)"
+ " (value)\n"
+ " Set the ring prefetch/host/writeback threshold"
+ " for tx/rx queue.\n\n"
+
+ "port config all (txfreet|txrst|rxfreet) (value)\n"
+ " Set free threshold for rx/tx, or set"
+ " tx rs bit threshold.\n\n"
+ "port config mtu X value\n"
+ " Set the MTU of port X to a given value\n\n"
+
+ "port config (port_id) (rxq|txq) (queue_id) ring_size (value)\n"
+ " Set a rx/tx queue's ring size configuration, the new"
+ " value will take effect after command that (re-)start the port"
+ " or command that setup the specific queue\n\n"
+
+ "port (port_id) (rxq|txq) (queue_id) (start|stop)\n"
+ " Start/stop a rx/tx queue of port X. Only take effect"
+ " when port X is started\n\n"
+
+ "port (port_id) (rxq|txq) (queue_id) deferred_start (on|off)\n"
+ " Switch on/off a deferred start of port X rx/tx queue. Only"
+ " take effect when port X is stopped.\n\n"
+
+ "port (port_id) (rxq|txq) (queue_id) setup\n"
+ " Setup a rx/tx queue of port X.\n\n"
+
+ "port config (port_id|all) l2-tunnel E-tag ether-type"
+ " (value)\n"
+ " Set the value of E-tag ether-type.\n\n"
+
+ "port config (port_id|all) l2-tunnel E-tag"
+ " (enable|disable)\n"
+ " Enable/disable the E-tag support.\n\n"
+
+ "port config (port_id) pctype mapping reset\n"
+ " Reset flow type to pctype mapping on a port\n\n"
+
+ "port config (port_id) pctype mapping update"
+ " (pctype_id_0[,pctype_id_1]*) (flow_type_id)\n"
+ " Update a flow type to pctype mapping item on a port\n\n"
+
+ "port config (port_id) pctype (pctype_id) hash_inset|"
+ "fdir_inset|fdir_flx_inset get|set|clear field\n"
+ " (field_idx)\n"
+ " Configure RSS|FDIR|FDIR_FLX input set for some pctype\n\n"
+
+ "port config (port_id) pctype (pctype_id) hash_inset|"
+ "fdir_inset|fdir_flx_inset clear all"
+ " Clear RSS|FDIR|FDIR_FLX input set completely for some pctype\n\n"
+
+ "port config (port_id) udp_tunnel_port add|rm vxlan|geneve (udp_port)\n\n"
+ " Add/remove UDP tunnel port for tunneling offload\n\n"
+
+ "port config <port_id> rx_offload vlan_strip|"
+ "ipv4_cksum|udp_cksum|tcp_cksum|tcp_lro|qinq_strip|"
+ "outer_ipv4_cksum|macsec_strip|header_split|"
+ "vlan_filter|vlan_extend|jumbo_frame|"
+ "scatter|timestamp|security|keep_crc on|off\n"
+ " Enable or disable a per port Rx offloading"
+ " on all Rx queues of a port\n\n"
+
+ "port (port_id) rxq (queue_id) rx_offload vlan_strip|"
+ "ipv4_cksum|udp_cksum|tcp_cksum|tcp_lro|qinq_strip|"
+ "outer_ipv4_cksum|macsec_strip|header_split|"
+ "vlan_filter|vlan_extend|jumbo_frame|"
+ "scatter|timestamp|security|keep_crc on|off\n"
+ " Enable or disable a per queue Rx offloading"
+ " only on a specific Rx queue\n\n"
+
+ "port config (port_id) tx_offload vlan_insert|"
+ "ipv4_cksum|udp_cksum|tcp_cksum|sctp_cksum|tcp_tso|"
+ "udp_tso|outer_ipv4_cksum|qinq_insert|vxlan_tnl_tso|"
+ "gre_tnl_tso|ipip_tnl_tso|geneve_tnl_tso|"
+ "macsec_insert|mt_lockfree|multi_segs|mbuf_fast_free|"
+ "security on|off\n"
+ " Enable or disable a per port Tx offloading"
+ " on all Tx queues of a port\n\n"
+
+ "port (port_id) txq (queue_id) tx_offload vlan_insert|"
+ "ipv4_cksum|udp_cksum|tcp_cksum|sctp_cksum|tcp_tso|"
+ "udp_tso|outer_ipv4_cksum|qinq_insert|vxlan_tnl_tso|"
+ "gre_tnl_tso|ipip_tnl_tso|geneve_tnl_tso|macsec_insert"
+ "|mt_lockfree|multi_segs|mbuf_fast_free|security"
+ " on|off\n"
+ " Enable or disable a per queue Tx offloading"
+ " only on a specific Tx queue\n\n"
+
+ "bpf-load rx|tx (port) (queue) (J|M|B) (file_name)\n"
+ " Load an eBPF program as a callback"
+ " for particular RX/TX queue\n\n"
+
+ "bpf-unload rx|tx (port) (queue)\n"
+ " Unload previously loaded eBPF program"
+ " for particular RX/TX queue\n\n"
+
+ "port config (port_id) tx_metadata (value)\n"
+ " Set Tx metadata value per port. Testpmd will add this value"
+ " to any Tx packet sent from this port\n\n"
+
+ "port config (port_id) dynf (name) set|clear\n"
+ " Register a dynf and Set/clear this flag on Tx. "
+ "Testpmd will set this value to any Tx packet "
+ "sent from this port\n\n"
+ );
+ }
+
+ if (show_all || !strcmp(res->section, "registers")) {
+
+ cmdline_printf(
+ cl,
+ "\n"
+ "Registers:\n"
+ "----------\n\n"
+
+ "read reg (port_id) (address)\n"
+ " Display value of a port register.\n\n"
+
+ "read regfield (port_id) (address) (bit_x) (bit_y)\n"
+ " Display a port register bit field.\n\n"
+
+ "read regbit (port_id) (address) (bit_x)\n"
+ " Display a single port register bit.\n\n"
+
+ "write reg (port_id) (address) (value)\n"
+ " Set value of a port register.\n\n"
+
+ "write regfield (port_id) (address) (bit_x) (bit_y)"
+ " (value)\n"
+ " Set bit field of a port register.\n\n"
+
+ "write regbit (port_id) (address) (bit_x) (value)\n"
+ " Set single bit value of a port register.\n\n"
+ );
+ }
+ if (show_all || !strcmp(res->section, "filters")) {
+
+ cmdline_printf(
+ cl,
+ "\n"
+ "filters:\n"
+ "--------\n\n"
+
+ "ethertype_filter (port_id) (add|del)"
+ " (mac_addr|mac_ignr) (mac_address) ethertype"
+ " (ether_type) (drop|fwd) queue (queue_id)\n"
+ " Add/Del an ethertype filter.\n\n"
+
+ "2tuple_filter (port_id) (add|del)"
+ " dst_port (dst_port_value) protocol (protocol_value)"
+ " mask (mask_value) tcp_flags (tcp_flags_value)"
+ " priority (prio_value) queue (queue_id)\n"
+ " Add/Del a 2tuple filter.\n\n"
+
+ "5tuple_filter (port_id) (add|del)"
+ " dst_ip (dst_address) src_ip (src_address)"
+ " dst_port (dst_port_value) src_port (src_port_value)"
+ " protocol (protocol_value)"
+ " mask (mask_value) tcp_flags (tcp_flags_value)"
+ " priority (prio_value) queue (queue_id)\n"
+ " Add/Del a 5tuple filter.\n\n"
+
+ "syn_filter (port_id) (add|del) priority (high|low) queue (queue_id)"
+ " Add/Del syn filter.\n\n"
+
+ "flex_filter (port_id) (add|del) len (len_value)"
+ " bytes (bytes_value) mask (mask_value)"
+ " priority (prio_value) queue (queue_id)\n"
+ " Add/Del a flex filter.\n\n"
+
+ "flow_director_filter (port_id) mode IP (add|del|update)"
+ " flow (ipv4-other|ipv4-frag|ipv6-other|ipv6-frag)"
+ " src (src_ip_address) dst (dst_ip_address)"
+ " tos (tos_value) proto (proto_value) ttl (ttl_value)"
+ " vlan (vlan_value) flexbytes (flexbytes_value)"
+ " (drop|fwd) pf|vf(vf_id) queue (queue_id)"
+ " fd_id (fd_id_value)\n"
+ " Add/Del an IP type flow director filter.\n\n"
+
+ "flow_director_filter (port_id) mode IP (add|del|update)"
+ " flow (ipv4-tcp|ipv4-udp|ipv6-tcp|ipv6-udp)"
+ " src (src_ip_address) (src_port)"
+ " dst (dst_ip_address) (dst_port)"
+ " tos (tos_value) ttl (ttl_value)"
+ " vlan (vlan_value) flexbytes (flexbytes_value)"
+ " (drop|fwd) pf|vf(vf_id) queue (queue_id)"
+ " fd_id (fd_id_value)\n"
+ " Add/Del an UDP/TCP type flow director filter.\n\n"
+
+ "flow_director_filter (port_id) mode IP (add|del|update)"
+ " flow (ipv4-sctp|ipv6-sctp)"
+ " src (src_ip_address) (src_port)"
+ " dst (dst_ip_address) (dst_port)"
+ " tag (verification_tag) "
+ " tos (tos_value) ttl (ttl_value)"
+ " vlan (vlan_value)"
+ " flexbytes (flexbytes_value) (drop|fwd)"
+ " pf|vf(vf_id) queue (queue_id) fd_id (fd_id_value)\n"
+ " Add/Del a SCTP type flow director filter.\n\n"
+
+ "flow_director_filter (port_id) mode IP (add|del|update)"
+ " flow l2_payload ether (ethertype)"
+ " flexbytes (flexbytes_value) (drop|fwd)"
+ " pf|vf(vf_id) queue (queue_id) fd_id (fd_id_value)\n"
+ " Add/Del a l2 payload type flow director filter.\n\n"
+
+ "flow_director_filter (port_id) mode MAC-VLAN (add|del|update)"
+ " mac (mac_address) vlan (vlan_value)"
+ " flexbytes (flexbytes_value) (drop|fwd)"
+ " queue (queue_id) fd_id (fd_id_value)\n"
+ " Add/Del a MAC-VLAN flow director filter.\n\n"
+
+ "flow_director_filter (port_id) mode Tunnel (add|del|update)"
+ " mac (mac_address) vlan (vlan_value)"
+ " tunnel (NVGRE|VxLAN) tunnel-id (tunnel_id_value)"
+ " flexbytes (flexbytes_value) (drop|fwd)"
+ " queue (queue_id) fd_id (fd_id_value)\n"
+ " Add/Del a Tunnel flow director filter.\n\n"
+
+ "flow_director_filter (port_id) mode raw (add|del|update)"
+ " flow (flow_id) (drop|fwd) queue (queue_id)"
+ " fd_id (fd_id_value) packet (packet file name)\n"
+ " Add/Del a raw type flow director filter.\n\n"
+
+ "flush_flow_director (port_id)\n"
+ " Flush all flow director entries of a device.\n\n"
+
+ "flow_director_mask (port_id) mode IP vlan (vlan_value)"
+ " src_mask (ipv4_src) (ipv6_src) (src_port)"
+ " dst_mask (ipv4_dst) (ipv6_dst) (dst_port)\n"
+ " Set flow director IP mask.\n\n"
+
+ "flow_director_mask (port_id) mode MAC-VLAN"
+ " vlan (vlan_value)\n"
+ " Set flow director MAC-VLAN mask.\n\n"
+
+ "flow_director_mask (port_id) mode Tunnel"
+ " vlan (vlan_value) mac (mac_value)"
+ " tunnel-type (tunnel_type_value)"
+ " tunnel-id (tunnel_id_value)\n"
+ " Set flow director Tunnel mask.\n\n"
+
+ "flow_director_flex_mask (port_id)"
+ " flow (none|ipv4-other|ipv4-frag|ipv4-tcp|ipv4-udp|ipv4-sctp|"
+ "ipv6-other|ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|l2_payload|all)"
+ " (mask)\n"
+ " Configure mask of flex payload.\n\n"
+
+ "flow_director_flex_payload (port_id)"
+ " (raw|l2|l3|l4) (config)\n"
+ " Configure flex payload selection.\n\n"
+
+ "get_sym_hash_ena_per_port (port_id)\n"
+ " get symmetric hash enable configuration per port.\n\n"
+
+ "set_sym_hash_ena_per_port (port_id) (enable|disable)\n"
+ " set symmetric hash enable configuration per port"
+ " to enable or disable.\n\n"
+
+ "get_hash_global_config (port_id)\n"
+ " Get the global configurations of hash filters.\n\n"
+
+ "set_hash_global_config (port_id) (toeplitz|simple_xor|symmetric_toeplitz|default)"
+ " (ipv4|ipv4-frag|ipv4-tcp|ipv4-udp|ipv4-sctp|ipv4-other|ipv6|"
+ "ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|ipv6-other|l2_payload)"
+ " (enable|disable)\n"
+ " Set the global configurations of hash filters.\n\n"
+
+ "set_hash_input_set (port_id) (ipv4|ipv4-frag|"
+ "ipv4-tcp|ipv4-udp|ipv4-sctp|ipv4-other|ipv6|"
+ "ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|ipv6-other|"
+ "l2_payload|<flowtype_id>) (ovlan|ivlan|src-ipv4|dst-ipv4|"
+ "src-ipv6|dst-ipv6|ipv4-tos|ipv4-proto|ipv6-tc|"
+ "ipv6-next-header|udp-src-port|udp-dst-port|"
+ "tcp-src-port|tcp-dst-port|sctp-src-port|"
+ "sctp-dst-port|sctp-veri-tag|udp-key|gre-key|fld-1st|"
+ "fld-2nd|fld-3rd|fld-4th|fld-5th|fld-6th|fld-7th|"
+ "fld-8th|none) (select|add)\n"
+ " Set the input set for hash.\n\n"
+
+ "set_fdir_input_set (port_id) "
+ "(ipv4-frag|ipv4-tcp|ipv4-udp|ipv4-sctp|ipv4-other|"
+ "ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|ipv6-other|"
+ "l2_payload) (ivlan|ethertype|src-ipv4|dst-ipv4|src-ipv6|"
+ "dst-ipv6|ipv4-tos|ipv4-proto|ipv4-ttl|ipv6-tc|"
+ "ipv6-next-header|ipv6-hop-limits|udp-src-port|"
+ "udp-dst-port|tcp-src-port|tcp-dst-port|"
+ "sctp-src-port|sctp-dst-port|sctp-veri-tag|none)"
+ " (select|add)\n"
+ " Set the input set for FDir.\n\n"
+
+ "flow validate {port_id}"
+ " [group {group_id}] [priority {level}]"
+ " [ingress] [egress]"
+ " pattern {item} [/ {item} [...]] / end"
+ " actions {action} [/ {action} [...]] / end\n"
+ " Check whether a flow rule can be created.\n\n"
+
+ "flow create {port_id}"
+ " [group {group_id}] [priority {level}]"
+ " [ingress] [egress]"
+ " pattern {item} [/ {item} [...]] / end"
+ " actions {action} [/ {action} [...]] / end\n"
+ " Create a flow rule.\n\n"
+
+ "flow destroy {port_id} rule {rule_id} [...]\n"
+ " Destroy specific flow rules.\n\n"
+
+ "flow flush {port_id}\n"
+ " Destroy all flow rules.\n\n"
+
+ "flow query {port_id} {rule_id} {action}\n"
+ " Query an existing flow rule.\n\n"
+
+ "flow list {port_id} [group {group_id}] [...]\n"
+ " List existing flow rules sorted by priority,"
+ " filtered by group identifiers.\n\n"
+
+ "flow isolate {port_id} {boolean}\n"
+ " Restrict ingress traffic to the defined"
+ " flow rules\n\n"
+
+ "flow aged {port_id} [destroy]\n"
+ " List and destroy aged flows"
+ " flow rules\n\n"
+
+ "set vxlan ip-version (ipv4|ipv6) vni (vni) udp-src"
+ " (udp-src) udp-dst (udp-dst) ip-src (ip-src) ip-dst"
+ " (ip-dst) eth-src (eth-src) eth-dst (eth-dst)\n"
+ " Configure the VXLAN encapsulation for flows.\n\n"
+
+ "set vxlan-with-vlan ip-version (ipv4|ipv6) vni (vni)"
+ " udp-src (udp-src) udp-dst (udp-dst) ip-src (ip-src)"
+ " ip-dst (ip-dst) vlan-tci (vlan-tci) eth-src (eth-src)"
+ " eth-dst (eth-dst)\n"
+ " Configure the VXLAN encapsulation for flows.\n\n"
+
+ "set vxlan-tos-ttl ip-version (ipv4|ipv6) vni (vni) udp-src"
+ " (udp-src) udp-dst (udp-dst) ip-tos (ip-tos) ip-ttl (ip-ttl)"
+ " ip-src (ip-src) ip-dst (ip-dst) eth-src (eth-src)"
+ " eth-dst (eth-dst)\n"
+ " Configure the VXLAN encapsulation for flows.\n\n"
+
+ "set nvgre ip-version (ipv4|ipv6) tni (tni) ip-src"
+ " (ip-src) ip-dst (ip-dst) eth-src (eth-src) eth-dst"
+ " (eth-dst)\n"
+ " Configure the NVGRE encapsulation for flows.\n\n"
+
+ "set nvgre-with-vlan ip-version (ipv4|ipv6) tni (tni)"
+ " ip-src (ip-src) ip-dst (ip-dst) vlan-tci (vlan-tci)"
+ " eth-src (eth-src) eth-dst (eth-dst)\n"
+ " Configure the NVGRE encapsulation for flows.\n\n"
+
+ "set raw_encap {flow items}\n"
+ " Configure the encapsulation with raw data.\n\n"
+
+ "set raw_decap {flow items}\n"
+ " Configure the decapsulation with raw data.\n\n"
+
+ );
+ }
+
+ if (show_all || !strcmp(res->section, "traffic_management")) {
+ cmdline_printf(
+ cl,
+ "\n"
+ "Traffic Management:\n"
+ "--------------\n"
+ "show port tm cap (port_id)\n"
+ " Display the port TM capability.\n\n"
+
+ "show port tm level cap (port_id) (level_id)\n"
+ " Display the port TM hierarchical level capability.\n\n"
+
+ "show port tm node cap (port_id) (node_id)\n"
+ " Display the port TM node capability.\n\n"
+
+ "show port tm node type (port_id) (node_id)\n"
+ " Display the port TM node type.\n\n"
+
+ "show port tm node stats (port_id) (node_id) (clear)\n"
+ " Display the port TM node stats.\n\n"
+
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+ "set port tm hierarchy default (port_id)\n"
+ " Set default traffic Management hierarchy on a port\n\n"
+#endif
+
+ "add port tm node shaper profile (port_id) (shaper_profile_id)"
+ " (cmit_tb_rate) (cmit_tb_size) (peak_tb_rate) (peak_tb_size)"
+ " (packet_length_adjust)\n"
+ " Add port tm node private shaper profile.\n\n"
+
+ "del port tm node shaper profile (port_id) (shaper_profile_id)\n"
+ " Delete port tm node private shaper profile.\n\n"
+
+ "add port tm node shared shaper (port_id) (shared_shaper_id)"
+ " (shaper_profile_id)\n"
+ " Add/update port tm node shared shaper.\n\n"
+
+ "del port tm node shared shaper (port_id) (shared_shaper_id)\n"
+ " Delete port tm node shared shaper.\n\n"
+
+ "set port tm node shaper profile (port_id) (node_id)"
+ " (shaper_profile_id)\n"
+ " Set port tm node shaper profile.\n\n"
+
+ "add port tm node wred profile (port_id) (wred_profile_id)"
+ " (color_g) (min_th_g) (max_th_g) (maxp_inv_g) (wq_log2_g)"
+ " (color_y) (min_th_y) (max_th_y) (maxp_inv_y) (wq_log2_y)"
+ " (color_r) (min_th_r) (max_th_r) (maxp_inv_r) (wq_log2_r)\n"
+ " Add port tm node wred profile.\n\n"
+
+ "del port tm node wred profile (port_id) (wred_profile_id)\n"
+ " Delete port tm node wred profile.\n\n"
+
+ "add port tm nonleaf node (port_id) (node_id) (parent_node_id)"
+ " (priority) (weight) (level_id) (shaper_profile_id)"
+ " (n_sp_priorities) (stats_mask) (n_shared_shapers)"
+ " [(shared_shaper_id_0) (shared_shaper_id_1)...]\n"
+ " Add port tm nonleaf node.\n\n"
+
+ "add port tm leaf node (port_id) (node_id) (parent_node_id)"
+ " (priority) (weight) (level_id) (shaper_profile_id)"
+ " (cman_mode) (wred_profile_id) (stats_mask) (n_shared_shapers)"
+ " [(shared_shaper_id_0) (shared_shaper_id_1)...]\n"
+ " Add port tm leaf node.\n\n"
+
+ "del port tm node (port_id) (node_id)\n"
+ " Delete port tm node.\n\n"
+
+ "set port tm node parent (port_id) (node_id) (parent_node_id)"
+ " (priority) (weight)\n"
+ " Set port tm node parent.\n\n"
+
+ "suspend port tm node (port_id) (node_id)"
+ " Suspend tm node.\n\n"
+
+ "resume port tm node (port_id) (node_id)"
+ " Resume tm node.\n\n"
+
+ "port tm hierarchy commit (port_id) (clean_on_fail)\n"
+ " Commit tm hierarchy.\n\n"
+
+ "set port tm mark ip_ecn (port) (green) (yellow)"
+ " (red)\n"
+ " Enables/Disables the traffic management marking"
+ " for IP ECN (Explicit Congestion Notification)"
+ " packets on a given port\n\n"
+
+ "set port tm mark ip_dscp (port) (green) (yellow)"
+ " (red)\n"
+ " Enables/Disables the traffic management marking"
+ " on the port for IP dscp packets\n\n"
+
+ "set port tm mark vlan_dei (port) (green) (yellow)"
+ " (red)\n"
+ " Enables/Disables the traffic management marking"
+ " on the port for VLAN packets with DEI enabled\n\n"
+ );
+ }
+
+ if (show_all || !strcmp(res->section, "devices")) {
+ cmdline_printf(
+ cl,
+ "\n"
+ "Device Operations:\n"
+ "--------------\n"
+ "device detach (identifier)\n"
+ " Detach device by identifier.\n\n"
+ );
+ }
+
+}
+
+cmdline_parse_token_string_t cmd_help_long_help =
+ TOKEN_STRING_INITIALIZER(struct cmd_help_long_result, help, "help");
+
+cmdline_parse_token_string_t cmd_help_long_section =
+ TOKEN_STRING_INITIALIZER(struct cmd_help_long_result, section,
+ "all#control#display#config#"
+ "ports#registers#filters#traffic_management#devices");
+
+cmdline_parse_inst_t cmd_help_long = {
+ .f = cmd_help_long_parsed,
+ .data = NULL,
+ .help_str = "help all|control|display|config|ports|register|"
+ "filters|traffic_management|devices: "
+ "Show help",
+ .tokens = {
+ (void *)&cmd_help_long_help,
+ (void *)&cmd_help_long_section,
+ NULL,
+ },
+};
+
+
+/* *** start/stop/close all ports *** */
+struct cmd_operate_port_result {
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t name;
+ cmdline_fixed_string_t value;
+};
+
+static void cmd_operate_port_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_operate_port_result *res = parsed_result;
+
+ if (!strcmp(res->name, "start"))
+ start_port(RTE_PORT_ALL);
+ else if (!strcmp(res->name, "stop"))
+ stop_port(RTE_PORT_ALL);
+ else if (!strcmp(res->name, "close"))
+ close_port(RTE_PORT_ALL);
+ else if (!strcmp(res->name, "reset"))
+ reset_port(RTE_PORT_ALL);
+ else
+ printf("Unknown parameter\n");
+}
+
+cmdline_parse_token_string_t cmd_operate_port_all_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_operate_port_result, keyword,
+ "port");
+cmdline_parse_token_string_t cmd_operate_port_all_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_operate_port_result, name,
+ "start#stop#close#reset");
+cmdline_parse_token_string_t cmd_operate_port_all_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_operate_port_result, value, "all");
+
+cmdline_parse_inst_t cmd_operate_port = {
+ .f = cmd_operate_port_parsed,
+ .data = NULL,
+ .help_str = "port start|stop|close all: Start/Stop/Close/Reset all ports",
+ .tokens = {
+ (void *)&cmd_operate_port_all_cmd,
+ (void *)&cmd_operate_port_all_port,
+ (void *)&cmd_operate_port_all_all,
+ NULL,
+ },
+};
+
+/* *** start/stop/close specific port *** */
+struct cmd_operate_specific_port_result {
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t name;
+ uint8_t value;
+};
+
+static void cmd_operate_specific_port_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_operate_specific_port_result *res = parsed_result;
+
+ if (!strcmp(res->name, "start"))
+ start_port(res->value);
+ else if (!strcmp(res->name, "stop"))
+ stop_port(res->value);
+ else if (!strcmp(res->name, "close"))
+ close_port(res->value);
+ else if (!strcmp(res->name, "reset"))
+ reset_port(res->value);
+ else
+ printf("Unknown parameter\n");
+}
+
+cmdline_parse_token_string_t cmd_operate_specific_port_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_operate_specific_port_result,
+ keyword, "port");
+cmdline_parse_token_string_t cmd_operate_specific_port_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_operate_specific_port_result,
+ name, "start#stop#close#reset");
+cmdline_parse_token_num_t cmd_operate_specific_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_operate_specific_port_result,
+ value, UINT8);
+
+cmdline_parse_inst_t cmd_operate_specific_port = {
+ .f = cmd_operate_specific_port_parsed,
+ .data = NULL,
+ .help_str = "port start|stop|close <port_id>: Start/Stop/Close/Reset port_id",
+ .tokens = {
+ (void *)&cmd_operate_specific_port_cmd,
+ (void *)&cmd_operate_specific_port_port,
+ (void *)&cmd_operate_specific_port_id,
+ NULL,
+ },
+};
+
+/* *** enable port setup (after attach) via iterator or event *** */
+struct cmd_set_port_setup_on_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t setup;
+ cmdline_fixed_string_t on;
+ cmdline_fixed_string_t mode;
+};
+
+static void cmd_set_port_setup_on_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_port_setup_on_result *res = parsed_result;
+
+ if (strcmp(res->mode, "event") == 0)
+ setup_on_probe_event = true;
+ else if (strcmp(res->mode, "iterator") == 0)
+ setup_on_probe_event = false;
+ else
+ printf("Unknown mode\n");
+}
+
+cmdline_parse_token_string_t cmd_set_port_setup_on_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_port_setup_on_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_set_port_setup_on_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_port_setup_on_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_set_port_setup_on_setup =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_port_setup_on_result,
+ setup, "setup");
+cmdline_parse_token_string_t cmd_set_port_setup_on_on =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_port_setup_on_result,
+ on, "on");
+cmdline_parse_token_string_t cmd_set_port_setup_on_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_port_setup_on_result,
+ mode, "iterator#event");
+
+cmdline_parse_inst_t cmd_set_port_setup_on = {
+ .f = cmd_set_port_setup_on_parsed,
+ .data = NULL,
+ .help_str = "set port setup on iterator|event",
+ .tokens = {
+ (void *)&cmd_set_port_setup_on_set,
+ (void *)&cmd_set_port_setup_on_port,
+ (void *)&cmd_set_port_setup_on_setup,
+ (void *)&cmd_set_port_setup_on_on,
+ (void *)&cmd_set_port_setup_on_mode,
+ NULL,
+ },
+};
+
+/* *** attach a specified port *** */
+struct cmd_operate_attach_port_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ cmdline_multi_string_t identifier;
+};
+
+static void cmd_operate_attach_port_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_operate_attach_port_result *res = parsed_result;
+
+ if (!strcmp(res->keyword, "attach"))
+ attach_port(res->identifier);
+ else
+ printf("Unknown parameter\n");
+}
+
+cmdline_parse_token_string_t cmd_operate_attach_port_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_operate_attach_port_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+ keyword, "attach");
+cmdline_parse_token_string_t cmd_operate_attach_port_identifier =
+ TOKEN_STRING_INITIALIZER(struct cmd_operate_attach_port_result,
+ identifier, TOKEN_STRING_MULTI);
+
+cmdline_parse_inst_t cmd_operate_attach_port = {
+ .f = cmd_operate_attach_port_parsed,
+ .data = NULL,
+ .help_str = "port attach <identifier>: "
+ "(identifier: pci address or virtual dev name)",
+ .tokens = {
+ (void *)&cmd_operate_attach_port_port,
+ (void *)&cmd_operate_attach_port_keyword,
+ (void *)&cmd_operate_attach_port_identifier,
+ NULL,
+ },
+};
+
+/* *** detach a specified port *** */
+struct cmd_operate_detach_port_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ portid_t port_id;
+};
+
+static void cmd_operate_detach_port_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_operate_detach_port_result *res = parsed_result;
+
+ if (!strcmp(res->keyword, "detach")) {
+ RTE_ETH_VALID_PORTID_OR_RET(res->port_id);
+ detach_port_device(res->port_id);
+ } else {
+ printf("Unknown parameter\n");
+ }
+}
+
+cmdline_parse_token_string_t cmd_operate_detach_port_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_operate_detach_port_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_port_result,
+ keyword, "detach");
+cmdline_parse_token_num_t cmd_operate_detach_port_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_operate_detach_port_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_operate_detach_port = {
+ .f = cmd_operate_detach_port_parsed,
+ .data = NULL,
+ .help_str = "port detach <port_id>",
+ .tokens = {
+ (void *)&cmd_operate_detach_port_port,
+ (void *)&cmd_operate_detach_port_keyword,
+ (void *)&cmd_operate_detach_port_port_id,
+ NULL,
+ },
+};
+
+/* *** detach device by identifier *** */
+struct cmd_operate_detach_device_result {
+ cmdline_fixed_string_t device;
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t identifier;
+};
+
+static void cmd_operate_detach_device_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_operate_detach_device_result *res = parsed_result;
+
+ if (!strcmp(res->keyword, "detach"))
+ detach_devargs(res->identifier);
+ else
+ printf("Unknown parameter\n");
+}
+
+cmdline_parse_token_string_t cmd_operate_detach_device_device =
+ TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_device_result,
+ device, "device");
+cmdline_parse_token_string_t cmd_operate_detach_device_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_device_result,
+ keyword, "detach");
+cmdline_parse_token_string_t cmd_operate_detach_device_identifier =
+ TOKEN_STRING_INITIALIZER(struct cmd_operate_detach_device_result,
+ identifier, NULL);
+
+cmdline_parse_inst_t cmd_operate_detach_device = {
+ .f = cmd_operate_detach_device_parsed,
+ .data = NULL,
+ .help_str = "device detach <identifier>:"
+ "(identifier: pci address or virtual dev name)",
+ .tokens = {
+ (void *)&cmd_operate_detach_device_device,
+ (void *)&cmd_operate_detach_device_keyword,
+ (void *)&cmd_operate_detach_device_identifier,
+ NULL,
+ },
+};
+/* *** configure speed for all ports *** */
+struct cmd_config_speed_all {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t all;
+ cmdline_fixed_string_t item1;
+ cmdline_fixed_string_t item2;
+ cmdline_fixed_string_t value1;
+ cmdline_fixed_string_t value2;
+};
+
+static int
+parse_and_check_speed_duplex(char *speedstr, char *duplexstr, uint32_t *speed)
+{
+
+ int duplex;
+
+ if (!strcmp(duplexstr, "half")) {
+ duplex = ETH_LINK_HALF_DUPLEX;
+ } else if (!strcmp(duplexstr, "full")) {
+ duplex = ETH_LINK_FULL_DUPLEX;
+ } else if (!strcmp(duplexstr, "auto")) {
+ duplex = ETH_LINK_FULL_DUPLEX;
+ } else {
+ printf("Unknown duplex parameter\n");
+ return -1;
+ }
+
+ if (!strcmp(speedstr, "10")) {
+ *speed = (duplex == ETH_LINK_HALF_DUPLEX) ?
+ ETH_LINK_SPEED_10M_HD : ETH_LINK_SPEED_10M;
+ } else if (!strcmp(speedstr, "100")) {
+ *speed = (duplex == ETH_LINK_HALF_DUPLEX) ?
+ ETH_LINK_SPEED_100M_HD : ETH_LINK_SPEED_100M;
+ } else {
+ if (duplex != ETH_LINK_FULL_DUPLEX) {
+ printf("Invalid speed/duplex parameters\n");
+ return -1;
+ }
+ if (!strcmp(speedstr, "1000")) {
+ *speed = ETH_LINK_SPEED_1G;
+ } else if (!strcmp(speedstr, "10000")) {
+ *speed = ETH_LINK_SPEED_10G;
+ } else if (!strcmp(speedstr, "25000")) {
+ *speed = ETH_LINK_SPEED_25G;
+ } else if (!strcmp(speedstr, "40000")) {
+ *speed = ETH_LINK_SPEED_40G;
+ } else if (!strcmp(speedstr, "50000")) {
+ *speed = ETH_LINK_SPEED_50G;
+ } else if (!strcmp(speedstr, "100000")) {
+ *speed = ETH_LINK_SPEED_100G;
+ } else if (!strcmp(speedstr, "200000")) {
+ *speed = ETH_LINK_SPEED_200G;
+ } else if (!strcmp(speedstr, "auto")) {
+ *speed = ETH_LINK_SPEED_AUTONEG;
+ } else {
+ printf("Unknown speed parameter\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+cmd_config_speed_all_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_speed_all *res = parsed_result;
+ uint32_t link_speed;
+ portid_t pid;
+
+ if (!all_ports_stopped()) {
+ printf("Please stop all ports first\n");
+ return;
+ }
+
+ if (parse_and_check_speed_duplex(res->value1, res->value2,
+ &link_speed) < 0)
+ return;
+
+ RTE_ETH_FOREACH_DEV(pid) {
+ ports[pid].dev_conf.link_speeds = link_speed;
+ }
+
+ cmd_reconfig_device_queue(RTE_PORT_ALL, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_config_speed_all_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, port, "port");
+cmdline_parse_token_string_t cmd_config_speed_all_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, keyword,
+ "config");
+cmdline_parse_token_string_t cmd_config_speed_all_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, all, "all");
+cmdline_parse_token_string_t cmd_config_speed_all_item1 =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, item1, "speed");
+cmdline_parse_token_string_t cmd_config_speed_all_value1 =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, value1,
+ "10#100#1000#10000#25000#40000#50000#100000#200000#auto");
+cmdline_parse_token_string_t cmd_config_speed_all_item2 =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, item2, "duplex");
+cmdline_parse_token_string_t cmd_config_speed_all_value2 =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, value2,
+ "half#full#auto");
+
+cmdline_parse_inst_t cmd_config_speed_all = {
+ .f = cmd_config_speed_all_parsed,
+ .data = NULL,
+ .help_str = "port config all speed "
+ "10|100|1000|10000|25000|40000|50000|100000|200000|auto duplex "
+ "half|full|auto",
+ .tokens = {
+ (void *)&cmd_config_speed_all_port,
+ (void *)&cmd_config_speed_all_keyword,
+ (void *)&cmd_config_speed_all_all,
+ (void *)&cmd_config_speed_all_item1,
+ (void *)&cmd_config_speed_all_value1,
+ (void *)&cmd_config_speed_all_item2,
+ (void *)&cmd_config_speed_all_value2,
+ NULL,
+ },
+};
+
+/* *** configure speed for specific port *** */
+struct cmd_config_speed_specific {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ portid_t id;
+ cmdline_fixed_string_t item1;
+ cmdline_fixed_string_t item2;
+ cmdline_fixed_string_t value1;
+ cmdline_fixed_string_t value2;
+};
+
+static void
+cmd_config_speed_specific_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_speed_specific *res = parsed_result;
+ uint32_t link_speed;
+
+ if (!all_ports_stopped()) {
+ printf("Please stop all ports first\n");
+ return;
+ }
+
+ if (port_id_is_invalid(res->id, ENABLED_WARN))
+ return;
+
+ if (parse_and_check_speed_duplex(res->value1, res->value2,
+ &link_speed) < 0)
+ return;
+
+ ports[res->id].dev_conf.link_speeds = link_speed;
+
+ cmd_reconfig_device_queue(RTE_PORT_ALL, 1, 1);
+}
+
+
+cmdline_parse_token_string_t cmd_config_speed_specific_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, port,
+ "port");
+cmdline_parse_token_string_t cmd_config_speed_specific_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, keyword,
+ "config");
+cmdline_parse_token_num_t cmd_config_speed_specific_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_speed_specific, id, UINT16);
+cmdline_parse_token_string_t cmd_config_speed_specific_item1 =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, item1,
+ "speed");
+cmdline_parse_token_string_t cmd_config_speed_specific_value1 =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, value1,
+ "10#100#1000#10000#25000#40000#50000#100000#200000#auto");
+cmdline_parse_token_string_t cmd_config_speed_specific_item2 =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, item2,
+ "duplex");
+cmdline_parse_token_string_t cmd_config_speed_specific_value2 =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, value2,
+ "half#full#auto");
+
+cmdline_parse_inst_t cmd_config_speed_specific = {
+ .f = cmd_config_speed_specific_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> speed "
+ "10|100|1000|10000|25000|40000|50000|100000|200000|auto duplex "
+ "half|full|auto",
+ .tokens = {
+ (void *)&cmd_config_speed_specific_port,
+ (void *)&cmd_config_speed_specific_keyword,
+ (void *)&cmd_config_speed_specific_id,
+ (void *)&cmd_config_speed_specific_item1,
+ (void *)&cmd_config_speed_specific_value1,
+ (void *)&cmd_config_speed_specific_item2,
+ (void *)&cmd_config_speed_specific_value2,
+ NULL,
+ },
+};
+
+/* *** configure loopback for all ports *** */
+struct cmd_config_loopback_all {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t all;
+ cmdline_fixed_string_t item;
+ uint32_t mode;
+};
+
+static void
+cmd_config_loopback_all_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_loopback_all *res = parsed_result;
+ portid_t pid;
+
+ if (!all_ports_stopped()) {
+ printf("Please stop all ports first\n");
+ return;
+ }
+
+ RTE_ETH_FOREACH_DEV(pid) {
+ ports[pid].dev_conf.lpbk_mode = res->mode;
+ }
+
+ cmd_reconfig_device_queue(RTE_PORT_ALL, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_config_loopback_all_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_loopback_all, port, "port");
+cmdline_parse_token_string_t cmd_config_loopback_all_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_loopback_all, keyword,
+ "config");
+cmdline_parse_token_string_t cmd_config_loopback_all_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_loopback_all, all, "all");
+cmdline_parse_token_string_t cmd_config_loopback_all_item =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_loopback_all, item,
+ "loopback");
+cmdline_parse_token_num_t cmd_config_loopback_all_mode =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_loopback_all, mode, UINT32);
+
+cmdline_parse_inst_t cmd_config_loopback_all = {
+ .f = cmd_config_loopback_all_parsed,
+ .data = NULL,
+ .help_str = "port config all loopback <mode>",
+ .tokens = {
+ (void *)&cmd_config_loopback_all_port,
+ (void *)&cmd_config_loopback_all_keyword,
+ (void *)&cmd_config_loopback_all_all,
+ (void *)&cmd_config_loopback_all_item,
+ (void *)&cmd_config_loopback_all_mode,
+ NULL,
+ },
+};
+
+/* *** configure loopback for specific port *** */
+struct cmd_config_loopback_specific {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ uint16_t port_id;
+ cmdline_fixed_string_t item;
+ uint32_t mode;
+};
+
+static void
+cmd_config_loopback_specific_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_loopback_specific *res = parsed_result;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+ if (!port_is_stopped(res->port_id)) {
+ printf("Please stop port %u first\n", res->port_id);
+ return;
+ }
+
+ ports[res->port_id].dev_conf.lpbk_mode = res->mode;
+
+ cmd_reconfig_device_queue(res->port_id, 1, 1);
+}
+
+
+cmdline_parse_token_string_t cmd_config_loopback_specific_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_loopback_specific, port,
+ "port");
+cmdline_parse_token_string_t cmd_config_loopback_specific_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_loopback_specific, keyword,
+ "config");
+cmdline_parse_token_num_t cmd_config_loopback_specific_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_loopback_specific, port_id,
+ UINT16);
+cmdline_parse_token_string_t cmd_config_loopback_specific_item =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_loopback_specific, item,
+ "loopback");
+cmdline_parse_token_num_t cmd_config_loopback_specific_mode =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_loopback_specific, mode,
+ UINT32);
+
+cmdline_parse_inst_t cmd_config_loopback_specific = {
+ .f = cmd_config_loopback_specific_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> loopback <mode>",
+ .tokens = {
+ (void *)&cmd_config_loopback_specific_port,
+ (void *)&cmd_config_loopback_specific_keyword,
+ (void *)&cmd_config_loopback_specific_id,
+ (void *)&cmd_config_loopback_specific_item,
+ (void *)&cmd_config_loopback_specific_mode,
+ NULL,
+ },
+};
+
+/* *** configure txq/rxq, txd/rxd *** */
+struct cmd_config_rx_tx {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t all;
+ cmdline_fixed_string_t name;
+ uint16_t value;
+};
+
+static void
+cmd_config_rx_tx_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_rx_tx *res = parsed_result;
+
+ if (!all_ports_stopped()) {
+ printf("Please stop all ports first\n");
+ return;
+ }
+ if (!strcmp(res->name, "rxq")) {
+ if (!res->value && !nb_txq) {
+ printf("Warning: Either rx or tx queues should be non zero\n");
+ return;
+ }
+ if (check_nb_rxq(res->value) != 0)
+ return;
+ nb_rxq = res->value;
+ }
+ else if (!strcmp(res->name, "txq")) {
+ if (!res->value && !nb_rxq) {
+ printf("Warning: Either rx or tx queues should be non zero\n");
+ return;
+ }
+ if (check_nb_txq(res->value) != 0)
+ return;
+ nb_txq = res->value;
+ }
+ else if (!strcmp(res->name, "rxd")) {
+ if (check_nb_rxd(res->value) != 0)
+ return;
+ nb_rxd = res->value;
+ } else if (!strcmp(res->name, "txd")) {
+ if (check_nb_txd(res->value) != 0)
+ return;
+
+ nb_txd = res->value;
+ } else {
+ printf("Unknown parameter\n");
+ return;
+ }
+
+ fwd_config_setup();
+
+ init_port_config();
+
+ cmd_reconfig_device_queue(RTE_PORT_ALL, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_config_rx_tx_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rx_tx, port, "port");
+cmdline_parse_token_string_t cmd_config_rx_tx_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rx_tx, keyword, "config");
+cmdline_parse_token_string_t cmd_config_rx_tx_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rx_tx, all, "all");
+cmdline_parse_token_string_t cmd_config_rx_tx_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rx_tx, name,
+ "rxq#txq#rxd#txd");
+cmdline_parse_token_num_t cmd_config_rx_tx_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_rx_tx, value, UINT16);
+
+cmdline_parse_inst_t cmd_config_rx_tx = {
+ .f = cmd_config_rx_tx_parsed,
+ .data = NULL,
+ .help_str = "port config all rxq|txq|rxd|txd <value>",
+ .tokens = {
+ (void *)&cmd_config_rx_tx_port,
+ (void *)&cmd_config_rx_tx_keyword,
+ (void *)&cmd_config_rx_tx_all,
+ (void *)&cmd_config_rx_tx_name,
+ (void *)&cmd_config_rx_tx_value,
+ NULL,
+ },
+};
+
+/* *** config max packet length *** */
+struct cmd_config_max_pkt_len_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t all;
+ cmdline_fixed_string_t name;
+ uint32_t value;
+};
+
+static void
+cmd_config_max_pkt_len_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_max_pkt_len_result *res = parsed_result;
+ portid_t pid;
+
+ if (!all_ports_stopped()) {
+ printf("Please stop all ports first\n");
+ return;
+ }
+
+ RTE_ETH_FOREACH_DEV(pid) {
+ struct rte_port *port = &ports[pid];
+ uint64_t rx_offloads = port->dev_conf.rxmode.offloads;
+
+ if (!strcmp(res->name, "max-pkt-len")) {
+ if (res->value < RTE_ETHER_MIN_LEN) {
+ printf("max-pkt-len can not be less than %d\n",
+ RTE_ETHER_MIN_LEN);
+ return;
+ }
+ if (res->value == port->dev_conf.rxmode.max_rx_pkt_len)
+ return;
+
+ port->dev_conf.rxmode.max_rx_pkt_len = res->value;
+ if (res->value > RTE_ETHER_MAX_LEN)
+ rx_offloads |= DEV_RX_OFFLOAD_JUMBO_FRAME;
+ else
+ rx_offloads &= ~DEV_RX_OFFLOAD_JUMBO_FRAME;
+ port->dev_conf.rxmode.offloads = rx_offloads;
+ } else {
+ printf("Unknown parameter\n");
+ return;
+ }
+ }
+
+ init_port_config();
+
+ cmd_reconfig_device_queue(RTE_PORT_ALL, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_config_max_pkt_len_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_max_pkt_len_result, port,
+ "port");
+cmdline_parse_token_string_t cmd_config_max_pkt_len_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_max_pkt_len_result, keyword,
+ "config");
+cmdline_parse_token_string_t cmd_config_max_pkt_len_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_max_pkt_len_result, all,
+ "all");
+cmdline_parse_token_string_t cmd_config_max_pkt_len_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_max_pkt_len_result, name,
+ "max-pkt-len");
+cmdline_parse_token_num_t cmd_config_max_pkt_len_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_max_pkt_len_result, value,
+ UINT32);
+
+cmdline_parse_inst_t cmd_config_max_pkt_len = {
+ .f = cmd_config_max_pkt_len_parsed,
+ .data = NULL,
+ .help_str = "port config all max-pkt-len <value>",
+ .tokens = {
+ (void *)&cmd_config_max_pkt_len_port,
+ (void *)&cmd_config_max_pkt_len_keyword,
+ (void *)&cmd_config_max_pkt_len_all,
+ (void *)&cmd_config_max_pkt_len_name,
+ (void *)&cmd_config_max_pkt_len_value,
+ NULL,
+ },
+};
+
+/* *** config max LRO aggregated packet size *** */
+struct cmd_config_max_lro_pkt_size_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t all;
+ cmdline_fixed_string_t name;
+ uint32_t value;
+};
+
+static void
+cmd_config_max_lro_pkt_size_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_max_lro_pkt_size_result *res = parsed_result;
+ portid_t pid;
+
+ if (!all_ports_stopped()) {
+ printf("Please stop all ports first\n");
+ return;
+ }
+
+ RTE_ETH_FOREACH_DEV(pid) {
+ struct rte_port *port = &ports[pid];
+
+ if (!strcmp(res->name, "max-lro-pkt-size")) {
+ if (res->value ==
+ port->dev_conf.rxmode.max_lro_pkt_size)
+ return;
+
+ port->dev_conf.rxmode.max_lro_pkt_size = res->value;
+ } else {
+ printf("Unknown parameter\n");
+ return;
+ }
+ }
+
+ init_port_config();
+
+ cmd_reconfig_device_queue(RTE_PORT_ALL, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_config_max_lro_pkt_size_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_max_lro_pkt_size_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_config_max_lro_pkt_size_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_max_lro_pkt_size_result,
+ keyword, "config");
+cmdline_parse_token_string_t cmd_config_max_lro_pkt_size_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_max_lro_pkt_size_result,
+ all, "all");
+cmdline_parse_token_string_t cmd_config_max_lro_pkt_size_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_max_lro_pkt_size_result,
+ name, "max-lro-pkt-size");
+cmdline_parse_token_num_t cmd_config_max_lro_pkt_size_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_max_lro_pkt_size_result,
+ value, UINT32);
+
+cmdline_parse_inst_t cmd_config_max_lro_pkt_size = {
+ .f = cmd_config_max_lro_pkt_size_parsed,
+ .data = NULL,
+ .help_str = "port config all max-lro-pkt-size <value>",
+ .tokens = {
+ (void *)&cmd_config_max_lro_pkt_size_port,
+ (void *)&cmd_config_max_lro_pkt_size_keyword,
+ (void *)&cmd_config_max_lro_pkt_size_all,
+ (void *)&cmd_config_max_lro_pkt_size_name,
+ (void *)&cmd_config_max_lro_pkt_size_value,
+ NULL,
+ },
+};
+
+/* *** configure port MTU *** */
+struct cmd_config_mtu_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t mtu;
+ portid_t port_id;
+ uint16_t value;
+};
+
+static void
+cmd_config_mtu_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_mtu_result *res = parsed_result;
+
+ if (res->value < RTE_ETHER_MIN_LEN) {
+ printf("mtu cannot be less than %d\n", RTE_ETHER_MIN_LEN);
+ return;
+ }
+ port_mtu_set(res->port_id, res->value);
+}
+
+cmdline_parse_token_string_t cmd_config_mtu_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_mtu_result, port,
+ "port");
+cmdline_parse_token_string_t cmd_config_mtu_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_mtu_result, keyword,
+ "config");
+cmdline_parse_token_string_t cmd_config_mtu_mtu =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_mtu_result, keyword,
+ "mtu");
+cmdline_parse_token_num_t cmd_config_mtu_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_mtu_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_config_mtu_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_mtu_result, value, UINT16);
+
+cmdline_parse_inst_t cmd_config_mtu = {
+ .f = cmd_config_mtu_parsed,
+ .data = NULL,
+ .help_str = "port config mtu <port_id> <value>",
+ .tokens = {
+ (void *)&cmd_config_mtu_port,
+ (void *)&cmd_config_mtu_keyword,
+ (void *)&cmd_config_mtu_mtu,
+ (void *)&cmd_config_mtu_port_id,
+ (void *)&cmd_config_mtu_value,
+ NULL,
+ },
+};
+
+/* *** configure rx mode *** */
+struct cmd_config_rx_mode_flag {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t all;
+ cmdline_fixed_string_t name;
+ cmdline_fixed_string_t value;
+};
+
+static void
+cmd_config_rx_mode_flag_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_rx_mode_flag *res = parsed_result;
+
+ if (!all_ports_stopped()) {
+ printf("Please stop all ports first\n");
+ return;
+ }
+
+ if (!strcmp(res->name, "drop-en")) {
+ if (!strcmp(res->value, "on"))
+ rx_drop_en = 1;
+ else if (!strcmp(res->value, "off"))
+ rx_drop_en = 0;
+ else {
+ printf("Unknown parameter\n");
+ return;
+ }
+ } else {
+ printf("Unknown parameter\n");
+ return;
+ }
+
+ init_port_config();
+
+ cmd_reconfig_device_queue(RTE_PORT_ALL, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_config_rx_mode_flag_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rx_mode_flag, port, "port");
+cmdline_parse_token_string_t cmd_config_rx_mode_flag_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rx_mode_flag, keyword,
+ "config");
+cmdline_parse_token_string_t cmd_config_rx_mode_flag_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rx_mode_flag, all, "all");
+cmdline_parse_token_string_t cmd_config_rx_mode_flag_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rx_mode_flag, name,
+ "drop-en");
+cmdline_parse_token_string_t cmd_config_rx_mode_flag_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rx_mode_flag, value,
+ "on#off");
+
+cmdline_parse_inst_t cmd_config_rx_mode_flag = {
+ .f = cmd_config_rx_mode_flag_parsed,
+ .data = NULL,
+ .help_str = "port config all drop-en on|off",
+ .tokens = {
+ (void *)&cmd_config_rx_mode_flag_port,
+ (void *)&cmd_config_rx_mode_flag_keyword,
+ (void *)&cmd_config_rx_mode_flag_all,
+ (void *)&cmd_config_rx_mode_flag_name,
+ (void *)&cmd_config_rx_mode_flag_value,
+ NULL,
+ },
+};
+
+/* *** configure rss *** */
+struct cmd_config_rss {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t all;
+ cmdline_fixed_string_t name;
+ cmdline_fixed_string_t value;
+};
+
+static void
+cmd_config_rss_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_rss *res = parsed_result;
+ struct rte_eth_rss_conf rss_conf = { .rss_key_len = 0, };
+ struct rte_eth_dev_info dev_info = { .flow_type_rss_offloads = 0, };
+ int use_default = 0;
+ int all_updated = 1;
+ int diag;
+ uint16_t i;
+ int ret;
+
+ if (!strcmp(res->value, "all"))
+ rss_conf.rss_hf = ETH_RSS_ETH | ETH_RSS_VLAN | ETH_RSS_IP |
+ ETH_RSS_TCP | ETH_RSS_UDP | ETH_RSS_SCTP |
+ ETH_RSS_L2_PAYLOAD | ETH_RSS_L2TPV3 | ETH_RSS_ESP |
+ ETH_RSS_AH | ETH_RSS_PFCP;
+ else if (!strcmp(res->value, "eth"))
+ rss_conf.rss_hf = ETH_RSS_ETH;
+ else if (!strcmp(res->value, "vlan"))
+ rss_conf.rss_hf = ETH_RSS_VLAN;
+ else if (!strcmp(res->value, "ip"))
+ rss_conf.rss_hf = ETH_RSS_IP;
+ else if (!strcmp(res->value, "udp"))
+ rss_conf.rss_hf = ETH_RSS_UDP;
+ else if (!strcmp(res->value, "tcp"))
+ rss_conf.rss_hf = ETH_RSS_TCP;
+ else if (!strcmp(res->value, "sctp"))
+ rss_conf.rss_hf = ETH_RSS_SCTP;
+ else if (!strcmp(res->value, "ether"))
+ rss_conf.rss_hf = ETH_RSS_L2_PAYLOAD;
+ else if (!strcmp(res->value, "port"))
+ rss_conf.rss_hf = ETH_RSS_PORT;
+ else if (!strcmp(res->value, "vxlan"))
+ rss_conf.rss_hf = ETH_RSS_VXLAN;
+ else if (!strcmp(res->value, "geneve"))
+ rss_conf.rss_hf = ETH_RSS_GENEVE;
+ else if (!strcmp(res->value, "nvgre"))
+ rss_conf.rss_hf = ETH_RSS_NVGRE;
+ else if (!strcmp(res->value, "l3-src-only"))
+ rss_conf.rss_hf = ETH_RSS_L3_SRC_ONLY;
+ else if (!strcmp(res->value, "l3-dst-only"))
+ rss_conf.rss_hf = ETH_RSS_L3_DST_ONLY;
+ else if (!strcmp(res->value, "l4-src-only"))
+ rss_conf.rss_hf = ETH_RSS_L4_SRC_ONLY;
+ else if (!strcmp(res->value, "l4-dst-only"))
+ rss_conf.rss_hf = ETH_RSS_L4_DST_ONLY;
+ else if (!strcmp(res->value, "l2-src-only"))
+ rss_conf.rss_hf = ETH_RSS_L2_SRC_ONLY;
+ else if (!strcmp(res->value, "l2-dst-only"))
+ rss_conf.rss_hf = ETH_RSS_L2_DST_ONLY;
+ else if (!strcmp(res->value, "l2tpv3"))
+ rss_conf.rss_hf = ETH_RSS_L2TPV3;
+ else if (!strcmp(res->value, "esp"))
+ rss_conf.rss_hf = ETH_RSS_ESP;
+ else if (!strcmp(res->value, "ah"))
+ rss_conf.rss_hf = ETH_RSS_AH;
+ else if (!strcmp(res->value, "pfcp"))
+ rss_conf.rss_hf = ETH_RSS_PFCP;
+ else if (!strcmp(res->value, "none"))
+ rss_conf.rss_hf = 0;
+ else if (!strcmp(res->value, "default"))
+ use_default = 1;
+ else if (isdigit(res->value[0]) && atoi(res->value) > 0 &&
+ atoi(res->value) < 64)
+ rss_conf.rss_hf = 1ULL << atoi(res->value);
+ else {
+ printf("Unknown parameter\n");
+ return;
+ }
+ rss_conf.rss_key = NULL;
+ /* Update global configuration for RSS types. */
+ RTE_ETH_FOREACH_DEV(i) {
+ struct rte_eth_rss_conf local_rss_conf;
+
+ ret = eth_dev_info_get_print_err(i, &dev_info);
+ if (ret != 0)
+ return;
+
+ if (use_default)
+ rss_conf.rss_hf = dev_info.flow_type_rss_offloads;
+
+ local_rss_conf = rss_conf;
+ local_rss_conf.rss_hf = rss_conf.rss_hf &
+ dev_info.flow_type_rss_offloads;
+ if (local_rss_conf.rss_hf != rss_conf.rss_hf) {
+ printf("Port %u modified RSS hash function based on hardware support,"
+ "requested:%#"PRIx64" configured:%#"PRIx64"\n",
+ i, rss_conf.rss_hf, local_rss_conf.rss_hf);
+ }
+ diag = rte_eth_dev_rss_hash_update(i, &local_rss_conf);
+ if (diag < 0) {
+ all_updated = 0;
+ printf("Configuration of RSS hash at ethernet port %d "
+ "failed with error (%d): %s.\n",
+ i, -diag, strerror(-diag));
+ }
+ }
+ if (all_updated && !use_default) {
+ rss_hf = rss_conf.rss_hf;
+ printf("rss_hf %#"PRIx64"\n", rss_hf);
+ }
+}
+
+cmdline_parse_token_string_t cmd_config_rss_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss, port, "port");
+cmdline_parse_token_string_t cmd_config_rss_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss, keyword, "config");
+cmdline_parse_token_string_t cmd_config_rss_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss, all, "all");
+cmdline_parse_token_string_t cmd_config_rss_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss, name, "rss");
+cmdline_parse_token_string_t cmd_config_rss_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss, value, NULL);
+
+cmdline_parse_inst_t cmd_config_rss = {
+ .f = cmd_config_rss_parsed,
+ .data = NULL,
+ .help_str = "port config all rss "
+ "all|default|eth|vlan|ip|tcp|udp|sctp|ether|port|vxlan|geneve|"
+ "nvgre|vxlan-gpe|l2tpv3|esp|ah|pfcp|none|<flowtype_id>",
+ .tokens = {
+ (void *)&cmd_config_rss_port,
+ (void *)&cmd_config_rss_keyword,
+ (void *)&cmd_config_rss_all,
+ (void *)&cmd_config_rss_name,
+ (void *)&cmd_config_rss_value,
+ NULL,
+ },
+};
+
+/* *** configure rss hash key *** */
+struct cmd_config_rss_hash_key {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t config;
+ portid_t port_id;
+ cmdline_fixed_string_t rss_hash_key;
+ cmdline_fixed_string_t rss_type;
+ cmdline_fixed_string_t key;
+};
+
+static uint8_t
+hexa_digit_to_value(char hexa_digit)
+{
+ if ((hexa_digit >= '0') && (hexa_digit <= '9'))
+ return (uint8_t) (hexa_digit - '0');
+ if ((hexa_digit >= 'a') && (hexa_digit <= 'f'))
+ return (uint8_t) ((hexa_digit - 'a') + 10);
+ if ((hexa_digit >= 'A') && (hexa_digit <= 'F'))
+ return (uint8_t) ((hexa_digit - 'A') + 10);
+ /* Invalid hexa digit */
+ return 0xFF;
+}
+
+static uint8_t
+parse_and_check_key_hexa_digit(char *key, int idx)
+{
+ uint8_t hexa_v;
+
+ hexa_v = hexa_digit_to_value(key[idx]);
+ if (hexa_v == 0xFF)
+ printf("invalid key: character %c at position %d is not a "
+ "valid hexa digit\n", key[idx], idx);
+ return hexa_v;
+}
+
+static void
+cmd_config_rss_hash_key_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_rss_hash_key *res = parsed_result;
+ uint8_t hash_key[RSS_HASH_KEY_LENGTH];
+ uint8_t xdgt0;
+ uint8_t xdgt1;
+ int i;
+ struct rte_eth_dev_info dev_info;
+ uint8_t hash_key_size;
+ uint32_t key_len;
+ int ret;
+
+ ret = eth_dev_info_get_print_err(res->port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if (dev_info.hash_key_size > 0 &&
+ dev_info.hash_key_size <= sizeof(hash_key))
+ hash_key_size = dev_info.hash_key_size;
+ else {
+ printf("dev_info did not provide a valid hash key size\n");
+ return;
+ }
+ /* Check the length of the RSS hash key */
+ key_len = strlen(res->key);
+ if (key_len != (hash_key_size * 2)) {
+ printf("key length: %d invalid - key must be a string of %d"
+ " hexa-decimal numbers\n",
+ (int) key_len, hash_key_size * 2);
+ return;
+ }
+ /* Translate RSS hash key into binary representation */
+ for (i = 0; i < hash_key_size; i++) {
+ xdgt0 = parse_and_check_key_hexa_digit(res->key, (i * 2));
+ if (xdgt0 == 0xFF)
+ return;
+ xdgt1 = parse_and_check_key_hexa_digit(res->key, (i * 2) + 1);
+ if (xdgt1 == 0xFF)
+ return;
+ hash_key[i] = (uint8_t) ((xdgt0 * 16) + xdgt1);
+ }
+ port_rss_hash_key_update(res->port_id, res->rss_type, hash_key,
+ hash_key_size);
+}
+
+cmdline_parse_token_string_t cmd_config_rss_hash_key_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss_hash_key, port, "port");
+cmdline_parse_token_string_t cmd_config_rss_hash_key_config =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss_hash_key, config,
+ "config");
+cmdline_parse_token_num_t cmd_config_rss_hash_key_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_rss_hash_key, port_id, UINT16);
+cmdline_parse_token_string_t cmd_config_rss_hash_key_rss_hash_key =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss_hash_key,
+ rss_hash_key, "rss-hash-key");
+cmdline_parse_token_string_t cmd_config_rss_hash_key_rss_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss_hash_key, rss_type,
+ "ipv4#ipv4-frag#ipv4-tcp#ipv4-udp#ipv4-sctp#"
+ "ipv4-other#ipv6#ipv6-frag#ipv6-tcp#ipv6-udp#"
+ "ipv6-sctp#ipv6-other#l2-payload#ipv6-ex#"
+ "ipv6-tcp-ex#ipv6-udp-ex#"
+ "l3-src-only#l3-dst-only#l4-src-only#l4-dst-only#"
+ "l2-src-only#l2-dst-only#s-vlan#c-vlan#"
+ "l2tpv3#esp#ah#pfcp");
+cmdline_parse_token_string_t cmd_config_rss_hash_key_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss_hash_key, key, NULL);
+
+cmdline_parse_inst_t cmd_config_rss_hash_key = {
+ .f = cmd_config_rss_hash_key_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> rss-hash-key "
+ "ipv4|ipv4-frag|ipv4-tcp|ipv4-udp|ipv4-sctp|ipv4-other|"
+ "ipv6|ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|ipv6-other|"
+ "l2-payload|ipv6-ex|ipv6-tcp-ex|ipv6-udp-ex|"
+ "l3-src-only|l3-dst-only|l4-src-only|l4-dst-only|"
+ "l2-src-only|l2-dst-only|s-vlan|c-vlan|"
+ "l2tpv3|esp|ah|pfcp "
+ "<string of hex digits (variable length, NIC dependent)>",
+ .tokens = {
+ (void *)&cmd_config_rss_hash_key_port,
+ (void *)&cmd_config_rss_hash_key_config,
+ (void *)&cmd_config_rss_hash_key_port_id,
+ (void *)&cmd_config_rss_hash_key_rss_hash_key,
+ (void *)&cmd_config_rss_hash_key_rss_type,
+ (void *)&cmd_config_rss_hash_key_value,
+ NULL,
+ },
+};
+
+/* *** configure port rxq/txq ring size *** */
+struct cmd_config_rxtx_ring_size {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t config;
+ portid_t portid;
+ cmdline_fixed_string_t rxtxq;
+ uint16_t qid;
+ cmdline_fixed_string_t rsize;
+ uint16_t size;
+};
+
+static void
+cmd_config_rxtx_ring_size_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_rxtx_ring_size *res = parsed_result;
+ struct rte_port *port;
+ uint8_t isrx;
+
+ if (port_id_is_invalid(res->portid, ENABLED_WARN))
+ return;
+
+ if (res->portid == (portid_t)RTE_PORT_ALL) {
+ printf("Invalid port id\n");
+ return;
+ }
+
+ port = &ports[res->portid];
+
+ if (!strcmp(res->rxtxq, "rxq"))
+ isrx = 1;
+ else if (!strcmp(res->rxtxq, "txq"))
+ isrx = 0;
+ else {
+ printf("Unknown parameter\n");
+ return;
+ }
+
+ if (isrx && rx_queue_id_is_invalid(res->qid))
+ return;
+ else if (!isrx && tx_queue_id_is_invalid(res->qid))
+ return;
+
+ if (isrx && res->size != 0 && res->size <= rx_free_thresh) {
+ printf("Invalid rx ring_size, must > rx_free_thresh: %d\n",
+ rx_free_thresh);
+ return;
+ }
+
+ if (isrx)
+ port->nb_rx_desc[res->qid] = res->size;
+ else
+ port->nb_tx_desc[res->qid] = res->size;
+
+ cmd_reconfig_device_queue(res->portid, 0, 1);
+}
+
+cmdline_parse_token_string_t cmd_config_rxtx_ring_size_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rxtx_ring_size,
+ port, "port");
+cmdline_parse_token_string_t cmd_config_rxtx_ring_size_config =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rxtx_ring_size,
+ config, "config");
+cmdline_parse_token_num_t cmd_config_rxtx_ring_size_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_rxtx_ring_size,
+ portid, UINT16);
+cmdline_parse_token_string_t cmd_config_rxtx_ring_size_rxtxq =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rxtx_ring_size,
+ rxtxq, "rxq#txq");
+cmdline_parse_token_num_t cmd_config_rxtx_ring_size_qid =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_rxtx_ring_size,
+ qid, UINT16);
+cmdline_parse_token_string_t cmd_config_rxtx_ring_size_rsize =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rxtx_ring_size,
+ rsize, "ring_size");
+cmdline_parse_token_num_t cmd_config_rxtx_ring_size_size =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_rxtx_ring_size,
+ size, UINT16);
+
+cmdline_parse_inst_t cmd_config_rxtx_ring_size = {
+ .f = cmd_config_rxtx_ring_size_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> rxq|txq <queue_id> ring_size <value>",
+ .tokens = {
+ (void *)&cmd_config_rxtx_ring_size_port,
+ (void *)&cmd_config_rxtx_ring_size_config,
+ (void *)&cmd_config_rxtx_ring_size_portid,
+ (void *)&cmd_config_rxtx_ring_size_rxtxq,
+ (void *)&cmd_config_rxtx_ring_size_qid,
+ (void *)&cmd_config_rxtx_ring_size_rsize,
+ (void *)&cmd_config_rxtx_ring_size_size,
+ NULL,
+ },
+};
+
+/* *** configure port rxq/txq start/stop *** */
+struct cmd_config_rxtx_queue {
+ cmdline_fixed_string_t port;
+ portid_t portid;
+ cmdline_fixed_string_t rxtxq;
+ uint16_t qid;
+ cmdline_fixed_string_t opname;
+};
+
+static void
+cmd_config_rxtx_queue_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_rxtx_queue *res = parsed_result;
+ uint8_t isrx;
+ uint8_t isstart;
+ int ret = 0;
+
+ if (test_done == 0) {
+ printf("Please stop forwarding first\n");
+ return;
+ }
+
+ if (port_id_is_invalid(res->portid, ENABLED_WARN))
+ return;
+
+ if (port_is_started(res->portid) != 1) {
+ printf("Please start port %u first\n", res->portid);
+ return;
+ }
+
+ if (!strcmp(res->rxtxq, "rxq"))
+ isrx = 1;
+ else if (!strcmp(res->rxtxq, "txq"))
+ isrx = 0;
+ else {
+ printf("Unknown parameter\n");
+ return;
+ }
+
+ if (isrx && rx_queue_id_is_invalid(res->qid))
+ return;
+ else if (!isrx && tx_queue_id_is_invalid(res->qid))
+ return;
+
+ if (!strcmp(res->opname, "start"))
+ isstart = 1;
+ else if (!strcmp(res->opname, "stop"))
+ isstart = 0;
+ else {
+ printf("Unknown parameter\n");
+ return;
+ }
+
+ if (isstart && isrx)
+ ret = rte_eth_dev_rx_queue_start(res->portid, res->qid);
+ else if (!isstart && isrx)
+ ret = rte_eth_dev_rx_queue_stop(res->portid, res->qid);
+ else if (isstart && !isrx)
+ ret = rte_eth_dev_tx_queue_start(res->portid, res->qid);
+ else
+ ret = rte_eth_dev_tx_queue_stop(res->portid, res->qid);
+
+ if (ret == -ENOTSUP)
+ printf("Function not supported in PMD driver\n");
+}
+
+cmdline_parse_token_string_t cmd_config_rxtx_queue_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rxtx_queue, port, "port");
+cmdline_parse_token_num_t cmd_config_rxtx_queue_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_rxtx_queue, portid, UINT16);
+cmdline_parse_token_string_t cmd_config_rxtx_queue_rxtxq =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rxtx_queue, rxtxq, "rxq#txq");
+cmdline_parse_token_num_t cmd_config_rxtx_queue_qid =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_rxtx_queue, qid, UINT16);
+cmdline_parse_token_string_t cmd_config_rxtx_queue_opname =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rxtx_queue, opname,
+ "start#stop");
+
+cmdline_parse_inst_t cmd_config_rxtx_queue = {
+ .f = cmd_config_rxtx_queue_parsed,
+ .data = NULL,
+ .help_str = "port <port_id> rxq|txq <queue_id> start|stop",
+ .tokens = {
+ (void *)&cmd_config_rxtx_queue_port,
+ (void *)&cmd_config_rxtx_queue_portid,
+ (void *)&cmd_config_rxtx_queue_rxtxq,
+ (void *)&cmd_config_rxtx_queue_qid,
+ (void *)&cmd_config_rxtx_queue_opname,
+ NULL,
+ },
+};
+
+/* *** configure port rxq/txq deferred start on/off *** */
+struct cmd_config_deferred_start_rxtx_queue {
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t rxtxq;
+ uint16_t qid;
+ cmdline_fixed_string_t opname;
+ cmdline_fixed_string_t state;
+};
+
+static void
+cmd_config_deferred_start_rxtx_queue_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_deferred_start_rxtx_queue *res = parsed_result;
+ struct rte_port *port;
+ uint8_t isrx;
+ uint8_t ison;
+ uint8_t needreconfig = 0;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+ if (port_is_started(res->port_id) != 0) {
+ printf("Please stop port %u first\n", res->port_id);
+ return;
+ }
+
+ port = &ports[res->port_id];
+
+ isrx = !strcmp(res->rxtxq, "rxq");
+
+ if (isrx && rx_queue_id_is_invalid(res->qid))
+ return;
+ else if (!isrx && tx_queue_id_is_invalid(res->qid))
+ return;
+
+ ison = !strcmp(res->state, "on");
+
+ if (isrx && port->rx_conf[res->qid].rx_deferred_start != ison) {
+ port->rx_conf[res->qid].rx_deferred_start = ison;
+ needreconfig = 1;
+ } else if (!isrx && port->tx_conf[res->qid].tx_deferred_start != ison) {
+ port->tx_conf[res->qid].tx_deferred_start = ison;
+ needreconfig = 1;
+ }
+
+ if (needreconfig)
+ cmd_reconfig_device_queue(res->port_id, 0, 1);
+}
+
+cmdline_parse_token_string_t cmd_config_deferred_start_rxtx_queue_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_deferred_start_rxtx_queue,
+ port, "port");
+cmdline_parse_token_num_t cmd_config_deferred_start_rxtx_queue_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_deferred_start_rxtx_queue,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_config_deferred_start_rxtx_queue_rxtxq =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_deferred_start_rxtx_queue,
+ rxtxq, "rxq#txq");
+cmdline_parse_token_num_t cmd_config_deferred_start_rxtx_queue_qid =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_deferred_start_rxtx_queue,
+ qid, UINT16);
+cmdline_parse_token_string_t cmd_config_deferred_start_rxtx_queue_opname =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_deferred_start_rxtx_queue,
+ opname, "deferred_start");
+cmdline_parse_token_string_t cmd_config_deferred_start_rxtx_queue_state =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_deferred_start_rxtx_queue,
+ state, "on#off");
+
+cmdline_parse_inst_t cmd_config_deferred_start_rxtx_queue = {
+ .f = cmd_config_deferred_start_rxtx_queue_parsed,
+ .data = NULL,
+ .help_str = "port <port_id> rxq|txq <queue_id> deferred_start on|off",
+ .tokens = {
+ (void *)&cmd_config_deferred_start_rxtx_queue_port,
+ (void *)&cmd_config_deferred_start_rxtx_queue_port_id,
+ (void *)&cmd_config_deferred_start_rxtx_queue_rxtxq,
+ (void *)&cmd_config_deferred_start_rxtx_queue_qid,
+ (void *)&cmd_config_deferred_start_rxtx_queue_opname,
+ (void *)&cmd_config_deferred_start_rxtx_queue_state,
+ NULL,
+ },
+};
+
+/* *** configure port rxq/txq setup *** */
+struct cmd_setup_rxtx_queue {
+ cmdline_fixed_string_t port;
+ portid_t portid;
+ cmdline_fixed_string_t rxtxq;
+ uint16_t qid;
+ cmdline_fixed_string_t setup;
+};
+
+/* Common CLI fields for queue setup */
+cmdline_parse_token_string_t cmd_setup_rxtx_queue_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_setup_rxtx_queue, port, "port");
+cmdline_parse_token_num_t cmd_setup_rxtx_queue_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_setup_rxtx_queue, portid, UINT16);
+cmdline_parse_token_string_t cmd_setup_rxtx_queue_rxtxq =
+ TOKEN_STRING_INITIALIZER(struct cmd_setup_rxtx_queue, rxtxq, "rxq#txq");
+cmdline_parse_token_num_t cmd_setup_rxtx_queue_qid =
+ TOKEN_NUM_INITIALIZER(struct cmd_setup_rxtx_queue, qid, UINT16);
+cmdline_parse_token_string_t cmd_setup_rxtx_queue_setup =
+ TOKEN_STRING_INITIALIZER(struct cmd_setup_rxtx_queue, setup, "setup");
+
+static void
+cmd_setup_rxtx_queue_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_setup_rxtx_queue *res = parsed_result;
+ struct rte_port *port;
+ struct rte_mempool *mp;
+ unsigned int socket_id;
+ uint8_t isrx = 0;
+ int ret;
+
+ if (port_id_is_invalid(res->portid, ENABLED_WARN))
+ return;
+
+ if (res->portid == (portid_t)RTE_PORT_ALL) {
+ printf("Invalid port id\n");
+ return;
+ }
+
+ if (!strcmp(res->rxtxq, "rxq"))
+ isrx = 1;
+ else if (!strcmp(res->rxtxq, "txq"))
+ isrx = 0;
+ else {
+ printf("Unknown parameter\n");
+ return;
+ }
+
+ if (isrx && rx_queue_id_is_invalid(res->qid)) {
+ printf("Invalid rx queue\n");
+ return;
+ } else if (!isrx && tx_queue_id_is_invalid(res->qid)) {
+ printf("Invalid tx queue\n");
+ return;
+ }
+
+ port = &ports[res->portid];
+ if (isrx) {
+ socket_id = rxring_numa[res->portid];
+ if (!numa_support || socket_id == NUMA_NO_CONFIG)
+ socket_id = port->socket_id;
+
+ mp = mbuf_pool_find(socket_id);
+ if (mp == NULL) {
+ printf("Failed to setup RX queue: "
+ "No mempool allocation"
+ " on the socket %d\n",
+ rxring_numa[res->portid]);
+ return;
+ }
+ ret = rte_eth_rx_queue_setup(res->portid,
+ res->qid,
+ port->nb_rx_desc[res->qid],
+ socket_id,
+ &port->rx_conf[res->qid],
+ mp);
+ if (ret)
+ printf("Failed to setup RX queue\n");
+ } else {
+ socket_id = txring_numa[res->portid];
+ if (!numa_support || socket_id == NUMA_NO_CONFIG)
+ socket_id = port->socket_id;
+
+ ret = rte_eth_tx_queue_setup(res->portid,
+ res->qid,
+ port->nb_tx_desc[res->qid],
+ socket_id,
+ &port->tx_conf[res->qid]);
+ if (ret)
+ printf("Failed to setup TX queue\n");
+ }
+}
+
+cmdline_parse_inst_t cmd_setup_rxtx_queue = {
+ .f = cmd_setup_rxtx_queue_parsed,
+ .data = NULL,
+ .help_str = "port <port_id> rxq|txq <queue_idx> setup",
+ .tokens = {
+ (void *)&cmd_setup_rxtx_queue_port,
+ (void *)&cmd_setup_rxtx_queue_portid,
+ (void *)&cmd_setup_rxtx_queue_rxtxq,
+ (void *)&cmd_setup_rxtx_queue_qid,
+ (void *)&cmd_setup_rxtx_queue_setup,
+ NULL,
+ },
+};
+
+
+/* *** Configure RSS RETA *** */
+struct cmd_config_rss_reta {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ portid_t port_id;
+ cmdline_fixed_string_t name;
+ cmdline_fixed_string_t list_name;
+ cmdline_fixed_string_t list_of_items;
+};
+
+static int
+parse_reta_config(const char *str,
+ struct rte_eth_rss_reta_entry64 *reta_conf,
+ uint16_t nb_entries)
+{
+ int i;
+ unsigned size;
+ uint16_t hash_index, idx, shift;
+ uint16_t nb_queue;
+ char s[256];
+ const char *p, *p0 = str;
+ char *end;
+ enum fieldnames {
+ FLD_HASH_INDEX = 0,
+ FLD_QUEUE,
+ _NUM_FLD
+ };
+ unsigned long int_fld[_NUM_FLD];
+ char *str_fld[_NUM_FLD];
+
+ 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] > 65535)
+ return -1;
+ }
+
+ hash_index = (uint16_t)int_fld[FLD_HASH_INDEX];
+ nb_queue = (uint16_t)int_fld[FLD_QUEUE];
+
+ if (hash_index >= nb_entries) {
+ printf("Invalid RETA hash index=%d\n", hash_index);
+ return -1;
+ }
+
+ idx = hash_index / RTE_RETA_GROUP_SIZE;
+ shift = hash_index % RTE_RETA_GROUP_SIZE;
+ reta_conf[idx].mask |= (1ULL << shift);
+ reta_conf[idx].reta[shift] = nb_queue;
+ }
+
+ return 0;
+}
+
+static void
+cmd_set_rss_reta_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ int ret;
+ struct rte_eth_dev_info dev_info;
+ struct rte_eth_rss_reta_entry64 reta_conf[8];
+ struct cmd_config_rss_reta *res = parsed_result;
+
+ ret = eth_dev_info_get_print_err(res->port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if (dev_info.reta_size == 0) {
+ printf("Redirection table size is 0 which is "
+ "invalid for RSS\n");
+ return;
+ } else
+ printf("The reta size of port %d is %u\n",
+ res->port_id, dev_info.reta_size);
+ if (dev_info.reta_size > ETH_RSS_RETA_SIZE_512) {
+ printf("Currently do not support more than %u entries of "
+ "redirection table\n", ETH_RSS_RETA_SIZE_512);
+ return;
+ }
+
+ memset(reta_conf, 0, sizeof(reta_conf));
+ if (!strcmp(res->list_name, "reta")) {
+ if (parse_reta_config(res->list_of_items, reta_conf,
+ dev_info.reta_size)) {
+ printf("Invalid RSS Redirection Table "
+ "config entered\n");
+ return;
+ }
+ ret = rte_eth_dev_rss_reta_update(res->port_id,
+ reta_conf, dev_info.reta_size);
+ if (ret != 0)
+ printf("Bad redirection table parameter, "
+ "return code = %d \n", ret);
+ }
+}
+
+cmdline_parse_token_string_t cmd_config_rss_reta_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss_reta, port, "port");
+cmdline_parse_token_string_t cmd_config_rss_reta_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss_reta, keyword, "config");
+cmdline_parse_token_num_t cmd_config_rss_reta_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_rss_reta, port_id, UINT16);
+cmdline_parse_token_string_t cmd_config_rss_reta_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss_reta, name, "rss");
+cmdline_parse_token_string_t cmd_config_rss_reta_list_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss_reta, list_name, "reta");
+cmdline_parse_token_string_t cmd_config_rss_reta_list_of_items =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_rss_reta, list_of_items,
+ NULL);
+cmdline_parse_inst_t cmd_config_rss_reta = {
+ .f = cmd_set_rss_reta_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> rss reta <hash,queue[,hash,queue]*>",
+ .tokens = {
+ (void *)&cmd_config_rss_reta_port,
+ (void *)&cmd_config_rss_reta_keyword,
+ (void *)&cmd_config_rss_reta_port_id,
+ (void *)&cmd_config_rss_reta_name,
+ (void *)&cmd_config_rss_reta_list_name,
+ (void *)&cmd_config_rss_reta_list_of_items,
+ NULL,
+ },
+};
+
+/* *** SHOW PORT RETA INFO *** */
+struct cmd_showport_reta {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t rss;
+ cmdline_fixed_string_t reta;
+ uint16_t size;
+ cmdline_fixed_string_t list_of_items;
+};
+
+static int
+showport_parse_reta_config(struct rte_eth_rss_reta_entry64 *conf,
+ uint16_t nb_entries,
+ char *str)
+{
+ uint32_t size;
+ const char *p, *p0 = str;
+ char s[256];
+ char *end;
+ char *str_fld[8];
+ uint16_t i;
+ uint16_t num = (nb_entries + RTE_RETA_GROUP_SIZE - 1) /
+ RTE_RETA_GROUP_SIZE;
+ int ret;
+
+ p = strchr(p0, '(');
+ if (p == NULL)
+ return -1;
+ p++;
+ p0 = strchr(p, ')');
+ if (p0 == NULL)
+ return -1;
+ size = p0 - p;
+ if (size >= sizeof(s)) {
+ printf("The string size exceeds the internal buffer size\n");
+ return -1;
+ }
+ snprintf(s, sizeof(s), "%.*s", size, p);
+ ret = rte_strsplit(s, sizeof(s), str_fld, num, ',');
+ if (ret <= 0 || ret != num) {
+ printf("The bits of masks do not match the number of "
+ "reta entries: %u\n", num);
+ return -1;
+ }
+ for (i = 0; i < ret; i++)
+ conf[i].mask = (uint64_t)strtoul(str_fld[i], &end, 0);
+
+ return 0;
+}
+
+static void
+cmd_showport_reta_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_showport_reta *res = parsed_result;
+ struct rte_eth_rss_reta_entry64 reta_conf[8];
+ struct rte_eth_dev_info dev_info;
+ uint16_t max_reta_size;
+ int ret;
+
+ ret = eth_dev_info_get_print_err(res->port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ max_reta_size = RTE_MIN(dev_info.reta_size, ETH_RSS_RETA_SIZE_512);
+ if (res->size == 0 || res->size > max_reta_size) {
+ printf("Invalid redirection table size: %u (1-%u)\n",
+ res->size, max_reta_size);
+ return;
+ }
+
+ memset(reta_conf, 0, sizeof(reta_conf));
+ if (showport_parse_reta_config(reta_conf, res->size,
+ res->list_of_items) < 0) {
+ printf("Invalid string: %s for reta masks\n",
+ res->list_of_items);
+ return;
+ }
+ port_rss_reta_info(res->port_id, reta_conf, res->size);
+}
+
+cmdline_parse_token_string_t cmd_showport_reta_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_reta, show, "show");
+cmdline_parse_token_string_t cmd_showport_reta_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_reta, port, "port");
+cmdline_parse_token_num_t cmd_showport_reta_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_showport_reta, port_id, UINT16);
+cmdline_parse_token_string_t cmd_showport_reta_rss =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_reta, rss, "rss");
+cmdline_parse_token_string_t cmd_showport_reta_reta =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_reta, reta, "reta");
+cmdline_parse_token_num_t cmd_showport_reta_size =
+ TOKEN_NUM_INITIALIZER(struct cmd_showport_reta, size, UINT16);
+cmdline_parse_token_string_t cmd_showport_reta_list_of_items =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_reta,
+ list_of_items, NULL);
+
+cmdline_parse_inst_t cmd_showport_reta = {
+ .f = cmd_showport_reta_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> rss reta <size> <mask0[,mask1]*>",
+ .tokens = {
+ (void *)&cmd_showport_reta_show,
+ (void *)&cmd_showport_reta_port,
+ (void *)&cmd_showport_reta_port_id,
+ (void *)&cmd_showport_reta_rss,
+ (void *)&cmd_showport_reta_reta,
+ (void *)&cmd_showport_reta_size,
+ (void *)&cmd_showport_reta_list_of_items,
+ NULL,
+ },
+};
+
+/* *** Show RSS hash configuration *** */
+struct cmd_showport_rss_hash {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t rss_hash;
+ cmdline_fixed_string_t rss_type;
+ cmdline_fixed_string_t key; /* optional argument */
+};
+
+static void cmd_showport_rss_hash_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ void *show_rss_key)
+{
+ struct cmd_showport_rss_hash *res = parsed_result;
+
+ port_rss_hash_conf_show(res->port_id, show_rss_key != NULL);
+}
+
+cmdline_parse_token_string_t cmd_showport_rss_hash_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_rss_hash, show, "show");
+cmdline_parse_token_string_t cmd_showport_rss_hash_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_rss_hash, port, "port");
+cmdline_parse_token_num_t cmd_showport_rss_hash_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_showport_rss_hash, port_id, UINT16);
+cmdline_parse_token_string_t cmd_showport_rss_hash_rss_hash =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_rss_hash, rss_hash,
+ "rss-hash");
+cmdline_parse_token_string_t cmd_showport_rss_hash_rss_key =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_rss_hash, key, "key");
+
+cmdline_parse_inst_t cmd_showport_rss_hash = {
+ .f = cmd_showport_rss_hash_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> rss-hash",
+ .tokens = {
+ (void *)&cmd_showport_rss_hash_show,
+ (void *)&cmd_showport_rss_hash_port,
+ (void *)&cmd_showport_rss_hash_port_id,
+ (void *)&cmd_showport_rss_hash_rss_hash,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_showport_rss_hash_key = {
+ .f = cmd_showport_rss_hash_parsed,
+ .data = (void *)1,
+ .help_str = "show port <port_id> rss-hash key",
+ .tokens = {
+ (void *)&cmd_showport_rss_hash_show,
+ (void *)&cmd_showport_rss_hash_port,
+ (void *)&cmd_showport_rss_hash_port_id,
+ (void *)&cmd_showport_rss_hash_rss_hash,
+ (void *)&cmd_showport_rss_hash_rss_key,
+ NULL,
+ },
+};
+
+/* *** Configure DCB *** */
+struct cmd_config_dcb {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t config;
+ portid_t port_id;
+ cmdline_fixed_string_t dcb;
+ cmdline_fixed_string_t vt;
+ cmdline_fixed_string_t vt_en;
+ uint8_t num_tcs;
+ cmdline_fixed_string_t pfc;
+ cmdline_fixed_string_t pfc_en;
+};
+
+static void
+cmd_config_dcb_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_dcb *res = parsed_result;
+ portid_t port_id = res->port_id;
+ struct rte_port *port;
+ uint8_t pfc_en;
+ int ret;
+
+ port = &ports[port_id];
+ /** Check if the port is not started **/
+ if (port->port_status != RTE_PORT_STOPPED) {
+ printf("Please stop port %d first\n", port_id);
+ return;
+ }
+
+ if ((res->num_tcs != ETH_4_TCS) && (res->num_tcs != ETH_8_TCS)) {
+ printf("The invalid number of traffic class,"
+ " only 4 or 8 allowed.\n");
+ return;
+ }
+
+ if (nb_fwd_lcores < res->num_tcs) {
+ printf("nb_cores shouldn't be less than number of TCs.\n");
+ return;
+ }
+ if (!strncmp(res->pfc_en, "on", 2))
+ pfc_en = 1;
+ else
+ pfc_en = 0;
+
+ /* DCB in VT mode */
+ if (!strncmp(res->vt_en, "on", 2))
+ ret = init_port_dcb_config(port_id, DCB_VT_ENABLED,
+ (enum rte_eth_nb_tcs)res->num_tcs,
+ pfc_en);
+ else
+ ret = init_port_dcb_config(port_id, DCB_ENABLED,
+ (enum rte_eth_nb_tcs)res->num_tcs,
+ pfc_en);
+
+
+ if (ret != 0) {
+ printf("Cannot initialize network ports.\n");
+ return;
+ }
+
+ cmd_reconfig_device_queue(port_id, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_config_dcb_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_dcb, port, "port");
+cmdline_parse_token_string_t cmd_config_dcb_config =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_dcb, config, "config");
+cmdline_parse_token_num_t cmd_config_dcb_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_dcb, port_id, UINT16);
+cmdline_parse_token_string_t cmd_config_dcb_dcb =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_dcb, dcb, "dcb");
+cmdline_parse_token_string_t cmd_config_dcb_vt =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_dcb, vt, "vt");
+cmdline_parse_token_string_t cmd_config_dcb_vt_en =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_dcb, vt_en, "on#off");
+cmdline_parse_token_num_t cmd_config_dcb_num_tcs =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_dcb, num_tcs, UINT8);
+cmdline_parse_token_string_t cmd_config_dcb_pfc=
+ TOKEN_STRING_INITIALIZER(struct cmd_config_dcb, pfc, "pfc");
+cmdline_parse_token_string_t cmd_config_dcb_pfc_en =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_dcb, pfc_en, "on#off");
+
+cmdline_parse_inst_t cmd_config_dcb = {
+ .f = cmd_config_dcb_parsed,
+ .data = NULL,
+ .help_str = "port config <port-id> dcb vt on|off <num_tcs> pfc on|off",
+ .tokens = {
+ (void *)&cmd_config_dcb_port,
+ (void *)&cmd_config_dcb_config,
+ (void *)&cmd_config_dcb_port_id,
+ (void *)&cmd_config_dcb_dcb,
+ (void *)&cmd_config_dcb_vt,
+ (void *)&cmd_config_dcb_vt_en,
+ (void *)&cmd_config_dcb_num_tcs,
+ (void *)&cmd_config_dcb_pfc,
+ (void *)&cmd_config_dcb_pfc_en,
+ NULL,
+ },
+};
+
+/* *** configure number of packets per burst *** */
+struct cmd_config_burst {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t all;
+ cmdline_fixed_string_t name;
+ uint16_t value;
+};
+
+static void
+cmd_config_burst_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_burst *res = parsed_result;
+ struct rte_eth_dev_info dev_info;
+ uint16_t rec_nb_pkts;
+ int ret;
+
+ if (!all_ports_stopped()) {
+ printf("Please stop all ports first\n");
+ return;
+ }
+
+ if (!strcmp(res->name, "burst")) {
+ if (res->value == 0) {
+ /* If user gives a value of zero, query the PMD for
+ * its recommended Rx burst size. Testpmd uses a single
+ * size for all ports, so assume all ports are the same
+ * NIC model and use the values from Port 0.
+ */
+ ret = eth_dev_info_get_print_err(0, &dev_info);
+ if (ret != 0)
+ return;
+
+ rec_nb_pkts = dev_info.default_rxportconf.burst_size;
+
+ if (rec_nb_pkts == 0) {
+ printf("PMD does not recommend a burst size.\n"
+ "User provided value must be between"
+ " 1 and %d\n", MAX_PKT_BURST);
+ return;
+ } else if (rec_nb_pkts > MAX_PKT_BURST) {
+ printf("PMD recommended burst size of %d"
+ " exceeds maximum value of %d\n",
+ rec_nb_pkts, MAX_PKT_BURST);
+ return;
+ }
+ printf("Using PMD-provided burst value of %d\n",
+ rec_nb_pkts);
+ nb_pkt_per_burst = rec_nb_pkts;
+ } else if (res->value > MAX_PKT_BURST) {
+ printf("burst must be >= 1 && <= %d\n", MAX_PKT_BURST);
+ return;
+ } else
+ nb_pkt_per_burst = res->value;
+ } else {
+ printf("Unknown parameter\n");
+ return;
+ }
+
+ init_port_config();
+
+ cmd_reconfig_device_queue(RTE_PORT_ALL, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_config_burst_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_burst, port, "port");
+cmdline_parse_token_string_t cmd_config_burst_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_burst, keyword, "config");
+cmdline_parse_token_string_t cmd_config_burst_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_burst, all, "all");
+cmdline_parse_token_string_t cmd_config_burst_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_burst, name, "burst");
+cmdline_parse_token_num_t cmd_config_burst_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_burst, value, UINT16);
+
+cmdline_parse_inst_t cmd_config_burst = {
+ .f = cmd_config_burst_parsed,
+ .data = NULL,
+ .help_str = "port config all burst <value>",
+ .tokens = {
+ (void *)&cmd_config_burst_port,
+ (void *)&cmd_config_burst_keyword,
+ (void *)&cmd_config_burst_all,
+ (void *)&cmd_config_burst_name,
+ (void *)&cmd_config_burst_value,
+ NULL,
+ },
+};
+
+/* *** configure rx/tx queues *** */
+struct cmd_config_thresh {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t all;
+ cmdline_fixed_string_t name;
+ uint8_t value;
+};
+
+static void
+cmd_config_thresh_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_thresh *res = parsed_result;
+
+ if (!all_ports_stopped()) {
+ printf("Please stop all ports first\n");
+ return;
+ }
+
+ if (!strcmp(res->name, "txpt"))
+ tx_pthresh = res->value;
+ else if(!strcmp(res->name, "txht"))
+ tx_hthresh = res->value;
+ else if(!strcmp(res->name, "txwt"))
+ tx_wthresh = res->value;
+ else if(!strcmp(res->name, "rxpt"))
+ rx_pthresh = res->value;
+ else if(!strcmp(res->name, "rxht"))
+ rx_hthresh = res->value;
+ else if(!strcmp(res->name, "rxwt"))
+ rx_wthresh = res->value;
+ else {
+ printf("Unknown parameter\n");
+ return;
+ }
+
+ init_port_config();
+
+ cmd_reconfig_device_queue(RTE_PORT_ALL, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_config_thresh_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_thresh, port, "port");
+cmdline_parse_token_string_t cmd_config_thresh_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_thresh, keyword, "config");
+cmdline_parse_token_string_t cmd_config_thresh_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_thresh, all, "all");
+cmdline_parse_token_string_t cmd_config_thresh_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_thresh, name,
+ "txpt#txht#txwt#rxpt#rxht#rxwt");
+cmdline_parse_token_num_t cmd_config_thresh_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_thresh, value, UINT8);
+
+cmdline_parse_inst_t cmd_config_thresh = {
+ .f = cmd_config_thresh_parsed,
+ .data = NULL,
+ .help_str = "port config all txpt|txht|txwt|rxpt|rxht|rxwt <value>",
+ .tokens = {
+ (void *)&cmd_config_thresh_port,
+ (void *)&cmd_config_thresh_keyword,
+ (void *)&cmd_config_thresh_all,
+ (void *)&cmd_config_thresh_name,
+ (void *)&cmd_config_thresh_value,
+ NULL,
+ },
+};
+
+/* *** configure free/rs threshold *** */
+struct cmd_config_threshold {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t all;
+ cmdline_fixed_string_t name;
+ uint16_t value;
+};
+
+static void
+cmd_config_threshold_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_threshold *res = parsed_result;
+
+ if (!all_ports_stopped()) {
+ printf("Please stop all ports first\n");
+ return;
+ }
+
+ if (!strcmp(res->name, "txfreet"))
+ tx_free_thresh = res->value;
+ else if (!strcmp(res->name, "txrst"))
+ tx_rs_thresh = res->value;
+ else if (!strcmp(res->name, "rxfreet"))
+ rx_free_thresh = res->value;
+ else {
+ printf("Unknown parameter\n");
+ return;
+ }
+
+ init_port_config();
+
+ cmd_reconfig_device_queue(RTE_PORT_ALL, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_config_threshold_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_threshold, port, "port");
+cmdline_parse_token_string_t cmd_config_threshold_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_threshold, keyword,
+ "config");
+cmdline_parse_token_string_t cmd_config_threshold_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_threshold, all, "all");
+cmdline_parse_token_string_t cmd_config_threshold_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_threshold, name,
+ "txfreet#txrst#rxfreet");
+cmdline_parse_token_num_t cmd_config_threshold_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_threshold, value, UINT16);
+
+cmdline_parse_inst_t cmd_config_threshold = {
+ .f = cmd_config_threshold_parsed,
+ .data = NULL,
+ .help_str = "port config all txfreet|txrst|rxfreet <value>",
+ .tokens = {
+ (void *)&cmd_config_threshold_port,
+ (void *)&cmd_config_threshold_keyword,
+ (void *)&cmd_config_threshold_all,
+ (void *)&cmd_config_threshold_name,
+ (void *)&cmd_config_threshold_value,
+ NULL,
+ },
+};
+
+/* *** stop *** */
+struct cmd_stop_result {
+ cmdline_fixed_string_t stop;
+};
+
+static void cmd_stop_parsed(__rte_unused void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ stop_packet_forwarding();
+}
+
+cmdline_parse_token_string_t cmd_stop_stop =
+ TOKEN_STRING_INITIALIZER(struct cmd_stop_result, stop, "stop");
+
+cmdline_parse_inst_t cmd_stop = {
+ .f = cmd_stop_parsed,
+ .data = NULL,
+ .help_str = "stop: Stop packet forwarding",
+ .tokens = {
+ (void *)&cmd_stop_stop,
+ NULL,
+ },
+};
+
+/* *** SET CORELIST and PORTLIST CONFIGURATION *** */
+
+unsigned int
+parse_item_list(char* str, const char* item_name, unsigned int max_items,
+ unsigned int *parsed_items, int check_unique_values)
+{
+ unsigned int nb_item;
+ unsigned int value;
+ unsigned int i;
+ unsigned int j;
+ int value_ok;
+ char c;
+
+ /*
+ * First parse all items in the list and store their value.
+ */
+ value = 0;
+ nb_item = 0;
+ value_ok = 0;
+ for (i = 0; i < strnlen(str, STR_TOKEN_SIZE); i++) {
+ c = str[i];
+ if ((c >= '0') && (c <= '9')) {
+ value = (unsigned int) (value * 10 + (c - '0'));
+ value_ok = 1;
+ continue;
+ }
+ if (c != ',') {
+ printf("character %c is not a decimal digit\n", c);
+ return 0;
+ }
+ if (! value_ok) {
+ printf("No valid value before comma\n");
+ return 0;
+ }
+ if (nb_item < max_items) {
+ parsed_items[nb_item] = value;
+ value_ok = 0;
+ value = 0;
+ }
+ nb_item++;
+ }
+ if (nb_item >= max_items) {
+ printf("Number of %s = %u > %u (maximum items)\n",
+ item_name, nb_item + 1, max_items);
+ return 0;
+ }
+ parsed_items[nb_item++] = value;
+ if (! check_unique_values)
+ return nb_item;
+
+ /*
+ * Then, check that all values in the list are differents.
+ * No optimization here...
+ */
+ for (i = 0; i < nb_item; i++) {
+ for (j = i + 1; j < nb_item; j++) {
+ if (parsed_items[j] == parsed_items[i]) {
+ printf("duplicated %s %u at index %u and %u\n",
+ item_name, parsed_items[i], i, j);
+ return 0;
+ }
+ }
+ }
+ return nb_item;
+}
+
+struct cmd_set_list_result {
+ cmdline_fixed_string_t cmd_keyword;
+ cmdline_fixed_string_t list_name;
+ cmdline_fixed_string_t list_of_items;
+};
+
+static void cmd_set_list_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_list_result *res;
+ union {
+ unsigned int lcorelist[RTE_MAX_LCORE];
+ unsigned int portlist[RTE_MAX_ETHPORTS];
+ } parsed_items;
+ unsigned int nb_item;
+
+ if (test_done == 0) {
+ printf("Please stop forwarding first\n");
+ return;
+ }
+
+ res = parsed_result;
+ if (!strcmp(res->list_name, "corelist")) {
+ nb_item = parse_item_list(res->list_of_items, "core",
+ RTE_MAX_LCORE,
+ parsed_items.lcorelist, 1);
+ if (nb_item > 0) {
+ set_fwd_lcores_list(parsed_items.lcorelist, nb_item);
+ fwd_config_setup();
+ }
+ return;
+ }
+ if (!strcmp(res->list_name, "portlist")) {
+ nb_item = parse_item_list(res->list_of_items, "port",
+ RTE_MAX_ETHPORTS,
+ parsed_items.portlist, 1);
+ if (nb_item > 0) {
+ set_fwd_ports_list(parsed_items.portlist, nb_item);
+ fwd_config_setup();
+ }
+ }
+}
+
+cmdline_parse_token_string_t cmd_set_list_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_list_result, cmd_keyword,
+ "set");
+cmdline_parse_token_string_t cmd_set_list_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_list_result, list_name,
+ "corelist#portlist");
+cmdline_parse_token_string_t cmd_set_list_of_items =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_list_result, list_of_items,
+ NULL);
+
+cmdline_parse_inst_t cmd_set_fwd_list = {
+ .f = cmd_set_list_parsed,
+ .data = NULL,
+ .help_str = "set corelist|portlist <list0[,list1]*>",
+ .tokens = {
+ (void *)&cmd_set_list_keyword,
+ (void *)&cmd_set_list_name,
+ (void *)&cmd_set_list_of_items,
+ NULL,
+ },
+};
+
+/* *** SET COREMASK and PORTMASK CONFIGURATION *** */
+
+struct cmd_setmask_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t mask;
+ uint64_t hexavalue;
+};
+
+static void cmd_set_mask_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_setmask_result *res = parsed_result;
+
+ if (test_done == 0) {
+ printf("Please stop forwarding first\n");
+ return;
+ }
+ if (!strcmp(res->mask, "coremask")) {
+ set_fwd_lcores_mask(res->hexavalue);
+ fwd_config_setup();
+ } else if (!strcmp(res->mask, "portmask")) {
+ set_fwd_ports_mask(res->hexavalue);
+ fwd_config_setup();
+ }
+}
+
+cmdline_parse_token_string_t cmd_setmask_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_setmask_result, set, "set");
+cmdline_parse_token_string_t cmd_setmask_mask =
+ TOKEN_STRING_INITIALIZER(struct cmd_setmask_result, mask,
+ "coremask#portmask");
+cmdline_parse_token_num_t cmd_setmask_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_setmask_result, hexavalue, UINT64);
+
+cmdline_parse_inst_t cmd_set_fwd_mask = {
+ .f = cmd_set_mask_parsed,
+ .data = NULL,
+ .help_str = "set coremask|portmask <hexadecimal value>",
+ .tokens = {
+ (void *)&cmd_setmask_set,
+ (void *)&cmd_setmask_mask,
+ (void *)&cmd_setmask_value,
+ NULL,
+ },
+};
+
+/*
+ * SET NBPORT, NBCORE, PACKET BURST, and VERBOSE LEVEL CONFIGURATION
+ */
+struct cmd_set_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t what;
+ uint16_t value;
+};
+
+static void cmd_set_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_result *res = parsed_result;
+ if (!strcmp(res->what, "nbport")) {
+ set_fwd_ports_number(res->value);
+ fwd_config_setup();
+ } else if (!strcmp(res->what, "nbcore")) {
+ set_fwd_lcores_number(res->value);
+ fwd_config_setup();
+ } else if (!strcmp(res->what, "burst"))
+ set_nb_pkt_per_burst(res->value);
+ else if (!strcmp(res->what, "verbose"))
+ set_verbose_level(res->value);
+}
+
+cmdline_parse_token_string_t cmd_set_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_result, set, "set");
+cmdline_parse_token_string_t cmd_set_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_result, what,
+ "nbport#nbcore#burst#verbose");
+cmdline_parse_token_num_t cmd_set_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_result, value, UINT16);
+
+cmdline_parse_inst_t cmd_set_numbers = {
+ .f = cmd_set_parsed,
+ .data = NULL,
+ .help_str = "set nbport|nbcore|burst|verbose <value>",
+ .tokens = {
+ (void *)&cmd_set_set,
+ (void *)&cmd_set_what,
+ (void *)&cmd_set_value,
+ NULL,
+ },
+};
+
+/* *** SET LOG LEVEL CONFIGURATION *** */
+
+struct cmd_set_log_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t log;
+ cmdline_fixed_string_t type;
+ uint32_t level;
+};
+
+static void
+cmd_set_log_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_log_result *res;
+ int ret;
+
+ res = parsed_result;
+ if (!strcmp(res->type, "global"))
+ rte_log_set_global_level(res->level);
+ else {
+ ret = rte_log_set_level_regexp(res->type, res->level);
+ if (ret < 0)
+ printf("Unable to set log level\n");
+ }
+}
+
+cmdline_parse_token_string_t cmd_set_log_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_log_result, set, "set");
+cmdline_parse_token_string_t cmd_set_log_log =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_log_result, log, "log");
+cmdline_parse_token_string_t cmd_set_log_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_log_result, type, NULL);
+cmdline_parse_token_num_t cmd_set_log_level =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_log_result, level, UINT32);
+
+cmdline_parse_inst_t cmd_set_log = {
+ .f = cmd_set_log_parsed,
+ .data = NULL,
+ .help_str = "set log global|<type> <level>",
+ .tokens = {
+ (void *)&cmd_set_log_set,
+ (void *)&cmd_set_log_log,
+ (void *)&cmd_set_log_type,
+ (void *)&cmd_set_log_level,
+ NULL,
+ },
+};
+
+/* *** SET SEGMENT LENGTHS OF TXONLY PACKETS *** */
+
+struct cmd_set_txpkts_result {
+ cmdline_fixed_string_t cmd_keyword;
+ cmdline_fixed_string_t txpkts;
+ cmdline_fixed_string_t seg_lengths;
+};
+
+static void
+cmd_set_txpkts_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_txpkts_result *res;
+ unsigned seg_lengths[RTE_MAX_SEGS_PER_PKT];
+ unsigned int nb_segs;
+
+ res = parsed_result;
+ nb_segs = parse_item_list(res->seg_lengths, "segment lengths",
+ RTE_MAX_SEGS_PER_PKT, seg_lengths, 0);
+ if (nb_segs > 0)
+ set_tx_pkt_segments(seg_lengths, nb_segs);
+}
+
+cmdline_parse_token_string_t cmd_set_txpkts_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_txpkts_result,
+ cmd_keyword, "set");
+cmdline_parse_token_string_t cmd_set_txpkts_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_txpkts_result,
+ txpkts, "txpkts");
+cmdline_parse_token_string_t cmd_set_txpkts_lengths =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_txpkts_result,
+ seg_lengths, NULL);
+
+cmdline_parse_inst_t cmd_set_txpkts = {
+ .f = cmd_set_txpkts_parsed,
+ .data = NULL,
+ .help_str = "set txpkts <len0[,len1]*>",
+ .tokens = {
+ (void *)&cmd_set_txpkts_keyword,
+ (void *)&cmd_set_txpkts_name,
+ (void *)&cmd_set_txpkts_lengths,
+ NULL,
+ },
+};
+
+/* *** SET COPY AND SPLIT POLICY ON TX PACKETS *** */
+
+struct cmd_set_txsplit_result {
+ cmdline_fixed_string_t cmd_keyword;
+ cmdline_fixed_string_t txsplit;
+ cmdline_fixed_string_t mode;
+};
+
+static void
+cmd_set_txsplit_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_txsplit_result *res;
+
+ res = parsed_result;
+ set_tx_pkt_split(res->mode);
+}
+
+cmdline_parse_token_string_t cmd_set_txsplit_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_txsplit_result,
+ cmd_keyword, "set");
+cmdline_parse_token_string_t cmd_set_txsplit_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_txsplit_result,
+ txsplit, "txsplit");
+cmdline_parse_token_string_t cmd_set_txsplit_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_txsplit_result,
+ mode, NULL);
+
+cmdline_parse_inst_t cmd_set_txsplit = {
+ .f = cmd_set_txsplit_parsed,
+ .data = NULL,
+ .help_str = "set txsplit on|off|rand",
+ .tokens = {
+ (void *)&cmd_set_txsplit_keyword,
+ (void *)&cmd_set_txsplit_name,
+ (void *)&cmd_set_txsplit_mode,
+ NULL,
+ },
+};
+
+/* *** ADD/REMOVE ALL VLAN IDENTIFIERS TO/FROM A PORT VLAN RX FILTER *** */
+struct cmd_rx_vlan_filter_all_result {
+ cmdline_fixed_string_t rx_vlan;
+ cmdline_fixed_string_t what;
+ cmdline_fixed_string_t all;
+ portid_t port_id;
+};
+
+static void
+cmd_rx_vlan_filter_all_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_rx_vlan_filter_all_result *res = parsed_result;
+
+ if (!strcmp(res->what, "add"))
+ rx_vlan_all_filter_set(res->port_id, 1);
+ else
+ rx_vlan_all_filter_set(res->port_id, 0);
+}
+
+cmdline_parse_token_string_t cmd_rx_vlan_filter_all_rx_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_rx_vlan_filter_all_result,
+ rx_vlan, "rx_vlan");
+cmdline_parse_token_string_t cmd_rx_vlan_filter_all_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_rx_vlan_filter_all_result,
+ what, "add#rm");
+cmdline_parse_token_string_t cmd_rx_vlan_filter_all_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_rx_vlan_filter_all_result,
+ all, "all");
+cmdline_parse_token_num_t cmd_rx_vlan_filter_all_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_rx_vlan_filter_all_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_rx_vlan_filter_all = {
+ .f = cmd_rx_vlan_filter_all_parsed,
+ .data = NULL,
+ .help_str = "rx_vlan add|rm all <port_id>: "
+ "Add/Remove all identifiers to/from the set of VLAN "
+ "identifiers filtered by a port",
+ .tokens = {
+ (void *)&cmd_rx_vlan_filter_all_rx_vlan,
+ (void *)&cmd_rx_vlan_filter_all_what,
+ (void *)&cmd_rx_vlan_filter_all_all,
+ (void *)&cmd_rx_vlan_filter_all_portid,
+ NULL,
+ },
+};
+
+/* *** VLAN OFFLOAD SET ON A PORT *** */
+struct cmd_vlan_offload_result {
+ cmdline_fixed_string_t vlan;
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vlan_type;
+ cmdline_fixed_string_t what;
+ cmdline_fixed_string_t on;
+ cmdline_fixed_string_t port_id;
+};
+
+static void
+cmd_vlan_offload_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ int on;
+ struct cmd_vlan_offload_result *res = parsed_result;
+ char *str;
+ int i, len = 0;
+ portid_t port_id = 0;
+ unsigned int tmp;
+
+ str = res->port_id;
+ len = strnlen(str, STR_TOKEN_SIZE);
+ i = 0;
+ /* Get port_id first */
+ while(i < len){
+ if(str[i] == ',')
+ break;
+
+ i++;
+ }
+ str[i]='\0';
+ tmp = strtoul(str, NULL, 0);
+ /* If port_id greater that what portid_t can represent, return */
+ if(tmp >= RTE_MAX_ETHPORTS)
+ return;
+ port_id = (portid_t)tmp;
+
+ if (!strcmp(res->on, "on"))
+ on = 1;
+ else
+ on = 0;
+
+ if (!strcmp(res->what, "strip"))
+ rx_vlan_strip_set(port_id, on);
+ else if(!strcmp(res->what, "stripq")){
+ uint16_t queue_id = 0;
+
+ /* No queue_id, return */
+ if(i + 1 >= len) {
+ printf("must specify (port,queue_id)\n");
+ return;
+ }
+ tmp = strtoul(str + i + 1, NULL, 0);
+ /* If queue_id greater that what 16-bits can represent, return */
+ if(tmp > 0xffff)
+ return;
+
+ queue_id = (uint16_t)tmp;
+ rx_vlan_strip_set_on_queue(port_id, queue_id, on);
+ }
+ else if (!strcmp(res->what, "filter"))
+ rx_vlan_filter_set(port_id, on);
+ else if (!strcmp(res->what, "qinq_strip"))
+ rx_vlan_qinq_strip_set(port_id, on);
+ else
+ vlan_extend_set(port_id, on);
+
+ return;
+}
+
+cmdline_parse_token_string_t cmd_vlan_offload_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_vlan_offload_result,
+ vlan, "vlan");
+cmdline_parse_token_string_t cmd_vlan_offload_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_vlan_offload_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_vlan_offload_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_vlan_offload_result,
+ what, "strip#filter#qinq_strip#extend#stripq");
+cmdline_parse_token_string_t cmd_vlan_offload_on =
+ TOKEN_STRING_INITIALIZER(struct cmd_vlan_offload_result,
+ on, "on#off");
+cmdline_parse_token_string_t cmd_vlan_offload_portid =
+ TOKEN_STRING_INITIALIZER(struct cmd_vlan_offload_result,
+ port_id, NULL);
+
+cmdline_parse_inst_t cmd_vlan_offload = {
+ .f = cmd_vlan_offload_parsed,
+ .data = NULL,
+ .help_str = "vlan set strip|filter|qinq_strip|extend|stripq on|off "
+ "<port_id[,queue_id]>: "
+ "Strip/Filter/QinQ for rx side Extend for both rx/tx sides",
+ .tokens = {
+ (void *)&cmd_vlan_offload_vlan,
+ (void *)&cmd_vlan_offload_set,
+ (void *)&cmd_vlan_offload_what,
+ (void *)&cmd_vlan_offload_on,
+ (void *)&cmd_vlan_offload_portid,
+ NULL,
+ },
+};
+
+/* *** VLAN TPID SET ON A PORT *** */
+struct cmd_vlan_tpid_result {
+ cmdline_fixed_string_t vlan;
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vlan_type;
+ cmdline_fixed_string_t what;
+ uint16_t tp_id;
+ portid_t port_id;
+};
+
+static void
+cmd_vlan_tpid_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vlan_tpid_result *res = parsed_result;
+ enum rte_vlan_type vlan_type;
+
+ if (!strcmp(res->vlan_type, "inner"))
+ vlan_type = ETH_VLAN_TYPE_INNER;
+ else if (!strcmp(res->vlan_type, "outer"))
+ vlan_type = ETH_VLAN_TYPE_OUTER;
+ else {
+ printf("Unknown vlan type\n");
+ return;
+ }
+ vlan_tpid_set(res->port_id, vlan_type, res->tp_id);
+}
+
+cmdline_parse_token_string_t cmd_vlan_tpid_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_vlan_tpid_result,
+ vlan, "vlan");
+cmdline_parse_token_string_t cmd_vlan_tpid_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_vlan_tpid_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_vlan_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_vlan_tpid_result,
+ vlan_type, "inner#outer");
+cmdline_parse_token_string_t cmd_vlan_tpid_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_vlan_tpid_result,
+ what, "tpid");
+cmdline_parse_token_num_t cmd_vlan_tpid_tpid =
+ TOKEN_NUM_INITIALIZER(struct cmd_vlan_tpid_result,
+ tp_id, UINT16);
+cmdline_parse_token_num_t cmd_vlan_tpid_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_vlan_tpid_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_vlan_tpid = {
+ .f = cmd_vlan_tpid_parsed,
+ .data = NULL,
+ .help_str = "vlan set inner|outer tpid <tp_id> <port_id>: "
+ "Set the VLAN Ether type",
+ .tokens = {
+ (void *)&cmd_vlan_tpid_vlan,
+ (void *)&cmd_vlan_tpid_set,
+ (void *)&cmd_vlan_type,
+ (void *)&cmd_vlan_tpid_what,
+ (void *)&cmd_vlan_tpid_tpid,
+ (void *)&cmd_vlan_tpid_portid,
+ NULL,
+ },
+};
+
+/* *** ADD/REMOVE A VLAN IDENTIFIER TO/FROM A PORT VLAN RX FILTER *** */
+struct cmd_rx_vlan_filter_result {
+ cmdline_fixed_string_t rx_vlan;
+ cmdline_fixed_string_t what;
+ uint16_t vlan_id;
+ portid_t port_id;
+};
+
+static void
+cmd_rx_vlan_filter_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_rx_vlan_filter_result *res = parsed_result;
+
+ if (!strcmp(res->what, "add"))
+ rx_vft_set(res->port_id, res->vlan_id, 1);
+ else
+ rx_vft_set(res->port_id, res->vlan_id, 0);
+}
+
+cmdline_parse_token_string_t cmd_rx_vlan_filter_rx_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_rx_vlan_filter_result,
+ rx_vlan, "rx_vlan");
+cmdline_parse_token_string_t cmd_rx_vlan_filter_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_rx_vlan_filter_result,
+ what, "add#rm");
+cmdline_parse_token_num_t cmd_rx_vlan_filter_vlanid =
+ TOKEN_NUM_INITIALIZER(struct cmd_rx_vlan_filter_result,
+ vlan_id, UINT16);
+cmdline_parse_token_num_t cmd_rx_vlan_filter_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_rx_vlan_filter_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_rx_vlan_filter = {
+ .f = cmd_rx_vlan_filter_parsed,
+ .data = NULL,
+ .help_str = "rx_vlan add|rm <vlan_id> <port_id>: "
+ "Add/Remove a VLAN identifier to/from the set of VLAN "
+ "identifiers filtered by a port",
+ .tokens = {
+ (void *)&cmd_rx_vlan_filter_rx_vlan,
+ (void *)&cmd_rx_vlan_filter_what,
+ (void *)&cmd_rx_vlan_filter_vlanid,
+ (void *)&cmd_rx_vlan_filter_portid,
+ NULL,
+ },
+};
+
+/* *** ENABLE HARDWARE INSERTION OF VLAN HEADER IN TX PACKETS *** */
+struct cmd_tx_vlan_set_result {
+ cmdline_fixed_string_t tx_vlan;
+ cmdline_fixed_string_t set;
+ portid_t port_id;
+ uint16_t vlan_id;
+};
+
+static void
+cmd_tx_vlan_set_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_tx_vlan_set_result *res = parsed_result;
+
+ if (!port_is_stopped(res->port_id)) {
+ printf("Please stop port %d first\n", res->port_id);
+ return;
+ }
+
+ tx_vlan_set(res->port_id, res->vlan_id);
+
+ cmd_reconfig_device_queue(res->port_id, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_tx_vlan_set_tx_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_tx_vlan_set_result,
+ tx_vlan, "tx_vlan");
+cmdline_parse_token_string_t cmd_tx_vlan_set_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_tx_vlan_set_result,
+ set, "set");
+cmdline_parse_token_num_t cmd_tx_vlan_set_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_tx_vlan_set_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_tx_vlan_set_vlanid =
+ TOKEN_NUM_INITIALIZER(struct cmd_tx_vlan_set_result,
+ vlan_id, UINT16);
+
+cmdline_parse_inst_t cmd_tx_vlan_set = {
+ .f = cmd_tx_vlan_set_parsed,
+ .data = NULL,
+ .help_str = "tx_vlan set <port_id> <vlan_id>: "
+ "Enable hardware insertion of a single VLAN header "
+ "with a given TAG Identifier in packets sent on a port",
+ .tokens = {
+ (void *)&cmd_tx_vlan_set_tx_vlan,
+ (void *)&cmd_tx_vlan_set_set,
+ (void *)&cmd_tx_vlan_set_portid,
+ (void *)&cmd_tx_vlan_set_vlanid,
+ NULL,
+ },
+};
+
+/* *** ENABLE HARDWARE INSERTION OF Double VLAN HEADER IN TX PACKETS *** */
+struct cmd_tx_vlan_set_qinq_result {
+ cmdline_fixed_string_t tx_vlan;
+ cmdline_fixed_string_t set;
+ portid_t port_id;
+ uint16_t vlan_id;
+ uint16_t vlan_id_outer;
+};
+
+static void
+cmd_tx_vlan_set_qinq_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_tx_vlan_set_qinq_result *res = parsed_result;
+
+ if (!port_is_stopped(res->port_id)) {
+ printf("Please stop port %d first\n", res->port_id);
+ return;
+ }
+
+ tx_qinq_set(res->port_id, res->vlan_id, res->vlan_id_outer);
+
+ cmd_reconfig_device_queue(res->port_id, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_tx_vlan_set_qinq_tx_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_tx_vlan_set_qinq_result,
+ tx_vlan, "tx_vlan");
+cmdline_parse_token_string_t cmd_tx_vlan_set_qinq_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_tx_vlan_set_qinq_result,
+ set, "set");
+cmdline_parse_token_num_t cmd_tx_vlan_set_qinq_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_tx_vlan_set_qinq_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_tx_vlan_set_qinq_vlanid =
+ TOKEN_NUM_INITIALIZER(struct cmd_tx_vlan_set_qinq_result,
+ vlan_id, UINT16);
+cmdline_parse_token_num_t cmd_tx_vlan_set_qinq_vlanid_outer =
+ TOKEN_NUM_INITIALIZER(struct cmd_tx_vlan_set_qinq_result,
+ vlan_id_outer, UINT16);
+
+cmdline_parse_inst_t cmd_tx_vlan_set_qinq = {
+ .f = cmd_tx_vlan_set_qinq_parsed,
+ .data = NULL,
+ .help_str = "tx_vlan set <port_id> <vlan_id> <outer_vlan_id>: "
+ "Enable hardware insertion of double VLAN header "
+ "with given TAG Identifiers in packets sent on a port",
+ .tokens = {
+ (void *)&cmd_tx_vlan_set_qinq_tx_vlan,
+ (void *)&cmd_tx_vlan_set_qinq_set,
+ (void *)&cmd_tx_vlan_set_qinq_portid,
+ (void *)&cmd_tx_vlan_set_qinq_vlanid,
+ (void *)&cmd_tx_vlan_set_qinq_vlanid_outer,
+ NULL,
+ },
+};
+
+/* *** ENABLE/DISABLE PORT BASED TX VLAN INSERTION *** */
+struct cmd_tx_vlan_set_pvid_result {
+ cmdline_fixed_string_t tx_vlan;
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t pvid;
+ portid_t port_id;
+ uint16_t vlan_id;
+ cmdline_fixed_string_t mode;
+};
+
+static void
+cmd_tx_vlan_set_pvid_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_tx_vlan_set_pvid_result *res = parsed_result;
+
+ if (strcmp(res->mode, "on") == 0)
+ tx_vlan_pvid_set(res->port_id, res->vlan_id, 1);
+ else
+ tx_vlan_pvid_set(res->port_id, res->vlan_id, 0);
+}
+
+cmdline_parse_token_string_t cmd_tx_vlan_set_pvid_tx_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_tx_vlan_set_pvid_result,
+ tx_vlan, "tx_vlan");
+cmdline_parse_token_string_t cmd_tx_vlan_set_pvid_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_tx_vlan_set_pvid_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_tx_vlan_set_pvid_pvid =
+ TOKEN_STRING_INITIALIZER(struct cmd_tx_vlan_set_pvid_result,
+ pvid, "pvid");
+cmdline_parse_token_num_t cmd_tx_vlan_set_pvid_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_tx_vlan_set_pvid_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_tx_vlan_set_pvid_vlan_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_tx_vlan_set_pvid_result,
+ vlan_id, UINT16);
+cmdline_parse_token_string_t cmd_tx_vlan_set_pvid_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_tx_vlan_set_pvid_result,
+ mode, "on#off");
+
+cmdline_parse_inst_t cmd_tx_vlan_set_pvid = {
+ .f = cmd_tx_vlan_set_pvid_parsed,
+ .data = NULL,
+ .help_str = "tx_vlan set pvid <port_id> <vlan_id> on|off",
+ .tokens = {
+ (void *)&cmd_tx_vlan_set_pvid_tx_vlan,
+ (void *)&cmd_tx_vlan_set_pvid_set,
+ (void *)&cmd_tx_vlan_set_pvid_pvid,
+ (void *)&cmd_tx_vlan_set_pvid_port_id,
+ (void *)&cmd_tx_vlan_set_pvid_vlan_id,
+ (void *)&cmd_tx_vlan_set_pvid_mode,
+ NULL,
+ },
+};
+
+/* *** DISABLE HARDWARE INSERTION OF VLAN HEADER IN TX PACKETS *** */
+struct cmd_tx_vlan_reset_result {
+ cmdline_fixed_string_t tx_vlan;
+ cmdline_fixed_string_t reset;
+ portid_t port_id;
+};
+
+static void
+cmd_tx_vlan_reset_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_tx_vlan_reset_result *res = parsed_result;
+
+ if (!port_is_stopped(res->port_id)) {
+ printf("Please stop port %d first\n", res->port_id);
+ return;
+ }
+
+ tx_vlan_reset(res->port_id);
+
+ cmd_reconfig_device_queue(res->port_id, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_tx_vlan_reset_tx_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_tx_vlan_reset_result,
+ tx_vlan, "tx_vlan");
+cmdline_parse_token_string_t cmd_tx_vlan_reset_reset =
+ TOKEN_STRING_INITIALIZER(struct cmd_tx_vlan_reset_result,
+ reset, "reset");
+cmdline_parse_token_num_t cmd_tx_vlan_reset_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_tx_vlan_reset_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_tx_vlan_reset = {
+ .f = cmd_tx_vlan_reset_parsed,
+ .data = NULL,
+ .help_str = "tx_vlan reset <port_id>: Disable hardware insertion of a "
+ "VLAN header in packets sent on a port",
+ .tokens = {
+ (void *)&cmd_tx_vlan_reset_tx_vlan,
+ (void *)&cmd_tx_vlan_reset_reset,
+ (void *)&cmd_tx_vlan_reset_portid,
+ NULL,
+ },
+};
+
+
+/* *** ENABLE HARDWARE INSERTION OF CHECKSUM IN TX PACKETS *** */
+struct cmd_csum_result {
+ cmdline_fixed_string_t csum;
+ cmdline_fixed_string_t mode;
+ cmdline_fixed_string_t proto;
+ cmdline_fixed_string_t hwsw;
+ portid_t port_id;
+};
+
+static void
+csum_show(int port_id)
+{
+ struct rte_eth_dev_info dev_info;
+ uint64_t tx_offloads;
+ int ret;
+
+ tx_offloads = ports[port_id].dev_conf.txmode.offloads;
+ printf("Parse tunnel is %s\n",
+ (ports[port_id].parse_tunnel) ? "on" : "off");
+ printf("IP checksum offload is %s\n",
+ (tx_offloads & DEV_TX_OFFLOAD_IPV4_CKSUM) ? "hw" : "sw");
+ printf("UDP checksum offload is %s\n",
+ (tx_offloads & DEV_TX_OFFLOAD_UDP_CKSUM) ? "hw" : "sw");
+ printf("TCP checksum offload is %s\n",
+ (tx_offloads & DEV_TX_OFFLOAD_TCP_CKSUM) ? "hw" : "sw");
+ printf("SCTP checksum offload is %s\n",
+ (tx_offloads & DEV_TX_OFFLOAD_SCTP_CKSUM) ? "hw" : "sw");
+ printf("Outer-Ip checksum offload is %s\n",
+ (tx_offloads & DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM) ? "hw" : "sw");
+ printf("Outer-Udp checksum offload is %s\n",
+ (tx_offloads & DEV_TX_OFFLOAD_OUTER_UDP_CKSUM) ? "hw" : "sw");
+
+ /* display warnings if configuration is not supported by the NIC */
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if ((tx_offloads & DEV_TX_OFFLOAD_IPV4_CKSUM) &&
+ (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_IPV4_CKSUM) == 0) {
+ printf("Warning: hardware IP checksum enabled but not "
+ "supported by port %d\n", port_id);
+ }
+ if ((tx_offloads & DEV_TX_OFFLOAD_UDP_CKSUM) &&
+ (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_UDP_CKSUM) == 0) {
+ printf("Warning: hardware UDP checksum enabled but not "
+ "supported by port %d\n", port_id);
+ }
+ if ((tx_offloads & DEV_TX_OFFLOAD_TCP_CKSUM) &&
+ (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_TCP_CKSUM) == 0) {
+ printf("Warning: hardware TCP checksum enabled but not "
+ "supported by port %d\n", port_id);
+ }
+ if ((tx_offloads & DEV_TX_OFFLOAD_SCTP_CKSUM) &&
+ (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_SCTP_CKSUM) == 0) {
+ printf("Warning: hardware SCTP checksum enabled but not "
+ "supported by port %d\n", port_id);
+ }
+ if ((tx_offloads & DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM) &&
+ (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM) == 0) {
+ printf("Warning: hardware outer IP checksum enabled but not "
+ "supported by port %d\n", port_id);
+ }
+ if ((tx_offloads & DEV_TX_OFFLOAD_OUTER_UDP_CKSUM) &&
+ (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_OUTER_UDP_CKSUM)
+ == 0) {
+ printf("Warning: hardware outer UDP checksum enabled but not "
+ "supported by port %d\n", port_id);
+ }
+}
+
+static void
+cmd_config_queue_tx_offloads(struct rte_port *port)
+{
+ int k;
+
+ /* Apply queue tx offloads configuration */
+ for (k = 0; k < port->dev_info.max_rx_queues; k++)
+ port->tx_conf[k].offloads =
+ port->dev_conf.txmode.offloads;
+}
+
+static void
+cmd_csum_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_csum_result *res = parsed_result;
+ int hw = 0;
+ uint64_t csum_offloads = 0;
+ struct rte_eth_dev_info dev_info;
+ int ret;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN)) {
+ printf("invalid port %d\n", res->port_id);
+ return;
+ }
+ if (!port_is_stopped(res->port_id)) {
+ printf("Please stop port %d first\n", res->port_id);
+ return;
+ }
+
+ ret = eth_dev_info_get_print_err(res->port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if (!strcmp(res->mode, "set")) {
+
+ if (!strcmp(res->hwsw, "hw"))
+ hw = 1;
+
+ if (!strcmp(res->proto, "ip")) {
+ if (hw == 0 || (dev_info.tx_offload_capa &
+ DEV_TX_OFFLOAD_IPV4_CKSUM)) {
+ csum_offloads |= DEV_TX_OFFLOAD_IPV4_CKSUM;
+ } else {
+ printf("IP checksum offload is not supported "
+ "by port %u\n", res->port_id);
+ }
+ } else if (!strcmp(res->proto, "udp")) {
+ if (hw == 0 || (dev_info.tx_offload_capa &
+ DEV_TX_OFFLOAD_UDP_CKSUM)) {
+ csum_offloads |= DEV_TX_OFFLOAD_UDP_CKSUM;
+ } else {
+ printf("UDP checksum offload is not supported "
+ "by port %u\n", res->port_id);
+ }
+ } else if (!strcmp(res->proto, "tcp")) {
+ if (hw == 0 || (dev_info.tx_offload_capa &
+ DEV_TX_OFFLOAD_TCP_CKSUM)) {
+ csum_offloads |= DEV_TX_OFFLOAD_TCP_CKSUM;
+ } else {
+ printf("TCP checksum offload is not supported "
+ "by port %u\n", res->port_id);
+ }
+ } else if (!strcmp(res->proto, "sctp")) {
+ if (hw == 0 || (dev_info.tx_offload_capa &
+ DEV_TX_OFFLOAD_SCTP_CKSUM)) {
+ csum_offloads |= DEV_TX_OFFLOAD_SCTP_CKSUM;
+ } else {
+ printf("SCTP checksum offload is not supported "
+ "by port %u\n", res->port_id);
+ }
+ } else if (!strcmp(res->proto, "outer-ip")) {
+ if (hw == 0 || (dev_info.tx_offload_capa &
+ DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM)) {
+ csum_offloads |=
+ DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM;
+ } else {
+ printf("Outer IP checksum offload is not "
+ "supported by port %u\n", res->port_id);
+ }
+ } else if (!strcmp(res->proto, "outer-udp")) {
+ if (hw == 0 || (dev_info.tx_offload_capa &
+ DEV_TX_OFFLOAD_OUTER_UDP_CKSUM)) {
+ csum_offloads |=
+ DEV_TX_OFFLOAD_OUTER_UDP_CKSUM;
+ } else {
+ printf("Outer UDP checksum offload is not "
+ "supported by port %u\n", res->port_id);
+ }
+ }
+
+ if (hw) {
+ ports[res->port_id].dev_conf.txmode.offloads |=
+ csum_offloads;
+ } else {
+ ports[res->port_id].dev_conf.txmode.offloads &=
+ (~csum_offloads);
+ }
+ cmd_config_queue_tx_offloads(&ports[res->port_id]);
+ }
+ csum_show(res->port_id);
+
+ cmd_reconfig_device_queue(res->port_id, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_csum_csum =
+ TOKEN_STRING_INITIALIZER(struct cmd_csum_result,
+ csum, "csum");
+cmdline_parse_token_string_t cmd_csum_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_csum_result,
+ mode, "set");
+cmdline_parse_token_string_t cmd_csum_proto =
+ TOKEN_STRING_INITIALIZER(struct cmd_csum_result,
+ proto, "ip#tcp#udp#sctp#outer-ip#outer-udp");
+cmdline_parse_token_string_t cmd_csum_hwsw =
+ TOKEN_STRING_INITIALIZER(struct cmd_csum_result,
+ hwsw, "hw#sw");
+cmdline_parse_token_num_t cmd_csum_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_csum_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_csum_set = {
+ .f = cmd_csum_parsed,
+ .data = NULL,
+ .help_str = "csum set ip|tcp|udp|sctp|outer-ip|outer-udp hw|sw <port_id>: "
+ "Enable/Disable hardware calculation of L3/L4 checksum when "
+ "using csum forward engine",
+ .tokens = {
+ (void *)&cmd_csum_csum,
+ (void *)&cmd_csum_mode,
+ (void *)&cmd_csum_proto,
+ (void *)&cmd_csum_hwsw,
+ (void *)&cmd_csum_portid,
+ NULL,
+ },
+};
+
+cmdline_parse_token_string_t cmd_csum_mode_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_csum_result,
+ mode, "show");
+
+cmdline_parse_inst_t cmd_csum_show = {
+ .f = cmd_csum_parsed,
+ .data = NULL,
+ .help_str = "csum show <port_id>: Show checksum offload configuration",
+ .tokens = {
+ (void *)&cmd_csum_csum,
+ (void *)&cmd_csum_mode_show,
+ (void *)&cmd_csum_portid,
+ NULL,
+ },
+};
+
+/* Enable/disable tunnel parsing */
+struct cmd_csum_tunnel_result {
+ cmdline_fixed_string_t csum;
+ cmdline_fixed_string_t parse;
+ cmdline_fixed_string_t onoff;
+ portid_t port_id;
+};
+
+static void
+cmd_csum_tunnel_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_csum_tunnel_result *res = parsed_result;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+ if (!strcmp(res->onoff, "on"))
+ ports[res->port_id].parse_tunnel = 1;
+ else
+ ports[res->port_id].parse_tunnel = 0;
+
+ csum_show(res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_csum_tunnel_csum =
+ TOKEN_STRING_INITIALIZER(struct cmd_csum_tunnel_result,
+ csum, "csum");
+cmdline_parse_token_string_t cmd_csum_tunnel_parse =
+ TOKEN_STRING_INITIALIZER(struct cmd_csum_tunnel_result,
+ parse, "parse-tunnel");
+cmdline_parse_token_string_t cmd_csum_tunnel_onoff =
+ TOKEN_STRING_INITIALIZER(struct cmd_csum_tunnel_result,
+ onoff, "on#off");
+cmdline_parse_token_num_t cmd_csum_tunnel_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_csum_tunnel_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_csum_tunnel = {
+ .f = cmd_csum_tunnel_parsed,
+ .data = NULL,
+ .help_str = "csum parse-tunnel on|off <port_id>: "
+ "Enable/Disable parsing of tunnels for csum engine",
+ .tokens = {
+ (void *)&cmd_csum_tunnel_csum,
+ (void *)&cmd_csum_tunnel_parse,
+ (void *)&cmd_csum_tunnel_onoff,
+ (void *)&cmd_csum_tunnel_portid,
+ NULL,
+ },
+};
+
+/* *** ENABLE HARDWARE SEGMENTATION IN TX NON-TUNNELED PACKETS *** */
+struct cmd_tso_set_result {
+ cmdline_fixed_string_t tso;
+ cmdline_fixed_string_t mode;
+ uint16_t tso_segsz;
+ portid_t port_id;
+};
+
+static void
+cmd_tso_set_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_tso_set_result *res = parsed_result;
+ struct rte_eth_dev_info dev_info;
+ int ret;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+ if (!port_is_stopped(res->port_id)) {
+ printf("Please stop port %d first\n", res->port_id);
+ return;
+ }
+
+ if (!strcmp(res->mode, "set"))
+ ports[res->port_id].tso_segsz = res->tso_segsz;
+
+ ret = eth_dev_info_get_print_err(res->port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if ((ports[res->port_id].tso_segsz != 0) &&
+ (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_TCP_TSO) == 0) {
+ printf("Error: TSO is not supported by port %d\n",
+ res->port_id);
+ return;
+ }
+
+ if (ports[res->port_id].tso_segsz == 0) {
+ ports[res->port_id].dev_conf.txmode.offloads &=
+ ~DEV_TX_OFFLOAD_TCP_TSO;
+ printf("TSO for non-tunneled packets is disabled\n");
+ } else {
+ ports[res->port_id].dev_conf.txmode.offloads |=
+ DEV_TX_OFFLOAD_TCP_TSO;
+ printf("TSO segment size for non-tunneled packets is %d\n",
+ ports[res->port_id].tso_segsz);
+ }
+ cmd_config_queue_tx_offloads(&ports[res->port_id]);
+
+ /* display warnings if configuration is not supported by the NIC */
+ ret = eth_dev_info_get_print_err(res->port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if ((ports[res->port_id].tso_segsz != 0) &&
+ (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_TCP_TSO) == 0) {
+ printf("Warning: TSO enabled but not "
+ "supported by port %d\n", res->port_id);
+ }
+
+ cmd_reconfig_device_queue(res->port_id, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_tso_set_tso =
+ TOKEN_STRING_INITIALIZER(struct cmd_tso_set_result,
+ tso, "tso");
+cmdline_parse_token_string_t cmd_tso_set_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_tso_set_result,
+ mode, "set");
+cmdline_parse_token_num_t cmd_tso_set_tso_segsz =
+ TOKEN_NUM_INITIALIZER(struct cmd_tso_set_result,
+ tso_segsz, UINT16);
+cmdline_parse_token_num_t cmd_tso_set_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_tso_set_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_tso_set = {
+ .f = cmd_tso_set_parsed,
+ .data = NULL,
+ .help_str = "tso set <tso_segsz> <port_id>: "
+ "Set TSO segment size of non-tunneled packets for csum engine "
+ "(0 to disable)",
+ .tokens = {
+ (void *)&cmd_tso_set_tso,
+ (void *)&cmd_tso_set_mode,
+ (void *)&cmd_tso_set_tso_segsz,
+ (void *)&cmd_tso_set_portid,
+ NULL,
+ },
+};
+
+cmdline_parse_token_string_t cmd_tso_show_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_tso_set_result,
+ mode, "show");
+
+
+cmdline_parse_inst_t cmd_tso_show = {
+ .f = cmd_tso_set_parsed,
+ .data = NULL,
+ .help_str = "tso show <port_id>: "
+ "Show TSO segment size of non-tunneled packets for csum engine",
+ .tokens = {
+ (void *)&cmd_tso_set_tso,
+ (void *)&cmd_tso_show_mode,
+ (void *)&cmd_tso_set_portid,
+ NULL,
+ },
+};
+
+/* *** ENABLE HARDWARE SEGMENTATION IN TX TUNNELED PACKETS *** */
+struct cmd_tunnel_tso_set_result {
+ cmdline_fixed_string_t tso;
+ cmdline_fixed_string_t mode;
+ uint16_t tso_segsz;
+ portid_t port_id;
+};
+
+static struct rte_eth_dev_info
+check_tunnel_tso_nic_support(portid_t port_id)
+{
+ struct rte_eth_dev_info dev_info;
+
+ if (eth_dev_info_get_print_err(port_id, &dev_info) != 0)
+ return dev_info;
+
+ if (!(dev_info.tx_offload_capa & DEV_TX_OFFLOAD_VXLAN_TNL_TSO))
+ printf("Warning: VXLAN TUNNEL TSO not supported therefore "
+ "not enabled for port %d\n", port_id);
+ if (!(dev_info.tx_offload_capa & DEV_TX_OFFLOAD_GRE_TNL_TSO))
+ printf("Warning: GRE TUNNEL TSO not supported therefore "
+ "not enabled for port %d\n", port_id);
+ if (!(dev_info.tx_offload_capa & DEV_TX_OFFLOAD_IPIP_TNL_TSO))
+ printf("Warning: IPIP TUNNEL TSO not supported therefore "
+ "not enabled for port %d\n", port_id);
+ if (!(dev_info.tx_offload_capa & DEV_TX_OFFLOAD_GENEVE_TNL_TSO))
+ printf("Warning: GENEVE TUNNEL TSO not supported therefore "
+ "not enabled for port %d\n", port_id);
+ if (!(dev_info.tx_offload_capa & DEV_TX_OFFLOAD_IP_TNL_TSO))
+ printf("Warning: IP TUNNEL TSO not supported therefore "
+ "not enabled for port %d\n", port_id);
+ if (!(dev_info.tx_offload_capa & DEV_TX_OFFLOAD_UDP_TNL_TSO))
+ printf("Warning: UDP TUNNEL TSO not supported therefore "
+ "not enabled for port %d\n", port_id);
+ return dev_info;
+}
+
+static void
+cmd_tunnel_tso_set_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_tunnel_tso_set_result *res = parsed_result;
+ struct rte_eth_dev_info dev_info;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+ if (!port_is_stopped(res->port_id)) {
+ printf("Please stop port %d first\n", res->port_id);
+ return;
+ }
+
+ if (!strcmp(res->mode, "set"))
+ ports[res->port_id].tunnel_tso_segsz = res->tso_segsz;
+
+ dev_info = check_tunnel_tso_nic_support(res->port_id);
+ if (ports[res->port_id].tunnel_tso_segsz == 0) {
+ ports[res->port_id].dev_conf.txmode.offloads &=
+ ~(DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
+ DEV_TX_OFFLOAD_GRE_TNL_TSO |
+ DEV_TX_OFFLOAD_IPIP_TNL_TSO |
+ DEV_TX_OFFLOAD_GENEVE_TNL_TSO |
+ DEV_TX_OFFLOAD_IP_TNL_TSO |
+ DEV_TX_OFFLOAD_UDP_TNL_TSO);
+ printf("TSO for tunneled packets is disabled\n");
+ } else {
+ uint64_t tso_offloads = (DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
+ DEV_TX_OFFLOAD_GRE_TNL_TSO |
+ DEV_TX_OFFLOAD_IPIP_TNL_TSO |
+ DEV_TX_OFFLOAD_GENEVE_TNL_TSO |
+ DEV_TX_OFFLOAD_IP_TNL_TSO |
+ DEV_TX_OFFLOAD_UDP_TNL_TSO);
+
+ ports[res->port_id].dev_conf.txmode.offloads |=
+ (tso_offloads & dev_info.tx_offload_capa);
+ printf("TSO segment size for tunneled packets is %d\n",
+ ports[res->port_id].tunnel_tso_segsz);
+
+ /* Below conditions are needed to make it work:
+ * (1) tunnel TSO is supported by the NIC;
+ * (2) "csum parse_tunnel" must be set so that tunneled pkts
+ * are recognized;
+ * (3) for tunneled pkts with outer L3 of IPv4,
+ * "csum set outer-ip" must be set to hw, because after tso,
+ * total_len of outer IP header is changed, and the checksum
+ * of outer IP header calculated by sw should be wrong; that
+ * is not necessary for IPv6 tunneled pkts because there's no
+ * checksum in IP header anymore.
+ */
+
+ if (!ports[res->port_id].parse_tunnel)
+ printf("Warning: csum parse_tunnel must be set "
+ "so that tunneled packets are recognized\n");
+ if (!(ports[res->port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM))
+ printf("Warning: csum set outer-ip must be set to hw "
+ "if outer L3 is IPv4; not necessary for IPv6\n");
+ }
+
+ cmd_config_queue_tx_offloads(&ports[res->port_id]);
+ cmd_reconfig_device_queue(res->port_id, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_tunnel_tso_set_tso =
+ TOKEN_STRING_INITIALIZER(struct cmd_tunnel_tso_set_result,
+ tso, "tunnel_tso");
+cmdline_parse_token_string_t cmd_tunnel_tso_set_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_tunnel_tso_set_result,
+ mode, "set");
+cmdline_parse_token_num_t cmd_tunnel_tso_set_tso_segsz =
+ TOKEN_NUM_INITIALIZER(struct cmd_tunnel_tso_set_result,
+ tso_segsz, UINT16);
+cmdline_parse_token_num_t cmd_tunnel_tso_set_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_tunnel_tso_set_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_tunnel_tso_set = {
+ .f = cmd_tunnel_tso_set_parsed,
+ .data = NULL,
+ .help_str = "tunnel_tso set <tso_segsz> <port_id>: "
+ "Set TSO segment size of tunneled packets for csum engine "
+ "(0 to disable)",
+ .tokens = {
+ (void *)&cmd_tunnel_tso_set_tso,
+ (void *)&cmd_tunnel_tso_set_mode,
+ (void *)&cmd_tunnel_tso_set_tso_segsz,
+ (void *)&cmd_tunnel_tso_set_portid,
+ NULL,
+ },
+};
+
+cmdline_parse_token_string_t cmd_tunnel_tso_show_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_tunnel_tso_set_result,
+ mode, "show");
+
+
+cmdline_parse_inst_t cmd_tunnel_tso_show = {
+ .f = cmd_tunnel_tso_set_parsed,
+ .data = NULL,
+ .help_str = "tunnel_tso show <port_id> "
+ "Show TSO segment size of tunneled packets for csum engine",
+ .tokens = {
+ (void *)&cmd_tunnel_tso_set_tso,
+ (void *)&cmd_tunnel_tso_show_mode,
+ (void *)&cmd_tunnel_tso_set_portid,
+ NULL,
+ },
+};
+
+/* *** SET GRO FOR A PORT *** */
+struct cmd_gro_enable_result {
+ cmdline_fixed_string_t cmd_set;
+ cmdline_fixed_string_t cmd_port;
+ cmdline_fixed_string_t cmd_keyword;
+ cmdline_fixed_string_t cmd_onoff;
+ portid_t cmd_pid;
+};
+
+static void
+cmd_gro_enable_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_gro_enable_result *res;
+
+ res = parsed_result;
+ if (!strcmp(res->cmd_keyword, "gro"))
+ setup_gro(res->cmd_onoff, res->cmd_pid);
+}
+
+cmdline_parse_token_string_t cmd_gro_enable_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_gro_enable_result,
+ cmd_set, "set");
+cmdline_parse_token_string_t cmd_gro_enable_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_gro_enable_result,
+ cmd_keyword, "port");
+cmdline_parse_token_num_t cmd_gro_enable_pid =
+ TOKEN_NUM_INITIALIZER(struct cmd_gro_enable_result,
+ cmd_pid, UINT16);
+cmdline_parse_token_string_t cmd_gro_enable_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_gro_enable_result,
+ cmd_keyword, "gro");
+cmdline_parse_token_string_t cmd_gro_enable_onoff =
+ TOKEN_STRING_INITIALIZER(struct cmd_gro_enable_result,
+ cmd_onoff, "on#off");
+
+cmdline_parse_inst_t cmd_gro_enable = {
+ .f = cmd_gro_enable_parsed,
+ .data = NULL,
+ .help_str = "set port <port_id> gro on|off",
+ .tokens = {
+ (void *)&cmd_gro_enable_set,
+ (void *)&cmd_gro_enable_port,
+ (void *)&cmd_gro_enable_pid,
+ (void *)&cmd_gro_enable_keyword,
+ (void *)&cmd_gro_enable_onoff,
+ NULL,
+ },
+};
+
+/* *** DISPLAY GRO CONFIGURATION *** */
+struct cmd_gro_show_result {
+ cmdline_fixed_string_t cmd_show;
+ cmdline_fixed_string_t cmd_port;
+ cmdline_fixed_string_t cmd_keyword;
+ portid_t cmd_pid;
+};
+
+static void
+cmd_gro_show_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_gro_show_result *res;
+
+ res = parsed_result;
+ if (!strcmp(res->cmd_keyword, "gro"))
+ show_gro(res->cmd_pid);
+}
+
+cmdline_parse_token_string_t cmd_gro_show_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_gro_show_result,
+ cmd_show, "show");
+cmdline_parse_token_string_t cmd_gro_show_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_gro_show_result,
+ cmd_port, "port");
+cmdline_parse_token_num_t cmd_gro_show_pid =
+ TOKEN_NUM_INITIALIZER(struct cmd_gro_show_result,
+ cmd_pid, UINT16);
+cmdline_parse_token_string_t cmd_gro_show_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_gro_show_result,
+ cmd_keyword, "gro");
+
+cmdline_parse_inst_t cmd_gro_show = {
+ .f = cmd_gro_show_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> gro",
+ .tokens = {
+ (void *)&cmd_gro_show_show,
+ (void *)&cmd_gro_show_port,
+ (void *)&cmd_gro_show_pid,
+ (void *)&cmd_gro_show_keyword,
+ NULL,
+ },
+};
+
+/* *** SET FLUSH CYCLES FOR GRO *** */
+struct cmd_gro_flush_result {
+ cmdline_fixed_string_t cmd_set;
+ cmdline_fixed_string_t cmd_keyword;
+ cmdline_fixed_string_t cmd_flush;
+ uint8_t cmd_cycles;
+};
+
+static void
+cmd_gro_flush_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_gro_flush_result *res;
+
+ res = parsed_result;
+ if ((!strcmp(res->cmd_keyword, "gro")) &&
+ (!strcmp(res->cmd_flush, "flush")))
+ setup_gro_flush_cycles(res->cmd_cycles);
+}
+
+cmdline_parse_token_string_t cmd_gro_flush_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_gro_flush_result,
+ cmd_set, "set");
+cmdline_parse_token_string_t cmd_gro_flush_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_gro_flush_result,
+ cmd_keyword, "gro");
+cmdline_parse_token_string_t cmd_gro_flush_flush =
+ TOKEN_STRING_INITIALIZER(struct cmd_gro_flush_result,
+ cmd_flush, "flush");
+cmdline_parse_token_num_t cmd_gro_flush_cycles =
+ TOKEN_NUM_INITIALIZER(struct cmd_gro_flush_result,
+ cmd_cycles, UINT8);
+
+cmdline_parse_inst_t cmd_gro_flush = {
+ .f = cmd_gro_flush_parsed,
+ .data = NULL,
+ .help_str = "set gro flush <cycles>",
+ .tokens = {
+ (void *)&cmd_gro_flush_set,
+ (void *)&cmd_gro_flush_keyword,
+ (void *)&cmd_gro_flush_flush,
+ (void *)&cmd_gro_flush_cycles,
+ NULL,
+ },
+};
+
+/* *** ENABLE/DISABLE GSO *** */
+struct cmd_gso_enable_result {
+ cmdline_fixed_string_t cmd_set;
+ cmdline_fixed_string_t cmd_port;
+ cmdline_fixed_string_t cmd_keyword;
+ cmdline_fixed_string_t cmd_mode;
+ portid_t cmd_pid;
+};
+
+static void
+cmd_gso_enable_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_gso_enable_result *res;
+
+ res = parsed_result;
+ if (!strcmp(res->cmd_keyword, "gso"))
+ setup_gso(res->cmd_mode, res->cmd_pid);
+}
+
+cmdline_parse_token_string_t cmd_gso_enable_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_gso_enable_result,
+ cmd_set, "set");
+cmdline_parse_token_string_t cmd_gso_enable_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_gso_enable_result,
+ cmd_port, "port");
+cmdline_parse_token_string_t cmd_gso_enable_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_gso_enable_result,
+ cmd_keyword, "gso");
+cmdline_parse_token_string_t cmd_gso_enable_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_gso_enable_result,
+ cmd_mode, "on#off");
+cmdline_parse_token_num_t cmd_gso_enable_pid =
+ TOKEN_NUM_INITIALIZER(struct cmd_gso_enable_result,
+ cmd_pid, UINT16);
+
+cmdline_parse_inst_t cmd_gso_enable = {
+ .f = cmd_gso_enable_parsed,
+ .data = NULL,
+ .help_str = "set port <port_id> gso on|off",
+ .tokens = {
+ (void *)&cmd_gso_enable_set,
+ (void *)&cmd_gso_enable_port,
+ (void *)&cmd_gso_enable_pid,
+ (void *)&cmd_gso_enable_keyword,
+ (void *)&cmd_gso_enable_mode,
+ NULL,
+ },
+};
+
+/* *** SET MAX PACKET LENGTH FOR GSO SEGMENTS *** */
+struct cmd_gso_size_result {
+ cmdline_fixed_string_t cmd_set;
+ cmdline_fixed_string_t cmd_keyword;
+ cmdline_fixed_string_t cmd_segsz;
+ uint16_t cmd_size;
+};
+
+static void
+cmd_gso_size_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_gso_size_result *res = parsed_result;
+
+ if (test_done == 0) {
+ printf("Before setting GSO segsz, please first"
+ " stop forwarding\n");
+ return;
+ }
+
+ if (!strcmp(res->cmd_keyword, "gso") &&
+ !strcmp(res->cmd_segsz, "segsz")) {
+ if (res->cmd_size < RTE_GSO_SEG_SIZE_MIN)
+ printf("gso_size should be larger than %zu."
+ " Please input a legal value\n",
+ RTE_GSO_SEG_SIZE_MIN);
+ else
+ gso_max_segment_size = res->cmd_size;
+ }
+}
+
+cmdline_parse_token_string_t cmd_gso_size_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_gso_size_result,
+ cmd_set, "set");
+cmdline_parse_token_string_t cmd_gso_size_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_gso_size_result,
+ cmd_keyword, "gso");
+cmdline_parse_token_string_t cmd_gso_size_segsz =
+ TOKEN_STRING_INITIALIZER(struct cmd_gso_size_result,
+ cmd_segsz, "segsz");
+cmdline_parse_token_num_t cmd_gso_size_size =
+ TOKEN_NUM_INITIALIZER(struct cmd_gso_size_result,
+ cmd_size, UINT16);
+
+cmdline_parse_inst_t cmd_gso_size = {
+ .f = cmd_gso_size_parsed,
+ .data = NULL,
+ .help_str = "set gso segsz <length>",
+ .tokens = {
+ (void *)&cmd_gso_size_set,
+ (void *)&cmd_gso_size_keyword,
+ (void *)&cmd_gso_size_segsz,
+ (void *)&cmd_gso_size_size,
+ NULL,
+ },
+};
+
+/* *** SHOW GSO CONFIGURATION *** */
+struct cmd_gso_show_result {
+ cmdline_fixed_string_t cmd_show;
+ cmdline_fixed_string_t cmd_port;
+ cmdline_fixed_string_t cmd_keyword;
+ portid_t cmd_pid;
+};
+
+static void
+cmd_gso_show_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_gso_show_result *res = parsed_result;
+
+ if (!rte_eth_dev_is_valid_port(res->cmd_pid)) {
+ printf("invalid port id %u\n", res->cmd_pid);
+ return;
+ }
+ if (!strcmp(res->cmd_keyword, "gso")) {
+ if (gso_ports[res->cmd_pid].enable) {
+ printf("Max GSO'd packet size: %uB\n"
+ "Supported GSO types: TCP/IPv4, "
+ "UDP/IPv4, VxLAN with inner "
+ "TCP/IPv4 packet, GRE with inner "
+ "TCP/IPv4 packet\n",
+ gso_max_segment_size);
+ } else
+ printf("GSO is not enabled on Port %u\n", res->cmd_pid);
+ }
+}
+
+cmdline_parse_token_string_t cmd_gso_show_show =
+TOKEN_STRING_INITIALIZER(struct cmd_gso_show_result,
+ cmd_show, "show");
+cmdline_parse_token_string_t cmd_gso_show_port =
+TOKEN_STRING_INITIALIZER(struct cmd_gso_show_result,
+ cmd_port, "port");
+cmdline_parse_token_string_t cmd_gso_show_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_gso_show_result,
+ cmd_keyword, "gso");
+cmdline_parse_token_num_t cmd_gso_show_pid =
+ TOKEN_NUM_INITIALIZER(struct cmd_gso_show_result,
+ cmd_pid, UINT16);
+
+cmdline_parse_inst_t cmd_gso_show = {
+ .f = cmd_gso_show_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> gso",
+ .tokens = {
+ (void *)&cmd_gso_show_show,
+ (void *)&cmd_gso_show_port,
+ (void *)&cmd_gso_show_pid,
+ (void *)&cmd_gso_show_keyword,
+ NULL,
+ },
+};
+
+/* *** ENABLE/DISABLE FLUSH ON RX STREAMS *** */
+struct cmd_set_flush_rx {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t flush_rx;
+ cmdline_fixed_string_t mode;
+};
+
+static void
+cmd_set_flush_rx_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_flush_rx *res = parsed_result;
+ no_flush_rx = (uint8_t)((strcmp(res->mode, "on") == 0) ? 0 : 1);
+}
+
+cmdline_parse_token_string_t cmd_setflushrx_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_flush_rx,
+ set, "set");
+cmdline_parse_token_string_t cmd_setflushrx_flush_rx =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_flush_rx,
+ flush_rx, "flush_rx");
+cmdline_parse_token_string_t cmd_setflushrx_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_flush_rx,
+ mode, "on#off");
+
+
+cmdline_parse_inst_t cmd_set_flush_rx = {
+ .f = cmd_set_flush_rx_parsed,
+ .help_str = "set flush_rx on|off: Enable/Disable flush on rx streams",
+ .data = NULL,
+ .tokens = {
+ (void *)&cmd_setflushrx_set,
+ (void *)&cmd_setflushrx_flush_rx,
+ (void *)&cmd_setflushrx_mode,
+ NULL,
+ },
+};
+
+/* *** ENABLE/DISABLE LINK STATUS CHECK *** */
+struct cmd_set_link_check {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t link_check;
+ cmdline_fixed_string_t mode;
+};
+
+static void
+cmd_set_link_check_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_link_check *res = parsed_result;
+ no_link_check = (uint8_t)((strcmp(res->mode, "on") == 0) ? 0 : 1);
+}
+
+cmdline_parse_token_string_t cmd_setlinkcheck_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_link_check,
+ set, "set");
+cmdline_parse_token_string_t cmd_setlinkcheck_link_check =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_link_check,
+ link_check, "link_check");
+cmdline_parse_token_string_t cmd_setlinkcheck_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_link_check,
+ mode, "on#off");
+
+
+cmdline_parse_inst_t cmd_set_link_check = {
+ .f = cmd_set_link_check_parsed,
+ .help_str = "set link_check on|off: Enable/Disable link status check "
+ "when starting/stopping a port",
+ .data = NULL,
+ .tokens = {
+ (void *)&cmd_setlinkcheck_set,
+ (void *)&cmd_setlinkcheck_link_check,
+ (void *)&cmd_setlinkcheck_mode,
+ NULL,
+ },
+};
+
+/* *** SET NIC BYPASS MODE *** */
+struct cmd_set_bypass_mode_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t bypass;
+ cmdline_fixed_string_t mode;
+ cmdline_fixed_string_t value;
+ portid_t port_id;
+};
+
+static void
+cmd_set_bypass_mode_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_bypass_mode_result *res = parsed_result;
+ portid_t port_id = res->port_id;
+ int32_t rc = -EINVAL;
+
+#if defined RTE_LIBRTE_IXGBE_PMD && defined RTE_LIBRTE_IXGBE_BYPASS
+ uint32_t bypass_mode = RTE_PMD_IXGBE_BYPASS_MODE_NORMAL;
+
+ if (!strcmp(res->value, "bypass"))
+ bypass_mode = RTE_PMD_IXGBE_BYPASS_MODE_BYPASS;
+ else if (!strcmp(res->value, "isolate"))
+ bypass_mode = RTE_PMD_IXGBE_BYPASS_MODE_ISOLATE;
+ else
+ bypass_mode = RTE_PMD_IXGBE_BYPASS_MODE_NORMAL;
+
+ /* Set the bypass mode for the relevant port. */
+ rc = rte_pmd_ixgbe_bypass_state_set(port_id, &bypass_mode);
+#endif
+ if (rc != 0)
+ printf("\t Failed to set bypass mode for port = %d.\n", port_id);
+}
+
+cmdline_parse_token_string_t cmd_setbypass_mode_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bypass_mode_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_setbypass_mode_bypass =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bypass_mode_result,
+ bypass, "bypass");
+cmdline_parse_token_string_t cmd_setbypass_mode_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bypass_mode_result,
+ mode, "mode");
+cmdline_parse_token_string_t cmd_setbypass_mode_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bypass_mode_result,
+ value, "normal#bypass#isolate");
+cmdline_parse_token_num_t cmd_setbypass_mode_port =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_bypass_mode_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_set_bypass_mode = {
+ .f = cmd_set_bypass_mode_parsed,
+ .help_str = "set bypass mode normal|bypass|isolate <port_id>: "
+ "Set the NIC bypass mode for port_id",
+ .data = NULL,
+ .tokens = {
+ (void *)&cmd_setbypass_mode_set,
+ (void *)&cmd_setbypass_mode_bypass,
+ (void *)&cmd_setbypass_mode_mode,
+ (void *)&cmd_setbypass_mode_value,
+ (void *)&cmd_setbypass_mode_port,
+ NULL,
+ },
+};
+
+/* *** SET NIC BYPASS EVENT *** */
+struct cmd_set_bypass_event_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t bypass;
+ cmdline_fixed_string_t event;
+ cmdline_fixed_string_t event_value;
+ cmdline_fixed_string_t mode;
+ cmdline_fixed_string_t mode_value;
+ portid_t port_id;
+};
+
+static void
+cmd_set_bypass_event_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ int32_t rc = -EINVAL;
+ struct cmd_set_bypass_event_result *res = parsed_result;
+ portid_t port_id = res->port_id;
+
+#if defined RTE_LIBRTE_IXGBE_PMD && defined RTE_LIBRTE_IXGBE_BYPASS
+ uint32_t bypass_event = RTE_PMD_IXGBE_BYPASS_EVENT_NONE;
+ uint32_t bypass_mode = RTE_PMD_IXGBE_BYPASS_MODE_NORMAL;
+
+ if (!strcmp(res->event_value, "timeout"))
+ bypass_event = RTE_PMD_IXGBE_BYPASS_EVENT_TIMEOUT;
+ else if (!strcmp(res->event_value, "os_on"))
+ bypass_event = RTE_PMD_IXGBE_BYPASS_EVENT_OS_ON;
+ else if (!strcmp(res->event_value, "os_off"))
+ bypass_event = RTE_PMD_IXGBE_BYPASS_EVENT_OS_OFF;
+ else if (!strcmp(res->event_value, "power_on"))
+ bypass_event = RTE_PMD_IXGBE_BYPASS_EVENT_POWER_ON;
+ else if (!strcmp(res->event_value, "power_off"))
+ bypass_event = RTE_PMD_IXGBE_BYPASS_EVENT_POWER_OFF;
+ else
+ bypass_event = RTE_PMD_IXGBE_BYPASS_EVENT_NONE;
+
+ if (!strcmp(res->mode_value, "bypass"))
+ bypass_mode = RTE_PMD_IXGBE_BYPASS_MODE_BYPASS;
+ else if (!strcmp(res->mode_value, "isolate"))
+ bypass_mode = RTE_PMD_IXGBE_BYPASS_MODE_ISOLATE;
+ else
+ bypass_mode = RTE_PMD_IXGBE_BYPASS_MODE_NORMAL;
+
+ /* Set the watchdog timeout. */
+ if (bypass_event == RTE_PMD_IXGBE_BYPASS_EVENT_TIMEOUT) {
+
+ rc = -EINVAL;
+ if (RTE_PMD_IXGBE_BYPASS_TMT_VALID(bypass_timeout)) {
+ rc = rte_pmd_ixgbe_bypass_wd_timeout_store(port_id,
+ bypass_timeout);
+ }
+ if (rc != 0) {
+ printf("Failed to set timeout value %u "
+ "for port %d, errto code: %d.\n",
+ bypass_timeout, port_id, rc);
+ }
+ }
+
+ /* Set the bypass event to transition to bypass mode. */
+ rc = rte_pmd_ixgbe_bypass_event_store(port_id, bypass_event,
+ bypass_mode);
+#endif
+
+ if (rc != 0)
+ printf("\t Failed to set bypass event for port = %d.\n",
+ port_id);
+}
+
+cmdline_parse_token_string_t cmd_setbypass_event_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bypass_event_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_setbypass_event_bypass =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bypass_event_result,
+ bypass, "bypass");
+cmdline_parse_token_string_t cmd_setbypass_event_event =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bypass_event_result,
+ event, "event");
+cmdline_parse_token_string_t cmd_setbypass_event_event_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bypass_event_result,
+ event_value, "none#timeout#os_off#os_on#power_on#power_off");
+cmdline_parse_token_string_t cmd_setbypass_event_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bypass_event_result,
+ mode, "mode");
+cmdline_parse_token_string_t cmd_setbypass_event_mode_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bypass_event_result,
+ mode_value, "normal#bypass#isolate");
+cmdline_parse_token_num_t cmd_setbypass_event_port =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_bypass_event_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_set_bypass_event = {
+ .f = cmd_set_bypass_event_parsed,
+ .help_str = "set bypass event none|timeout|os_on|os_off|power_on|"
+ "power_off mode normal|bypass|isolate <port_id>: "
+ "Set the NIC bypass event mode for port_id",
+ .data = NULL,
+ .tokens = {
+ (void *)&cmd_setbypass_event_set,
+ (void *)&cmd_setbypass_event_bypass,
+ (void *)&cmd_setbypass_event_event,
+ (void *)&cmd_setbypass_event_event_value,
+ (void *)&cmd_setbypass_event_mode,
+ (void *)&cmd_setbypass_event_mode_value,
+ (void *)&cmd_setbypass_event_port,
+ NULL,
+ },
+};
+
+
+/* *** SET NIC BYPASS TIMEOUT *** */
+struct cmd_set_bypass_timeout_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t bypass;
+ cmdline_fixed_string_t timeout;
+ cmdline_fixed_string_t value;
+};
+
+static void
+cmd_set_bypass_timeout_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ __rte_unused struct cmd_set_bypass_timeout_result *res = parsed_result;
+
+#if defined RTE_LIBRTE_IXGBE_PMD && defined RTE_LIBRTE_IXGBE_BYPASS
+ if (!strcmp(res->value, "1.5"))
+ bypass_timeout = RTE_PMD_IXGBE_BYPASS_TMT_1_5_SEC;
+ else if (!strcmp(res->value, "2"))
+ bypass_timeout = RTE_PMD_IXGBE_BYPASS_TMT_2_SEC;
+ else if (!strcmp(res->value, "3"))
+ bypass_timeout = RTE_PMD_IXGBE_BYPASS_TMT_3_SEC;
+ else if (!strcmp(res->value, "4"))
+ bypass_timeout = RTE_PMD_IXGBE_BYPASS_TMT_4_SEC;
+ else if (!strcmp(res->value, "8"))
+ bypass_timeout = RTE_PMD_IXGBE_BYPASS_TMT_8_SEC;
+ else if (!strcmp(res->value, "16"))
+ bypass_timeout = RTE_PMD_IXGBE_BYPASS_TMT_16_SEC;
+ else if (!strcmp(res->value, "32"))
+ bypass_timeout = RTE_PMD_IXGBE_BYPASS_TMT_32_SEC;
+ else
+ bypass_timeout = RTE_PMD_IXGBE_BYPASS_TMT_OFF;
+#endif
+}
+
+cmdline_parse_token_string_t cmd_setbypass_timeout_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bypass_timeout_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_setbypass_timeout_bypass =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bypass_timeout_result,
+ bypass, "bypass");
+cmdline_parse_token_string_t cmd_setbypass_timeout_timeout =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bypass_timeout_result,
+ timeout, "timeout");
+cmdline_parse_token_string_t cmd_setbypass_timeout_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bypass_timeout_result,
+ value, "0#1.5#2#3#4#8#16#32");
+
+cmdline_parse_inst_t cmd_set_bypass_timeout = {
+ .f = cmd_set_bypass_timeout_parsed,
+ .help_str = "set bypass timeout 0|1.5|2|3|4|8|16|32: "
+ "Set the NIC bypass watchdog timeout in seconds",
+ .data = NULL,
+ .tokens = {
+ (void *)&cmd_setbypass_timeout_set,
+ (void *)&cmd_setbypass_timeout_bypass,
+ (void *)&cmd_setbypass_timeout_timeout,
+ (void *)&cmd_setbypass_timeout_value,
+ NULL,
+ },
+};
+
+/* *** SHOW NIC BYPASS MODE *** */
+struct cmd_show_bypass_config_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t bypass;
+ cmdline_fixed_string_t config;
+ portid_t port_id;
+};
+
+static void
+cmd_show_bypass_config_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_bypass_config_result *res = parsed_result;
+ portid_t port_id = res->port_id;
+ int rc = -EINVAL;
+#if defined RTE_LIBRTE_IXGBE_PMD && defined RTE_LIBRTE_IXGBE_BYPASS
+ uint32_t event_mode;
+ uint32_t bypass_mode;
+ uint32_t timeout = bypass_timeout;
+ unsigned int i;
+
+ static const char * const timeouts[RTE_PMD_IXGBE_BYPASS_TMT_NUM] =
+ {"off", "1.5", "2", "3", "4", "8", "16", "32"};
+ static const char * const modes[RTE_PMD_IXGBE_BYPASS_MODE_NUM] =
+ {"UNKNOWN", "normal", "bypass", "isolate"};
+ static const char * const events[RTE_PMD_IXGBE_BYPASS_EVENT_NUM] = {
+ "NONE",
+ "OS/board on",
+ "power supply on",
+ "OS/board off",
+ "power supply off",
+ "timeout"};
+
+ /* Display the bypass mode.*/
+ if (rte_pmd_ixgbe_bypass_state_show(port_id, &bypass_mode) != 0) {
+ printf("\tFailed to get bypass mode for port = %d\n", port_id);
+ return;
+ }
+ else {
+ if (!RTE_PMD_IXGBE_BYPASS_MODE_VALID(bypass_mode))
+ bypass_mode = RTE_PMD_IXGBE_BYPASS_MODE_NONE;
+
+ printf("\tbypass mode = %s\n", modes[bypass_mode]);
+ }
+
+ /* Display the bypass timeout.*/
+ if (!RTE_PMD_IXGBE_BYPASS_TMT_VALID(timeout))
+ timeout = RTE_PMD_IXGBE_BYPASS_TMT_OFF;
+
+ printf("\tbypass timeout = %s\n", timeouts[timeout]);
+
+ /* Display the bypass events and associated modes. */
+ for (i = RTE_PMD_IXGBE_BYPASS_EVENT_START; i < RTE_DIM(events); i++) {
+
+ if (rte_pmd_ixgbe_bypass_event_show(port_id, i, &event_mode)) {
+ printf("\tFailed to get bypass mode for event = %s\n",
+ events[i]);
+ } else {
+ if (!RTE_PMD_IXGBE_BYPASS_MODE_VALID(event_mode))
+ event_mode = RTE_PMD_IXGBE_BYPASS_MODE_NONE;
+
+ printf("\tbypass event: %-16s = %s\n", events[i],
+ modes[event_mode]);
+ }
+ }
+#endif
+ if (rc != 0)
+ printf("\tFailed to get bypass configuration for port = %d\n",
+ port_id);
+}
+
+cmdline_parse_token_string_t cmd_showbypass_config_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_bypass_config_result,
+ show, "show");
+cmdline_parse_token_string_t cmd_showbypass_config_bypass =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_bypass_config_result,
+ bypass, "bypass");
+cmdline_parse_token_string_t cmd_showbypass_config_config =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_bypass_config_result,
+ config, "config");
+cmdline_parse_token_num_t cmd_showbypass_config_port =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_bypass_config_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_show_bypass_config = {
+ .f = cmd_show_bypass_config_parsed,
+ .help_str = "show bypass config <port_id>: "
+ "Show the NIC bypass config for port_id",
+ .data = NULL,
+ .tokens = {
+ (void *)&cmd_showbypass_config_show,
+ (void *)&cmd_showbypass_config_bypass,
+ (void *)&cmd_showbypass_config_config,
+ (void *)&cmd_showbypass_config_port,
+ NULL,
+ },
+};
+
+#ifdef RTE_LIBRTE_PMD_BOND
+/* *** SET BONDING MODE *** */
+struct cmd_set_bonding_mode_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t bonding;
+ cmdline_fixed_string_t mode;
+ uint8_t value;
+ portid_t port_id;
+};
+
+static void cmd_set_bonding_mode_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_bonding_mode_result *res = parsed_result;
+ portid_t port_id = res->port_id;
+
+ /* Set the bonding mode for the relevant port. */
+ if (0 != rte_eth_bond_mode_set(port_id, res->value))
+ printf("\t Failed to set bonding mode for port = %d.\n", port_id);
+}
+
+cmdline_parse_token_string_t cmd_setbonding_mode_set =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_mode_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_setbonding_mode_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_mode_result,
+ bonding, "bonding");
+cmdline_parse_token_string_t cmd_setbonding_mode_mode =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_mode_result,
+ mode, "mode");
+cmdline_parse_token_num_t cmd_setbonding_mode_value =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_mode_result,
+ value, UINT8);
+cmdline_parse_token_num_t cmd_setbonding_mode_port =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_mode_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_set_bonding_mode = {
+ .f = cmd_set_bonding_mode_parsed,
+ .help_str = "set bonding mode <mode_value> <port_id>: "
+ "Set the bonding mode for port_id",
+ .data = NULL,
+ .tokens = {
+ (void *) &cmd_setbonding_mode_set,
+ (void *) &cmd_setbonding_mode_bonding,
+ (void *) &cmd_setbonding_mode_mode,
+ (void *) &cmd_setbonding_mode_value,
+ (void *) &cmd_setbonding_mode_port,
+ NULL
+ }
+};
+
+/* *** SET BONDING SLOW_QUEUE SW/HW *** */
+struct cmd_set_bonding_lacp_dedicated_queues_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t bonding;
+ cmdline_fixed_string_t lacp;
+ cmdline_fixed_string_t dedicated_queues;
+ portid_t port_id;
+ cmdline_fixed_string_t mode;
+};
+
+static void cmd_set_bonding_lacp_dedicated_queues_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_bonding_lacp_dedicated_queues_result *res = parsed_result;
+ portid_t port_id = res->port_id;
+ struct rte_port *port;
+
+ port = &ports[port_id];
+
+ /** Check if the port is not started **/
+ if (port->port_status != RTE_PORT_STOPPED) {
+ printf("Please stop port %d first\n", port_id);
+ return;
+ }
+
+ if (!strcmp(res->mode, "enable")) {
+ if (rte_eth_bond_8023ad_dedicated_queues_enable(port_id) == 0)
+ printf("Dedicate queues for LACP control packets"
+ " enabled\n");
+ else
+ printf("Enabling dedicate queues for LACP control "
+ "packets on port %d failed\n", port_id);
+ } else if (!strcmp(res->mode, "disable")) {
+ if (rte_eth_bond_8023ad_dedicated_queues_disable(port_id) == 0)
+ printf("Dedicated queues for LACP control packets "
+ "disabled\n");
+ else
+ printf("Disabling dedicated queues for LACP control "
+ "traffic on port %d failed\n", port_id);
+ }
+}
+
+cmdline_parse_token_string_t cmd_setbonding_lacp_dedicated_queues_set =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_lacp_dedicated_queues_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_setbonding_lacp_dedicated_queues_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_lacp_dedicated_queues_result,
+ bonding, "bonding");
+cmdline_parse_token_string_t cmd_setbonding_lacp_dedicated_queues_lacp =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_lacp_dedicated_queues_result,
+ lacp, "lacp");
+cmdline_parse_token_string_t cmd_setbonding_lacp_dedicated_queues_dedicated_queues =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_lacp_dedicated_queues_result,
+ dedicated_queues, "dedicated_queues");
+cmdline_parse_token_num_t cmd_setbonding_lacp_dedicated_queues_port_id =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_lacp_dedicated_queues_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_setbonding_lacp_dedicated_queues_mode =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_lacp_dedicated_queues_result,
+ mode, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_lacp_dedicated_queues = {
+ .f = cmd_set_bonding_lacp_dedicated_queues_parsed,
+ .help_str = "set bonding lacp dedicated_queues <port_id> "
+ "enable|disable: "
+ "Enable/disable dedicated queues for LACP control traffic for port_id",
+ .data = NULL,
+ .tokens = {
+ (void *)&cmd_setbonding_lacp_dedicated_queues_set,
+ (void *)&cmd_setbonding_lacp_dedicated_queues_bonding,
+ (void *)&cmd_setbonding_lacp_dedicated_queues_lacp,
+ (void *)&cmd_setbonding_lacp_dedicated_queues_dedicated_queues,
+ (void *)&cmd_setbonding_lacp_dedicated_queues_port_id,
+ (void *)&cmd_setbonding_lacp_dedicated_queues_mode,
+ NULL
+ }
+};
+
+/* *** SET BALANCE XMIT POLICY *** */
+struct cmd_set_bonding_balance_xmit_policy_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t bonding;
+ cmdline_fixed_string_t balance_xmit_policy;
+ portid_t port_id;
+ cmdline_fixed_string_t policy;
+};
+
+static void cmd_set_bonding_balance_xmit_policy_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_bonding_balance_xmit_policy_result *res = parsed_result;
+ portid_t port_id = res->port_id;
+ uint8_t policy;
+
+ if (!strcmp(res->policy, "l2")) {
+ policy = BALANCE_XMIT_POLICY_LAYER2;
+ } else if (!strcmp(res->policy, "l23")) {
+ policy = BALANCE_XMIT_POLICY_LAYER23;
+ } else if (!strcmp(res->policy, "l34")) {
+ policy = BALANCE_XMIT_POLICY_LAYER34;
+ } else {
+ printf("\t Invalid xmit policy selection");
+ return;
+ }
+
+ /* Set the bonding mode for the relevant port. */
+ if (0 != rte_eth_bond_xmit_policy_set(port_id, policy)) {
+ printf("\t Failed to set bonding balance xmit policy for port = %d.\n",
+ port_id);
+ }
+}
+
+cmdline_parse_token_string_t cmd_setbonding_balance_xmit_policy_set =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_setbonding_balance_xmit_policy_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+ bonding, "bonding");
+cmdline_parse_token_string_t cmd_setbonding_balance_xmit_policy_balance_xmit_policy =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+ balance_xmit_policy, "balance_xmit_policy");
+cmdline_parse_token_num_t cmd_setbonding_balance_xmit_policy_port =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_setbonding_balance_xmit_policy_policy =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result,
+ policy, "l2#l23#l34");
+
+cmdline_parse_inst_t cmd_set_balance_xmit_policy = {
+ .f = cmd_set_bonding_balance_xmit_policy_parsed,
+ .help_str = "set bonding balance_xmit_policy <port_id> "
+ "l2|l23|l34: "
+ "Set the bonding balance_xmit_policy for port_id",
+ .data = NULL,
+ .tokens = {
+ (void *)&cmd_setbonding_balance_xmit_policy_set,
+ (void *)&cmd_setbonding_balance_xmit_policy_bonding,
+ (void *)&cmd_setbonding_balance_xmit_policy_balance_xmit_policy,
+ (void *)&cmd_setbonding_balance_xmit_policy_port,
+ (void *)&cmd_setbonding_balance_xmit_policy_policy,
+ NULL
+ }
+};
+
+/* *** SHOW NIC BONDING CONFIGURATION *** */
+struct cmd_show_bonding_config_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t bonding;
+ cmdline_fixed_string_t config;
+ portid_t port_id;
+};
+
+static void cmd_show_bonding_config_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_bonding_config_result *res = parsed_result;
+ int bonding_mode, agg_mode;
+ portid_t slaves[RTE_MAX_ETHPORTS];
+ int num_slaves, num_active_slaves;
+ int primary_id;
+ int i;
+ portid_t port_id = res->port_id;
+
+ /* Display the bonding mode.*/
+ bonding_mode = rte_eth_bond_mode_get(port_id);
+ if (bonding_mode < 0) {
+ printf("\tFailed to get bonding mode for port = %d\n", port_id);
+ return;
+ } else
+ printf("\tBonding mode: %d\n", bonding_mode);
+
+ if (bonding_mode == BONDING_MODE_BALANCE) {
+ int balance_xmit_policy;
+
+ balance_xmit_policy = rte_eth_bond_xmit_policy_get(port_id);
+ if (balance_xmit_policy < 0) {
+ printf("\tFailed to get balance xmit policy for port = %d\n",
+ port_id);
+ return;
+ } else {
+ printf("\tBalance Xmit Policy: ");
+
+ switch (balance_xmit_policy) {
+ case BALANCE_XMIT_POLICY_LAYER2:
+ printf("BALANCE_XMIT_POLICY_LAYER2");
+ break;
+ case BALANCE_XMIT_POLICY_LAYER23:
+ printf("BALANCE_XMIT_POLICY_LAYER23");
+ break;
+ case BALANCE_XMIT_POLICY_LAYER34:
+ printf("BALANCE_XMIT_POLICY_LAYER34");
+ break;
+ }
+ printf("\n");
+ }
+ }
+
+ if (bonding_mode == BONDING_MODE_8023AD) {
+ agg_mode = rte_eth_bond_8023ad_agg_selection_get(port_id);
+ printf("\tIEEE802.3AD Aggregator Mode: ");
+ switch (agg_mode) {
+ case AGG_BANDWIDTH:
+ printf("bandwidth");
+ break;
+ case AGG_STABLE:
+ printf("stable");
+ break;
+ case AGG_COUNT:
+ printf("count");
+ break;
+ }
+ printf("\n");
+ }
+
+ num_slaves = rte_eth_bond_slaves_get(port_id, slaves, RTE_MAX_ETHPORTS);
+
+ if (num_slaves < 0) {
+ printf("\tFailed to get slave list for port = %d\n", port_id);
+ return;
+ }
+ if (num_slaves > 0) {
+ printf("\tSlaves (%d): [", num_slaves);
+ for (i = 0; i < num_slaves - 1; i++)
+ printf("%d ", slaves[i]);
+
+ printf("%d]\n", slaves[num_slaves - 1]);
+ } else {
+ printf("\tSlaves: []\n");
+
+ }
+
+ num_active_slaves = rte_eth_bond_active_slaves_get(port_id, slaves,
+ RTE_MAX_ETHPORTS);
+
+ if (num_active_slaves < 0) {
+ printf("\tFailed to get active slave list for port = %d\n", port_id);
+ return;
+ }
+ if (num_active_slaves > 0) {
+ printf("\tActive Slaves (%d): [", num_active_slaves);
+ for (i = 0; i < num_active_slaves - 1; i++)
+ printf("%d ", slaves[i]);
+
+ printf("%d]\n", slaves[num_active_slaves - 1]);
+
+ } else {
+ printf("\tActive Slaves: []\n");
+
+ }
+
+ primary_id = rte_eth_bond_primary_get(port_id);
+ if (primary_id < 0) {
+ printf("\tFailed to get primary slave for port = %d\n", port_id);
+ return;
+ } else
+ printf("\tPrimary: [%d]\n", primary_id);
+
+}
+
+cmdline_parse_token_string_t cmd_showbonding_config_show =
+TOKEN_STRING_INITIALIZER(struct cmd_show_bonding_config_result,
+ show, "show");
+cmdline_parse_token_string_t cmd_showbonding_config_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_show_bonding_config_result,
+ bonding, "bonding");
+cmdline_parse_token_string_t cmd_showbonding_config_config =
+TOKEN_STRING_INITIALIZER(struct cmd_show_bonding_config_result,
+ config, "config");
+cmdline_parse_token_num_t cmd_showbonding_config_port =
+TOKEN_NUM_INITIALIZER(struct cmd_show_bonding_config_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_show_bonding_config = {
+ .f = cmd_show_bonding_config_parsed,
+ .help_str = "show bonding config <port_id>: "
+ "Show the bonding config for port_id",
+ .data = NULL,
+ .tokens = {
+ (void *)&cmd_showbonding_config_show,
+ (void *)&cmd_showbonding_config_bonding,
+ (void *)&cmd_showbonding_config_config,
+ (void *)&cmd_showbonding_config_port,
+ NULL
+ }
+};
+
+/* *** SET BONDING PRIMARY *** */
+struct cmd_set_bonding_primary_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t bonding;
+ cmdline_fixed_string_t primary;
+ portid_t slave_id;
+ portid_t port_id;
+};
+
+static void cmd_set_bonding_primary_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_bonding_primary_result *res = parsed_result;
+ portid_t master_port_id = res->port_id;
+ portid_t slave_port_id = res->slave_id;
+
+ /* Set the primary slave for a bonded device. */
+ if (0 != rte_eth_bond_primary_set(master_port_id, slave_port_id)) {
+ printf("\t Failed to set primary slave for port = %d.\n",
+ master_port_id);
+ return;
+ }
+ init_port_config();
+}
+
+cmdline_parse_token_string_t cmd_setbonding_primary_set =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_primary_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_setbonding_primary_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_primary_result,
+ bonding, "bonding");
+cmdline_parse_token_string_t cmd_setbonding_primary_primary =
+TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_primary_result,
+ primary, "primary");
+cmdline_parse_token_num_t cmd_setbonding_primary_slave =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_primary_result,
+ slave_id, UINT16);
+cmdline_parse_token_num_t cmd_setbonding_primary_port =
+TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_primary_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_set_bonding_primary = {
+ .f = cmd_set_bonding_primary_parsed,
+ .help_str = "set bonding primary <slave_id> <port_id>: "
+ "Set the primary slave for port_id",
+ .data = NULL,
+ .tokens = {
+ (void *)&cmd_setbonding_primary_set,
+ (void *)&cmd_setbonding_primary_bonding,
+ (void *)&cmd_setbonding_primary_primary,
+ (void *)&cmd_setbonding_primary_slave,
+ (void *)&cmd_setbonding_primary_port,
+ NULL
+ }
+};
+
+/* *** ADD SLAVE *** */
+struct cmd_add_bonding_slave_result {
+ cmdline_fixed_string_t add;
+ cmdline_fixed_string_t bonding;
+ cmdline_fixed_string_t slave;
+ portid_t slave_id;
+ portid_t port_id;
+};
+
+static void cmd_add_bonding_slave_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_add_bonding_slave_result *res = parsed_result;
+ portid_t master_port_id = res->port_id;
+ portid_t slave_port_id = res->slave_id;
+
+ /* add the slave for a bonded device. */
+ if (0 != rte_eth_bond_slave_add(master_port_id, slave_port_id)) {
+ printf("\t Failed to add slave %d to master port = %d.\n",
+ slave_port_id, master_port_id);
+ return;
+ }
+ init_port_config();
+ set_port_slave_flag(slave_port_id);
+}
+
+cmdline_parse_token_string_t cmd_addbonding_slave_add =
+TOKEN_STRING_INITIALIZER(struct cmd_add_bonding_slave_result,
+ add, "add");
+cmdline_parse_token_string_t cmd_addbonding_slave_bonding =
+TOKEN_STRING_INITIALIZER(struct cmd_add_bonding_slave_result,
+ bonding, "bonding");
+cmdline_parse_token_string_t cmd_addbonding_slave_slave =
+TOKEN_STRING_INITIALIZER(struct cmd_add_bonding_slave_result,
+ slave, "slave");
+cmdline_parse_token_num_t cmd_addbonding_slave_slaveid =
+TOKEN_NUM_INITIALIZER(struct cmd_add_bonding_slave_result,
+ slave_id, UINT16);
+cmdline_parse_token_num_t cmd_addbonding_slave_port =
+TOKEN_NUM_INITIALIZER(struct cmd_add_bonding_slave_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_add_bonding_slave = {
+ .f = cmd_add_bonding_slave_parsed,
+ .help_str = "add bonding slave <slave_id> <port_id>: "
+ "Add a slave device to a bonded device",
+ .data = NULL,
+ .tokens = {
+ (void *)&cmd_addbonding_slave_add,
+ (void *)&cmd_addbonding_slave_bonding,
+ (void *)&cmd_addbonding_slave_slave,
+ (void *)&cmd_addbonding_slave_slaveid,
+ (void *)&cmd_addbonding_slave_port,
+ NULL
+ }
+};
+
+/* *** REMOVE SLAVE *** */
+struct cmd_remove_bonding_slave_result {
+ cmdline_fixed_string_t remove;
+ cmdline_fixed_string_t bonding;
+ cmdline_fixed_string_t slave;
+ portid_t slave_id;
+ portid_t port_id;
+};
+
+static void cmd_remove_bonding_slave_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_remove_bonding_slave_result *res = parsed_result;
+ portid_t master_port_id = res->port_id;
+ portid_t slave_port_id = res->slave_id;
+
+ /* remove the slave from a bonded device. */
+ if (0 != rte_eth_bond_slave_remove(master_port_id, slave_port_id)) {
+ printf("\t Failed to remove slave %d from master port = %d.\n",
+ slave_port_id, master_port_id);
+ return;
+ }
+ init_port_config();
+ clear_port_slave_flag(slave_port_id);
+}
+
+cmdline_parse_token_string_t cmd_removebonding_slave_remove =
+ TOKEN_STRING_INITIALIZER(struct cmd_remove_bonding_slave_result,
+ remove, "remove");
+cmdline_parse_token_string_t cmd_removebonding_slave_bonding =
+ TOKEN_STRING_INITIALIZER(struct cmd_remove_bonding_slave_result,
+ bonding, "bonding");
+cmdline_parse_token_string_t cmd_removebonding_slave_slave =
+ TOKEN_STRING_INITIALIZER(struct cmd_remove_bonding_slave_result,
+ slave, "slave");
+cmdline_parse_token_num_t cmd_removebonding_slave_slaveid =
+ TOKEN_NUM_INITIALIZER(struct cmd_remove_bonding_slave_result,
+ slave_id, UINT16);
+cmdline_parse_token_num_t cmd_removebonding_slave_port =
+ TOKEN_NUM_INITIALIZER(struct cmd_remove_bonding_slave_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_remove_bonding_slave = {
+ .f = cmd_remove_bonding_slave_parsed,
+ .help_str = "remove bonding slave <slave_id> <port_id>: "
+ "Remove a slave device from a bonded device",
+ .data = NULL,
+ .tokens = {
+ (void *)&cmd_removebonding_slave_remove,
+ (void *)&cmd_removebonding_slave_bonding,
+ (void *)&cmd_removebonding_slave_slave,
+ (void *)&cmd_removebonding_slave_slaveid,
+ (void *)&cmd_removebonding_slave_port,
+ NULL
+ }
+};
+
+/* *** CREATE BONDED DEVICE *** */
+struct cmd_create_bonded_device_result {
+ cmdline_fixed_string_t create;
+ cmdline_fixed_string_t bonded;
+ cmdline_fixed_string_t device;
+ uint8_t mode;
+ uint8_t socket;
+};
+
+static int bond_dev_num = 0;
+
+static void cmd_create_bonded_device_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_create_bonded_device_result *res = parsed_result;
+ char ethdev_name[RTE_ETH_NAME_MAX_LEN];
+ int port_id;
+ int ret;
+
+ if (test_done == 0) {
+ printf("Please stop forwarding first\n");
+ return;
+ }
+
+ snprintf(ethdev_name, RTE_ETH_NAME_MAX_LEN, "net_bonding_testpmd_%d",
+ bond_dev_num++);
+
+ /* Create a new bonded device. */
+ port_id = rte_eth_bond_create(ethdev_name, res->mode, res->socket);
+ if (port_id < 0) {
+ printf("\t Failed to create bonded device.\n");
+ return;
+ } else {
+ printf("Created new bonded device %s on (port %d).\n", ethdev_name,
+ port_id);
+
+ /* Update number of ports */
+ nb_ports = rte_eth_dev_count_avail();
+ reconfig(port_id, res->socket);
+ ret = rte_eth_promiscuous_enable(port_id);
+ if (ret != 0)
+ printf("Failed to enable promiscuous mode for port %u: %s - ignore\n",
+ port_id, rte_strerror(-ret));
+
+ ports[port_id].need_setup = 0;
+ ports[port_id].port_status = RTE_PORT_STOPPED;
+ }
+
+}
+
+cmdline_parse_token_string_t cmd_createbonded_device_create =
+ TOKEN_STRING_INITIALIZER(struct cmd_create_bonded_device_result,
+ create, "create");
+cmdline_parse_token_string_t cmd_createbonded_device_bonded =
+ TOKEN_STRING_INITIALIZER(struct cmd_create_bonded_device_result,
+ bonded, "bonded");
+cmdline_parse_token_string_t cmd_createbonded_device_device =
+ TOKEN_STRING_INITIALIZER(struct cmd_create_bonded_device_result,
+ device, "device");
+cmdline_parse_token_num_t cmd_createbonded_device_mode =
+ TOKEN_NUM_INITIALIZER(struct cmd_create_bonded_device_result,
+ mode, UINT8);
+cmdline_parse_token_num_t cmd_createbonded_device_socket =
+ TOKEN_NUM_INITIALIZER(struct cmd_create_bonded_device_result,
+ socket, UINT8);
+
+cmdline_parse_inst_t cmd_create_bonded_device = {
+ .f = cmd_create_bonded_device_parsed,
+ .help_str = "create bonded device <mode> <socket>: "
+ "Create a new bonded device with specific bonding mode and socket",
+ .data = NULL,
+ .tokens = {
+ (void *)&cmd_createbonded_device_create,
+ (void *)&cmd_createbonded_device_bonded,
+ (void *)&cmd_createbonded_device_device,
+ (void *)&cmd_createbonded_device_mode,
+ (void *)&cmd_createbonded_device_socket,
+ NULL
+ }
+};
+
+/* *** SET MAC ADDRESS IN BONDED DEVICE *** */
+struct cmd_set_bond_mac_addr_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t bonding;
+ cmdline_fixed_string_t mac_addr;
+ uint16_t port_num;
+ struct rte_ether_addr address;
+};
+
+static void cmd_set_bond_mac_addr_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_bond_mac_addr_result *res = parsed_result;
+ int ret;
+
+ if (port_id_is_invalid(res->port_num, ENABLED_WARN))
+ return;
+
+ ret = rte_eth_bond_mac_address_set(res->port_num, &res->address);
+
+ /* check the return value and print it if is < 0 */
+ if (ret < 0)
+ printf("set_bond_mac_addr error: (%s)\n", strerror(-ret));
+}
+
+cmdline_parse_token_string_t cmd_set_bond_mac_addr_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mac_addr_result, set, "set");
+cmdline_parse_token_string_t cmd_set_bond_mac_addr_bonding =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mac_addr_result, bonding,
+ "bonding");
+cmdline_parse_token_string_t cmd_set_bond_mac_addr_mac =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mac_addr_result, mac_addr,
+ "mac_addr");
+cmdline_parse_token_num_t cmd_set_bond_mac_addr_portnum =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_bond_mac_addr_result,
+ port_num, UINT16);
+cmdline_parse_token_etheraddr_t cmd_set_bond_mac_addr_addr =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_bond_mac_addr_result, address);
+
+cmdline_parse_inst_t cmd_set_bond_mac_addr = {
+ .f = cmd_set_bond_mac_addr_parsed,
+ .data = (void *) 0,
+ .help_str = "set bonding mac_addr <port_id> <mac_addr>",
+ .tokens = {
+ (void *)&cmd_set_bond_mac_addr_set,
+ (void *)&cmd_set_bond_mac_addr_bonding,
+ (void *)&cmd_set_bond_mac_addr_mac,
+ (void *)&cmd_set_bond_mac_addr_portnum,
+ (void *)&cmd_set_bond_mac_addr_addr,
+ NULL
+ }
+};
+
+
+/* *** SET LINK STATUS MONITORING POLLING PERIOD ON BONDED DEVICE *** */
+struct cmd_set_bond_mon_period_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t bonding;
+ cmdline_fixed_string_t mon_period;
+ uint16_t port_num;
+ uint32_t period_ms;
+};
+
+static void cmd_set_bond_mon_period_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_bond_mon_period_result *res = parsed_result;
+ int ret;
+
+ ret = rte_eth_bond_link_monitoring_set(res->port_num, res->period_ms);
+
+ /* check the return value and print it if is < 0 */
+ if (ret < 0)
+ printf("set_bond_mac_addr error: (%s)\n", strerror(-ret));
+}
+
+cmdline_parse_token_string_t cmd_set_bond_mon_period_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mon_period_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_set_bond_mon_period_bonding =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mon_period_result,
+ bonding, "bonding");
+cmdline_parse_token_string_t cmd_set_bond_mon_period_mon_period =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bond_mon_period_result,
+ mon_period, "mon_period");
+cmdline_parse_token_num_t cmd_set_bond_mon_period_portnum =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_bond_mon_period_result,
+ port_num, UINT16);
+cmdline_parse_token_num_t cmd_set_bond_mon_period_period_ms =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_bond_mon_period_result,
+ period_ms, UINT32);
+
+cmdline_parse_inst_t cmd_set_bond_mon_period = {
+ .f = cmd_set_bond_mon_period_parsed,
+ .data = (void *) 0,
+ .help_str = "set bonding mon_period <port_id> <period_ms>",
+ .tokens = {
+ (void *)&cmd_set_bond_mon_period_set,
+ (void *)&cmd_set_bond_mon_period_bonding,
+ (void *)&cmd_set_bond_mon_period_mon_period,
+ (void *)&cmd_set_bond_mon_period_portnum,
+ (void *)&cmd_set_bond_mon_period_period_ms,
+ NULL
+ }
+};
+
+
+
+struct cmd_set_bonding_agg_mode_policy_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t bonding;
+ cmdline_fixed_string_t agg_mode;
+ uint16_t port_num;
+ cmdline_fixed_string_t policy;
+};
+
+
+static void
+cmd_set_bonding_agg_mode(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_bonding_agg_mode_policy_result *res = parsed_result;
+ uint8_t policy = AGG_BANDWIDTH;
+
+ if (!strcmp(res->policy, "bandwidth"))
+ policy = AGG_BANDWIDTH;
+ else if (!strcmp(res->policy, "stable"))
+ policy = AGG_STABLE;
+ else if (!strcmp(res->policy, "count"))
+ policy = AGG_COUNT;
+
+ rte_eth_bond_8023ad_agg_selection_set(res->port_num, policy);
+}
+
+
+cmdline_parse_token_string_t cmd_set_bonding_agg_mode_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_agg_mode_policy_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_set_bonding_agg_mode_bonding =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_agg_mode_policy_result,
+ bonding, "bonding");
+
+cmdline_parse_token_string_t cmd_set_bonding_agg_mode_agg_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_agg_mode_policy_result,
+ agg_mode, "agg_mode");
+
+cmdline_parse_token_num_t cmd_set_bonding_agg_mode_portnum =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_agg_mode_policy_result,
+ port_num, UINT16);
+
+cmdline_parse_token_string_t cmd_set_bonding_agg_mode_policy_string =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_bonding_balance_xmit_policy_result,
+ policy, "stable#bandwidth#count");
+
+cmdline_parse_inst_t cmd_set_bonding_agg_mode_policy = {
+ .f = cmd_set_bonding_agg_mode,
+ .data = (void *) 0,
+ .help_str = "set bonding mode IEEE802.3AD aggregator policy <port_id> <agg_name>",
+ .tokens = {
+ (void *)&cmd_set_bonding_agg_mode_set,
+ (void *)&cmd_set_bonding_agg_mode_bonding,
+ (void *)&cmd_set_bonding_agg_mode_agg_mode,
+ (void *)&cmd_set_bonding_agg_mode_portnum,
+ (void *)&cmd_set_bonding_agg_mode_policy_string,
+ NULL
+ }
+};
+
+
+#endif /* RTE_LIBRTE_PMD_BOND */
+
+/* *** SET FORWARDING MODE *** */
+struct cmd_set_fwd_mode_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t fwd;
+ cmdline_fixed_string_t mode;
+};
+
+static void cmd_set_fwd_mode_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_fwd_mode_result *res = parsed_result;
+
+ retry_enabled = 0;
+ set_pkt_forwarding_mode(res->mode);
+}
+
+cmdline_parse_token_string_t cmd_setfwd_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_mode_result, set, "set");
+cmdline_parse_token_string_t cmd_setfwd_fwd =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_mode_result, fwd, "fwd");
+cmdline_parse_token_string_t cmd_setfwd_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_mode_result, mode,
+ "" /* defined at init */);
+
+cmdline_parse_inst_t cmd_set_fwd_mode = {
+ .f = cmd_set_fwd_mode_parsed,
+ .data = NULL,
+ .help_str = NULL, /* defined at init */
+ .tokens = {
+ (void *)&cmd_setfwd_set,
+ (void *)&cmd_setfwd_fwd,
+ (void *)&cmd_setfwd_mode,
+ NULL,
+ },
+};
+
+static void cmd_set_fwd_mode_init(void)
+{
+ char *modes, *c;
+ static char token[128];
+ static char help[256];
+ cmdline_parse_token_string_t *token_struct;
+
+ modes = list_pkt_forwarding_modes();
+ snprintf(help, sizeof(help), "set fwd %s: "
+ "Set packet forwarding mode", modes);
+ cmd_set_fwd_mode.help_str = help;
+
+ /* string token separator is # */
+ for (c = token; *modes != '\0'; modes++)
+ if (*modes == '|')
+ *c++ = '#';
+ else
+ *c++ = *modes;
+ token_struct = (cmdline_parse_token_string_t*)cmd_set_fwd_mode.tokens[2];
+ token_struct->string_data.str = token;
+}
+
+/* *** SET RETRY FORWARDING MODE *** */
+struct cmd_set_fwd_retry_mode_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t fwd;
+ cmdline_fixed_string_t mode;
+ cmdline_fixed_string_t retry;
+};
+
+static void cmd_set_fwd_retry_mode_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_fwd_retry_mode_result *res = parsed_result;
+
+ retry_enabled = 1;
+ set_pkt_forwarding_mode(res->mode);
+}
+
+cmdline_parse_token_string_t cmd_setfwd_retry_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_retry_mode_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_setfwd_retry_fwd =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_retry_mode_result,
+ fwd, "fwd");
+cmdline_parse_token_string_t cmd_setfwd_retry_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_retry_mode_result,
+ mode,
+ "" /* defined at init */);
+cmdline_parse_token_string_t cmd_setfwd_retry_retry =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_retry_mode_result,
+ retry, "retry");
+
+cmdline_parse_inst_t cmd_set_fwd_retry_mode = {
+ .f = cmd_set_fwd_retry_mode_parsed,
+ .data = NULL,
+ .help_str = NULL, /* defined at init */
+ .tokens = {
+ (void *)&cmd_setfwd_retry_set,
+ (void *)&cmd_setfwd_retry_fwd,
+ (void *)&cmd_setfwd_retry_mode,
+ (void *)&cmd_setfwd_retry_retry,
+ NULL,
+ },
+};
+
+static void cmd_set_fwd_retry_mode_init(void)
+{
+ char *modes, *c;
+ static char token[128];
+ static char help[256];
+ cmdline_parse_token_string_t *token_struct;
+
+ modes = list_pkt_forwarding_retry_modes();
+ snprintf(help, sizeof(help), "set fwd %s retry: "
+ "Set packet forwarding mode with retry", modes);
+ cmd_set_fwd_retry_mode.help_str = help;
+
+ /* string token separator is # */
+ for (c = token; *modes != '\0'; modes++)
+ if (*modes == '|')
+ *c++ = '#';
+ else
+ *c++ = *modes;
+ token_struct = (cmdline_parse_token_string_t *)
+ cmd_set_fwd_retry_mode.tokens[2];
+ token_struct->string_data.str = token;
+}
+
+/* *** SET BURST TX DELAY TIME RETRY NUMBER *** */
+struct cmd_set_burst_tx_retry_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t burst;
+ cmdline_fixed_string_t tx;
+ cmdline_fixed_string_t delay;
+ uint32_t time;
+ cmdline_fixed_string_t retry;
+ uint32_t retry_num;
+};
+
+static void cmd_set_burst_tx_retry_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_burst_tx_retry_result *res = parsed_result;
+
+ if (!strcmp(res->set, "set") && !strcmp(res->burst, "burst")
+ && !strcmp(res->tx, "tx")) {
+ if (!strcmp(res->delay, "delay"))
+ burst_tx_delay_time = res->time;
+ if (!strcmp(res->retry, "retry"))
+ burst_tx_retry_num = res->retry_num;
+ }
+
+}
+
+cmdline_parse_token_string_t cmd_set_burst_tx_retry_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_burst_tx_retry_result, set, "set");
+cmdline_parse_token_string_t cmd_set_burst_tx_retry_burst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_burst_tx_retry_result, burst,
+ "burst");
+cmdline_parse_token_string_t cmd_set_burst_tx_retry_tx =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_burst_tx_retry_result, tx, "tx");
+cmdline_parse_token_string_t cmd_set_burst_tx_retry_delay =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_burst_tx_retry_result, delay, "delay");
+cmdline_parse_token_num_t cmd_set_burst_tx_retry_time =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_burst_tx_retry_result, time, UINT32);
+cmdline_parse_token_string_t cmd_set_burst_tx_retry_retry =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_burst_tx_retry_result, retry, "retry");
+cmdline_parse_token_num_t cmd_set_burst_tx_retry_retry_num =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_burst_tx_retry_result, retry_num, UINT32);
+
+cmdline_parse_inst_t cmd_set_burst_tx_retry = {
+ .f = cmd_set_burst_tx_retry_parsed,
+ .help_str = "set burst tx delay <delay_usec> retry <num_retry>",
+ .tokens = {
+ (void *)&cmd_set_burst_tx_retry_set,
+ (void *)&cmd_set_burst_tx_retry_burst,
+ (void *)&cmd_set_burst_tx_retry_tx,
+ (void *)&cmd_set_burst_tx_retry_delay,
+ (void *)&cmd_set_burst_tx_retry_time,
+ (void *)&cmd_set_burst_tx_retry_retry,
+ (void *)&cmd_set_burst_tx_retry_retry_num,
+ NULL,
+ },
+};
+
+/* *** SET PROMISC MODE *** */
+struct cmd_set_promisc_mode_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t promisc;
+ cmdline_fixed_string_t port_all; /* valid if "allports" argument == 1 */
+ uint16_t port_num; /* valid if "allports" argument == 0 */
+ cmdline_fixed_string_t mode;
+};
+
+static void cmd_set_promisc_mode_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ void *allports)
+{
+ struct cmd_set_promisc_mode_result *res = parsed_result;
+ int enable;
+ portid_t i;
+
+ if (!strcmp(res->mode, "on"))
+ enable = 1;
+ else
+ enable = 0;
+
+ /* all ports */
+ if (allports) {
+ RTE_ETH_FOREACH_DEV(i)
+ eth_set_promisc_mode(i, enable);
+ } else {
+ eth_set_promisc_mode(res->port_num, enable);
+ }
+}
+
+cmdline_parse_token_string_t cmd_setpromisc_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_promisc_mode_result, set, "set");
+cmdline_parse_token_string_t cmd_setpromisc_promisc =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_promisc_mode_result, promisc,
+ "promisc");
+cmdline_parse_token_string_t cmd_setpromisc_portall =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_promisc_mode_result, port_all,
+ "all");
+cmdline_parse_token_num_t cmd_setpromisc_portnum =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_promisc_mode_result, port_num,
+ UINT16);
+cmdline_parse_token_string_t cmd_setpromisc_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_promisc_mode_result, mode,
+ "on#off");
+
+cmdline_parse_inst_t cmd_set_promisc_mode_all = {
+ .f = cmd_set_promisc_mode_parsed,
+ .data = (void *)1,
+ .help_str = "set promisc all on|off: Set promisc mode for all ports",
+ .tokens = {
+ (void *)&cmd_setpromisc_set,
+ (void *)&cmd_setpromisc_promisc,
+ (void *)&cmd_setpromisc_portall,
+ (void *)&cmd_setpromisc_mode,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_promisc_mode_one = {
+ .f = cmd_set_promisc_mode_parsed,
+ .data = (void *)0,
+ .help_str = "set promisc <port_id> on|off: Set promisc mode on port_id",
+ .tokens = {
+ (void *)&cmd_setpromisc_set,
+ (void *)&cmd_setpromisc_promisc,
+ (void *)&cmd_setpromisc_portnum,
+ (void *)&cmd_setpromisc_mode,
+ NULL,
+ },
+};
+
+/* *** SET ALLMULTI MODE *** */
+struct cmd_set_allmulti_mode_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t allmulti;
+ cmdline_fixed_string_t port_all; /* valid if "allports" argument == 1 */
+ uint16_t port_num; /* valid if "allports" argument == 0 */
+ cmdline_fixed_string_t mode;
+};
+
+static void cmd_set_allmulti_mode_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ void *allports)
+{
+ struct cmd_set_allmulti_mode_result *res = parsed_result;
+ int enable;
+ portid_t i;
+
+ if (!strcmp(res->mode, "on"))
+ enable = 1;
+ else
+ enable = 0;
+
+ /* all ports */
+ if (allports) {
+ RTE_ETH_FOREACH_DEV(i) {
+ eth_set_allmulticast_mode(i, enable);
+ }
+ }
+ else {
+ eth_set_allmulticast_mode(res->port_num, enable);
+ }
+}
+
+cmdline_parse_token_string_t cmd_setallmulti_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_allmulti_mode_result, set, "set");
+cmdline_parse_token_string_t cmd_setallmulti_allmulti =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_allmulti_mode_result, allmulti,
+ "allmulti");
+cmdline_parse_token_string_t cmd_setallmulti_portall =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_allmulti_mode_result, port_all,
+ "all");
+cmdline_parse_token_num_t cmd_setallmulti_portnum =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_allmulti_mode_result, port_num,
+ UINT16);
+cmdline_parse_token_string_t cmd_setallmulti_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_allmulti_mode_result, mode,
+ "on#off");
+
+cmdline_parse_inst_t cmd_set_allmulti_mode_all = {
+ .f = cmd_set_allmulti_mode_parsed,
+ .data = (void *)1,
+ .help_str = "set allmulti all on|off: Set allmulti mode for all ports",
+ .tokens = {
+ (void *)&cmd_setallmulti_set,
+ (void *)&cmd_setallmulti_allmulti,
+ (void *)&cmd_setallmulti_portall,
+ (void *)&cmd_setallmulti_mode,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_allmulti_mode_one = {
+ .f = cmd_set_allmulti_mode_parsed,
+ .data = (void *)0,
+ .help_str = "set allmulti <port_id> on|off: "
+ "Set allmulti mode on port_id",
+ .tokens = {
+ (void *)&cmd_setallmulti_set,
+ (void *)&cmd_setallmulti_allmulti,
+ (void *)&cmd_setallmulti_portnum,
+ (void *)&cmd_setallmulti_mode,
+ NULL,
+ },
+};
+
+/* *** SETUP ETHERNET LINK FLOW CONTROL *** */
+struct cmd_link_flow_ctrl_set_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t flow_ctrl;
+ cmdline_fixed_string_t rx;
+ cmdline_fixed_string_t rx_lfc_mode;
+ cmdline_fixed_string_t tx;
+ cmdline_fixed_string_t tx_lfc_mode;
+ cmdline_fixed_string_t mac_ctrl_frame_fwd;
+ cmdline_fixed_string_t mac_ctrl_frame_fwd_mode;
+ cmdline_fixed_string_t autoneg_str;
+ cmdline_fixed_string_t autoneg;
+ cmdline_fixed_string_t hw_str;
+ uint32_t high_water;
+ cmdline_fixed_string_t lw_str;
+ uint32_t low_water;
+ cmdline_fixed_string_t pt_str;
+ uint16_t pause_time;
+ cmdline_fixed_string_t xon_str;
+ uint16_t send_xon;
+ portid_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_lfc_set_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_lfc_set_flow_ctrl =
+ TOKEN_STRING_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ flow_ctrl, "flow_ctrl");
+cmdline_parse_token_string_t cmd_lfc_set_rx =
+ TOKEN_STRING_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ rx, "rx");
+cmdline_parse_token_string_t cmd_lfc_set_rx_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ rx_lfc_mode, "on#off");
+cmdline_parse_token_string_t cmd_lfc_set_tx =
+ TOKEN_STRING_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ tx, "tx");
+cmdline_parse_token_string_t cmd_lfc_set_tx_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ tx_lfc_mode, "on#off");
+cmdline_parse_token_string_t cmd_lfc_set_high_water_str =
+ TOKEN_STRING_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ hw_str, "high_water");
+cmdline_parse_token_num_t cmd_lfc_set_high_water =
+ TOKEN_NUM_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ high_water, UINT32);
+cmdline_parse_token_string_t cmd_lfc_set_low_water_str =
+ TOKEN_STRING_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ lw_str, "low_water");
+cmdline_parse_token_num_t cmd_lfc_set_low_water =
+ TOKEN_NUM_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ low_water, UINT32);
+cmdline_parse_token_string_t cmd_lfc_set_pause_time_str =
+ TOKEN_STRING_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ pt_str, "pause_time");
+cmdline_parse_token_num_t cmd_lfc_set_pause_time =
+ TOKEN_NUM_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ pause_time, UINT16);
+cmdline_parse_token_string_t cmd_lfc_set_send_xon_str =
+ TOKEN_STRING_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ xon_str, "send_xon");
+cmdline_parse_token_num_t cmd_lfc_set_send_xon =
+ TOKEN_NUM_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ send_xon, UINT16);
+cmdline_parse_token_string_t cmd_lfc_set_mac_ctrl_frame_fwd_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ mac_ctrl_frame_fwd, "mac_ctrl_frame_fwd");
+cmdline_parse_token_string_t cmd_lfc_set_mac_ctrl_frame_fwd =
+ TOKEN_STRING_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ mac_ctrl_frame_fwd_mode, "on#off");
+cmdline_parse_token_string_t cmd_lfc_set_autoneg_str =
+ TOKEN_STRING_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ autoneg_str, "autoneg");
+cmdline_parse_token_string_t cmd_lfc_set_autoneg =
+ TOKEN_STRING_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ autoneg, "on#off");
+cmdline_parse_token_num_t cmd_lfc_set_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_link_flow_ctrl_set_result,
+ port_id, UINT16);
+
+/* forward declaration */
+static void
+cmd_link_flow_ctrl_set_parsed(void *parsed_result, struct cmdline *cl,
+ void *data);
+
+cmdline_parse_inst_t cmd_link_flow_control_set = {
+ .f = cmd_link_flow_ctrl_set_parsed,
+ .data = NULL,
+ .help_str = "set flow_ctrl rx on|off tx on|off <high_water> "
+ "<low_water> <pause_time> <send_xon> mac_ctrl_frame_fwd on|off "
+ "autoneg on|off <port_id>: Configure the Ethernet flow control",
+ .tokens = {
+ (void *)&cmd_lfc_set_set,
+ (void *)&cmd_lfc_set_flow_ctrl,
+ (void *)&cmd_lfc_set_rx,
+ (void *)&cmd_lfc_set_rx_mode,
+ (void *)&cmd_lfc_set_tx,
+ (void *)&cmd_lfc_set_tx_mode,
+ (void *)&cmd_lfc_set_high_water,
+ (void *)&cmd_lfc_set_low_water,
+ (void *)&cmd_lfc_set_pause_time,
+ (void *)&cmd_lfc_set_send_xon,
+ (void *)&cmd_lfc_set_mac_ctrl_frame_fwd_mode,
+ (void *)&cmd_lfc_set_mac_ctrl_frame_fwd,
+ (void *)&cmd_lfc_set_autoneg_str,
+ (void *)&cmd_lfc_set_autoneg,
+ (void *)&cmd_lfc_set_portid,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_link_flow_control_set_rx = {
+ .f = cmd_link_flow_ctrl_set_parsed,
+ .data = (void *)&cmd_link_flow_control_set_rx,
+ .help_str = "set flow_ctrl rx on|off <port_id>: "
+ "Change rx flow control parameter",
+ .tokens = {
+ (void *)&cmd_lfc_set_set,
+ (void *)&cmd_lfc_set_flow_ctrl,
+ (void *)&cmd_lfc_set_rx,
+ (void *)&cmd_lfc_set_rx_mode,
+ (void *)&cmd_lfc_set_portid,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_link_flow_control_set_tx = {
+ .f = cmd_link_flow_ctrl_set_parsed,
+ .data = (void *)&cmd_link_flow_control_set_tx,
+ .help_str = "set flow_ctrl tx on|off <port_id>: "
+ "Change tx flow control parameter",
+ .tokens = {
+ (void *)&cmd_lfc_set_set,
+ (void *)&cmd_lfc_set_flow_ctrl,
+ (void *)&cmd_lfc_set_tx,
+ (void *)&cmd_lfc_set_tx_mode,
+ (void *)&cmd_lfc_set_portid,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_link_flow_control_set_hw = {
+ .f = cmd_link_flow_ctrl_set_parsed,
+ .data = (void *)&cmd_link_flow_control_set_hw,
+ .help_str = "set flow_ctrl high_water <value> <port_id>: "
+ "Change high water flow control parameter",
+ .tokens = {
+ (void *)&cmd_lfc_set_set,
+ (void *)&cmd_lfc_set_flow_ctrl,
+ (void *)&cmd_lfc_set_high_water_str,
+ (void *)&cmd_lfc_set_high_water,
+ (void *)&cmd_lfc_set_portid,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_link_flow_control_set_lw = {
+ .f = cmd_link_flow_ctrl_set_parsed,
+ .data = (void *)&cmd_link_flow_control_set_lw,
+ .help_str = "set flow_ctrl low_water <value> <port_id>: "
+ "Change low water flow control parameter",
+ .tokens = {
+ (void *)&cmd_lfc_set_set,
+ (void *)&cmd_lfc_set_flow_ctrl,
+ (void *)&cmd_lfc_set_low_water_str,
+ (void *)&cmd_lfc_set_low_water,
+ (void *)&cmd_lfc_set_portid,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_link_flow_control_set_pt = {
+ .f = cmd_link_flow_ctrl_set_parsed,
+ .data = (void *)&cmd_link_flow_control_set_pt,
+ .help_str = "set flow_ctrl pause_time <value> <port_id>: "
+ "Change pause time flow control parameter",
+ .tokens = {
+ (void *)&cmd_lfc_set_set,
+ (void *)&cmd_lfc_set_flow_ctrl,
+ (void *)&cmd_lfc_set_pause_time_str,
+ (void *)&cmd_lfc_set_pause_time,
+ (void *)&cmd_lfc_set_portid,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_link_flow_control_set_xon = {
+ .f = cmd_link_flow_ctrl_set_parsed,
+ .data = (void *)&cmd_link_flow_control_set_xon,
+ .help_str = "set flow_ctrl send_xon <value> <port_id>: "
+ "Change send_xon flow control parameter",
+ .tokens = {
+ (void *)&cmd_lfc_set_set,
+ (void *)&cmd_lfc_set_flow_ctrl,
+ (void *)&cmd_lfc_set_send_xon_str,
+ (void *)&cmd_lfc_set_send_xon,
+ (void *)&cmd_lfc_set_portid,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_link_flow_control_set_macfwd = {
+ .f = cmd_link_flow_ctrl_set_parsed,
+ .data = (void *)&cmd_link_flow_control_set_macfwd,
+ .help_str = "set flow_ctrl mac_ctrl_frame_fwd on|off <port_id>: "
+ "Change mac ctrl fwd flow control parameter",
+ .tokens = {
+ (void *)&cmd_lfc_set_set,
+ (void *)&cmd_lfc_set_flow_ctrl,
+ (void *)&cmd_lfc_set_mac_ctrl_frame_fwd_mode,
+ (void *)&cmd_lfc_set_mac_ctrl_frame_fwd,
+ (void *)&cmd_lfc_set_portid,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_link_flow_control_set_autoneg = {
+ .f = cmd_link_flow_ctrl_set_parsed,
+ .data = (void *)&cmd_link_flow_control_set_autoneg,
+ .help_str = "set flow_ctrl autoneg on|off <port_id>: "
+ "Change autoneg flow control parameter",
+ .tokens = {
+ (void *)&cmd_lfc_set_set,
+ (void *)&cmd_lfc_set_flow_ctrl,
+ (void *)&cmd_lfc_set_autoneg_str,
+ (void *)&cmd_lfc_set_autoneg,
+ (void *)&cmd_lfc_set_portid,
+ NULL,
+ },
+};
+
+static void
+cmd_link_flow_ctrl_set_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ void *data)
+{
+ struct cmd_link_flow_ctrl_set_result *res = parsed_result;
+ cmdline_parse_inst_t *cmd = data;
+ struct rte_eth_fc_conf fc_conf;
+ int rx_fc_en = 0;
+ int tx_fc_en = 0;
+ int ret;
+
+ /*
+ * Rx on/off, flow control is enabled/disabled on RX side. This can indicate
+ * the RTE_FC_TX_PAUSE, Transmit pause frame at the Rx side.
+ * Tx on/off, flow control is enabled/disabled on TX side. This can indicate
+ * the RTE_FC_RX_PAUSE, Respond to the pause frame at the Tx side.
+ */
+ static enum rte_eth_fc_mode rx_tx_onoff_2_lfc_mode[2][2] = {
+ {RTE_FC_NONE, RTE_FC_TX_PAUSE}, {RTE_FC_RX_PAUSE, RTE_FC_FULL}
+ };
+
+ /* Partial command line, retrieve current configuration */
+ if (cmd) {
+ ret = rte_eth_dev_flow_ctrl_get(res->port_id, &fc_conf);
+ if (ret != 0) {
+ printf("cannot get current flow ctrl parameters, return"
+ "code = %d\n", ret);
+ return;
+ }
+
+ if ((fc_conf.mode == RTE_FC_RX_PAUSE) ||
+ (fc_conf.mode == RTE_FC_FULL))
+ rx_fc_en = 1;
+ if ((fc_conf.mode == RTE_FC_TX_PAUSE) ||
+ (fc_conf.mode == RTE_FC_FULL))
+ tx_fc_en = 1;
+ }
+
+ if (!cmd || cmd == &cmd_link_flow_control_set_rx)
+ rx_fc_en = (!strcmp(res->rx_lfc_mode, "on")) ? 1 : 0;
+
+ if (!cmd || cmd == &cmd_link_flow_control_set_tx)
+ tx_fc_en = (!strcmp(res->tx_lfc_mode, "on")) ? 1 : 0;
+
+ fc_conf.mode = rx_tx_onoff_2_lfc_mode[rx_fc_en][tx_fc_en];
+
+ if (!cmd || cmd == &cmd_link_flow_control_set_hw)
+ fc_conf.high_water = res->high_water;
+
+ if (!cmd || cmd == &cmd_link_flow_control_set_lw)
+ fc_conf.low_water = res->low_water;
+
+ if (!cmd || cmd == &cmd_link_flow_control_set_pt)
+ fc_conf.pause_time = res->pause_time;
+
+ if (!cmd || cmd == &cmd_link_flow_control_set_xon)
+ fc_conf.send_xon = res->send_xon;
+
+ if (!cmd || cmd == &cmd_link_flow_control_set_macfwd) {
+ if (!strcmp(res->mac_ctrl_frame_fwd_mode, "on"))
+ fc_conf.mac_ctrl_frame_fwd = 1;
+ else
+ fc_conf.mac_ctrl_frame_fwd = 0;
+ }
+
+ if (!cmd || cmd == &cmd_link_flow_control_set_autoneg)
+ fc_conf.autoneg = (!strcmp(res->autoneg, "on")) ? 1 : 0;
+
+ ret = rte_eth_dev_flow_ctrl_set(res->port_id, &fc_conf);
+ if (ret != 0)
+ printf("bad flow contrl parameter, return code = %d \n", ret);
+}
+
+/* *** SETUP ETHERNET PRIORITY FLOW CONTROL *** */
+struct cmd_priority_flow_ctrl_set_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t pfc_ctrl;
+ cmdline_fixed_string_t rx;
+ cmdline_fixed_string_t rx_pfc_mode;
+ cmdline_fixed_string_t tx;
+ cmdline_fixed_string_t tx_pfc_mode;
+ uint32_t high_water;
+ uint32_t low_water;
+ uint16_t pause_time;
+ uint8_t priority;
+ portid_t port_id;
+};
+
+static void
+cmd_priority_flow_ctrl_set_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_priority_flow_ctrl_set_result *res = parsed_result;
+ struct rte_eth_pfc_conf pfc_conf;
+ int rx_fc_enable, tx_fc_enable;
+ int ret;
+
+ /*
+ * Rx on/off, flow control is enabled/disabled on RX side. This can indicate
+ * the RTE_FC_TX_PAUSE, Transmit pause frame at the Rx side.
+ * Tx on/off, flow control is enabled/disabled on TX side. This can indicate
+ * the RTE_FC_RX_PAUSE, Respond to the pause frame at the Tx side.
+ */
+ static enum rte_eth_fc_mode rx_tx_onoff_2_pfc_mode[2][2] = {
+ {RTE_FC_NONE, RTE_FC_TX_PAUSE}, {RTE_FC_RX_PAUSE, RTE_FC_FULL}
+ };
+
+ memset(&pfc_conf, 0, sizeof(struct rte_eth_pfc_conf));
+ rx_fc_enable = (!strncmp(res->rx_pfc_mode, "on",2)) ? 1 : 0;
+ tx_fc_enable = (!strncmp(res->tx_pfc_mode, "on",2)) ? 1 : 0;
+ pfc_conf.fc.mode = rx_tx_onoff_2_pfc_mode[rx_fc_enable][tx_fc_enable];
+ pfc_conf.fc.high_water = res->high_water;
+ pfc_conf.fc.low_water = res->low_water;
+ pfc_conf.fc.pause_time = res->pause_time;
+ pfc_conf.priority = res->priority;
+
+ ret = rte_eth_dev_priority_flow_ctrl_set(res->port_id, &pfc_conf);
+ if (ret != 0)
+ printf("bad priority flow contrl parameter, return code = %d \n", ret);
+}
+
+cmdline_parse_token_string_t cmd_pfc_set_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_priority_flow_ctrl_set_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_pfc_set_flow_ctrl =
+ TOKEN_STRING_INITIALIZER(struct cmd_priority_flow_ctrl_set_result,
+ pfc_ctrl, "pfc_ctrl");
+cmdline_parse_token_string_t cmd_pfc_set_rx =
+ TOKEN_STRING_INITIALIZER(struct cmd_priority_flow_ctrl_set_result,
+ rx, "rx");
+cmdline_parse_token_string_t cmd_pfc_set_rx_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_priority_flow_ctrl_set_result,
+ rx_pfc_mode, "on#off");
+cmdline_parse_token_string_t cmd_pfc_set_tx =
+ TOKEN_STRING_INITIALIZER(struct cmd_priority_flow_ctrl_set_result,
+ tx, "tx");
+cmdline_parse_token_string_t cmd_pfc_set_tx_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_priority_flow_ctrl_set_result,
+ tx_pfc_mode, "on#off");
+cmdline_parse_token_num_t cmd_pfc_set_high_water =
+ TOKEN_NUM_INITIALIZER(struct cmd_priority_flow_ctrl_set_result,
+ high_water, UINT32);
+cmdline_parse_token_num_t cmd_pfc_set_low_water =
+ TOKEN_NUM_INITIALIZER(struct cmd_priority_flow_ctrl_set_result,
+ low_water, UINT32);
+cmdline_parse_token_num_t cmd_pfc_set_pause_time =
+ TOKEN_NUM_INITIALIZER(struct cmd_priority_flow_ctrl_set_result,
+ pause_time, UINT16);
+cmdline_parse_token_num_t cmd_pfc_set_priority =
+ TOKEN_NUM_INITIALIZER(struct cmd_priority_flow_ctrl_set_result,
+ priority, UINT8);
+cmdline_parse_token_num_t cmd_pfc_set_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_priority_flow_ctrl_set_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_priority_flow_control_set = {
+ .f = cmd_priority_flow_ctrl_set_parsed,
+ .data = NULL,
+ .help_str = "set pfc_ctrl rx on|off tx on|off <high_water> <low_water> "
+ "<pause_time> <priority> <port_id>: "
+ "Configure the Ethernet priority flow control",
+ .tokens = {
+ (void *)&cmd_pfc_set_set,
+ (void *)&cmd_pfc_set_flow_ctrl,
+ (void *)&cmd_pfc_set_rx,
+ (void *)&cmd_pfc_set_rx_mode,
+ (void *)&cmd_pfc_set_tx,
+ (void *)&cmd_pfc_set_tx_mode,
+ (void *)&cmd_pfc_set_high_water,
+ (void *)&cmd_pfc_set_low_water,
+ (void *)&cmd_pfc_set_pause_time,
+ (void *)&cmd_pfc_set_priority,
+ (void *)&cmd_pfc_set_portid,
+ NULL,
+ },
+};
+
+/* *** RESET CONFIGURATION *** */
+struct cmd_reset_result {
+ cmdline_fixed_string_t reset;
+ cmdline_fixed_string_t def;
+};
+
+static void cmd_reset_parsed(__rte_unused void *parsed_result,
+ struct cmdline *cl,
+ __rte_unused void *data)
+{
+ cmdline_printf(cl, "Reset to default forwarding configuration...\n");
+ set_def_fwd_config();
+}
+
+cmdline_parse_token_string_t cmd_reset_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_reset_result, reset, "set");
+cmdline_parse_token_string_t cmd_reset_def =
+ TOKEN_STRING_INITIALIZER(struct cmd_reset_result, def,
+ "default");
+
+cmdline_parse_inst_t cmd_reset = {
+ .f = cmd_reset_parsed,
+ .data = NULL,
+ .help_str = "set default: Reset default forwarding configuration",
+ .tokens = {
+ (void *)&cmd_reset_set,
+ (void *)&cmd_reset_def,
+ NULL,
+ },
+};
+
+/* *** START FORWARDING *** */
+struct cmd_start_result {
+ cmdline_fixed_string_t start;
+};
+
+cmdline_parse_token_string_t cmd_start_start =
+ TOKEN_STRING_INITIALIZER(struct cmd_start_result, start, "start");
+
+static void cmd_start_parsed(__rte_unused void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ start_packet_forwarding(0);
+}
+
+cmdline_parse_inst_t cmd_start = {
+ .f = cmd_start_parsed,
+ .data = NULL,
+ .help_str = "start: Start packet forwarding",
+ .tokens = {
+ (void *)&cmd_start_start,
+ NULL,
+ },
+};
+
+/* *** START FORWARDING WITH ONE TX BURST FIRST *** */
+struct cmd_start_tx_first_result {
+ cmdline_fixed_string_t start;
+ cmdline_fixed_string_t tx_first;
+};
+
+static void
+cmd_start_tx_first_parsed(__rte_unused void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ start_packet_forwarding(1);
+}
+
+cmdline_parse_token_string_t cmd_start_tx_first_start =
+ TOKEN_STRING_INITIALIZER(struct cmd_start_tx_first_result, start,
+ "start");
+cmdline_parse_token_string_t cmd_start_tx_first_tx_first =
+ TOKEN_STRING_INITIALIZER(struct cmd_start_tx_first_result,
+ tx_first, "tx_first");
+
+cmdline_parse_inst_t cmd_start_tx_first = {
+ .f = cmd_start_tx_first_parsed,
+ .data = NULL,
+ .help_str = "start tx_first: Start packet forwarding, "
+ "after sending 1 burst of packets",
+ .tokens = {
+ (void *)&cmd_start_tx_first_start,
+ (void *)&cmd_start_tx_first_tx_first,
+ NULL,
+ },
+};
+
+/* *** START FORWARDING WITH N TX BURST FIRST *** */
+struct cmd_start_tx_first_n_result {
+ cmdline_fixed_string_t start;
+ cmdline_fixed_string_t tx_first;
+ uint32_t tx_num;
+};
+
+static void
+cmd_start_tx_first_n_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_start_tx_first_n_result *res = parsed_result;
+
+ start_packet_forwarding(res->tx_num);
+}
+
+cmdline_parse_token_string_t cmd_start_tx_first_n_start =
+ TOKEN_STRING_INITIALIZER(struct cmd_start_tx_first_n_result,
+ start, "start");
+cmdline_parse_token_string_t cmd_start_tx_first_n_tx_first =
+ TOKEN_STRING_INITIALIZER(struct cmd_start_tx_first_n_result,
+ tx_first, "tx_first");
+cmdline_parse_token_num_t cmd_start_tx_first_n_tx_num =
+ TOKEN_NUM_INITIALIZER(struct cmd_start_tx_first_n_result,
+ tx_num, UINT32);
+
+cmdline_parse_inst_t cmd_start_tx_first_n = {
+ .f = cmd_start_tx_first_n_parsed,
+ .data = NULL,
+ .help_str = "start tx_first <num>: "
+ "packet forwarding, after sending <num> bursts of packets",
+ .tokens = {
+ (void *)&cmd_start_tx_first_n_start,
+ (void *)&cmd_start_tx_first_n_tx_first,
+ (void *)&cmd_start_tx_first_n_tx_num,
+ NULL,
+ },
+};
+
+/* *** SET LINK UP *** */
+struct cmd_set_link_up_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t link_up;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_set_link_up_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_link_up_result, set, "set");
+cmdline_parse_token_string_t cmd_set_link_up_link_up =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_link_up_result, link_up,
+ "link-up");
+cmdline_parse_token_string_t cmd_set_link_up_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_link_up_result, port, "port");
+cmdline_parse_token_num_t cmd_set_link_up_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_link_up_result, port_id, UINT16);
+
+static void cmd_set_link_up_parsed(__rte_unused void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_link_up_result *res = parsed_result;
+ dev_set_link_up(res->port_id);
+}
+
+cmdline_parse_inst_t cmd_set_link_up = {
+ .f = cmd_set_link_up_parsed,
+ .data = NULL,
+ .help_str = "set link-up port <port id>",
+ .tokens = {
+ (void *)&cmd_set_link_up_set,
+ (void *)&cmd_set_link_up_link_up,
+ (void *)&cmd_set_link_up_port,
+ (void *)&cmd_set_link_up_port_id,
+ NULL,
+ },
+};
+
+/* *** SET LINK DOWN *** */
+struct cmd_set_link_down_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t link_down;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_set_link_down_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_link_down_result, set, "set");
+cmdline_parse_token_string_t cmd_set_link_down_link_down =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_link_down_result, link_down,
+ "link-down");
+cmdline_parse_token_string_t cmd_set_link_down_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_link_down_result, port, "port");
+cmdline_parse_token_num_t cmd_set_link_down_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_link_down_result, port_id, UINT16);
+
+static void cmd_set_link_down_parsed(
+ __rte_unused void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_link_down_result *res = parsed_result;
+ dev_set_link_down(res->port_id);
+}
+
+cmdline_parse_inst_t cmd_set_link_down = {
+ .f = cmd_set_link_down_parsed,
+ .data = NULL,
+ .help_str = "set link-down port <port id>",
+ .tokens = {
+ (void *)&cmd_set_link_down_set,
+ (void *)&cmd_set_link_down_link_down,
+ (void *)&cmd_set_link_down_port,
+ (void *)&cmd_set_link_down_port_id,
+ NULL,
+ },
+};
+
+/* *** SHOW CFG *** */
+struct cmd_showcfg_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t cfg;
+ cmdline_fixed_string_t what;
+};
+
+static void cmd_showcfg_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_showcfg_result *res = parsed_result;
+ if (!strcmp(res->what, "rxtx"))
+ rxtx_config_display();
+ else if (!strcmp(res->what, "cores"))
+ fwd_lcores_config_display();
+ else if (!strcmp(res->what, "fwd"))
+ pkt_fwd_config_display(&cur_fwd_config);
+ else if (!strcmp(res->what, "txpkts"))
+ show_tx_pkt_segments();
+}
+
+cmdline_parse_token_string_t cmd_showcfg_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_showcfg_result, show, "show");
+cmdline_parse_token_string_t cmd_showcfg_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_showcfg_result, cfg, "config");
+cmdline_parse_token_string_t cmd_showcfg_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_showcfg_result, what,
+ "rxtx#cores#fwd#txpkts");
+
+cmdline_parse_inst_t cmd_showcfg = {
+ .f = cmd_showcfg_parsed,
+ .data = NULL,
+ .help_str = "show config rxtx|cores|fwd|txpkts",
+ .tokens = {
+ (void *)&cmd_showcfg_show,
+ (void *)&cmd_showcfg_port,
+ (void *)&cmd_showcfg_what,
+ NULL,
+ },
+};
+
+/* *** SHOW ALL PORT INFO *** */
+struct cmd_showportall_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t what;
+ cmdline_fixed_string_t all;
+};
+
+static void cmd_showportall_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ portid_t i;
+
+ struct cmd_showportall_result *res = parsed_result;
+ if (!strcmp(res->show, "clear")) {
+ if (!strcmp(res->what, "stats"))
+ RTE_ETH_FOREACH_DEV(i)
+ nic_stats_clear(i);
+ else if (!strcmp(res->what, "xstats"))
+ RTE_ETH_FOREACH_DEV(i)
+ nic_xstats_clear(i);
+ } else if (!strcmp(res->what, "info"))
+ RTE_ETH_FOREACH_DEV(i)
+ port_infos_display(i);
+ else if (!strcmp(res->what, "summary")) {
+ port_summary_header_display();
+ RTE_ETH_FOREACH_DEV(i)
+ port_summary_display(i);
+ }
+ else if (!strcmp(res->what, "stats"))
+ RTE_ETH_FOREACH_DEV(i)
+ nic_stats_display(i);
+ else if (!strcmp(res->what, "xstats"))
+ RTE_ETH_FOREACH_DEV(i)
+ nic_xstats_display(i);
+ else if (!strcmp(res->what, "fdir"))
+ RTE_ETH_FOREACH_DEV(i)
+ fdir_get_infos(i);
+ else if (!strcmp(res->what, "stat_qmap"))
+ RTE_ETH_FOREACH_DEV(i)
+ nic_stats_mapping_display(i);
+ else if (!strcmp(res->what, "dcb_tc"))
+ RTE_ETH_FOREACH_DEV(i)
+ port_dcb_info_display(i);
+ else if (!strcmp(res->what, "cap"))
+ RTE_ETH_FOREACH_DEV(i)
+ port_offload_cap_display(i);
+}
+
+cmdline_parse_token_string_t cmd_showportall_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_showportall_result, show,
+ "show#clear");
+cmdline_parse_token_string_t cmd_showportall_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_showportall_result, port, "port");
+cmdline_parse_token_string_t cmd_showportall_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_showportall_result, what,
+ "info#summary#stats#xstats#fdir#stat_qmap#dcb_tc#cap");
+cmdline_parse_token_string_t cmd_showportall_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_showportall_result, all, "all");
+cmdline_parse_inst_t cmd_showportall = {
+ .f = cmd_showportall_parsed,
+ .data = NULL,
+ .help_str = "show|clear port "
+ "info|summary|stats|xstats|fdir|stat_qmap|dcb_tc|cap all",
+ .tokens = {
+ (void *)&cmd_showportall_show,
+ (void *)&cmd_showportall_port,
+ (void *)&cmd_showportall_what,
+ (void *)&cmd_showportall_all,
+ NULL,
+ },
+};
+
+/* *** SHOW PORT INFO *** */
+struct cmd_showport_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t what;
+ uint16_t portnum;
+};
+
+static void cmd_showport_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_showport_result *res = parsed_result;
+ if (!strcmp(res->show, "clear")) {
+ if (!strcmp(res->what, "stats"))
+ nic_stats_clear(res->portnum);
+ else if (!strcmp(res->what, "xstats"))
+ nic_xstats_clear(res->portnum);
+ } else if (!strcmp(res->what, "info"))
+ port_infos_display(res->portnum);
+ else if (!strcmp(res->what, "summary")) {
+ port_summary_header_display();
+ port_summary_display(res->portnum);
+ }
+ else if (!strcmp(res->what, "stats"))
+ nic_stats_display(res->portnum);
+ else if (!strcmp(res->what, "xstats"))
+ nic_xstats_display(res->portnum);
+ else if (!strcmp(res->what, "fdir"))
+ fdir_get_infos(res->portnum);
+ else if (!strcmp(res->what, "stat_qmap"))
+ nic_stats_mapping_display(res->portnum);
+ else if (!strcmp(res->what, "dcb_tc"))
+ port_dcb_info_display(res->portnum);
+ else if (!strcmp(res->what, "cap"))
+ port_offload_cap_display(res->portnum);
+}
+
+cmdline_parse_token_string_t cmd_showport_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_result, show,
+ "show#clear");
+cmdline_parse_token_string_t cmd_showport_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_result, port, "port");
+cmdline_parse_token_string_t cmd_showport_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_result, what,
+ "info#summary#stats#xstats#fdir#stat_qmap#dcb_tc#cap");
+cmdline_parse_token_num_t cmd_showport_portnum =
+ TOKEN_NUM_INITIALIZER(struct cmd_showport_result, portnum, UINT16);
+
+cmdline_parse_inst_t cmd_showport = {
+ .f = cmd_showport_parsed,
+ .data = NULL,
+ .help_str = "show|clear port "
+ "info|summary|stats|xstats|fdir|stat_qmap|dcb_tc|cap "
+ "<port_id>",
+ .tokens = {
+ (void *)&cmd_showport_show,
+ (void *)&cmd_showport_port,
+ (void *)&cmd_showport_what,
+ (void *)&cmd_showport_portnum,
+ NULL,
+ },
+};
+
+/* *** SHOW DEVICE INFO *** */
+struct cmd_showdevice_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t device;
+ cmdline_fixed_string_t what;
+ cmdline_fixed_string_t identifier;
+};
+
+static void cmd_showdevice_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_showdevice_result *res = parsed_result;
+ if (!strcmp(res->what, "info")) {
+ if (!strcmp(res->identifier, "all"))
+ device_infos_display(NULL);
+ else
+ device_infos_display(res->identifier);
+ }
+}
+
+cmdline_parse_token_string_t cmd_showdevice_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result, show,
+ "show");
+cmdline_parse_token_string_t cmd_showdevice_device =
+ TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result, device, "device");
+cmdline_parse_token_string_t cmd_showdevice_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result, what,
+ "info");
+cmdline_parse_token_string_t cmd_showdevice_identifier =
+ TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+ identifier, NULL);
+
+cmdline_parse_inst_t cmd_showdevice = {
+ .f = cmd_showdevice_parsed,
+ .data = NULL,
+ .help_str = "show device info <identifier>|all",
+ .tokens = {
+ (void *)&cmd_showdevice_show,
+ (void *)&cmd_showdevice_device,
+ (void *)&cmd_showdevice_what,
+ (void *)&cmd_showdevice_identifier,
+ NULL,
+ },
+};
+/* *** SHOW QUEUE INFO *** */
+struct cmd_showqueue_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t type;
+ cmdline_fixed_string_t what;
+ uint16_t portnum;
+ uint16_t queuenum;
+};
+
+static void
+cmd_showqueue_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_showqueue_result *res = parsed_result;
+
+ if (!strcmp(res->type, "rxq"))
+ rx_queue_infos_display(res->portnum, res->queuenum);
+ else if (!strcmp(res->type, "txq"))
+ tx_queue_infos_display(res->portnum, res->queuenum);
+}
+
+cmdline_parse_token_string_t cmd_showqueue_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_showqueue_result, show, "show");
+cmdline_parse_token_string_t cmd_showqueue_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_showqueue_result, type, "rxq#txq");
+cmdline_parse_token_string_t cmd_showqueue_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_showqueue_result, what, "info");
+cmdline_parse_token_num_t cmd_showqueue_portnum =
+ TOKEN_NUM_INITIALIZER(struct cmd_showqueue_result, portnum, UINT16);
+cmdline_parse_token_num_t cmd_showqueue_queuenum =
+ TOKEN_NUM_INITIALIZER(struct cmd_showqueue_result, queuenum, UINT16);
+
+cmdline_parse_inst_t cmd_showqueue = {
+ .f = cmd_showqueue_parsed,
+ .data = NULL,
+ .help_str = "show rxq|txq info <port_id> <queue_id>",
+ .tokens = {
+ (void *)&cmd_showqueue_show,
+ (void *)&cmd_showqueue_type,
+ (void *)&cmd_showqueue_what,
+ (void *)&cmd_showqueue_portnum,
+ (void *)&cmd_showqueue_queuenum,
+ NULL,
+ },
+};
+
+/* show/clear fwd engine statistics */
+struct fwd_result {
+ cmdline_fixed_string_t action;
+ cmdline_fixed_string_t fwd;
+ cmdline_fixed_string_t stats;
+ cmdline_fixed_string_t all;
+};
+
+cmdline_parse_token_string_t cmd_fwd_action =
+ TOKEN_STRING_INITIALIZER(struct fwd_result, action, "show#clear");
+cmdline_parse_token_string_t cmd_fwd_fwd =
+ TOKEN_STRING_INITIALIZER(struct fwd_result, fwd, "fwd");
+cmdline_parse_token_string_t cmd_fwd_stats =
+ TOKEN_STRING_INITIALIZER(struct fwd_result, stats, "stats");
+cmdline_parse_token_string_t cmd_fwd_all =
+ TOKEN_STRING_INITIALIZER(struct fwd_result, all, "all");
+
+static void
+cmd_showfwdall_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct fwd_result *res = parsed_result;
+
+ if (!strcmp(res->action, "show"))
+ fwd_stats_display();
+ else
+ fwd_stats_reset();
+}
+
+static cmdline_parse_inst_t cmd_showfwdall = {
+ .f = cmd_showfwdall_parsed,
+ .data = NULL,
+ .help_str = "show|clear fwd stats all",
+ .tokens = {
+ (void *)&cmd_fwd_action,
+ (void *)&cmd_fwd_fwd,
+ (void *)&cmd_fwd_stats,
+ (void *)&cmd_fwd_all,
+ NULL,
+ },
+};
+
+/* *** READ PORT REGISTER *** */
+struct cmd_read_reg_result {
+ cmdline_fixed_string_t read;
+ cmdline_fixed_string_t reg;
+ portid_t port_id;
+ uint32_t reg_off;
+};
+
+static void
+cmd_read_reg_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_read_reg_result *res = parsed_result;
+ port_reg_display(res->port_id, res->reg_off);
+}
+
+cmdline_parse_token_string_t cmd_read_reg_read =
+ TOKEN_STRING_INITIALIZER(struct cmd_read_reg_result, read, "read");
+cmdline_parse_token_string_t cmd_read_reg_reg =
+ TOKEN_STRING_INITIALIZER(struct cmd_read_reg_result, reg, "reg");
+cmdline_parse_token_num_t cmd_read_reg_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_read_reg_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_read_reg_reg_off =
+ TOKEN_NUM_INITIALIZER(struct cmd_read_reg_result, reg_off, UINT32);
+
+cmdline_parse_inst_t cmd_read_reg = {
+ .f = cmd_read_reg_parsed,
+ .data = NULL,
+ .help_str = "read reg <port_id> <reg_off>",
+ .tokens = {
+ (void *)&cmd_read_reg_read,
+ (void *)&cmd_read_reg_reg,
+ (void *)&cmd_read_reg_port_id,
+ (void *)&cmd_read_reg_reg_off,
+ NULL,
+ },
+};
+
+/* *** READ PORT REGISTER BIT FIELD *** */
+struct cmd_read_reg_bit_field_result {
+ cmdline_fixed_string_t read;
+ cmdline_fixed_string_t regfield;
+ portid_t port_id;
+ uint32_t reg_off;
+ uint8_t bit1_pos;
+ uint8_t bit2_pos;
+};
+
+static void
+cmd_read_reg_bit_field_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_read_reg_bit_field_result *res = parsed_result;
+ port_reg_bit_field_display(res->port_id, res->reg_off,
+ res->bit1_pos, res->bit2_pos);
+}
+
+cmdline_parse_token_string_t cmd_read_reg_bit_field_read =
+ TOKEN_STRING_INITIALIZER(struct cmd_read_reg_bit_field_result, read,
+ "read");
+cmdline_parse_token_string_t cmd_read_reg_bit_field_regfield =
+ TOKEN_STRING_INITIALIZER(struct cmd_read_reg_bit_field_result,
+ regfield, "regfield");
+cmdline_parse_token_num_t cmd_read_reg_bit_field_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_read_reg_bit_field_result, port_id,
+ UINT16);
+cmdline_parse_token_num_t cmd_read_reg_bit_field_reg_off =
+ TOKEN_NUM_INITIALIZER(struct cmd_read_reg_bit_field_result, reg_off,
+ UINT32);
+cmdline_parse_token_num_t cmd_read_reg_bit_field_bit1_pos =
+ TOKEN_NUM_INITIALIZER(struct cmd_read_reg_bit_field_result, bit1_pos,
+ UINT8);
+cmdline_parse_token_num_t cmd_read_reg_bit_field_bit2_pos =
+ TOKEN_NUM_INITIALIZER(struct cmd_read_reg_bit_field_result, bit2_pos,
+ UINT8);
+
+cmdline_parse_inst_t cmd_read_reg_bit_field = {
+ .f = cmd_read_reg_bit_field_parsed,
+ .data = NULL,
+ .help_str = "read regfield <port_id> <reg_off> <bit_x> <bit_y>: "
+ "Read register bit field between bit_x and bit_y included",
+ .tokens = {
+ (void *)&cmd_read_reg_bit_field_read,
+ (void *)&cmd_read_reg_bit_field_regfield,
+ (void *)&cmd_read_reg_bit_field_port_id,
+ (void *)&cmd_read_reg_bit_field_reg_off,
+ (void *)&cmd_read_reg_bit_field_bit1_pos,
+ (void *)&cmd_read_reg_bit_field_bit2_pos,
+ NULL,
+ },
+};
+
+/* *** READ PORT REGISTER BIT *** */
+struct cmd_read_reg_bit_result {
+ cmdline_fixed_string_t read;
+ cmdline_fixed_string_t regbit;
+ portid_t port_id;
+ uint32_t reg_off;
+ uint8_t bit_pos;
+};
+
+static void
+cmd_read_reg_bit_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_read_reg_bit_result *res = parsed_result;
+ port_reg_bit_display(res->port_id, res->reg_off, res->bit_pos);
+}
+
+cmdline_parse_token_string_t cmd_read_reg_bit_read =
+ TOKEN_STRING_INITIALIZER(struct cmd_read_reg_bit_result, read, "read");
+cmdline_parse_token_string_t cmd_read_reg_bit_regbit =
+ TOKEN_STRING_INITIALIZER(struct cmd_read_reg_bit_result,
+ regbit, "regbit");
+cmdline_parse_token_num_t cmd_read_reg_bit_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_read_reg_bit_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_read_reg_bit_reg_off =
+ TOKEN_NUM_INITIALIZER(struct cmd_read_reg_bit_result, reg_off, UINT32);
+cmdline_parse_token_num_t cmd_read_reg_bit_bit_pos =
+ TOKEN_NUM_INITIALIZER(struct cmd_read_reg_bit_result, bit_pos, UINT8);
+
+cmdline_parse_inst_t cmd_read_reg_bit = {
+ .f = cmd_read_reg_bit_parsed,
+ .data = NULL,
+ .help_str = "read regbit <port_id> <reg_off> <bit_x>: 0 <= bit_x <= 31",
+ .tokens = {
+ (void *)&cmd_read_reg_bit_read,
+ (void *)&cmd_read_reg_bit_regbit,
+ (void *)&cmd_read_reg_bit_port_id,
+ (void *)&cmd_read_reg_bit_reg_off,
+ (void *)&cmd_read_reg_bit_bit_pos,
+ NULL,
+ },
+};
+
+/* *** WRITE PORT REGISTER *** */
+struct cmd_write_reg_result {
+ cmdline_fixed_string_t write;
+ cmdline_fixed_string_t reg;
+ portid_t port_id;
+ uint32_t reg_off;
+ uint32_t value;
+};
+
+static void
+cmd_write_reg_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_write_reg_result *res = parsed_result;
+ port_reg_set(res->port_id, res->reg_off, res->value);
+}
+
+cmdline_parse_token_string_t cmd_write_reg_write =
+ TOKEN_STRING_INITIALIZER(struct cmd_write_reg_result, write, "write");
+cmdline_parse_token_string_t cmd_write_reg_reg =
+ TOKEN_STRING_INITIALIZER(struct cmd_write_reg_result, reg, "reg");
+cmdline_parse_token_num_t cmd_write_reg_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_write_reg_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_write_reg_reg_off =
+ TOKEN_NUM_INITIALIZER(struct cmd_write_reg_result, reg_off, UINT32);
+cmdline_parse_token_num_t cmd_write_reg_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_write_reg_result, value, UINT32);
+
+cmdline_parse_inst_t cmd_write_reg = {
+ .f = cmd_write_reg_parsed,
+ .data = NULL,
+ .help_str = "write reg <port_id> <reg_off> <reg_value>",
+ .tokens = {
+ (void *)&cmd_write_reg_write,
+ (void *)&cmd_write_reg_reg,
+ (void *)&cmd_write_reg_port_id,
+ (void *)&cmd_write_reg_reg_off,
+ (void *)&cmd_write_reg_value,
+ NULL,
+ },
+};
+
+/* *** WRITE PORT REGISTER BIT FIELD *** */
+struct cmd_write_reg_bit_field_result {
+ cmdline_fixed_string_t write;
+ cmdline_fixed_string_t regfield;
+ portid_t port_id;
+ uint32_t reg_off;
+ uint8_t bit1_pos;
+ uint8_t bit2_pos;
+ uint32_t value;
+};
+
+static void
+cmd_write_reg_bit_field_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_write_reg_bit_field_result *res = parsed_result;
+ port_reg_bit_field_set(res->port_id, res->reg_off,
+ res->bit1_pos, res->bit2_pos, res->value);
+}
+
+cmdline_parse_token_string_t cmd_write_reg_bit_field_write =
+ TOKEN_STRING_INITIALIZER(struct cmd_write_reg_bit_field_result, write,
+ "write");
+cmdline_parse_token_string_t cmd_write_reg_bit_field_regfield =
+ TOKEN_STRING_INITIALIZER(struct cmd_write_reg_bit_field_result,
+ regfield, "regfield");
+cmdline_parse_token_num_t cmd_write_reg_bit_field_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_write_reg_bit_field_result, port_id,
+ UINT16);
+cmdline_parse_token_num_t cmd_write_reg_bit_field_reg_off =
+ TOKEN_NUM_INITIALIZER(struct cmd_write_reg_bit_field_result, reg_off,
+ UINT32);
+cmdline_parse_token_num_t cmd_write_reg_bit_field_bit1_pos =
+ TOKEN_NUM_INITIALIZER(struct cmd_write_reg_bit_field_result, bit1_pos,
+ UINT8);
+cmdline_parse_token_num_t cmd_write_reg_bit_field_bit2_pos =
+ TOKEN_NUM_INITIALIZER(struct cmd_write_reg_bit_field_result, bit2_pos,
+ UINT8);
+cmdline_parse_token_num_t cmd_write_reg_bit_field_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_write_reg_bit_field_result, value,
+ UINT32);
+
+cmdline_parse_inst_t cmd_write_reg_bit_field = {
+ .f = cmd_write_reg_bit_field_parsed,
+ .data = NULL,
+ .help_str = "write regfield <port_id> <reg_off> <bit_x> <bit_y> "
+ "<reg_value>: "
+ "Set register bit field between bit_x and bit_y included",
+ .tokens = {
+ (void *)&cmd_write_reg_bit_field_write,
+ (void *)&cmd_write_reg_bit_field_regfield,
+ (void *)&cmd_write_reg_bit_field_port_id,
+ (void *)&cmd_write_reg_bit_field_reg_off,
+ (void *)&cmd_write_reg_bit_field_bit1_pos,
+ (void *)&cmd_write_reg_bit_field_bit2_pos,
+ (void *)&cmd_write_reg_bit_field_value,
+ NULL,
+ },
+};
+
+/* *** WRITE PORT REGISTER BIT *** */
+struct cmd_write_reg_bit_result {
+ cmdline_fixed_string_t write;
+ cmdline_fixed_string_t regbit;
+ portid_t port_id;
+ uint32_t reg_off;
+ uint8_t bit_pos;
+ uint8_t value;
+};
+
+static void
+cmd_write_reg_bit_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_write_reg_bit_result *res = parsed_result;
+ port_reg_bit_set(res->port_id, res->reg_off, res->bit_pos, res->value);
+}
+
+cmdline_parse_token_string_t cmd_write_reg_bit_write =
+ TOKEN_STRING_INITIALIZER(struct cmd_write_reg_bit_result, write,
+ "write");
+cmdline_parse_token_string_t cmd_write_reg_bit_regbit =
+ TOKEN_STRING_INITIALIZER(struct cmd_write_reg_bit_result,
+ regbit, "regbit");
+cmdline_parse_token_num_t cmd_write_reg_bit_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_write_reg_bit_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_write_reg_bit_reg_off =
+ TOKEN_NUM_INITIALIZER(struct cmd_write_reg_bit_result, reg_off, UINT32);
+cmdline_parse_token_num_t cmd_write_reg_bit_bit_pos =
+ TOKEN_NUM_INITIALIZER(struct cmd_write_reg_bit_result, bit_pos, UINT8);
+cmdline_parse_token_num_t cmd_write_reg_bit_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_write_reg_bit_result, value, UINT8);
+
+cmdline_parse_inst_t cmd_write_reg_bit = {
+ .f = cmd_write_reg_bit_parsed,
+ .data = NULL,
+ .help_str = "write regbit <port_id> <reg_off> <bit_x> 0|1: "
+ "0 <= bit_x <= 31",
+ .tokens = {
+ (void *)&cmd_write_reg_bit_write,
+ (void *)&cmd_write_reg_bit_regbit,
+ (void *)&cmd_write_reg_bit_port_id,
+ (void *)&cmd_write_reg_bit_reg_off,
+ (void *)&cmd_write_reg_bit_bit_pos,
+ (void *)&cmd_write_reg_bit_value,
+ NULL,
+ },
+};
+
+/* *** READ A RING DESCRIPTOR OF A PORT RX/TX QUEUE *** */
+struct cmd_read_rxd_txd_result {
+ cmdline_fixed_string_t read;
+ cmdline_fixed_string_t rxd_txd;
+ portid_t port_id;
+ uint16_t queue_id;
+ uint16_t desc_id;
+};
+
+static void
+cmd_read_rxd_txd_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_read_rxd_txd_result *res = parsed_result;
+
+ if (!strcmp(res->rxd_txd, "rxd"))
+ rx_ring_desc_display(res->port_id, res->queue_id, res->desc_id);
+ else if (!strcmp(res->rxd_txd, "txd"))
+ tx_ring_desc_display(res->port_id, res->queue_id, res->desc_id);
+}
+
+cmdline_parse_token_string_t cmd_read_rxd_txd_read =
+ TOKEN_STRING_INITIALIZER(struct cmd_read_rxd_txd_result, read, "read");
+cmdline_parse_token_string_t cmd_read_rxd_txd_rxd_txd =
+ TOKEN_STRING_INITIALIZER(struct cmd_read_rxd_txd_result, rxd_txd,
+ "rxd#txd");
+cmdline_parse_token_num_t cmd_read_rxd_txd_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_read_rxd_txd_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_read_rxd_txd_queue_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_read_rxd_txd_result, queue_id, UINT16);
+cmdline_parse_token_num_t cmd_read_rxd_txd_desc_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_read_rxd_txd_result, desc_id, UINT16);
+
+cmdline_parse_inst_t cmd_read_rxd_txd = {
+ .f = cmd_read_rxd_txd_parsed,
+ .data = NULL,
+ .help_str = "read rxd|txd <port_id> <queue_id> <desc_id>",
+ .tokens = {
+ (void *)&cmd_read_rxd_txd_read,
+ (void *)&cmd_read_rxd_txd_rxd_txd,
+ (void *)&cmd_read_rxd_txd_port_id,
+ (void *)&cmd_read_rxd_txd_queue_id,
+ (void *)&cmd_read_rxd_txd_desc_id,
+ NULL,
+ },
+};
+
+/* *** QUIT *** */
+struct cmd_quit_result {
+ cmdline_fixed_string_t quit;
+};
+
+static void cmd_quit_parsed(__rte_unused void *parsed_result,
+ struct cmdline *cl,
+ __rte_unused void *data)
+{
+ cmdline_quit(cl);
+}
+
+cmdline_parse_token_string_t cmd_quit_quit =
+ TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
+
+cmdline_parse_inst_t cmd_quit = {
+ .f = cmd_quit_parsed,
+ .data = NULL,
+ .help_str = "quit: Exit application",
+ .tokens = {
+ (void *)&cmd_quit_quit,
+ NULL,
+ },
+};
+
+/* *** ADD/REMOVE MAC ADDRESS FROM A PORT *** */
+struct cmd_mac_addr_result {
+ cmdline_fixed_string_t mac_addr_cmd;
+ cmdline_fixed_string_t what;
+ uint16_t port_num;
+ struct rte_ether_addr address;
+};
+
+static void cmd_mac_addr_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_mac_addr_result *res = parsed_result;
+ int ret;
+
+ if (strcmp(res->what, "add") == 0)
+ ret = rte_eth_dev_mac_addr_add(res->port_num, &res->address, 0);
+ else if (strcmp(res->what, "set") == 0)
+ ret = rte_eth_dev_default_mac_addr_set(res->port_num,
+ &res->address);
+ else
+ ret = rte_eth_dev_mac_addr_remove(res->port_num, &res->address);
+
+ /* check the return value and print it if is < 0 */
+ if(ret < 0)
+ printf("mac_addr_cmd error: (%s)\n", strerror(-ret));
+
+}
+
+cmdline_parse_token_string_t cmd_mac_addr_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_mac_addr_result, mac_addr_cmd,
+ "mac_addr");
+cmdline_parse_token_string_t cmd_mac_addr_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_mac_addr_result, what,
+ "add#remove#set");
+cmdline_parse_token_num_t cmd_mac_addr_portnum =
+ TOKEN_NUM_INITIALIZER(struct cmd_mac_addr_result, port_num,
+ UINT16);
+cmdline_parse_token_etheraddr_t cmd_mac_addr_addr =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_mac_addr_result, address);
+
+cmdline_parse_inst_t cmd_mac_addr = {
+ .f = cmd_mac_addr_parsed,
+ .data = (void *)0,
+ .help_str = "mac_addr add|remove|set <port_id> <mac_addr>: "
+ "Add/Remove/Set MAC address on port_id",
+ .tokens = {
+ (void *)&cmd_mac_addr_cmd,
+ (void *)&cmd_mac_addr_what,
+ (void *)&cmd_mac_addr_portnum,
+ (void *)&cmd_mac_addr_addr,
+ NULL,
+ },
+};
+
+/* *** SET THE PEER ADDRESS FOR CERTAIN PORT *** */
+struct cmd_eth_peer_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t eth_peer;
+ portid_t port_id;
+ cmdline_fixed_string_t peer_addr;
+};
+
+static void cmd_set_eth_peer_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_eth_peer_result *res = parsed_result;
+
+ if (test_done == 0) {
+ printf("Please stop forwarding first\n");
+ return;
+ }
+ if (!strcmp(res->eth_peer, "eth-peer")) {
+ set_fwd_eth_peer(res->port_id, res->peer_addr);
+ fwd_config_setup();
+ }
+}
+cmdline_parse_token_string_t cmd_eth_peer_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_eth_peer_result, set, "set");
+cmdline_parse_token_string_t cmd_eth_peer =
+ TOKEN_STRING_INITIALIZER(struct cmd_eth_peer_result, eth_peer, "eth-peer");
+cmdline_parse_token_num_t cmd_eth_peer_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_eth_peer_result, port_id, UINT16);
+cmdline_parse_token_string_t cmd_eth_peer_addr =
+ TOKEN_STRING_INITIALIZER(struct cmd_eth_peer_result, peer_addr, NULL);
+
+cmdline_parse_inst_t cmd_set_fwd_eth_peer = {
+ .f = cmd_set_eth_peer_parsed,
+ .data = NULL,
+ .help_str = "set eth-peer <port_id> <peer_mac>",
+ .tokens = {
+ (void *)&cmd_eth_peer_set,
+ (void *)&cmd_eth_peer,
+ (void *)&cmd_eth_peer_port_id,
+ (void *)&cmd_eth_peer_addr,
+ NULL,
+ },
+};
+
+/* *** CONFIGURE QUEUE STATS COUNTER MAPPINGS *** */
+struct cmd_set_qmap_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t qmap;
+ cmdline_fixed_string_t what;
+ portid_t port_id;
+ uint16_t queue_id;
+ uint8_t map_value;
+};
+
+static void
+cmd_set_qmap_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_qmap_result *res = parsed_result;
+ int is_rx = (strcmp(res->what, "tx") == 0) ? 0 : 1;
+
+ set_qmap(res->port_id, (uint8_t)is_rx, res->queue_id, res->map_value);
+}
+
+cmdline_parse_token_string_t cmd_setqmap_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_qmap_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_setqmap_qmap =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_qmap_result,
+ qmap, "stat_qmap");
+cmdline_parse_token_string_t cmd_setqmap_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_qmap_result,
+ what, "tx#rx");
+cmdline_parse_token_num_t cmd_setqmap_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_qmap_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_setqmap_queueid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_qmap_result,
+ queue_id, UINT16);
+cmdline_parse_token_num_t cmd_setqmap_mapvalue =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_qmap_result,
+ map_value, UINT8);
+
+cmdline_parse_inst_t cmd_set_qmap = {
+ .f = cmd_set_qmap_parsed,
+ .data = NULL,
+ .help_str = "set stat_qmap rx|tx <port_id> <queue_id> <map_value>: "
+ "Set statistics mapping value on tx|rx queue_id of port_id",
+ .tokens = {
+ (void *)&cmd_setqmap_set,
+ (void *)&cmd_setqmap_qmap,
+ (void *)&cmd_setqmap_what,
+ (void *)&cmd_setqmap_portid,
+ (void *)&cmd_setqmap_queueid,
+ (void *)&cmd_setqmap_mapvalue,
+ NULL,
+ },
+};
+
+/* *** SET OPTION TO HIDE ZERO VALUES FOR XSTATS DISPLAY *** */
+struct cmd_set_xstats_hide_zero_result {
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t name;
+ cmdline_fixed_string_t on_off;
+};
+
+static void
+cmd_set_xstats_hide_zero_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_xstats_hide_zero_result *res;
+ uint16_t on_off = 0;
+
+ res = parsed_result;
+ on_off = !strcmp(res->on_off, "on") ? 1 : 0;
+ set_xstats_hide_zero(on_off);
+}
+
+cmdline_parse_token_string_t cmd_set_xstats_hide_zero_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_xstats_hide_zero_result,
+ keyword, "set");
+cmdline_parse_token_string_t cmd_set_xstats_hide_zero_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_xstats_hide_zero_result,
+ name, "xstats-hide-zero");
+cmdline_parse_token_string_t cmd_set_xstats_hide_zero_on_off =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_xstats_hide_zero_result,
+ on_off, "on#off");
+
+cmdline_parse_inst_t cmd_set_xstats_hide_zero = {
+ .f = cmd_set_xstats_hide_zero_parsed,
+ .data = NULL,
+ .help_str = "set xstats-hide-zero on|off",
+ .tokens = {
+ (void *)&cmd_set_xstats_hide_zero_keyword,
+ (void *)&cmd_set_xstats_hide_zero_name,
+ (void *)&cmd_set_xstats_hide_zero_on_off,
+ NULL,
+ },
+};
+
+/* *** CONFIGURE UNICAST HASH TABLE *** */
+struct cmd_set_uc_hash_table {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t what;
+ struct rte_ether_addr address;
+ cmdline_fixed_string_t mode;
+};
+
+static void
+cmd_set_uc_hash_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ int ret=0;
+ struct cmd_set_uc_hash_table *res = parsed_result;
+
+ int is_on = (strcmp(res->mode, "on") == 0) ? 1 : 0;
+
+ if (strcmp(res->what, "uta") == 0)
+ ret = rte_eth_dev_uc_hash_table_set(res->port_id,
+ &res->address,(uint8_t)is_on);
+ if (ret < 0)
+ printf("bad unicast hash table parameter, return code = %d \n", ret);
+
+}
+
+cmdline_parse_token_string_t cmd_set_uc_hash_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_uc_hash_table,
+ set, "set");
+cmdline_parse_token_string_t cmd_set_uc_hash_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_uc_hash_table,
+ port, "port");
+cmdline_parse_token_num_t cmd_set_uc_hash_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_uc_hash_table,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_set_uc_hash_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_uc_hash_table,
+ what, "uta");
+cmdline_parse_token_etheraddr_t cmd_set_uc_hash_mac =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_uc_hash_table,
+ address);
+cmdline_parse_token_string_t cmd_set_uc_hash_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_uc_hash_table,
+ mode, "on#off");
+
+cmdline_parse_inst_t cmd_set_uc_hash_filter = {
+ .f = cmd_set_uc_hash_parsed,
+ .data = NULL,
+ .help_str = "set port <port_id> uta <mac_addr> on|off)",
+ .tokens = {
+ (void *)&cmd_set_uc_hash_set,
+ (void *)&cmd_set_uc_hash_port,
+ (void *)&cmd_set_uc_hash_portid,
+ (void *)&cmd_set_uc_hash_what,
+ (void *)&cmd_set_uc_hash_mac,
+ (void *)&cmd_set_uc_hash_mode,
+ NULL,
+ },
+};
+
+struct cmd_set_uc_all_hash_table {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t what;
+ cmdline_fixed_string_t value;
+ cmdline_fixed_string_t mode;
+};
+
+static void
+cmd_set_uc_all_hash_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ int ret=0;
+ struct cmd_set_uc_all_hash_table *res = parsed_result;
+
+ int is_on = (strcmp(res->mode, "on") == 0) ? 1 : 0;
+
+ if ((strcmp(res->what, "uta") == 0) &&
+ (strcmp(res->value, "all") == 0))
+ ret = rte_eth_dev_uc_all_hash_table_set(res->port_id,(uint8_t) is_on);
+ if (ret < 0)
+ printf("bad unicast hash table parameter,"
+ "return code = %d \n", ret);
+}
+
+cmdline_parse_token_string_t cmd_set_uc_all_hash_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_uc_all_hash_table,
+ set, "set");
+cmdline_parse_token_string_t cmd_set_uc_all_hash_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_uc_all_hash_table,
+ port, "port");
+cmdline_parse_token_num_t cmd_set_uc_all_hash_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_uc_all_hash_table,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_set_uc_all_hash_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_uc_all_hash_table,
+ what, "uta");
+cmdline_parse_token_string_t cmd_set_uc_all_hash_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_uc_all_hash_table,
+ value,"all");
+cmdline_parse_token_string_t cmd_set_uc_all_hash_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_uc_all_hash_table,
+ mode, "on#off");
+
+cmdline_parse_inst_t cmd_set_uc_all_hash_filter = {
+ .f = cmd_set_uc_all_hash_parsed,
+ .data = NULL,
+ .help_str = "set port <port_id> uta all on|off",
+ .tokens = {
+ (void *)&cmd_set_uc_all_hash_set,
+ (void *)&cmd_set_uc_all_hash_port,
+ (void *)&cmd_set_uc_all_hash_portid,
+ (void *)&cmd_set_uc_all_hash_what,
+ (void *)&cmd_set_uc_all_hash_value,
+ (void *)&cmd_set_uc_all_hash_mode,
+ NULL,
+ },
+};
+
+/* *** CONFIGURE MACVLAN FILTER FOR VF(s) *** */
+struct cmd_set_vf_macvlan_filter {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t vf;
+ uint8_t vf_id;
+ struct rte_ether_addr address;
+ cmdline_fixed_string_t filter_type;
+ cmdline_fixed_string_t mode;
+};
+
+static void
+cmd_set_vf_macvlan_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ int is_on, ret = 0;
+ struct cmd_set_vf_macvlan_filter *res = parsed_result;
+ struct rte_eth_mac_filter filter;
+
+ memset(&filter, 0, sizeof(struct rte_eth_mac_filter));
+
+ rte_memcpy(&filter.mac_addr, &res->address, RTE_ETHER_ADDR_LEN);
+
+ /* set VF MAC filter */
+ filter.is_vf = 1;
+
+ /* set VF ID */
+ filter.dst_id = res->vf_id;
+
+ if (!strcmp(res->filter_type, "exact-mac"))
+ filter.filter_type = RTE_MAC_PERFECT_MATCH;
+ else if (!strcmp(res->filter_type, "exact-mac-vlan"))
+ filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
+ else if (!strcmp(res->filter_type, "hashmac"))
+ filter.filter_type = RTE_MAC_HASH_MATCH;
+ else if (!strcmp(res->filter_type, "hashmac-vlan"))
+ filter.filter_type = RTE_MACVLAN_HASH_MATCH;
+
+ is_on = (strcmp(res->mode, "on") == 0) ? 1 : 0;
+
+ if (is_on)
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_MACVLAN,
+ RTE_ETH_FILTER_ADD,
+ &filter);
+ else
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_MACVLAN,
+ RTE_ETH_FILTER_DELETE,
+ &filter);
+
+ if (ret < 0)
+ printf("bad set MAC hash parameter, return code = %d\n", ret);
+
+}
+
+cmdline_parse_token_string_t cmd_set_vf_macvlan_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_macvlan_filter,
+ set, "set");
+cmdline_parse_token_string_t cmd_set_vf_macvlan_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_macvlan_filter,
+ port, "port");
+cmdline_parse_token_num_t cmd_set_vf_macvlan_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_vf_macvlan_filter,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_set_vf_macvlan_vf =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_macvlan_filter,
+ vf, "vf");
+cmdline_parse_token_num_t cmd_set_vf_macvlan_vf_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_vf_macvlan_filter,
+ vf_id, UINT8);
+cmdline_parse_token_etheraddr_t cmd_set_vf_macvlan_mac =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_vf_macvlan_filter,
+ address);
+cmdline_parse_token_string_t cmd_set_vf_macvlan_filter_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_macvlan_filter,
+ filter_type, "exact-mac#exact-mac-vlan"
+ "#hashmac#hashmac-vlan");
+cmdline_parse_token_string_t cmd_set_vf_macvlan_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_macvlan_filter,
+ mode, "on#off");
+
+cmdline_parse_inst_t cmd_set_vf_macvlan_filter = {
+ .f = cmd_set_vf_macvlan_parsed,
+ .data = NULL,
+ .help_str = "set port <port_id> vf <vf_id> <mac_addr> "
+ "exact-mac|exact-mac-vlan|hashmac|hashmac-vlan on|off: "
+ "Exact match rule: exact match of MAC or MAC and VLAN; "
+ "hash match rule: hash match of MAC and exact match of VLAN",
+ .tokens = {
+ (void *)&cmd_set_vf_macvlan_set,
+ (void *)&cmd_set_vf_macvlan_port,
+ (void *)&cmd_set_vf_macvlan_portid,
+ (void *)&cmd_set_vf_macvlan_vf,
+ (void *)&cmd_set_vf_macvlan_vf_id,
+ (void *)&cmd_set_vf_macvlan_mac,
+ (void *)&cmd_set_vf_macvlan_filter_type,
+ (void *)&cmd_set_vf_macvlan_mode,
+ NULL,
+ },
+};
+
+/* *** CONFIGURE VF TRAFFIC CONTROL *** */
+struct cmd_set_vf_traffic {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t vf;
+ uint8_t vf_id;
+ cmdline_fixed_string_t what;
+ cmdline_fixed_string_t mode;
+};
+
+static void
+cmd_set_vf_traffic_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_vf_traffic *res = parsed_result;
+ int is_rx = (strcmp(res->what, "rx") == 0) ? 1 : 0;
+ int is_on = (strcmp(res->mode, "on") == 0) ? 1 : 0;
+
+ set_vf_traffic(res->port_id, (uint8_t)is_rx, res->vf_id,(uint8_t) is_on);
+}
+
+cmdline_parse_token_string_t cmd_setvf_traffic_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_traffic,
+ set, "set");
+cmdline_parse_token_string_t cmd_setvf_traffic_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_traffic,
+ port, "port");
+cmdline_parse_token_num_t cmd_setvf_traffic_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_vf_traffic,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_setvf_traffic_vf =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_traffic,
+ vf, "vf");
+cmdline_parse_token_num_t cmd_setvf_traffic_vfid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_vf_traffic,
+ vf_id, UINT8);
+cmdline_parse_token_string_t cmd_setvf_traffic_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_traffic,
+ what, "tx#rx");
+cmdline_parse_token_string_t cmd_setvf_traffic_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_traffic,
+ mode, "on#off");
+
+cmdline_parse_inst_t cmd_set_vf_traffic = {
+ .f = cmd_set_vf_traffic_parsed,
+ .data = NULL,
+ .help_str = "set port <port_id> vf <vf_id> rx|tx on|off",
+ .tokens = {
+ (void *)&cmd_setvf_traffic_set,
+ (void *)&cmd_setvf_traffic_port,
+ (void *)&cmd_setvf_traffic_portid,
+ (void *)&cmd_setvf_traffic_vf,
+ (void *)&cmd_setvf_traffic_vfid,
+ (void *)&cmd_setvf_traffic_what,
+ (void *)&cmd_setvf_traffic_mode,
+ NULL,
+ },
+};
+
+/* *** CONFIGURE VF RECEIVE MODE *** */
+struct cmd_set_vf_rxmode {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t vf;
+ uint8_t vf_id;
+ cmdline_fixed_string_t what;
+ cmdline_fixed_string_t mode;
+ cmdline_fixed_string_t on;
+};
+
+static void
+cmd_set_vf_rxmode_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ int ret = -ENOTSUP;
+ uint16_t vf_rxmode = 0;
+ struct cmd_set_vf_rxmode *res = parsed_result;
+
+ int is_on = (strcmp(res->on, "on") == 0) ? 1 : 0;
+ if (!strcmp(res->what,"rxmode")) {
+ if (!strcmp(res->mode, "AUPE"))
+ vf_rxmode |= ETH_VMDQ_ACCEPT_UNTAG;
+ else if (!strcmp(res->mode, "ROPE"))
+ vf_rxmode |= ETH_VMDQ_ACCEPT_HASH_UC;
+ else if (!strcmp(res->mode, "BAM"))
+ vf_rxmode |= ETH_VMDQ_ACCEPT_BROADCAST;
+ else if (!strncmp(res->mode, "MPE",3))
+ vf_rxmode |= ETH_VMDQ_ACCEPT_MULTICAST;
+ }
+
+ RTE_SET_USED(is_on);
+
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_ixgbe_set_vf_rxmode(res->port_id, res->vf_id,
+ vf_rxmode, (uint8_t)is_on);
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_bnxt_set_vf_rxmode(res->port_id, res->vf_id,
+ vf_rxmode, (uint8_t)is_on);
+#endif
+ if (ret < 0)
+ printf("bad VF receive mode parameter, return code = %d \n",
+ ret);
+}
+
+cmdline_parse_token_string_t cmd_set_vf_rxmode_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_rxmode,
+ set, "set");
+cmdline_parse_token_string_t cmd_set_vf_rxmode_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_rxmode,
+ port, "port");
+cmdline_parse_token_num_t cmd_set_vf_rxmode_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_vf_rxmode,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_set_vf_rxmode_vf =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_rxmode,
+ vf, "vf");
+cmdline_parse_token_num_t cmd_set_vf_rxmode_vfid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_vf_rxmode,
+ vf_id, UINT8);
+cmdline_parse_token_string_t cmd_set_vf_rxmode_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_rxmode,
+ what, "rxmode");
+cmdline_parse_token_string_t cmd_set_vf_rxmode_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_rxmode,
+ mode, "AUPE#ROPE#BAM#MPE");
+cmdline_parse_token_string_t cmd_set_vf_rxmode_on =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vf_rxmode,
+ on, "on#off");
+
+cmdline_parse_inst_t cmd_set_vf_rxmode = {
+ .f = cmd_set_vf_rxmode_parsed,
+ .data = NULL,
+ .help_str = "set port <port_id> vf <vf_id> rxmode "
+ "AUPE|ROPE|BAM|MPE on|off",
+ .tokens = {
+ (void *)&cmd_set_vf_rxmode_set,
+ (void *)&cmd_set_vf_rxmode_port,
+ (void *)&cmd_set_vf_rxmode_portid,
+ (void *)&cmd_set_vf_rxmode_vf,
+ (void *)&cmd_set_vf_rxmode_vfid,
+ (void *)&cmd_set_vf_rxmode_what,
+ (void *)&cmd_set_vf_rxmode_mode,
+ (void *)&cmd_set_vf_rxmode_on,
+ NULL,
+ },
+};
+
+/* *** ADD MAC ADDRESS FILTER FOR A VF OF A PORT *** */
+struct cmd_vf_mac_addr_result {
+ cmdline_fixed_string_t mac_addr_cmd;
+ cmdline_fixed_string_t what;
+ cmdline_fixed_string_t port;
+ uint16_t port_num;
+ cmdline_fixed_string_t vf;
+ uint8_t vf_num;
+ struct rte_ether_addr address;
+};
+
+static void cmd_vf_mac_addr_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_mac_addr_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ if (strcmp(res->what, "add") != 0)
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_i40e_add_vf_mac_addr(res->port_num, res->vf_num,
+ &res->address);
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_bnxt_mac_addr_add(res->port_num, &res->address,
+ res->vf_num);
+#endif
+
+ if(ret < 0)
+ printf("vf_mac_addr_cmd error: (%s)\n", strerror(-ret));
+
+}
+
+cmdline_parse_token_string_t cmd_vf_mac_addr_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_vf_mac_addr_result,
+ mac_addr_cmd,"mac_addr");
+cmdline_parse_token_string_t cmd_vf_mac_addr_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_vf_mac_addr_result,
+ what,"add");
+cmdline_parse_token_string_t cmd_vf_mac_addr_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_vf_mac_addr_result,
+ port,"port");
+cmdline_parse_token_num_t cmd_vf_mac_addr_portnum =
+ TOKEN_NUM_INITIALIZER(struct cmd_vf_mac_addr_result,
+ port_num, UINT16);
+cmdline_parse_token_string_t cmd_vf_mac_addr_vf =
+ TOKEN_STRING_INITIALIZER(struct cmd_vf_mac_addr_result,
+ vf,"vf");
+cmdline_parse_token_num_t cmd_vf_mac_addr_vfnum =
+ TOKEN_NUM_INITIALIZER(struct cmd_vf_mac_addr_result,
+ vf_num, UINT8);
+cmdline_parse_token_etheraddr_t cmd_vf_mac_addr_addr =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_vf_mac_addr_result,
+ address);
+
+cmdline_parse_inst_t cmd_vf_mac_addr_filter = {
+ .f = cmd_vf_mac_addr_parsed,
+ .data = (void *)0,
+ .help_str = "mac_addr add port <port_id> vf <vf_id> <mac_addr>: "
+ "Add MAC address filtering for a VF on port_id",
+ .tokens = {
+ (void *)&cmd_vf_mac_addr_cmd,
+ (void *)&cmd_vf_mac_addr_what,
+ (void *)&cmd_vf_mac_addr_port,
+ (void *)&cmd_vf_mac_addr_portnum,
+ (void *)&cmd_vf_mac_addr_vf,
+ (void *)&cmd_vf_mac_addr_vfnum,
+ (void *)&cmd_vf_mac_addr_addr,
+ NULL,
+ },
+};
+
+/* *** ADD/REMOVE A VLAN IDENTIFIER TO/FROM A PORT VLAN RX FILTER *** */
+struct cmd_vf_rx_vlan_filter {
+ cmdline_fixed_string_t rx_vlan;
+ cmdline_fixed_string_t what;
+ uint16_t vlan_id;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t vf;
+ uint64_t vf_mask;
+};
+
+static void
+cmd_vf_rx_vlan_filter_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_rx_vlan_filter *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ __rte_unused int is_add = (strcmp(res->what, "add") == 0) ? 1 : 0;
+
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_ixgbe_set_vf_vlan_filter(res->port_id,
+ res->vlan_id, res->vf_mask, is_add);
+#endif
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_i40e_set_vf_vlan_filter(res->port_id,
+ res->vlan_id, res->vf_mask, is_add);
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_bnxt_set_vf_vlan_filter(res->port_id,
+ res->vlan_id, res->vf_mask, is_add);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vlan_id %d or vf_mask %"PRIu64"\n",
+ res->vlan_id, res->vf_mask);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented or supported\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_token_string_t cmd_vf_rx_vlan_filter_rx_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_vf_rx_vlan_filter,
+ rx_vlan, "rx_vlan");
+cmdline_parse_token_string_t cmd_vf_rx_vlan_filter_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_vf_rx_vlan_filter,
+ what, "add#rm");
+cmdline_parse_token_num_t cmd_vf_rx_vlan_filter_vlanid =
+ TOKEN_NUM_INITIALIZER(struct cmd_vf_rx_vlan_filter,
+ vlan_id, UINT16);
+cmdline_parse_token_string_t cmd_vf_rx_vlan_filter_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_vf_rx_vlan_filter,
+ port, "port");
+cmdline_parse_token_num_t cmd_vf_rx_vlan_filter_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_vf_rx_vlan_filter,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_vf_rx_vlan_filter_vf =
+ TOKEN_STRING_INITIALIZER(struct cmd_vf_rx_vlan_filter,
+ vf, "vf");
+cmdline_parse_token_num_t cmd_vf_rx_vlan_filter_vf_mask =
+ TOKEN_NUM_INITIALIZER(struct cmd_vf_rx_vlan_filter,
+ vf_mask, UINT64);
+
+cmdline_parse_inst_t cmd_vf_rxvlan_filter = {
+ .f = cmd_vf_rx_vlan_filter_parsed,
+ .data = NULL,
+ .help_str = "rx_vlan add|rm <vlan_id> port <port_id> vf <vf_mask>: "
+ "(vf_mask = hexadecimal VF mask)",
+ .tokens = {
+ (void *)&cmd_vf_rx_vlan_filter_rx_vlan,
+ (void *)&cmd_vf_rx_vlan_filter_what,
+ (void *)&cmd_vf_rx_vlan_filter_vlanid,
+ (void *)&cmd_vf_rx_vlan_filter_port,
+ (void *)&cmd_vf_rx_vlan_filter_portid,
+ (void *)&cmd_vf_rx_vlan_filter_vf,
+ (void *)&cmd_vf_rx_vlan_filter_vf_mask,
+ NULL,
+ },
+};
+
+/* *** SET RATE LIMIT FOR A QUEUE OF A PORT *** */
+struct cmd_queue_rate_limit_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ uint16_t port_num;
+ cmdline_fixed_string_t queue;
+ uint8_t queue_num;
+ cmdline_fixed_string_t rate;
+ uint16_t rate_num;
+};
+
+static void cmd_queue_rate_limit_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_queue_rate_limit_result *res = parsed_result;
+ int ret = 0;
+
+ if ((strcmp(res->set, "set") == 0) && (strcmp(res->port, "port") == 0)
+ && (strcmp(res->queue, "queue") == 0)
+ && (strcmp(res->rate, "rate") == 0))
+ ret = set_queue_rate_limit(res->port_num, res->queue_num,
+ res->rate_num);
+ if (ret < 0)
+ printf("queue_rate_limit_cmd error: (%s)\n", strerror(-ret));
+
+}
+
+cmdline_parse_token_string_t cmd_queue_rate_limit_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_queue_rate_limit_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_queue_rate_limit_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_queue_rate_limit_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_queue_rate_limit_portnum =
+ TOKEN_NUM_INITIALIZER(struct cmd_queue_rate_limit_result,
+ port_num, UINT16);
+cmdline_parse_token_string_t cmd_queue_rate_limit_queue =
+ TOKEN_STRING_INITIALIZER(struct cmd_queue_rate_limit_result,
+ queue, "queue");
+cmdline_parse_token_num_t cmd_queue_rate_limit_queuenum =
+ TOKEN_NUM_INITIALIZER(struct cmd_queue_rate_limit_result,
+ queue_num, UINT8);
+cmdline_parse_token_string_t cmd_queue_rate_limit_rate =
+ TOKEN_STRING_INITIALIZER(struct cmd_queue_rate_limit_result,
+ rate, "rate");
+cmdline_parse_token_num_t cmd_queue_rate_limit_ratenum =
+ TOKEN_NUM_INITIALIZER(struct cmd_queue_rate_limit_result,
+ rate_num, UINT16);
+
+cmdline_parse_inst_t cmd_queue_rate_limit = {
+ .f = cmd_queue_rate_limit_parsed,
+ .data = (void *)0,
+ .help_str = "set port <port_id> queue <queue_id> rate <rate_value>: "
+ "Set rate limit for a queue on port_id",
+ .tokens = {
+ (void *)&cmd_queue_rate_limit_set,
+ (void *)&cmd_queue_rate_limit_port,
+ (void *)&cmd_queue_rate_limit_portnum,
+ (void *)&cmd_queue_rate_limit_queue,
+ (void *)&cmd_queue_rate_limit_queuenum,
+ (void *)&cmd_queue_rate_limit_rate,
+ (void *)&cmd_queue_rate_limit_ratenum,
+ NULL,
+ },
+};
+
+/* *** SET RATE LIMIT FOR A VF OF A PORT *** */
+struct cmd_vf_rate_limit_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ uint16_t port_num;
+ cmdline_fixed_string_t vf;
+ uint8_t vf_num;
+ cmdline_fixed_string_t rate;
+ uint16_t rate_num;
+ cmdline_fixed_string_t q_msk;
+ uint64_t q_msk_val;
+};
+
+static void cmd_vf_rate_limit_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_rate_limit_result *res = parsed_result;
+ int ret = 0;
+
+ if ((strcmp(res->set, "set") == 0) && (strcmp(res->port, "port") == 0)
+ && (strcmp(res->vf, "vf") == 0)
+ && (strcmp(res->rate, "rate") == 0)
+ && (strcmp(res->q_msk, "queue_mask") == 0))
+ ret = set_vf_rate_limit(res->port_num, res->vf_num,
+ res->rate_num, res->q_msk_val);
+ if (ret < 0)
+ printf("vf_rate_limit_cmd error: (%s)\n", strerror(-ret));
+
+}
+
+cmdline_parse_token_string_t cmd_vf_rate_limit_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_vf_rate_limit_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_vf_rate_limit_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_vf_rate_limit_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_vf_rate_limit_portnum =
+ TOKEN_NUM_INITIALIZER(struct cmd_vf_rate_limit_result,
+ port_num, UINT16);
+cmdline_parse_token_string_t cmd_vf_rate_limit_vf =
+ TOKEN_STRING_INITIALIZER(struct cmd_vf_rate_limit_result,
+ vf, "vf");
+cmdline_parse_token_num_t cmd_vf_rate_limit_vfnum =
+ TOKEN_NUM_INITIALIZER(struct cmd_vf_rate_limit_result,
+ vf_num, UINT8);
+cmdline_parse_token_string_t cmd_vf_rate_limit_rate =
+ TOKEN_STRING_INITIALIZER(struct cmd_vf_rate_limit_result,
+ rate, "rate");
+cmdline_parse_token_num_t cmd_vf_rate_limit_ratenum =
+ TOKEN_NUM_INITIALIZER(struct cmd_vf_rate_limit_result,
+ rate_num, UINT16);
+cmdline_parse_token_string_t cmd_vf_rate_limit_q_msk =
+ TOKEN_STRING_INITIALIZER(struct cmd_vf_rate_limit_result,
+ q_msk, "queue_mask");
+cmdline_parse_token_num_t cmd_vf_rate_limit_q_msk_val =
+ TOKEN_NUM_INITIALIZER(struct cmd_vf_rate_limit_result,
+ q_msk_val, UINT64);
+
+cmdline_parse_inst_t cmd_vf_rate_limit = {
+ .f = cmd_vf_rate_limit_parsed,
+ .data = (void *)0,
+ .help_str = "set port <port_id> vf <vf_id> rate <rate_value> "
+ "queue_mask <queue_mask_value>: "
+ "Set rate limit for queues of VF on port_id",
+ .tokens = {
+ (void *)&cmd_vf_rate_limit_set,
+ (void *)&cmd_vf_rate_limit_port,
+ (void *)&cmd_vf_rate_limit_portnum,
+ (void *)&cmd_vf_rate_limit_vf,
+ (void *)&cmd_vf_rate_limit_vfnum,
+ (void *)&cmd_vf_rate_limit_rate,
+ (void *)&cmd_vf_rate_limit_ratenum,
+ (void *)&cmd_vf_rate_limit_q_msk,
+ (void *)&cmd_vf_rate_limit_q_msk_val,
+ NULL,
+ },
+};
+
+/* *** ADD TUNNEL FILTER OF A PORT *** */
+struct cmd_tunnel_filter_result {
+ cmdline_fixed_string_t cmd;
+ cmdline_fixed_string_t what;
+ portid_t port_id;
+ struct rte_ether_addr outer_mac;
+ struct rte_ether_addr inner_mac;
+ cmdline_ipaddr_t ip_value;
+ uint16_t inner_vlan;
+ cmdline_fixed_string_t tunnel_type;
+ cmdline_fixed_string_t filter_type;
+ uint32_t tenant_id;
+ uint16_t queue_num;
+};
+
+static void
+cmd_tunnel_filter_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_tunnel_filter_result *res = parsed_result;
+ struct rte_eth_tunnel_filter_conf tunnel_filter_conf;
+ int ret = 0;
+
+ memset(&tunnel_filter_conf, 0, sizeof(tunnel_filter_conf));
+
+ rte_ether_addr_copy(&res->outer_mac, &tunnel_filter_conf.outer_mac);
+ rte_ether_addr_copy(&res->inner_mac, &tunnel_filter_conf.inner_mac);
+ tunnel_filter_conf.inner_vlan = res->inner_vlan;
+
+ if (res->ip_value.family == AF_INET) {
+ tunnel_filter_conf.ip_addr.ipv4_addr =
+ res->ip_value.addr.ipv4.s_addr;
+ tunnel_filter_conf.ip_type = RTE_TUNNEL_IPTYPE_IPV4;
+ } else {
+ memcpy(&(tunnel_filter_conf.ip_addr.ipv6_addr),
+ &(res->ip_value.addr.ipv6),
+ sizeof(struct in6_addr));
+ tunnel_filter_conf.ip_type = RTE_TUNNEL_IPTYPE_IPV6;
+ }
+
+ if (!strcmp(res->filter_type, "imac-ivlan"))
+ tunnel_filter_conf.filter_type = RTE_TUNNEL_FILTER_IMAC_IVLAN;
+ else if (!strcmp(res->filter_type, "imac-ivlan-tenid"))
+ tunnel_filter_conf.filter_type =
+ RTE_TUNNEL_FILTER_IMAC_IVLAN_TENID;
+ else if (!strcmp(res->filter_type, "imac-tenid"))
+ tunnel_filter_conf.filter_type = RTE_TUNNEL_FILTER_IMAC_TENID;
+ else if (!strcmp(res->filter_type, "imac"))
+ tunnel_filter_conf.filter_type = ETH_TUNNEL_FILTER_IMAC;
+ else if (!strcmp(res->filter_type, "omac-imac-tenid"))
+ tunnel_filter_conf.filter_type =
+ RTE_TUNNEL_FILTER_OMAC_TENID_IMAC;
+ else if (!strcmp(res->filter_type, "oip"))
+ tunnel_filter_conf.filter_type = ETH_TUNNEL_FILTER_OIP;
+ else if (!strcmp(res->filter_type, "iip"))
+ tunnel_filter_conf.filter_type = ETH_TUNNEL_FILTER_IIP;
+ else {
+ printf("The filter type is not supported");
+ return;
+ }
+
+ if (!strcmp(res->tunnel_type, "vxlan"))
+ tunnel_filter_conf.tunnel_type = RTE_TUNNEL_TYPE_VXLAN;
+ else if (!strcmp(res->tunnel_type, "vxlan-gpe"))
+ tunnel_filter_conf.tunnel_type = RTE_TUNNEL_TYPE_VXLAN_GPE;
+ else if (!strcmp(res->tunnel_type, "nvgre"))
+ tunnel_filter_conf.tunnel_type = RTE_TUNNEL_TYPE_NVGRE;
+ else if (!strcmp(res->tunnel_type, "ipingre"))
+ tunnel_filter_conf.tunnel_type = RTE_TUNNEL_TYPE_IP_IN_GRE;
+ else {
+ printf("The tunnel type %s not supported.\n", res->tunnel_type);
+ return;
+ }
+
+ tunnel_filter_conf.tenant_id = res->tenant_id;
+ tunnel_filter_conf.queue_id = res->queue_num;
+ if (!strcmp(res->what, "add"))
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_TUNNEL,
+ RTE_ETH_FILTER_ADD,
+ &tunnel_filter_conf);
+ else
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_TUNNEL,
+ RTE_ETH_FILTER_DELETE,
+ &tunnel_filter_conf);
+ if (ret < 0)
+ printf("cmd_tunnel_filter_parsed error: (%s)\n",
+ strerror(-ret));
+
+}
+cmdline_parse_token_string_t cmd_tunnel_filter_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_tunnel_filter_result,
+ cmd, "tunnel_filter");
+cmdline_parse_token_string_t cmd_tunnel_filter_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_tunnel_filter_result,
+ what, "add#rm");
+cmdline_parse_token_num_t cmd_tunnel_filter_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_tunnel_filter_result,
+ port_id, UINT16);
+cmdline_parse_token_etheraddr_t cmd_tunnel_filter_outer_mac =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_tunnel_filter_result,
+ outer_mac);
+cmdline_parse_token_etheraddr_t cmd_tunnel_filter_inner_mac =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_tunnel_filter_result,
+ inner_mac);
+cmdline_parse_token_num_t cmd_tunnel_filter_innner_vlan =
+ TOKEN_NUM_INITIALIZER(struct cmd_tunnel_filter_result,
+ inner_vlan, UINT16);
+cmdline_parse_token_ipaddr_t cmd_tunnel_filter_ip_value =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_tunnel_filter_result,
+ ip_value);
+cmdline_parse_token_string_t cmd_tunnel_filter_tunnel_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_tunnel_filter_result,
+ tunnel_type, "vxlan#nvgre#ipingre#vxlan-gpe");
+
+cmdline_parse_token_string_t cmd_tunnel_filter_filter_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_tunnel_filter_result,
+ filter_type, "oip#iip#imac-ivlan#imac-ivlan-tenid#imac-tenid#"
+ "imac#omac-imac-tenid");
+cmdline_parse_token_num_t cmd_tunnel_filter_tenant_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_tunnel_filter_result,
+ tenant_id, UINT32);
+cmdline_parse_token_num_t cmd_tunnel_filter_queue_num =
+ TOKEN_NUM_INITIALIZER(struct cmd_tunnel_filter_result,
+ queue_num, UINT16);
+
+cmdline_parse_inst_t cmd_tunnel_filter = {
+ .f = cmd_tunnel_filter_parsed,
+ .data = (void *)0,
+ .help_str = "tunnel_filter add|rm <port_id> <outer_mac> <inner_mac> "
+ "<ip> <inner_vlan> vxlan|nvgre|ipingre oip|iip|imac-ivlan|"
+ "imac-ivlan-tenid|imac-tenid|imac|omac-imac-tenid <tenant_id> "
+ "<queue_id>: Add/Rm tunnel filter of a port",
+ .tokens = {
+ (void *)&cmd_tunnel_filter_cmd,
+ (void *)&cmd_tunnel_filter_what,
+ (void *)&cmd_tunnel_filter_port_id,
+ (void *)&cmd_tunnel_filter_outer_mac,
+ (void *)&cmd_tunnel_filter_inner_mac,
+ (void *)&cmd_tunnel_filter_ip_value,
+ (void *)&cmd_tunnel_filter_innner_vlan,
+ (void *)&cmd_tunnel_filter_tunnel_type,
+ (void *)&cmd_tunnel_filter_filter_type,
+ (void *)&cmd_tunnel_filter_tenant_id,
+ (void *)&cmd_tunnel_filter_queue_num,
+ NULL,
+ },
+};
+
+/* *** CONFIGURE TUNNEL UDP PORT *** */
+struct cmd_tunnel_udp_config {
+ cmdline_fixed_string_t cmd;
+ cmdline_fixed_string_t what;
+ uint16_t udp_port;
+ portid_t port_id;
+};
+
+static void
+cmd_tunnel_udp_config_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_tunnel_udp_config *res = parsed_result;
+ struct rte_eth_udp_tunnel tunnel_udp;
+ int ret;
+
+ tunnel_udp.udp_port = res->udp_port;
+
+ if (!strcmp(res->cmd, "rx_vxlan_port"))
+ tunnel_udp.prot_type = RTE_TUNNEL_TYPE_VXLAN;
+
+ if (!strcmp(res->what, "add"))
+ ret = rte_eth_dev_udp_tunnel_port_add(res->port_id,
+ &tunnel_udp);
+ else
+ ret = rte_eth_dev_udp_tunnel_port_delete(res->port_id,
+ &tunnel_udp);
+
+ if (ret < 0)
+ printf("udp tunneling add error: (%s)\n", strerror(-ret));
+}
+
+cmdline_parse_token_string_t cmd_tunnel_udp_config_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_tunnel_udp_config,
+ cmd, "rx_vxlan_port");
+cmdline_parse_token_string_t cmd_tunnel_udp_config_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_tunnel_udp_config,
+ what, "add#rm");
+cmdline_parse_token_num_t cmd_tunnel_udp_config_udp_port =
+ TOKEN_NUM_INITIALIZER(struct cmd_tunnel_udp_config,
+ udp_port, UINT16);
+cmdline_parse_token_num_t cmd_tunnel_udp_config_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_tunnel_udp_config,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_tunnel_udp_config = {
+ .f = cmd_tunnel_udp_config_parsed,
+ .data = (void *)0,
+ .help_str = "rx_vxlan_port add|rm <udp_port> <port_id>: "
+ "Add/Remove a tunneling UDP port filter",
+ .tokens = {
+ (void *)&cmd_tunnel_udp_config_cmd,
+ (void *)&cmd_tunnel_udp_config_what,
+ (void *)&cmd_tunnel_udp_config_udp_port,
+ (void *)&cmd_tunnel_udp_config_port_id,
+ NULL,
+ },
+};
+
+struct cmd_config_tunnel_udp_port {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t config;
+ portid_t port_id;
+ cmdline_fixed_string_t udp_tunnel_port;
+ cmdline_fixed_string_t action;
+ cmdline_fixed_string_t tunnel_type;
+ uint16_t udp_port;
+};
+
+static void
+cmd_cfg_tunnel_udp_port_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_tunnel_udp_port *res = parsed_result;
+ struct rte_eth_udp_tunnel tunnel_udp;
+ int ret = 0;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+ tunnel_udp.udp_port = res->udp_port;
+
+ if (!strcmp(res->tunnel_type, "vxlan")) {
+ tunnel_udp.prot_type = RTE_TUNNEL_TYPE_VXLAN;
+ } else if (!strcmp(res->tunnel_type, "geneve")) {
+ tunnel_udp.prot_type = RTE_TUNNEL_TYPE_GENEVE;
+ } else if (!strcmp(res->tunnel_type, "vxlan-gpe")) {
+ tunnel_udp.prot_type = RTE_TUNNEL_TYPE_VXLAN_GPE;
+ } else {
+ printf("Invalid tunnel type\n");
+ return;
+ }
+
+ if (!strcmp(res->action, "add"))
+ ret = rte_eth_dev_udp_tunnel_port_add(res->port_id,
+ &tunnel_udp);
+ else
+ ret = rte_eth_dev_udp_tunnel_port_delete(res->port_id,
+ &tunnel_udp);
+
+ if (ret < 0)
+ printf("udp tunneling port add error: (%s)\n", strerror(-ret));
+}
+
+cmdline_parse_token_string_t cmd_config_tunnel_udp_port_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_tunnel_udp_port, port,
+ "port");
+cmdline_parse_token_string_t cmd_config_tunnel_udp_port_config =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_tunnel_udp_port, config,
+ "config");
+cmdline_parse_token_num_t cmd_config_tunnel_udp_port_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_tunnel_udp_port, port_id,
+ UINT16);
+cmdline_parse_token_string_t cmd_config_tunnel_udp_port_tunnel_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_tunnel_udp_port,
+ udp_tunnel_port,
+ "udp_tunnel_port");
+cmdline_parse_token_string_t cmd_config_tunnel_udp_port_action =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_tunnel_udp_port, action,
+ "add#rm");
+cmdline_parse_token_string_t cmd_config_tunnel_udp_port_tunnel_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_tunnel_udp_port, tunnel_type,
+ "vxlan#geneve#vxlan-gpe");
+cmdline_parse_token_num_t cmd_config_tunnel_udp_port_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_tunnel_udp_port, udp_port,
+ UINT16);
+
+cmdline_parse_inst_t cmd_cfg_tunnel_udp_port = {
+ .f = cmd_cfg_tunnel_udp_port_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> udp_tunnel_port add|rm vxlan|geneve|vxlan-gpe <udp_port>",
+ .tokens = {
+ (void *)&cmd_config_tunnel_udp_port_port,
+ (void *)&cmd_config_tunnel_udp_port_config,
+ (void *)&cmd_config_tunnel_udp_port_port_id,
+ (void *)&cmd_config_tunnel_udp_port_tunnel_port,
+ (void *)&cmd_config_tunnel_udp_port_action,
+ (void *)&cmd_config_tunnel_udp_port_tunnel_type,
+ (void *)&cmd_config_tunnel_udp_port_value,
+ NULL,
+ },
+};
+
+/* *** GLOBAL CONFIG *** */
+struct cmd_global_config_result {
+ cmdline_fixed_string_t cmd;
+ portid_t port_id;
+ cmdline_fixed_string_t cfg_type;
+ uint8_t len;
+};
+
+static void
+cmd_global_config_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_global_config_result *res = parsed_result;
+ struct rte_eth_global_cfg conf;
+ int ret;
+
+ memset(&conf, 0, sizeof(conf));
+ conf.cfg_type = RTE_ETH_GLOBAL_CFG_TYPE_GRE_KEY_LEN;
+ conf.cfg.gre_key_len = res->len;
+ ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_NONE,
+ RTE_ETH_FILTER_SET, &conf);
+ if (ret != 0)
+ printf("Global config error\n");
+}
+
+cmdline_parse_token_string_t cmd_global_config_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_global_config_result, cmd,
+ "global_config");
+cmdline_parse_token_num_t cmd_global_config_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_global_config_result, port_id,
+ UINT16);
+cmdline_parse_token_string_t cmd_global_config_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_global_config_result,
+ cfg_type, "gre-key-len");
+cmdline_parse_token_num_t cmd_global_config_gre_key_len =
+ TOKEN_NUM_INITIALIZER(struct cmd_global_config_result,
+ len, UINT8);
+
+cmdline_parse_inst_t cmd_global_config = {
+ .f = cmd_global_config_parsed,
+ .data = (void *)NULL,
+ .help_str = "global_config <port_id> gre-key-len <key_len>",
+ .tokens = {
+ (void *)&cmd_global_config_cmd,
+ (void *)&cmd_global_config_port_id,
+ (void *)&cmd_global_config_type,
+ (void *)&cmd_global_config_gre_key_len,
+ NULL,
+ },
+};
+
+/* *** CONFIGURE VM MIRROR VLAN/POOL RULE *** */
+struct cmd_set_mirror_mask_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t mirror;
+ uint8_t rule_id;
+ cmdline_fixed_string_t what;
+ cmdline_fixed_string_t value;
+ cmdline_fixed_string_t dstpool;
+ uint8_t dstpool_id;
+ cmdline_fixed_string_t on;
+};
+
+cmdline_parse_token_string_t cmd_mirror_mask_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mirror_mask_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_mirror_mask_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mirror_mask_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_mirror_mask_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mirror_mask_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_mirror_mask_mirror =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mirror_mask_result,
+ mirror, "mirror-rule");
+cmdline_parse_token_num_t cmd_mirror_mask_ruleid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mirror_mask_result,
+ rule_id, UINT8);
+cmdline_parse_token_string_t cmd_mirror_mask_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mirror_mask_result,
+ what, "pool-mirror-up#pool-mirror-down"
+ "#vlan-mirror");
+cmdline_parse_token_string_t cmd_mirror_mask_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mirror_mask_result,
+ value, NULL);
+cmdline_parse_token_string_t cmd_mirror_mask_dstpool =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mirror_mask_result,
+ dstpool, "dst-pool");
+cmdline_parse_token_num_t cmd_mirror_mask_poolid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mirror_mask_result,
+ dstpool_id, UINT8);
+cmdline_parse_token_string_t cmd_mirror_mask_on =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mirror_mask_result,
+ on, "on#off");
+
+static void
+cmd_set_mirror_mask_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ int ret,nb_item,i;
+ struct cmd_set_mirror_mask_result *res = parsed_result;
+ struct rte_eth_mirror_conf mr_conf;
+
+ memset(&mr_conf, 0, sizeof(struct rte_eth_mirror_conf));
+
+ unsigned int vlan_list[ETH_MIRROR_MAX_VLANS];
+
+ mr_conf.dst_pool = res->dstpool_id;
+
+ if (!strcmp(res->what, "pool-mirror-up")) {
+ mr_conf.pool_mask = strtoull(res->value, NULL, 16);
+ mr_conf.rule_type = ETH_MIRROR_VIRTUAL_POOL_UP;
+ } else if (!strcmp(res->what, "pool-mirror-down")) {
+ mr_conf.pool_mask = strtoull(res->value, NULL, 16);
+ mr_conf.rule_type = ETH_MIRROR_VIRTUAL_POOL_DOWN;
+ } else if (!strcmp(res->what, "vlan-mirror")) {
+ mr_conf.rule_type = ETH_MIRROR_VLAN;
+ nb_item = parse_item_list(res->value, "vlan",
+ ETH_MIRROR_MAX_VLANS, vlan_list, 1);
+ if (nb_item <= 0)
+ return;
+
+ for (i = 0; i < nb_item; i++) {
+ if (vlan_list[i] > RTE_ETHER_MAX_VLAN_ID) {
+ printf("Invalid vlan_id: must be < 4096\n");
+ return;
+ }
+
+ mr_conf.vlan.vlan_id[i] = (uint16_t)vlan_list[i];
+ mr_conf.vlan.vlan_mask |= 1ULL << i;
+ }
+ }
+
+ if (!strcmp(res->on, "on"))
+ ret = rte_eth_mirror_rule_set(res->port_id, &mr_conf,
+ res->rule_id, 1);
+ else
+ ret = rte_eth_mirror_rule_set(res->port_id, &mr_conf,
+ res->rule_id, 0);
+ if (ret < 0)
+ printf("mirror rule add error: (%s)\n", strerror(-ret));
+}
+
+cmdline_parse_inst_t cmd_set_mirror_mask = {
+ .f = cmd_set_mirror_mask_parsed,
+ .data = NULL,
+ .help_str = "set port <port_id> mirror-rule <rule_id> "
+ "pool-mirror-up|pool-mirror-down|vlan-mirror "
+ "<pool_mask|vlan_id[,vlan_id]*> dst-pool <pool_id> on|off",
+ .tokens = {
+ (void *)&cmd_mirror_mask_set,
+ (void *)&cmd_mirror_mask_port,
+ (void *)&cmd_mirror_mask_portid,
+ (void *)&cmd_mirror_mask_mirror,
+ (void *)&cmd_mirror_mask_ruleid,
+ (void *)&cmd_mirror_mask_what,
+ (void *)&cmd_mirror_mask_value,
+ (void *)&cmd_mirror_mask_dstpool,
+ (void *)&cmd_mirror_mask_poolid,
+ (void *)&cmd_mirror_mask_on,
+ NULL,
+ },
+};
+
+/* *** CONFIGURE VM MIRROR UPLINK/DOWNLINK RULE *** */
+struct cmd_set_mirror_link_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t mirror;
+ uint8_t rule_id;
+ cmdline_fixed_string_t what;
+ cmdline_fixed_string_t dstpool;
+ uint8_t dstpool_id;
+ cmdline_fixed_string_t on;
+};
+
+cmdline_parse_token_string_t cmd_mirror_link_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mirror_link_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_mirror_link_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mirror_link_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_mirror_link_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mirror_link_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_mirror_link_mirror =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mirror_link_result,
+ mirror, "mirror-rule");
+cmdline_parse_token_num_t cmd_mirror_link_ruleid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mirror_link_result,
+ rule_id, UINT8);
+cmdline_parse_token_string_t cmd_mirror_link_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mirror_link_result,
+ what, "uplink-mirror#downlink-mirror");
+cmdline_parse_token_string_t cmd_mirror_link_dstpool =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mirror_link_result,
+ dstpool, "dst-pool");
+cmdline_parse_token_num_t cmd_mirror_link_poolid =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mirror_link_result,
+ dstpool_id, UINT8);
+cmdline_parse_token_string_t cmd_mirror_link_on =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mirror_link_result,
+ on, "on#off");
+
+static void
+cmd_set_mirror_link_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ int ret;
+ struct cmd_set_mirror_link_result *res = parsed_result;
+ struct rte_eth_mirror_conf mr_conf;
+
+ memset(&mr_conf, 0, sizeof(struct rte_eth_mirror_conf));
+ if (!strcmp(res->what, "uplink-mirror"))
+ mr_conf.rule_type = ETH_MIRROR_UPLINK_PORT;
+ else
+ mr_conf.rule_type = ETH_MIRROR_DOWNLINK_PORT;
+
+ mr_conf.dst_pool = res->dstpool_id;
+
+ if (!strcmp(res->on, "on"))
+ ret = rte_eth_mirror_rule_set(res->port_id, &mr_conf,
+ res->rule_id, 1);
+ else
+ ret = rte_eth_mirror_rule_set(res->port_id, &mr_conf,
+ res->rule_id, 0);
+
+ /* check the return value and print it if is < 0 */
+ if (ret < 0)
+ printf("mirror rule add error: (%s)\n", strerror(-ret));
+
+}
+
+cmdline_parse_inst_t cmd_set_mirror_link = {
+ .f = cmd_set_mirror_link_parsed,
+ .data = NULL,
+ .help_str = "set port <port_id> mirror-rule <rule_id> "
+ "uplink-mirror|downlink-mirror dst-pool <pool_id> on|off",
+ .tokens = {
+ (void *)&cmd_mirror_link_set,
+ (void *)&cmd_mirror_link_port,
+ (void *)&cmd_mirror_link_portid,
+ (void *)&cmd_mirror_link_mirror,
+ (void *)&cmd_mirror_link_ruleid,
+ (void *)&cmd_mirror_link_what,
+ (void *)&cmd_mirror_link_dstpool,
+ (void *)&cmd_mirror_link_poolid,
+ (void *)&cmd_mirror_link_on,
+ NULL,
+ },
+};
+
+/* *** RESET VM MIRROR RULE *** */
+struct cmd_rm_mirror_rule_result {
+ cmdline_fixed_string_t reset;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t mirror;
+ uint8_t rule_id;
+};
+
+cmdline_parse_token_string_t cmd_rm_mirror_rule_reset =
+ TOKEN_STRING_INITIALIZER(struct cmd_rm_mirror_rule_result,
+ reset, "reset");
+cmdline_parse_token_string_t cmd_rm_mirror_rule_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_rm_mirror_rule_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_rm_mirror_rule_portid =
+ TOKEN_NUM_INITIALIZER(struct cmd_rm_mirror_rule_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_rm_mirror_rule_mirror =
+ TOKEN_STRING_INITIALIZER(struct cmd_rm_mirror_rule_result,
+ mirror, "mirror-rule");
+cmdline_parse_token_num_t cmd_rm_mirror_rule_ruleid =
+ TOKEN_NUM_INITIALIZER(struct cmd_rm_mirror_rule_result,
+ rule_id, UINT8);
+
+static void
+cmd_reset_mirror_rule_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ int ret;
+ struct cmd_set_mirror_link_result *res = parsed_result;
+ /* check rule_id */
+ ret = rte_eth_mirror_rule_reset(res->port_id,res->rule_id);
+ if(ret < 0)
+ printf("mirror rule remove error: (%s)\n", strerror(-ret));
+}
+
+cmdline_parse_inst_t cmd_reset_mirror_rule = {
+ .f = cmd_reset_mirror_rule_parsed,
+ .data = NULL,
+ .help_str = "reset port <port_id> mirror-rule <rule_id>",
+ .tokens = {
+ (void *)&cmd_rm_mirror_rule_reset,
+ (void *)&cmd_rm_mirror_rule_port,
+ (void *)&cmd_rm_mirror_rule_portid,
+ (void *)&cmd_rm_mirror_rule_mirror,
+ (void *)&cmd_rm_mirror_rule_ruleid,
+ NULL,
+ },
+};
+
+/* ******************************************************************************** */
+
+struct cmd_dump_result {
+ cmdline_fixed_string_t dump;
+};
+
+static void
+dump_struct_sizes(void)
+{
+#define DUMP_SIZE(t) printf("sizeof(" #t ") = %u\n", (unsigned)sizeof(t));
+ DUMP_SIZE(struct rte_mbuf);
+ DUMP_SIZE(struct rte_mempool);
+ DUMP_SIZE(struct rte_ring);
+#undef DUMP_SIZE
+}
+
+
+/* Dump the socket memory statistics on console */
+static void
+dump_socket_mem(FILE *f)
+{
+ struct rte_malloc_socket_stats socket_stats;
+ unsigned int i;
+ size_t total = 0;
+ size_t alloc = 0;
+ size_t free = 0;
+ unsigned int n_alloc = 0;
+ unsigned int n_free = 0;
+ static size_t last_allocs;
+ static size_t last_total;
+
+
+ for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
+ if (rte_malloc_get_socket_stats(i, &socket_stats) ||
+ !socket_stats.heap_totalsz_bytes)
+ continue;
+ total += socket_stats.heap_totalsz_bytes;
+ alloc += socket_stats.heap_allocsz_bytes;
+ free += socket_stats.heap_freesz_bytes;
+ n_alloc += socket_stats.alloc_count;
+ n_free += socket_stats.free_count;
+ fprintf(f,
+ "Socket %u: size(M) total: %.6lf alloc: %.6lf(%.3lf%%) free: %.6lf \tcount alloc: %-4u free: %u\n",
+ i,
+ (double)socket_stats.heap_totalsz_bytes / (1024 * 1024),
+ (double)socket_stats.heap_allocsz_bytes / (1024 * 1024),
+ (double)socket_stats.heap_allocsz_bytes * 100 /
+ (double)socket_stats.heap_totalsz_bytes,
+ (double)socket_stats.heap_freesz_bytes / (1024 * 1024),
+ socket_stats.alloc_count,
+ socket_stats.free_count);
+ }
+ fprintf(f,
+ "Total : size(M) total: %.6lf alloc: %.6lf(%.3lf%%) free: %.6lf \tcount alloc: %-4u free: %u\n",
+ (double)total / (1024 * 1024), (double)alloc / (1024 * 1024),
+ (double)alloc * 100 / (double)total,
+ (double)free / (1024 * 1024),
+ n_alloc, n_free);
+ if (last_allocs)
+ fprintf(stdout, "Memory total change: %.6lf(M), allocation change: %.6lf(M)\n",
+ ((double)total - (double)last_total) / (1024 * 1024),
+ (double)(alloc - (double)last_allocs) / 1024 / 1024);
+ last_allocs = alloc;
+ last_total = total;
+}
+
+static void cmd_dump_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_dump_result *res = parsed_result;
+
+ if (!strcmp(res->dump, "dump_physmem"))
+ rte_dump_physmem_layout(stdout);
+ else if (!strcmp(res->dump, "dump_socket_mem"))
+ dump_socket_mem(stdout);
+ else if (!strcmp(res->dump, "dump_memzone"))
+ rte_memzone_dump(stdout);
+ else if (!strcmp(res->dump, "dump_struct_sizes"))
+ dump_struct_sizes();
+ else if (!strcmp(res->dump, "dump_ring"))
+ rte_ring_list_dump(stdout);
+ else if (!strcmp(res->dump, "dump_mempool"))
+ rte_mempool_list_dump(stdout);
+ else if (!strcmp(res->dump, "dump_devargs"))
+ rte_devargs_dump(stdout);
+ else if (!strcmp(res->dump, "dump_log_types"))
+ rte_log_dump(stdout);
+}
+
+cmdline_parse_token_string_t cmd_dump_dump =
+ TOKEN_STRING_INITIALIZER(struct cmd_dump_result, dump,
+ "dump_physmem#"
+ "dump_memzone#"
+ "dump_socket_mem#"
+ "dump_struct_sizes#"
+ "dump_ring#"
+ "dump_mempool#"
+ "dump_devargs#"
+ "dump_log_types");
+
+cmdline_parse_inst_t cmd_dump = {
+ .f = cmd_dump_parsed, /* function to call */
+ .data = NULL, /* 2nd arg of func */
+ .help_str = "Dump status",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_dump_dump,
+ NULL,
+ },
+};
+
+/* ******************************************************************************** */
+
+struct cmd_dump_one_result {
+ cmdline_fixed_string_t dump;
+ cmdline_fixed_string_t name;
+};
+
+static void cmd_dump_one_parsed(void *parsed_result, struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_dump_one_result *res = parsed_result;
+
+ if (!strcmp(res->dump, "dump_ring")) {
+ struct rte_ring *r;
+ r = rte_ring_lookup(res->name);
+ if (r == NULL) {
+ cmdline_printf(cl, "Cannot find ring\n");
+ return;
+ }
+ rte_ring_dump(stdout, r);
+ } else if (!strcmp(res->dump, "dump_mempool")) {
+ struct rte_mempool *mp;
+ mp = rte_mempool_lookup(res->name);
+ if (mp == NULL) {
+ cmdline_printf(cl, "Cannot find mempool\n");
+ return;
+ }
+ rte_mempool_dump(stdout, mp);
+ }
+}
+
+cmdline_parse_token_string_t cmd_dump_one_dump =
+ TOKEN_STRING_INITIALIZER(struct cmd_dump_one_result, dump,
+ "dump_ring#dump_mempool");
+
+cmdline_parse_token_string_t cmd_dump_one_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_dump_one_result, name, NULL);
+
+cmdline_parse_inst_t cmd_dump_one = {
+ .f = cmd_dump_one_parsed, /* function to call */
+ .data = NULL, /* 2nd arg of func */
+ .help_str = "dump_ring|dump_mempool <name>: Dump one ring/mempool",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_dump_one_dump,
+ (void *)&cmd_dump_one_name,
+ NULL,
+ },
+};
+
+/* *** Add/Del syn filter *** */
+struct cmd_syn_filter_result {
+ cmdline_fixed_string_t filter;
+ portid_t port_id;
+ cmdline_fixed_string_t ops;
+ cmdline_fixed_string_t priority;
+ cmdline_fixed_string_t high;
+ cmdline_fixed_string_t queue;
+ uint16_t queue_id;
+};
+
+static void
+cmd_syn_filter_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_syn_filter_result *res = parsed_result;
+ struct rte_eth_syn_filter syn_filter;
+ int ret = 0;
+
+ ret = rte_eth_dev_filter_supported(res->port_id,
+ RTE_ETH_FILTER_SYN);
+ if (ret < 0) {
+ printf("syn filter is not supported on port %u.\n",
+ res->port_id);
+ return;
+ }
+
+ memset(&syn_filter, 0, sizeof(syn_filter));
+
+ if (!strcmp(res->ops, "add")) {
+ if (!strcmp(res->high, "high"))
+ syn_filter.hig_pri = 1;
+ else
+ syn_filter.hig_pri = 0;
+
+ syn_filter.queue = res->queue_id;
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_SYN,
+ RTE_ETH_FILTER_ADD,
+ &syn_filter);
+ } else
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_SYN,
+ RTE_ETH_FILTER_DELETE,
+ &syn_filter);
+
+ if (ret < 0)
+ printf("syn filter programming error: (%s)\n",
+ strerror(-ret));
+}
+
+cmdline_parse_token_string_t cmd_syn_filter_filter =
+ TOKEN_STRING_INITIALIZER(struct cmd_syn_filter_result,
+ filter, "syn_filter");
+cmdline_parse_token_num_t cmd_syn_filter_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_syn_filter_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_syn_filter_ops =
+ TOKEN_STRING_INITIALIZER(struct cmd_syn_filter_result,
+ ops, "add#del");
+cmdline_parse_token_string_t cmd_syn_filter_priority =
+ TOKEN_STRING_INITIALIZER(struct cmd_syn_filter_result,
+ priority, "priority");
+cmdline_parse_token_string_t cmd_syn_filter_high =
+ TOKEN_STRING_INITIALIZER(struct cmd_syn_filter_result,
+ high, "high#low");
+cmdline_parse_token_string_t cmd_syn_filter_queue =
+ TOKEN_STRING_INITIALIZER(struct cmd_syn_filter_result,
+ queue, "queue");
+cmdline_parse_token_num_t cmd_syn_filter_queue_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_syn_filter_result,
+ queue_id, UINT16);
+
+cmdline_parse_inst_t cmd_syn_filter = {
+ .f = cmd_syn_filter_parsed,
+ .data = NULL,
+ .help_str = "syn_filter <port_id> add|del priority high|low queue "
+ "<queue_id>: Add/Delete syn filter",
+ .tokens = {
+ (void *)&cmd_syn_filter_filter,
+ (void *)&cmd_syn_filter_port_id,
+ (void *)&cmd_syn_filter_ops,
+ (void *)&cmd_syn_filter_priority,
+ (void *)&cmd_syn_filter_high,
+ (void *)&cmd_syn_filter_queue,
+ (void *)&cmd_syn_filter_queue_id,
+ NULL,
+ },
+};
+
+/* *** queue region set *** */
+struct cmd_queue_region_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t cmd;
+ cmdline_fixed_string_t region;
+ uint8_t region_id;
+ cmdline_fixed_string_t queue_start_index;
+ uint8_t queue_id;
+ cmdline_fixed_string_t queue_num;
+ uint8_t queue_num_value;
+};
+
+static void
+cmd_queue_region_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_queue_region_result *res = parsed_result;
+ int ret = -ENOTSUP;
+#ifdef RTE_LIBRTE_I40E_PMD
+ struct rte_pmd_i40e_queue_region_conf region_conf;
+ enum rte_pmd_i40e_queue_region_op op_type;
+#endif
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ memset(&region_conf, 0, sizeof(region_conf));
+ op_type = RTE_PMD_I40E_RSS_QUEUE_REGION_SET;
+ region_conf.region_id = res->region_id;
+ region_conf.queue_num = res->queue_num_value;
+ region_conf.queue_start_index = res->queue_id;
+
+ ret = rte_pmd_i40e_rss_queue_region_conf(res->port_id,
+ op_type, &region_conf);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -ENOTSUP:
+ printf("function not implemented or supported\n");
+ break;
+ default:
+ printf("queue region config error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_token_string_t cmd_queue_region_set =
+TOKEN_STRING_INITIALIZER(struct cmd_queue_region_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_queue_region_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_queue_region_result, port, "port");
+cmdline_parse_token_num_t cmd_queue_region_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_queue_region_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_queue_region_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_queue_region_result,
+ cmd, "queue-region");
+cmdline_parse_token_string_t cmd_queue_region_id =
+ TOKEN_STRING_INITIALIZER(struct cmd_queue_region_result,
+ region, "region_id");
+cmdline_parse_token_num_t cmd_queue_region_index =
+ TOKEN_NUM_INITIALIZER(struct cmd_queue_region_result,
+ region_id, UINT8);
+cmdline_parse_token_string_t cmd_queue_region_queue_start_index =
+ TOKEN_STRING_INITIALIZER(struct cmd_queue_region_result,
+ queue_start_index, "queue_start_index");
+cmdline_parse_token_num_t cmd_queue_region_queue_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_queue_region_result,
+ queue_id, UINT8);
+cmdline_parse_token_string_t cmd_queue_region_queue_num =
+ TOKEN_STRING_INITIALIZER(struct cmd_queue_region_result,
+ queue_num, "queue_num");
+cmdline_parse_token_num_t cmd_queue_region_queue_num_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_queue_region_result,
+ queue_num_value, UINT8);
+
+cmdline_parse_inst_t cmd_queue_region = {
+ .f = cmd_queue_region_parsed,
+ .data = NULL,
+ .help_str = "set port <port_id> queue-region region_id <value> "
+ "queue_start_index <value> queue_num <value>: Set a queue region",
+ .tokens = {
+ (void *)&cmd_queue_region_set,
+ (void *)&cmd_queue_region_port,
+ (void *)&cmd_queue_region_port_id,
+ (void *)&cmd_queue_region_cmd,
+ (void *)&cmd_queue_region_id,
+ (void *)&cmd_queue_region_index,
+ (void *)&cmd_queue_region_queue_start_index,
+ (void *)&cmd_queue_region_queue_id,
+ (void *)&cmd_queue_region_queue_num,
+ (void *)&cmd_queue_region_queue_num_value,
+ NULL,
+ },
+};
+
+/* *** queue region and flowtype set *** */
+struct cmd_region_flowtype_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t cmd;
+ cmdline_fixed_string_t region;
+ uint8_t region_id;
+ cmdline_fixed_string_t flowtype;
+ uint8_t flowtype_id;
+};
+
+static void
+cmd_region_flowtype_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_region_flowtype_result *res = parsed_result;
+ int ret = -ENOTSUP;
+#ifdef RTE_LIBRTE_I40E_PMD
+ struct rte_pmd_i40e_queue_region_conf region_conf;
+ enum rte_pmd_i40e_queue_region_op op_type;
+#endif
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ memset(&region_conf, 0, sizeof(region_conf));
+
+ op_type = RTE_PMD_I40E_RSS_QUEUE_REGION_FLOWTYPE_SET;
+ region_conf.region_id = res->region_id;
+ region_conf.hw_flowtype = res->flowtype_id;
+
+ ret = rte_pmd_i40e_rss_queue_region_conf(res->port_id,
+ op_type, &region_conf);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -ENOTSUP:
+ printf("function not implemented or supported\n");
+ break;
+ default:
+ printf("region flowtype config error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_token_string_t cmd_region_flowtype_set =
+TOKEN_STRING_INITIALIZER(struct cmd_region_flowtype_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_region_flowtype_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_region_flowtype_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_region_flowtype_port_index =
+ TOKEN_NUM_INITIALIZER(struct cmd_region_flowtype_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_region_flowtype_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_region_flowtype_result,
+ cmd, "queue-region");
+cmdline_parse_token_string_t cmd_region_flowtype_index =
+ TOKEN_STRING_INITIALIZER(struct cmd_region_flowtype_result,
+ region, "region_id");
+cmdline_parse_token_num_t cmd_region_flowtype_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_region_flowtype_result,
+ region_id, UINT8);
+cmdline_parse_token_string_t cmd_region_flowtype_flow_index =
+ TOKEN_STRING_INITIALIZER(struct cmd_region_flowtype_result,
+ flowtype, "flowtype");
+cmdline_parse_token_num_t cmd_region_flowtype_flow_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_region_flowtype_result,
+ flowtype_id, UINT8);
+cmdline_parse_inst_t cmd_region_flowtype = {
+ .f = cmd_region_flowtype_parsed,
+ .data = NULL,
+ .help_str = "set port <port_id> queue-region region_id <value> "
+ "flowtype <value>: Set a flowtype region index",
+ .tokens = {
+ (void *)&cmd_region_flowtype_set,
+ (void *)&cmd_region_flowtype_port,
+ (void *)&cmd_region_flowtype_port_index,
+ (void *)&cmd_region_flowtype_cmd,
+ (void *)&cmd_region_flowtype_index,
+ (void *)&cmd_region_flowtype_id,
+ (void *)&cmd_region_flowtype_flow_index,
+ (void *)&cmd_region_flowtype_flow_id,
+ NULL,
+ },
+};
+
+/* *** User Priority (UP) to queue region (region_id) set *** */
+struct cmd_user_priority_region_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t cmd;
+ cmdline_fixed_string_t user_priority;
+ uint8_t user_priority_id;
+ cmdline_fixed_string_t region;
+ uint8_t region_id;
+};
+
+static void
+cmd_user_priority_region_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_user_priority_region_result *res = parsed_result;
+ int ret = -ENOTSUP;
+#ifdef RTE_LIBRTE_I40E_PMD
+ struct rte_pmd_i40e_queue_region_conf region_conf;
+ enum rte_pmd_i40e_queue_region_op op_type;
+#endif
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ memset(&region_conf, 0, sizeof(region_conf));
+ op_type = RTE_PMD_I40E_RSS_QUEUE_REGION_USER_PRIORITY_SET;
+ region_conf.user_priority = res->user_priority_id;
+ region_conf.region_id = res->region_id;
+
+ ret = rte_pmd_i40e_rss_queue_region_conf(res->port_id,
+ op_type, &region_conf);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -ENOTSUP:
+ printf("function not implemented or supported\n");
+ break;
+ default:
+ printf("user_priority region config error: (%s)\n",
+ strerror(-ret));
+ }
+}
+
+cmdline_parse_token_string_t cmd_user_priority_region_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_user_priority_region_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_user_priority_region_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_user_priority_region_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_user_priority_region_port_index =
+ TOKEN_NUM_INITIALIZER(struct cmd_user_priority_region_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_user_priority_region_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_user_priority_region_result,
+ cmd, "queue-region");
+cmdline_parse_token_string_t cmd_user_priority_region_UP =
+ TOKEN_STRING_INITIALIZER(struct cmd_user_priority_region_result,
+ user_priority, "UP");
+cmdline_parse_token_num_t cmd_user_priority_region_UP_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_user_priority_region_result,
+ user_priority_id, UINT8);
+cmdline_parse_token_string_t cmd_user_priority_region_region =
+ TOKEN_STRING_INITIALIZER(struct cmd_user_priority_region_result,
+ region, "region_id");
+cmdline_parse_token_num_t cmd_user_priority_region_region_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_user_priority_region_result,
+ region_id, UINT8);
+
+cmdline_parse_inst_t cmd_user_priority_region = {
+ .f = cmd_user_priority_region_parsed,
+ .data = NULL,
+ .help_str = "set port <port_id> queue-region UP <value> "
+ "region_id <value>: Set the mapping of User Priority (UP) "
+ "to queue region (region_id) ",
+ .tokens = {
+ (void *)&cmd_user_priority_region_set,
+ (void *)&cmd_user_priority_region_port,
+ (void *)&cmd_user_priority_region_port_index,
+ (void *)&cmd_user_priority_region_cmd,
+ (void *)&cmd_user_priority_region_UP,
+ (void *)&cmd_user_priority_region_UP_id,
+ (void *)&cmd_user_priority_region_region,
+ (void *)&cmd_user_priority_region_region_id,
+ NULL,
+ },
+};
+
+/* *** flush all queue region related configuration *** */
+struct cmd_flush_queue_region_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t cmd;
+ cmdline_fixed_string_t flush;
+ cmdline_fixed_string_t what;
+};
+
+static void
+cmd_flush_queue_region_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_flush_queue_region_result *res = parsed_result;
+ int ret = -ENOTSUP;
+#ifdef RTE_LIBRTE_I40E_PMD
+ struct rte_pmd_i40e_queue_region_conf region_conf;
+ enum rte_pmd_i40e_queue_region_op op_type;
+#endif
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ memset(&region_conf, 0, sizeof(region_conf));
+
+ if (strcmp(res->what, "on") == 0)
+ op_type = RTE_PMD_I40E_RSS_QUEUE_REGION_ALL_FLUSH_ON;
+ else
+ op_type = RTE_PMD_I40E_RSS_QUEUE_REGION_ALL_FLUSH_OFF;
+
+ ret = rte_pmd_i40e_rss_queue_region_conf(res->port_id,
+ op_type, &region_conf);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -ENOTSUP:
+ printf("function not implemented or supported\n");
+ break;
+ default:
+ printf("queue region config flush error: (%s)\n",
+ strerror(-ret));
+ }
+}
+
+cmdline_parse_token_string_t cmd_flush_queue_region_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_flush_queue_region_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_flush_queue_region_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_flush_queue_region_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_flush_queue_region_port_index =
+ TOKEN_NUM_INITIALIZER(struct cmd_flush_queue_region_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_flush_queue_region_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_flush_queue_region_result,
+ cmd, "queue-region");
+cmdline_parse_token_string_t cmd_flush_queue_region_flush =
+ TOKEN_STRING_INITIALIZER(struct cmd_flush_queue_region_result,
+ flush, "flush");
+cmdline_parse_token_string_t cmd_flush_queue_region_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_flush_queue_region_result,
+ what, "on#off");
+
+cmdline_parse_inst_t cmd_flush_queue_region = {
+ .f = cmd_flush_queue_region_parsed,
+ .data = NULL,
+ .help_str = "set port <port_id> queue-region flush on|off"
+ ": flush all queue region related configuration",
+ .tokens = {
+ (void *)&cmd_flush_queue_region_set,
+ (void *)&cmd_flush_queue_region_port,
+ (void *)&cmd_flush_queue_region_port_index,
+ (void *)&cmd_flush_queue_region_cmd,
+ (void *)&cmd_flush_queue_region_flush,
+ (void *)&cmd_flush_queue_region_what,
+ NULL,
+ },
+};
+
+/* *** get all queue region related configuration info *** */
+struct cmd_show_queue_region_info {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t cmd;
+};
+
+static void
+cmd_show_queue_region_info_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_queue_region_info *res = parsed_result;
+ int ret = -ENOTSUP;
+#ifdef RTE_LIBRTE_I40E_PMD
+ struct rte_pmd_i40e_queue_regions rte_pmd_regions;
+ enum rte_pmd_i40e_queue_region_op op_type;
+#endif
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ memset(&rte_pmd_regions, 0, sizeof(rte_pmd_regions));
+
+ op_type = RTE_PMD_I40E_RSS_QUEUE_REGION_INFO_GET;
+
+ ret = rte_pmd_i40e_rss_queue_region_conf(res->port_id,
+ op_type, &rte_pmd_regions);
+
+ port_queue_region_info_display(res->port_id, &rte_pmd_regions);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -ENOTSUP:
+ printf("function not implemented or supported\n");
+ break;
+ default:
+ printf("queue region config info show error: (%s)\n",
+ strerror(-ret));
+ }
+}
+
+cmdline_parse_token_string_t cmd_show_queue_region_info_get =
+TOKEN_STRING_INITIALIZER(struct cmd_show_queue_region_info,
+ show, "show");
+cmdline_parse_token_string_t cmd_show_queue_region_info_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_queue_region_info,
+ port, "port");
+cmdline_parse_token_num_t cmd_show_queue_region_info_port_index =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_queue_region_info,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_show_queue_region_info_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_queue_region_info,
+ cmd, "queue-region");
+
+cmdline_parse_inst_t cmd_show_queue_region_info_all = {
+ .f = cmd_show_queue_region_info_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> queue-region"
+ ": show all queue region related configuration info",
+ .tokens = {
+ (void *)&cmd_show_queue_region_info_get,
+ (void *)&cmd_show_queue_region_info_port,
+ (void *)&cmd_show_queue_region_info_port_index,
+ (void *)&cmd_show_queue_region_info_cmd,
+ NULL,
+ },
+};
+
+/* *** ADD/REMOVE A 2tuple FILTER *** */
+struct cmd_2tuple_filter_result {
+ cmdline_fixed_string_t filter;
+ portid_t port_id;
+ cmdline_fixed_string_t ops;
+ cmdline_fixed_string_t dst_port;
+ uint16_t dst_port_value;
+ cmdline_fixed_string_t protocol;
+ uint8_t protocol_value;
+ cmdline_fixed_string_t mask;
+ uint8_t mask_value;
+ cmdline_fixed_string_t tcp_flags;
+ uint8_t tcp_flags_value;
+ cmdline_fixed_string_t priority;
+ uint8_t priority_value;
+ cmdline_fixed_string_t queue;
+ uint16_t queue_id;
+};
+
+static void
+cmd_2tuple_filter_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct rte_eth_ntuple_filter filter;
+ struct cmd_2tuple_filter_result *res = parsed_result;
+ int ret = 0;
+
+ ret = rte_eth_dev_filter_supported(res->port_id, RTE_ETH_FILTER_NTUPLE);
+ if (ret < 0) {
+ printf("ntuple filter is not supported on port %u.\n",
+ res->port_id);
+ return;
+ }
+
+ memset(&filter, 0, sizeof(struct rte_eth_ntuple_filter));
+
+ filter.flags = RTE_2TUPLE_FLAGS;
+ filter.dst_port_mask = (res->mask_value & 0x02) ? UINT16_MAX : 0;
+ filter.proto_mask = (res->mask_value & 0x01) ? UINT8_MAX : 0;
+ filter.proto = res->protocol_value;
+ filter.priority = res->priority_value;
+ if (res->tcp_flags_value != 0 && filter.proto != IPPROTO_TCP) {
+ printf("nonzero tcp_flags is only meaningful"
+ " when protocol is TCP.\n");
+ return;
+ }
+ if (res->tcp_flags_value > RTE_NTUPLE_TCP_FLAGS_MASK) {
+ printf("invalid TCP flags.\n");
+ return;
+ }
+
+ if (res->tcp_flags_value != 0) {
+ filter.flags |= RTE_NTUPLE_FLAGS_TCP_FLAG;
+ filter.tcp_flags = res->tcp_flags_value;
+ }
+
+ /* need convert to big endian. */
+ filter.dst_port = rte_cpu_to_be_16(res->dst_port_value);
+ filter.queue = res->queue_id;
+
+ if (!strcmp(res->ops, "add"))
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_NTUPLE,
+ RTE_ETH_FILTER_ADD,
+ &filter);
+ else
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_NTUPLE,
+ RTE_ETH_FILTER_DELETE,
+ &filter);
+ if (ret < 0)
+ printf("2tuple filter programming error: (%s)\n",
+ strerror(-ret));
+
+}
+
+cmdline_parse_token_string_t cmd_2tuple_filter_filter =
+ TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result,
+ filter, "2tuple_filter");
+cmdline_parse_token_num_t cmd_2tuple_filter_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_2tuple_filter_ops =
+ TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result,
+ ops, "add#del");
+cmdline_parse_token_string_t cmd_2tuple_filter_dst_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result,
+ dst_port, "dst_port");
+cmdline_parse_token_num_t cmd_2tuple_filter_dst_port_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result,
+ dst_port_value, UINT16);
+cmdline_parse_token_string_t cmd_2tuple_filter_protocol =
+ TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result,
+ protocol, "protocol");
+cmdline_parse_token_num_t cmd_2tuple_filter_protocol_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result,
+ protocol_value, UINT8);
+cmdline_parse_token_string_t cmd_2tuple_filter_mask =
+ TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result,
+ mask, "mask");
+cmdline_parse_token_num_t cmd_2tuple_filter_mask_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result,
+ mask_value, INT8);
+cmdline_parse_token_string_t cmd_2tuple_filter_tcp_flags =
+ TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result,
+ tcp_flags, "tcp_flags");
+cmdline_parse_token_num_t cmd_2tuple_filter_tcp_flags_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result,
+ tcp_flags_value, UINT8);
+cmdline_parse_token_string_t cmd_2tuple_filter_priority =
+ TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result,
+ priority, "priority");
+cmdline_parse_token_num_t cmd_2tuple_filter_priority_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result,
+ priority_value, UINT8);
+cmdline_parse_token_string_t cmd_2tuple_filter_queue =
+ TOKEN_STRING_INITIALIZER(struct cmd_2tuple_filter_result,
+ queue, "queue");
+cmdline_parse_token_num_t cmd_2tuple_filter_queue_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_2tuple_filter_result,
+ queue_id, UINT16);
+
+cmdline_parse_inst_t cmd_2tuple_filter = {
+ .f = cmd_2tuple_filter_parsed,
+ .data = NULL,
+ .help_str = "2tuple_filter <port_id> add|del dst_port <value> protocol "
+ "<value> mask <value> tcp_flags <value> priority <value> queue "
+ "<queue_id>: Add a 2tuple filter",
+ .tokens = {
+ (void *)&cmd_2tuple_filter_filter,
+ (void *)&cmd_2tuple_filter_port_id,
+ (void *)&cmd_2tuple_filter_ops,
+ (void *)&cmd_2tuple_filter_dst_port,
+ (void *)&cmd_2tuple_filter_dst_port_value,
+ (void *)&cmd_2tuple_filter_protocol,
+ (void *)&cmd_2tuple_filter_protocol_value,
+ (void *)&cmd_2tuple_filter_mask,
+ (void *)&cmd_2tuple_filter_mask_value,
+ (void *)&cmd_2tuple_filter_tcp_flags,
+ (void *)&cmd_2tuple_filter_tcp_flags_value,
+ (void *)&cmd_2tuple_filter_priority,
+ (void *)&cmd_2tuple_filter_priority_value,
+ (void *)&cmd_2tuple_filter_queue,
+ (void *)&cmd_2tuple_filter_queue_id,
+ NULL,
+ },
+};
+
+/* *** ADD/REMOVE A 5tuple FILTER *** */
+struct cmd_5tuple_filter_result {
+ cmdline_fixed_string_t filter;
+ portid_t port_id;
+ cmdline_fixed_string_t ops;
+ cmdline_fixed_string_t dst_ip;
+ cmdline_ipaddr_t dst_ip_value;
+ cmdline_fixed_string_t src_ip;
+ cmdline_ipaddr_t src_ip_value;
+ cmdline_fixed_string_t dst_port;
+ uint16_t dst_port_value;
+ cmdline_fixed_string_t src_port;
+ uint16_t src_port_value;
+ cmdline_fixed_string_t protocol;
+ uint8_t protocol_value;
+ cmdline_fixed_string_t mask;
+ uint8_t mask_value;
+ cmdline_fixed_string_t tcp_flags;
+ uint8_t tcp_flags_value;
+ cmdline_fixed_string_t priority;
+ uint8_t priority_value;
+ cmdline_fixed_string_t queue;
+ uint16_t queue_id;
+};
+
+static void
+cmd_5tuple_filter_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct rte_eth_ntuple_filter filter;
+ struct cmd_5tuple_filter_result *res = parsed_result;
+ int ret = 0;
+
+ ret = rte_eth_dev_filter_supported(res->port_id, RTE_ETH_FILTER_NTUPLE);
+ if (ret < 0) {
+ printf("ntuple filter is not supported on port %u.\n",
+ res->port_id);
+ return;
+ }
+
+ memset(&filter, 0, sizeof(struct rte_eth_ntuple_filter));
+
+ filter.flags = RTE_5TUPLE_FLAGS;
+ filter.dst_ip_mask = (res->mask_value & 0x10) ? UINT32_MAX : 0;
+ filter.src_ip_mask = (res->mask_value & 0x08) ? UINT32_MAX : 0;
+ filter.dst_port_mask = (res->mask_value & 0x04) ? UINT16_MAX : 0;
+ filter.src_port_mask = (res->mask_value & 0x02) ? UINT16_MAX : 0;
+ filter.proto_mask = (res->mask_value & 0x01) ? UINT8_MAX : 0;
+ filter.proto = res->protocol_value;
+ filter.priority = res->priority_value;
+ if (res->tcp_flags_value != 0 && filter.proto != IPPROTO_TCP) {
+ printf("nonzero tcp_flags is only meaningful"
+ " when protocol is TCP.\n");
+ return;
+ }
+ if (res->tcp_flags_value > RTE_NTUPLE_TCP_FLAGS_MASK) {
+ printf("invalid TCP flags.\n");
+ return;
+ }
+
+ if (res->tcp_flags_value != 0) {
+ filter.flags |= RTE_NTUPLE_FLAGS_TCP_FLAG;
+ filter.tcp_flags = res->tcp_flags_value;
+ }
+
+ if (res->dst_ip_value.family == AF_INET)
+ /* no need to convert, already big endian. */
+ filter.dst_ip = res->dst_ip_value.addr.ipv4.s_addr;
+ else {
+ if (filter.dst_ip_mask == 0) {
+ printf("can not support ipv6 involved compare.\n");
+ return;
+ }
+ filter.dst_ip = 0;
+ }
+
+ if (res->src_ip_value.family == AF_INET)
+ /* no need to convert, already big endian. */
+ filter.src_ip = res->src_ip_value.addr.ipv4.s_addr;
+ else {
+ if (filter.src_ip_mask == 0) {
+ printf("can not support ipv6 involved compare.\n");
+ return;
+ }
+ filter.src_ip = 0;
+ }
+ /* need convert to big endian. */
+ filter.dst_port = rte_cpu_to_be_16(res->dst_port_value);
+ filter.src_port = rte_cpu_to_be_16(res->src_port_value);
+ filter.queue = res->queue_id;
+
+ if (!strcmp(res->ops, "add"))
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_NTUPLE,
+ RTE_ETH_FILTER_ADD,
+ &filter);
+ else
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_NTUPLE,
+ RTE_ETH_FILTER_DELETE,
+ &filter);
+ if (ret < 0)
+ printf("5tuple filter programming error: (%s)\n",
+ strerror(-ret));
+}
+
+cmdline_parse_token_string_t cmd_5tuple_filter_filter =
+ TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result,
+ filter, "5tuple_filter");
+cmdline_parse_token_num_t cmd_5tuple_filter_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_5tuple_filter_ops =
+ TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result,
+ ops, "add#del");
+cmdline_parse_token_string_t cmd_5tuple_filter_dst_ip =
+ TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result,
+ dst_ip, "dst_ip");
+cmdline_parse_token_ipaddr_t cmd_5tuple_filter_dst_ip_value =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_5tuple_filter_result,
+ dst_ip_value);
+cmdline_parse_token_string_t cmd_5tuple_filter_src_ip =
+ TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result,
+ src_ip, "src_ip");
+cmdline_parse_token_ipaddr_t cmd_5tuple_filter_src_ip_value =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_5tuple_filter_result,
+ src_ip_value);
+cmdline_parse_token_string_t cmd_5tuple_filter_dst_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result,
+ dst_port, "dst_port");
+cmdline_parse_token_num_t cmd_5tuple_filter_dst_port_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result,
+ dst_port_value, UINT16);
+cmdline_parse_token_string_t cmd_5tuple_filter_src_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result,
+ src_port, "src_port");
+cmdline_parse_token_num_t cmd_5tuple_filter_src_port_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result,
+ src_port_value, UINT16);
+cmdline_parse_token_string_t cmd_5tuple_filter_protocol =
+ TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result,
+ protocol, "protocol");
+cmdline_parse_token_num_t cmd_5tuple_filter_protocol_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result,
+ protocol_value, UINT8);
+cmdline_parse_token_string_t cmd_5tuple_filter_mask =
+ TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result,
+ mask, "mask");
+cmdline_parse_token_num_t cmd_5tuple_filter_mask_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result,
+ mask_value, INT8);
+cmdline_parse_token_string_t cmd_5tuple_filter_tcp_flags =
+ TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result,
+ tcp_flags, "tcp_flags");
+cmdline_parse_token_num_t cmd_5tuple_filter_tcp_flags_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result,
+ tcp_flags_value, UINT8);
+cmdline_parse_token_string_t cmd_5tuple_filter_priority =
+ TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result,
+ priority, "priority");
+cmdline_parse_token_num_t cmd_5tuple_filter_priority_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result,
+ priority_value, UINT8);
+cmdline_parse_token_string_t cmd_5tuple_filter_queue =
+ TOKEN_STRING_INITIALIZER(struct cmd_5tuple_filter_result,
+ queue, "queue");
+cmdline_parse_token_num_t cmd_5tuple_filter_queue_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_5tuple_filter_result,
+ queue_id, UINT16);
+
+cmdline_parse_inst_t cmd_5tuple_filter = {
+ .f = cmd_5tuple_filter_parsed,
+ .data = NULL,
+ .help_str = "5tuple_filter <port_id> add|del dst_ip <value> "
+ "src_ip <value> dst_port <value> src_port <value> "
+ "protocol <value> mask <value> tcp_flags <value> "
+ "priority <value> queue <queue_id>: Add/Del a 5tuple filter",
+ .tokens = {
+ (void *)&cmd_5tuple_filter_filter,
+ (void *)&cmd_5tuple_filter_port_id,
+ (void *)&cmd_5tuple_filter_ops,
+ (void *)&cmd_5tuple_filter_dst_ip,
+ (void *)&cmd_5tuple_filter_dst_ip_value,
+ (void *)&cmd_5tuple_filter_src_ip,
+ (void *)&cmd_5tuple_filter_src_ip_value,
+ (void *)&cmd_5tuple_filter_dst_port,
+ (void *)&cmd_5tuple_filter_dst_port_value,
+ (void *)&cmd_5tuple_filter_src_port,
+ (void *)&cmd_5tuple_filter_src_port_value,
+ (void *)&cmd_5tuple_filter_protocol,
+ (void *)&cmd_5tuple_filter_protocol_value,
+ (void *)&cmd_5tuple_filter_mask,
+ (void *)&cmd_5tuple_filter_mask_value,
+ (void *)&cmd_5tuple_filter_tcp_flags,
+ (void *)&cmd_5tuple_filter_tcp_flags_value,
+ (void *)&cmd_5tuple_filter_priority,
+ (void *)&cmd_5tuple_filter_priority_value,
+ (void *)&cmd_5tuple_filter_queue,
+ (void *)&cmd_5tuple_filter_queue_id,
+ NULL,
+ },
+};
+
+/* *** ADD/REMOVE A flex FILTER *** */
+struct cmd_flex_filter_result {
+ cmdline_fixed_string_t filter;
+ cmdline_fixed_string_t ops;
+ portid_t port_id;
+ cmdline_fixed_string_t len;
+ uint8_t len_value;
+ cmdline_fixed_string_t bytes;
+ cmdline_fixed_string_t bytes_value;
+ cmdline_fixed_string_t mask;
+ cmdline_fixed_string_t mask_value;
+ cmdline_fixed_string_t priority;
+ uint8_t priority_value;
+ cmdline_fixed_string_t queue;
+ uint16_t queue_id;
+};
+
+static int xdigit2val(unsigned char c)
+{
+ int val;
+ if (isdigit(c))
+ val = c - '0';
+ else if (isupper(c))
+ val = c - 'A' + 10;
+ else
+ val = c - 'a' + 10;
+ return val;
+}
+
+static void
+cmd_flex_filter_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ int ret = 0;
+ struct rte_eth_flex_filter filter;
+ struct cmd_flex_filter_result *res = parsed_result;
+ char *bytes_ptr, *mask_ptr;
+ uint16_t len, i, j = 0;
+ char c;
+ int val;
+ uint8_t byte = 0;
+
+ if (res->len_value > RTE_FLEX_FILTER_MAXLEN) {
+ printf("the len exceed the max length 128\n");
+ return;
+ }
+ memset(&filter, 0, sizeof(struct rte_eth_flex_filter));
+ filter.len = res->len_value;
+ filter.priority = res->priority_value;
+ filter.queue = res->queue_id;
+ bytes_ptr = res->bytes_value;
+ mask_ptr = res->mask_value;
+
+ /* translate bytes string to array. */
+ if (bytes_ptr[0] == '0' && ((bytes_ptr[1] == 'x') ||
+ (bytes_ptr[1] == 'X')))
+ bytes_ptr += 2;
+ len = strnlen(bytes_ptr, res->len_value * 2);
+ if (len == 0 || (len % 8 != 0)) {
+ printf("please check len and bytes input\n");
+ return;
+ }
+ for (i = 0; i < len; i++) {
+ c = bytes_ptr[i];
+ if (isxdigit(c) == 0) {
+ /* invalid characters. */
+ printf("invalid input\n");
+ return;
+ }
+ val = xdigit2val(c);
+ if (i % 2) {
+ byte |= val;
+ filter.bytes[j] = byte;
+ printf("bytes[%d]:%02x ", j, filter.bytes[j]);
+ j++;
+ byte = 0;
+ } else
+ byte |= val << 4;
+ }
+ printf("\n");
+ /* translate mask string to uint8_t array. */
+ if (mask_ptr[0] == '0' && ((mask_ptr[1] == 'x') ||
+ (mask_ptr[1] == 'X')))
+ mask_ptr += 2;
+ len = strnlen(mask_ptr, (res->len_value + 3) / 4);
+ if (len == 0) {
+ printf("invalid input\n");
+ return;
+ }
+ j = 0;
+ byte = 0;
+ for (i = 0; i < len; i++) {
+ c = mask_ptr[i];
+ if (isxdigit(c) == 0) {
+ /* invalid characters. */
+ printf("invalid input\n");
+ return;
+ }
+ val = xdigit2val(c);
+ if (i % 2) {
+ byte |= val;
+ filter.mask[j] = byte;
+ printf("mask[%d]:%02x ", j, filter.mask[j]);
+ j++;
+ byte = 0;
+ } else
+ byte |= val << 4;
+ }
+ printf("\n");
+
+ if (!strcmp(res->ops, "add"))
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_FLEXIBLE,
+ RTE_ETH_FILTER_ADD,
+ &filter);
+ else
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_FLEXIBLE,
+ RTE_ETH_FILTER_DELETE,
+ &filter);
+
+ if (ret < 0)
+ printf("flex filter setting error: (%s)\n", strerror(-ret));
+}
+
+cmdline_parse_token_string_t cmd_flex_filter_filter =
+ TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
+ filter, "flex_filter");
+cmdline_parse_token_num_t cmd_flex_filter_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_flex_filter_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_flex_filter_ops =
+ TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
+ ops, "add#del");
+cmdline_parse_token_string_t cmd_flex_filter_len =
+ TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
+ len, "len");
+cmdline_parse_token_num_t cmd_flex_filter_len_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_flex_filter_result,
+ len_value, UINT8);
+cmdline_parse_token_string_t cmd_flex_filter_bytes =
+ TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
+ bytes, "bytes");
+cmdline_parse_token_string_t cmd_flex_filter_bytes_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
+ bytes_value, NULL);
+cmdline_parse_token_string_t cmd_flex_filter_mask =
+ TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
+ mask, "mask");
+cmdline_parse_token_string_t cmd_flex_filter_mask_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
+ mask_value, NULL);
+cmdline_parse_token_string_t cmd_flex_filter_priority =
+ TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
+ priority, "priority");
+cmdline_parse_token_num_t cmd_flex_filter_priority_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_flex_filter_result,
+ priority_value, UINT8);
+cmdline_parse_token_string_t cmd_flex_filter_queue =
+ TOKEN_STRING_INITIALIZER(struct cmd_flex_filter_result,
+ queue, "queue");
+cmdline_parse_token_num_t cmd_flex_filter_queue_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_flex_filter_result,
+ queue_id, UINT16);
+cmdline_parse_inst_t cmd_flex_filter = {
+ .f = cmd_flex_filter_parsed,
+ .data = NULL,
+ .help_str = "flex_filter <port_id> add|del len <value> bytes "
+ "<value> mask <value> priority <value> queue <queue_id>: "
+ "Add/Del a flex filter",
+ .tokens = {
+ (void *)&cmd_flex_filter_filter,
+ (void *)&cmd_flex_filter_port_id,
+ (void *)&cmd_flex_filter_ops,
+ (void *)&cmd_flex_filter_len,
+ (void *)&cmd_flex_filter_len_value,
+ (void *)&cmd_flex_filter_bytes,
+ (void *)&cmd_flex_filter_bytes_value,
+ (void *)&cmd_flex_filter_mask,
+ (void *)&cmd_flex_filter_mask_value,
+ (void *)&cmd_flex_filter_priority,
+ (void *)&cmd_flex_filter_priority_value,
+ (void *)&cmd_flex_filter_queue,
+ (void *)&cmd_flex_filter_queue_id,
+ NULL,
+ },
+};
+
+/* *** Filters Control *** */
+
+/* *** deal with ethertype filter *** */
+struct cmd_ethertype_filter_result {
+ cmdline_fixed_string_t filter;
+ portid_t port_id;
+ cmdline_fixed_string_t ops;
+ cmdline_fixed_string_t mac;
+ struct rte_ether_addr mac_addr;
+ cmdline_fixed_string_t ethertype;
+ uint16_t ethertype_value;
+ cmdline_fixed_string_t drop;
+ cmdline_fixed_string_t queue;
+ uint16_t queue_id;
+};
+
+cmdline_parse_token_string_t cmd_ethertype_filter_filter =
+ TOKEN_STRING_INITIALIZER(struct cmd_ethertype_filter_result,
+ filter, "ethertype_filter");
+cmdline_parse_token_num_t cmd_ethertype_filter_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_ethertype_filter_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_ethertype_filter_ops =
+ TOKEN_STRING_INITIALIZER(struct cmd_ethertype_filter_result,
+ ops, "add#del");
+cmdline_parse_token_string_t cmd_ethertype_filter_mac =
+ TOKEN_STRING_INITIALIZER(struct cmd_ethertype_filter_result,
+ mac, "mac_addr#mac_ignr");
+cmdline_parse_token_etheraddr_t cmd_ethertype_filter_mac_addr =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_ethertype_filter_result,
+ mac_addr);
+cmdline_parse_token_string_t cmd_ethertype_filter_ethertype =
+ TOKEN_STRING_INITIALIZER(struct cmd_ethertype_filter_result,
+ ethertype, "ethertype");
+cmdline_parse_token_num_t cmd_ethertype_filter_ethertype_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_ethertype_filter_result,
+ ethertype_value, UINT16);
+cmdline_parse_token_string_t cmd_ethertype_filter_drop =
+ TOKEN_STRING_INITIALIZER(struct cmd_ethertype_filter_result,
+ drop, "drop#fwd");
+cmdline_parse_token_string_t cmd_ethertype_filter_queue =
+ TOKEN_STRING_INITIALIZER(struct cmd_ethertype_filter_result,
+ queue, "queue");
+cmdline_parse_token_num_t cmd_ethertype_filter_queue_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_ethertype_filter_result,
+ queue_id, UINT16);
+
+static void
+cmd_ethertype_filter_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_ethertype_filter_result *res = parsed_result;
+ struct rte_eth_ethertype_filter filter;
+ int ret = 0;
+
+ ret = rte_eth_dev_filter_supported(res->port_id,
+ RTE_ETH_FILTER_ETHERTYPE);
+ if (ret < 0) {
+ printf("ethertype filter is not supported on port %u.\n",
+ res->port_id);
+ return;
+ }
+
+ memset(&filter, 0, sizeof(filter));
+ if (!strcmp(res->mac, "mac_addr")) {
+ filter.flags |= RTE_ETHTYPE_FLAGS_MAC;
+ rte_memcpy(&filter.mac_addr, &res->mac_addr,
+ sizeof(struct rte_ether_addr));
+ }
+ if (!strcmp(res->drop, "drop"))
+ filter.flags |= RTE_ETHTYPE_FLAGS_DROP;
+ filter.ether_type = res->ethertype_value;
+ filter.queue = res->queue_id;
+
+ if (!strcmp(res->ops, "add"))
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_ETHERTYPE,
+ RTE_ETH_FILTER_ADD,
+ &filter);
+ else
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_ETHERTYPE,
+ RTE_ETH_FILTER_DELETE,
+ &filter);
+ if (ret < 0)
+ printf("ethertype filter programming error: (%s)\n",
+ strerror(-ret));
+}
+
+cmdline_parse_inst_t cmd_ethertype_filter = {
+ .f = cmd_ethertype_filter_parsed,
+ .data = NULL,
+ .help_str = "ethertype_filter <port_id> add|del mac_addr|mac_ignr "
+ "<mac_addr> ethertype <value> drop|fw queue <queue_id>: "
+ "Add or delete an ethertype filter entry",
+ .tokens = {
+ (void *)&cmd_ethertype_filter_filter,
+ (void *)&cmd_ethertype_filter_port_id,
+ (void *)&cmd_ethertype_filter_ops,
+ (void *)&cmd_ethertype_filter_mac,
+ (void *)&cmd_ethertype_filter_mac_addr,
+ (void *)&cmd_ethertype_filter_ethertype,
+ (void *)&cmd_ethertype_filter_ethertype_value,
+ (void *)&cmd_ethertype_filter_drop,
+ (void *)&cmd_ethertype_filter_queue,
+ (void *)&cmd_ethertype_filter_queue_id,
+ NULL,
+ },
+};
+
+/* *** deal with flow director filter *** */
+struct cmd_flow_director_result {
+ cmdline_fixed_string_t flow_director_filter;
+ portid_t port_id;
+ cmdline_fixed_string_t mode;
+ cmdline_fixed_string_t mode_value;
+ cmdline_fixed_string_t ops;
+ cmdline_fixed_string_t flow;
+ cmdline_fixed_string_t flow_type;
+ cmdline_fixed_string_t ether;
+ uint16_t ether_type;
+ cmdline_fixed_string_t src;
+ cmdline_ipaddr_t ip_src;
+ uint16_t port_src;
+ cmdline_fixed_string_t dst;
+ cmdline_ipaddr_t ip_dst;
+ uint16_t port_dst;
+ cmdline_fixed_string_t verify_tag;
+ uint32_t verify_tag_value;
+ cmdline_fixed_string_t tos;
+ uint8_t tos_value;
+ cmdline_fixed_string_t proto;
+ uint8_t proto_value;
+ cmdline_fixed_string_t ttl;
+ uint8_t ttl_value;
+ cmdline_fixed_string_t vlan;
+ uint16_t vlan_value;
+ cmdline_fixed_string_t flexbytes;
+ cmdline_fixed_string_t flexbytes_value;
+ cmdline_fixed_string_t pf_vf;
+ cmdline_fixed_string_t drop;
+ cmdline_fixed_string_t queue;
+ uint16_t queue_id;
+ cmdline_fixed_string_t fd_id;
+ uint32_t fd_id_value;
+ cmdline_fixed_string_t mac;
+ struct rte_ether_addr mac_addr;
+ cmdline_fixed_string_t tunnel;
+ cmdline_fixed_string_t tunnel_type;
+ cmdline_fixed_string_t tunnel_id;
+ uint32_t tunnel_id_value;
+ cmdline_fixed_string_t packet;
+ char filepath[];
+};
+
+static inline int
+parse_flexbytes(const char *q_arg, uint8_t *flexbytes, uint16_t max_num)
+{
+ char s[256];
+ const char *p, *p0 = q_arg;
+ char *end;
+ unsigned long int_fld;
+ char *str_fld[max_num];
+ int i;
+ unsigned size;
+ int ret = -1;
+
+ p = strchr(p0, '(');
+ if (p == NULL)
+ return -1;
+ ++p;
+ p0 = strchr(p, ')');
+ if (p0 == NULL)
+ return -1;
+
+ size = p0 - p;
+ if (size >= sizeof(s))
+ return -1;
+
+ snprintf(s, sizeof(s), "%.*s", size, p);
+ ret = rte_strsplit(s, sizeof(s), str_fld, max_num, ',');
+ if (ret < 0 || ret > max_num)
+ return -1;
+ for (i = 0; i < ret; i++) {
+ errno = 0;
+ int_fld = strtoul(str_fld[i], &end, 0);
+ if (errno != 0 || *end != '\0' || int_fld > UINT8_MAX)
+ return -1;
+ flexbytes[i] = (uint8_t)int_fld;
+ }
+ return ret;
+}
+
+static uint16_t
+str2flowtype(char *string)
+{
+ uint8_t i = 0;
+ static const struct {
+ char str[32];
+ uint16_t type;
+ } flowtype_str[] = {
+ {"raw", RTE_ETH_FLOW_RAW},
+ {"ipv4", RTE_ETH_FLOW_IPV4},
+ {"ipv4-frag", RTE_ETH_FLOW_FRAG_IPV4},
+ {"ipv4-tcp", RTE_ETH_FLOW_NONFRAG_IPV4_TCP},
+ {"ipv4-udp", RTE_ETH_FLOW_NONFRAG_IPV4_UDP},
+ {"ipv4-sctp", RTE_ETH_FLOW_NONFRAG_IPV4_SCTP},
+ {"ipv4-other", RTE_ETH_FLOW_NONFRAG_IPV4_OTHER},
+ {"ipv6", RTE_ETH_FLOW_IPV6},
+ {"ipv6-frag", RTE_ETH_FLOW_FRAG_IPV6},
+ {"ipv6-tcp", RTE_ETH_FLOW_NONFRAG_IPV6_TCP},
+ {"ipv6-udp", RTE_ETH_FLOW_NONFRAG_IPV6_UDP},
+ {"ipv6-sctp", RTE_ETH_FLOW_NONFRAG_IPV6_SCTP},
+ {"ipv6-other", RTE_ETH_FLOW_NONFRAG_IPV6_OTHER},
+ {"l2_payload", RTE_ETH_FLOW_L2_PAYLOAD},
+ };
+
+ for (i = 0; i < RTE_DIM(flowtype_str); i++) {
+ if (!strcmp(flowtype_str[i].str, string))
+ return flowtype_str[i].type;
+ }
+
+ if (isdigit(string[0]) && atoi(string) > 0 && atoi(string) < 64)
+ return (uint16_t)atoi(string);
+
+ return RTE_ETH_FLOW_UNKNOWN;
+}
+
+static enum rte_eth_fdir_tunnel_type
+str2fdir_tunneltype(char *string)
+{
+ uint8_t i = 0;
+
+ static const struct {
+ char str[32];
+ enum rte_eth_fdir_tunnel_type type;
+ } tunneltype_str[] = {
+ {"NVGRE", RTE_FDIR_TUNNEL_TYPE_NVGRE},
+ {"VxLAN", RTE_FDIR_TUNNEL_TYPE_VXLAN},
+ };
+
+ for (i = 0; i < RTE_DIM(tunneltype_str); i++) {
+ if (!strcmp(tunneltype_str[i].str, string))
+ return tunneltype_str[i].type;
+ }
+ return RTE_FDIR_TUNNEL_TYPE_UNKNOWN;
+}
+
+#define IPV4_ADDR_TO_UINT(ip_addr, ip) \
+do { \
+ if ((ip_addr).family == AF_INET) \
+ (ip) = (ip_addr).addr.ipv4.s_addr; \
+ else { \
+ printf("invalid parameter.\n"); \
+ return; \
+ } \
+} while (0)
+
+#define IPV6_ADDR_TO_ARRAY(ip_addr, ip) \
+do { \
+ if ((ip_addr).family == AF_INET6) \
+ rte_memcpy(&(ip), \
+ &((ip_addr).addr.ipv6), \
+ sizeof(struct in6_addr)); \
+ else { \
+ printf("invalid parameter.\n"); \
+ return; \
+ } \
+} while (0)
+
+static void
+cmd_flow_director_filter_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_flow_director_result *res = parsed_result;
+ struct rte_eth_fdir_filter entry;
+ uint8_t flexbytes[RTE_ETH_FDIR_MAX_FLEXLEN];
+ char *end;
+ unsigned long vf_id;
+ int ret = 0;
+
+ ret = rte_eth_dev_filter_supported(res->port_id, RTE_ETH_FILTER_FDIR);
+ if (ret < 0) {
+ printf("flow director is not supported on port %u.\n",
+ res->port_id);
+ return;
+ }
+ memset(flexbytes, 0, sizeof(flexbytes));
+ memset(&entry, 0, sizeof(struct rte_eth_fdir_filter));
+
+ if (fdir_conf.mode == RTE_FDIR_MODE_PERFECT_MAC_VLAN) {
+ if (strcmp(res->mode_value, "MAC-VLAN")) {
+ printf("Please set mode to MAC-VLAN.\n");
+ return;
+ }
+ } else if (fdir_conf.mode == RTE_FDIR_MODE_PERFECT_TUNNEL) {
+ if (strcmp(res->mode_value, "Tunnel")) {
+ printf("Please set mode to Tunnel.\n");
+ return;
+ }
+ } else {
+ if (!strcmp(res->mode_value, "raw")) {
+#ifdef RTE_LIBRTE_I40E_PMD
+ struct rte_pmd_i40e_flow_type_mapping
+ mapping[RTE_PMD_I40E_FLOW_TYPE_MAX];
+ struct rte_pmd_i40e_pkt_template_conf conf;
+ uint16_t flow_type = str2flowtype(res->flow_type);
+ uint16_t i, port = res->port_id;
+ uint8_t add;
+
+ memset(&conf, 0, sizeof(conf));
+
+ if (flow_type == RTE_ETH_FLOW_UNKNOWN) {
+ printf("Invalid flow type specified.\n");
+ return;
+ }
+ ret = rte_pmd_i40e_flow_type_mapping_get(res->port_id,
+ mapping);
+ if (ret)
+ return;
+ if (mapping[flow_type].pctype == 0ULL) {
+ printf("Invalid flow type specified.\n");
+ return;
+ }
+ for (i = 0; i < RTE_PMD_I40E_PCTYPE_MAX; i++) {
+ if (mapping[flow_type].pctype & (1ULL << i)) {
+ conf.input.pctype = i;
+ break;
+ }
+ }
+
+ conf.input.packet = open_file(res->filepath,
+ &conf.input.length);
+ if (!conf.input.packet)
+ return;
+ if (!strcmp(res->drop, "drop"))
+ conf.action.behavior =
+ RTE_PMD_I40E_PKT_TEMPLATE_REJECT;
+ else
+ conf.action.behavior =
+ RTE_PMD_I40E_PKT_TEMPLATE_ACCEPT;
+ conf.action.report_status =
+ RTE_PMD_I40E_PKT_TEMPLATE_REPORT_ID;
+ conf.action.rx_queue = res->queue_id;
+ conf.soft_id = res->fd_id_value;
+ add = strcmp(res->ops, "del") ? 1 : 0;
+ ret = rte_pmd_i40e_flow_add_del_packet_template(port,
+ &conf,
+ add);
+ if (ret < 0)
+ printf("flow director config error: (%s)\n",
+ strerror(-ret));
+ close_file(conf.input.packet);
+#endif
+ return;
+ } else if (strcmp(res->mode_value, "IP")) {
+ printf("Please set mode to IP or raw.\n");
+ return;
+ }
+ entry.input.flow_type = str2flowtype(res->flow_type);
+ }
+
+ ret = parse_flexbytes(res->flexbytes_value,
+ flexbytes,
+ RTE_ETH_FDIR_MAX_FLEXLEN);
+ if (ret < 0) {
+ printf("error: Cannot parse flexbytes input.\n");
+ return;
+ }
+
+ switch (entry.input.flow_type) {
+ case RTE_ETH_FLOW_FRAG_IPV4:
+ case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
+ entry.input.flow.ip4_flow.proto = res->proto_value;
+ /* fall-through */
+ case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
+ case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
+ IPV4_ADDR_TO_UINT(res->ip_dst,
+ entry.input.flow.ip4_flow.dst_ip);
+ IPV4_ADDR_TO_UINT(res->ip_src,
+ entry.input.flow.ip4_flow.src_ip);
+ entry.input.flow.ip4_flow.tos = res->tos_value;
+ entry.input.flow.ip4_flow.ttl = res->ttl_value;
+ /* need convert to big endian. */
+ entry.input.flow.udp4_flow.dst_port =
+ rte_cpu_to_be_16(res->port_dst);
+ entry.input.flow.udp4_flow.src_port =
+ rte_cpu_to_be_16(res->port_src);
+ break;
+ case RTE_ETH_FLOW_NONFRAG_IPV4_SCTP:
+ IPV4_ADDR_TO_UINT(res->ip_dst,
+ entry.input.flow.sctp4_flow.ip.dst_ip);
+ IPV4_ADDR_TO_UINT(res->ip_src,
+ entry.input.flow.sctp4_flow.ip.src_ip);
+ entry.input.flow.ip4_flow.tos = res->tos_value;
+ entry.input.flow.ip4_flow.ttl = res->ttl_value;
+ /* need convert to big endian. */
+ entry.input.flow.sctp4_flow.dst_port =
+ rte_cpu_to_be_16(res->port_dst);
+ entry.input.flow.sctp4_flow.src_port =
+ rte_cpu_to_be_16(res->port_src);
+ entry.input.flow.sctp4_flow.verify_tag =
+ rte_cpu_to_be_32(res->verify_tag_value);
+ break;
+ case RTE_ETH_FLOW_FRAG_IPV6:
+ case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
+ entry.input.flow.ipv6_flow.proto = res->proto_value;
+ /* fall-through */
+ case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
+ case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
+ IPV6_ADDR_TO_ARRAY(res->ip_dst,
+ entry.input.flow.ipv6_flow.dst_ip);
+ IPV6_ADDR_TO_ARRAY(res->ip_src,
+ entry.input.flow.ipv6_flow.src_ip);
+ entry.input.flow.ipv6_flow.tc = res->tos_value;
+ entry.input.flow.ipv6_flow.hop_limits = res->ttl_value;
+ /* need convert to big endian. */
+ entry.input.flow.udp6_flow.dst_port =
+ rte_cpu_to_be_16(res->port_dst);
+ entry.input.flow.udp6_flow.src_port =
+ rte_cpu_to_be_16(res->port_src);
+ break;
+ case RTE_ETH_FLOW_NONFRAG_IPV6_SCTP:
+ IPV6_ADDR_TO_ARRAY(res->ip_dst,
+ entry.input.flow.sctp6_flow.ip.dst_ip);
+ IPV6_ADDR_TO_ARRAY(res->ip_src,
+ entry.input.flow.sctp6_flow.ip.src_ip);
+ entry.input.flow.ipv6_flow.tc = res->tos_value;
+ entry.input.flow.ipv6_flow.hop_limits = res->ttl_value;
+ /* need convert to big endian. */
+ entry.input.flow.sctp6_flow.dst_port =
+ rte_cpu_to_be_16(res->port_dst);
+ entry.input.flow.sctp6_flow.src_port =
+ rte_cpu_to_be_16(res->port_src);
+ entry.input.flow.sctp6_flow.verify_tag =
+ rte_cpu_to_be_32(res->verify_tag_value);
+ break;
+ case RTE_ETH_FLOW_L2_PAYLOAD:
+ entry.input.flow.l2_flow.ether_type =
+ rte_cpu_to_be_16(res->ether_type);
+ break;
+ default:
+ break;
+ }
+
+ if (fdir_conf.mode == RTE_FDIR_MODE_PERFECT_MAC_VLAN)
+ rte_memcpy(&entry.input.flow.mac_vlan_flow.mac_addr,
+ &res->mac_addr,
+ sizeof(struct rte_ether_addr));
+
+ if (fdir_conf.mode == RTE_FDIR_MODE_PERFECT_TUNNEL) {
+ rte_memcpy(&entry.input.flow.tunnel_flow.mac_addr,
+ &res->mac_addr,
+ sizeof(struct rte_ether_addr));
+ entry.input.flow.tunnel_flow.tunnel_type =
+ str2fdir_tunneltype(res->tunnel_type);
+ entry.input.flow.tunnel_flow.tunnel_id =
+ rte_cpu_to_be_32(res->tunnel_id_value);
+ }
+
+ rte_memcpy(entry.input.flow_ext.flexbytes,
+ flexbytes,
+ RTE_ETH_FDIR_MAX_FLEXLEN);
+
+ entry.input.flow_ext.vlan_tci = rte_cpu_to_be_16(res->vlan_value);
+
+ entry.action.flex_off = 0; /*use 0 by default */
+ if (!strcmp(res->drop, "drop"))
+ entry.action.behavior = RTE_ETH_FDIR_REJECT;
+ else
+ entry.action.behavior = RTE_ETH_FDIR_ACCEPT;
+
+ if (fdir_conf.mode != RTE_FDIR_MODE_PERFECT_MAC_VLAN &&
+ fdir_conf.mode != RTE_FDIR_MODE_PERFECT_TUNNEL) {
+ if (!strcmp(res->pf_vf, "pf"))
+ entry.input.flow_ext.is_vf = 0;
+ else if (!strncmp(res->pf_vf, "vf", 2)) {
+ struct rte_eth_dev_info dev_info;
+
+ ret = eth_dev_info_get_print_err(res->port_id,
+ &dev_info);
+ if (ret != 0)
+ return;
+
+ errno = 0;
+ vf_id = strtoul(res->pf_vf + 2, &end, 10);
+ if (errno != 0 || *end != '\0' ||
+ vf_id >= dev_info.max_vfs) {
+ printf("invalid parameter %s.\n", res->pf_vf);
+ return;
+ }
+ entry.input.flow_ext.is_vf = 1;
+ entry.input.flow_ext.dst_id = (uint16_t)vf_id;
+ } else {
+ printf("invalid parameter %s.\n", res->pf_vf);
+ return;
+ }
+ }
+
+ /* set to report FD ID by default */
+ entry.action.report_status = RTE_ETH_FDIR_REPORT_ID;
+ entry.action.rx_queue = res->queue_id;
+ entry.soft_id = res->fd_id_value;
+ if (!strcmp(res->ops, "add"))
+ ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_FDIR,
+ RTE_ETH_FILTER_ADD, &entry);
+ else if (!strcmp(res->ops, "del"))
+ ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_FDIR,
+ RTE_ETH_FILTER_DELETE, &entry);
+ else
+ ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_FDIR,
+ RTE_ETH_FILTER_UPDATE, &entry);
+ if (ret < 0)
+ printf("flow director programming error: (%s)\n",
+ strerror(-ret));
+}
+
+cmdline_parse_token_string_t cmd_flow_director_filter =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ flow_director_filter, "flow_director_filter");
+cmdline_parse_token_num_t cmd_flow_director_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_flow_director_ops =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ ops, "add#del#update");
+cmdline_parse_token_string_t cmd_flow_director_flow =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ flow, "flow");
+cmdline_parse_token_string_t cmd_flow_director_flow_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ flow_type, NULL);
+cmdline_parse_token_string_t cmd_flow_director_ether =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ ether, "ether");
+cmdline_parse_token_num_t cmd_flow_director_ether_type =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+ ether_type, UINT16);
+cmdline_parse_token_string_t cmd_flow_director_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ src, "src");
+cmdline_parse_token_ipaddr_t cmd_flow_director_ip_src =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_flow_director_result,
+ ip_src);
+cmdline_parse_token_num_t cmd_flow_director_port_src =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+ port_src, UINT16);
+cmdline_parse_token_string_t cmd_flow_director_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ dst, "dst");
+cmdline_parse_token_ipaddr_t cmd_flow_director_ip_dst =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_flow_director_result,
+ ip_dst);
+cmdline_parse_token_num_t cmd_flow_director_port_dst =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+ port_dst, UINT16);
+cmdline_parse_token_string_t cmd_flow_director_verify_tag =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ verify_tag, "verify_tag");
+cmdline_parse_token_num_t cmd_flow_director_verify_tag_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+ verify_tag_value, UINT32);
+cmdline_parse_token_string_t cmd_flow_director_tos =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ tos, "tos");
+cmdline_parse_token_num_t cmd_flow_director_tos_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+ tos_value, UINT8);
+cmdline_parse_token_string_t cmd_flow_director_proto =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ proto, "proto");
+cmdline_parse_token_num_t cmd_flow_director_proto_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+ proto_value, UINT8);
+cmdline_parse_token_string_t cmd_flow_director_ttl =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ ttl, "ttl");
+cmdline_parse_token_num_t cmd_flow_director_ttl_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+ ttl_value, UINT8);
+cmdline_parse_token_string_t cmd_flow_director_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ vlan, "vlan");
+cmdline_parse_token_num_t cmd_flow_director_vlan_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+ vlan_value, UINT16);
+cmdline_parse_token_string_t cmd_flow_director_flexbytes =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ flexbytes, "flexbytes");
+cmdline_parse_token_string_t cmd_flow_director_flexbytes_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ flexbytes_value, NULL);
+cmdline_parse_token_string_t cmd_flow_director_drop =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ drop, "drop#fwd");
+cmdline_parse_token_string_t cmd_flow_director_pf_vf =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ pf_vf, NULL);
+cmdline_parse_token_string_t cmd_flow_director_queue =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ queue, "queue");
+cmdline_parse_token_num_t cmd_flow_director_queue_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+ queue_id, UINT16);
+cmdline_parse_token_string_t cmd_flow_director_fd_id =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ fd_id, "fd_id");
+cmdline_parse_token_num_t cmd_flow_director_fd_id_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+ fd_id_value, UINT32);
+
+cmdline_parse_token_string_t cmd_flow_director_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ mode, "mode");
+cmdline_parse_token_string_t cmd_flow_director_mode_ip =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ mode_value, "IP");
+cmdline_parse_token_string_t cmd_flow_director_mode_mac_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ mode_value, "MAC-VLAN");
+cmdline_parse_token_string_t cmd_flow_director_mode_tunnel =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ mode_value, "Tunnel");
+cmdline_parse_token_string_t cmd_flow_director_mode_raw =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ mode_value, "raw");
+cmdline_parse_token_string_t cmd_flow_director_mac =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ mac, "mac");
+cmdline_parse_token_etheraddr_t cmd_flow_director_mac_addr =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_flow_director_result,
+ mac_addr);
+cmdline_parse_token_string_t cmd_flow_director_tunnel =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ tunnel, "tunnel");
+cmdline_parse_token_string_t cmd_flow_director_tunnel_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ tunnel_type, "NVGRE#VxLAN");
+cmdline_parse_token_string_t cmd_flow_director_tunnel_id =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ tunnel_id, "tunnel-id");
+cmdline_parse_token_num_t cmd_flow_director_tunnel_id_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_result,
+ tunnel_id_value, UINT32);
+cmdline_parse_token_string_t cmd_flow_director_packet =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ packet, "packet");
+cmdline_parse_token_string_t cmd_flow_director_filepath =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_result,
+ filepath, NULL);
+
+cmdline_parse_inst_t cmd_add_del_ip_flow_director = {
+ .f = cmd_flow_director_filter_parsed,
+ .data = NULL,
+ .help_str = "flow_director_filter <port_id> mode IP add|del|update flow"
+ " ipv4-other|ipv4-frag|ipv4-tcp|ipv4-udp|ipv4-sctp|"
+ "ipv6-other|ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|"
+ "l2_payload src <src_ip> dst <dst_ip> tos <tos_value> "
+ "proto <proto_value> ttl <ttl_value> vlan <vlan_value> "
+ "flexbytes <flexbyte_values> drop|fw <pf_vf> queue <queue_id> "
+ "fd_id <fd_id_value>: "
+ "Add or delete an ip flow director entry on NIC",
+ .tokens = {
+ (void *)&cmd_flow_director_filter,
+ (void *)&cmd_flow_director_port_id,
+ (void *)&cmd_flow_director_mode,
+ (void *)&cmd_flow_director_mode_ip,
+ (void *)&cmd_flow_director_ops,
+ (void *)&cmd_flow_director_flow,
+ (void *)&cmd_flow_director_flow_type,
+ (void *)&cmd_flow_director_src,
+ (void *)&cmd_flow_director_ip_src,
+ (void *)&cmd_flow_director_dst,
+ (void *)&cmd_flow_director_ip_dst,
+ (void *)&cmd_flow_director_tos,
+ (void *)&cmd_flow_director_tos_value,
+ (void *)&cmd_flow_director_proto,
+ (void *)&cmd_flow_director_proto_value,
+ (void *)&cmd_flow_director_ttl,
+ (void *)&cmd_flow_director_ttl_value,
+ (void *)&cmd_flow_director_vlan,
+ (void *)&cmd_flow_director_vlan_value,
+ (void *)&cmd_flow_director_flexbytes,
+ (void *)&cmd_flow_director_flexbytes_value,
+ (void *)&cmd_flow_director_drop,
+ (void *)&cmd_flow_director_pf_vf,
+ (void *)&cmd_flow_director_queue,
+ (void *)&cmd_flow_director_queue_id,
+ (void *)&cmd_flow_director_fd_id,
+ (void *)&cmd_flow_director_fd_id_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_add_del_udp_flow_director = {
+ .f = cmd_flow_director_filter_parsed,
+ .data = NULL,
+ .help_str = "flow_director_filter ... : Add or delete an udp/tcp flow "
+ "director entry on NIC",
+ .tokens = {
+ (void *)&cmd_flow_director_filter,
+ (void *)&cmd_flow_director_port_id,
+ (void *)&cmd_flow_director_mode,
+ (void *)&cmd_flow_director_mode_ip,
+ (void *)&cmd_flow_director_ops,
+ (void *)&cmd_flow_director_flow,
+ (void *)&cmd_flow_director_flow_type,
+ (void *)&cmd_flow_director_src,
+ (void *)&cmd_flow_director_ip_src,
+ (void *)&cmd_flow_director_port_src,
+ (void *)&cmd_flow_director_dst,
+ (void *)&cmd_flow_director_ip_dst,
+ (void *)&cmd_flow_director_port_dst,
+ (void *)&cmd_flow_director_tos,
+ (void *)&cmd_flow_director_tos_value,
+ (void *)&cmd_flow_director_ttl,
+ (void *)&cmd_flow_director_ttl_value,
+ (void *)&cmd_flow_director_vlan,
+ (void *)&cmd_flow_director_vlan_value,
+ (void *)&cmd_flow_director_flexbytes,
+ (void *)&cmd_flow_director_flexbytes_value,
+ (void *)&cmd_flow_director_drop,
+ (void *)&cmd_flow_director_pf_vf,
+ (void *)&cmd_flow_director_queue,
+ (void *)&cmd_flow_director_queue_id,
+ (void *)&cmd_flow_director_fd_id,
+ (void *)&cmd_flow_director_fd_id_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_add_del_sctp_flow_director = {
+ .f = cmd_flow_director_filter_parsed,
+ .data = NULL,
+ .help_str = "flow_director_filter ... : Add or delete a sctp flow "
+ "director entry on NIC",
+ .tokens = {
+ (void *)&cmd_flow_director_filter,
+ (void *)&cmd_flow_director_port_id,
+ (void *)&cmd_flow_director_mode,
+ (void *)&cmd_flow_director_mode_ip,
+ (void *)&cmd_flow_director_ops,
+ (void *)&cmd_flow_director_flow,
+ (void *)&cmd_flow_director_flow_type,
+ (void *)&cmd_flow_director_src,
+ (void *)&cmd_flow_director_ip_src,
+ (void *)&cmd_flow_director_port_src,
+ (void *)&cmd_flow_director_dst,
+ (void *)&cmd_flow_director_ip_dst,
+ (void *)&cmd_flow_director_port_dst,
+ (void *)&cmd_flow_director_verify_tag,
+ (void *)&cmd_flow_director_verify_tag_value,
+ (void *)&cmd_flow_director_tos,
+ (void *)&cmd_flow_director_tos_value,
+ (void *)&cmd_flow_director_ttl,
+ (void *)&cmd_flow_director_ttl_value,
+ (void *)&cmd_flow_director_vlan,
+ (void *)&cmd_flow_director_vlan_value,
+ (void *)&cmd_flow_director_flexbytes,
+ (void *)&cmd_flow_director_flexbytes_value,
+ (void *)&cmd_flow_director_drop,
+ (void *)&cmd_flow_director_pf_vf,
+ (void *)&cmd_flow_director_queue,
+ (void *)&cmd_flow_director_queue_id,
+ (void *)&cmd_flow_director_fd_id,
+ (void *)&cmd_flow_director_fd_id_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_add_del_l2_flow_director = {
+ .f = cmd_flow_director_filter_parsed,
+ .data = NULL,
+ .help_str = "flow_director_filter ... : Add or delete a L2 flow "
+ "director entry on NIC",
+ .tokens = {
+ (void *)&cmd_flow_director_filter,
+ (void *)&cmd_flow_director_port_id,
+ (void *)&cmd_flow_director_mode,
+ (void *)&cmd_flow_director_mode_ip,
+ (void *)&cmd_flow_director_ops,
+ (void *)&cmd_flow_director_flow,
+ (void *)&cmd_flow_director_flow_type,
+ (void *)&cmd_flow_director_ether,
+ (void *)&cmd_flow_director_ether_type,
+ (void *)&cmd_flow_director_flexbytes,
+ (void *)&cmd_flow_director_flexbytes_value,
+ (void *)&cmd_flow_director_drop,
+ (void *)&cmd_flow_director_pf_vf,
+ (void *)&cmd_flow_director_queue,
+ (void *)&cmd_flow_director_queue_id,
+ (void *)&cmd_flow_director_fd_id,
+ (void *)&cmd_flow_director_fd_id_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_add_del_mac_vlan_flow_director = {
+ .f = cmd_flow_director_filter_parsed,
+ .data = NULL,
+ .help_str = "flow_director_filter ... : Add or delete a MAC VLAN flow "
+ "director entry on NIC",
+ .tokens = {
+ (void *)&cmd_flow_director_filter,
+ (void *)&cmd_flow_director_port_id,
+ (void *)&cmd_flow_director_mode,
+ (void *)&cmd_flow_director_mode_mac_vlan,
+ (void *)&cmd_flow_director_ops,
+ (void *)&cmd_flow_director_mac,
+ (void *)&cmd_flow_director_mac_addr,
+ (void *)&cmd_flow_director_vlan,
+ (void *)&cmd_flow_director_vlan_value,
+ (void *)&cmd_flow_director_flexbytes,
+ (void *)&cmd_flow_director_flexbytes_value,
+ (void *)&cmd_flow_director_drop,
+ (void *)&cmd_flow_director_queue,
+ (void *)&cmd_flow_director_queue_id,
+ (void *)&cmd_flow_director_fd_id,
+ (void *)&cmd_flow_director_fd_id_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_add_del_tunnel_flow_director = {
+ .f = cmd_flow_director_filter_parsed,
+ .data = NULL,
+ .help_str = "flow_director_filter ... : Add or delete a tunnel flow "
+ "director entry on NIC",
+ .tokens = {
+ (void *)&cmd_flow_director_filter,
+ (void *)&cmd_flow_director_port_id,
+ (void *)&cmd_flow_director_mode,
+ (void *)&cmd_flow_director_mode_tunnel,
+ (void *)&cmd_flow_director_ops,
+ (void *)&cmd_flow_director_mac,
+ (void *)&cmd_flow_director_mac_addr,
+ (void *)&cmd_flow_director_vlan,
+ (void *)&cmd_flow_director_vlan_value,
+ (void *)&cmd_flow_director_tunnel,
+ (void *)&cmd_flow_director_tunnel_type,
+ (void *)&cmd_flow_director_tunnel_id,
+ (void *)&cmd_flow_director_tunnel_id_value,
+ (void *)&cmd_flow_director_flexbytes,
+ (void *)&cmd_flow_director_flexbytes_value,
+ (void *)&cmd_flow_director_drop,
+ (void *)&cmd_flow_director_queue,
+ (void *)&cmd_flow_director_queue_id,
+ (void *)&cmd_flow_director_fd_id,
+ (void *)&cmd_flow_director_fd_id_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_add_del_raw_flow_director = {
+ .f = cmd_flow_director_filter_parsed,
+ .data = NULL,
+ .help_str = "flow_director_filter ... : Add or delete a raw flow "
+ "director entry on NIC",
+ .tokens = {
+ (void *)&cmd_flow_director_filter,
+ (void *)&cmd_flow_director_port_id,
+ (void *)&cmd_flow_director_mode,
+ (void *)&cmd_flow_director_mode_raw,
+ (void *)&cmd_flow_director_ops,
+ (void *)&cmd_flow_director_flow,
+ (void *)&cmd_flow_director_flow_type,
+ (void *)&cmd_flow_director_drop,
+ (void *)&cmd_flow_director_queue,
+ (void *)&cmd_flow_director_queue_id,
+ (void *)&cmd_flow_director_fd_id,
+ (void *)&cmd_flow_director_fd_id_value,
+ (void *)&cmd_flow_director_packet,
+ (void *)&cmd_flow_director_filepath,
+ NULL,
+ },
+};
+
+struct cmd_flush_flow_director_result {
+ cmdline_fixed_string_t flush_flow_director;
+ portid_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_flush_flow_director_flush =
+ TOKEN_STRING_INITIALIZER(struct cmd_flush_flow_director_result,
+ flush_flow_director, "flush_flow_director");
+cmdline_parse_token_num_t cmd_flush_flow_director_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_flush_flow_director_result,
+ port_id, UINT16);
+
+static void
+cmd_flush_flow_director_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_flow_director_result *res = parsed_result;
+ int ret = 0;
+
+ ret = rte_eth_dev_filter_supported(res->port_id, RTE_ETH_FILTER_FDIR);
+ if (ret < 0) {
+ printf("flow director is not supported on port %u.\n",
+ res->port_id);
+ return;
+ }
+
+ ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_FDIR,
+ RTE_ETH_FILTER_FLUSH, NULL);
+ if (ret < 0)
+ printf("flow director table flushing error: (%s)\n",
+ strerror(-ret));
+}
+
+cmdline_parse_inst_t cmd_flush_flow_director = {
+ .f = cmd_flush_flow_director_parsed,
+ .data = NULL,
+ .help_str = "flush_flow_director <port_id>: "
+ "Flush all flow director entries of a device on NIC",
+ .tokens = {
+ (void *)&cmd_flush_flow_director_flush,
+ (void *)&cmd_flush_flow_director_port_id,
+ NULL,
+ },
+};
+
+/* *** deal with flow director mask *** */
+struct cmd_flow_director_mask_result {
+ cmdline_fixed_string_t flow_director_mask;
+ portid_t port_id;
+ cmdline_fixed_string_t mode;
+ cmdline_fixed_string_t mode_value;
+ cmdline_fixed_string_t vlan;
+ uint16_t vlan_mask;
+ cmdline_fixed_string_t src_mask;
+ cmdline_ipaddr_t ipv4_src;
+ cmdline_ipaddr_t ipv6_src;
+ uint16_t port_src;
+ cmdline_fixed_string_t dst_mask;
+ cmdline_ipaddr_t ipv4_dst;
+ cmdline_ipaddr_t ipv6_dst;
+ uint16_t port_dst;
+ cmdline_fixed_string_t mac;
+ uint8_t mac_addr_byte_mask;
+ cmdline_fixed_string_t tunnel_id;
+ uint32_t tunnel_id_mask;
+ cmdline_fixed_string_t tunnel_type;
+ uint8_t tunnel_type_mask;
+};
+
+static void
+cmd_flow_director_mask_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_flow_director_mask_result *res = parsed_result;
+ struct rte_eth_fdir_masks *mask;
+ struct rte_port *port;
+
+ port = &ports[res->port_id];
+ /** Check if the port is not started **/
+ if (port->port_status != RTE_PORT_STOPPED) {
+ printf("Please stop port %d first\n", res->port_id);
+ return;
+ }
+
+ mask = &port->dev_conf.fdir_conf.mask;
+
+ if (fdir_conf.mode == RTE_FDIR_MODE_PERFECT_MAC_VLAN) {
+ if (strcmp(res->mode_value, "MAC-VLAN")) {
+ printf("Please set mode to MAC-VLAN.\n");
+ return;
+ }
+
+ mask->vlan_tci_mask = rte_cpu_to_be_16(res->vlan_mask);
+ } else if (fdir_conf.mode == RTE_FDIR_MODE_PERFECT_TUNNEL) {
+ if (strcmp(res->mode_value, "Tunnel")) {
+ printf("Please set mode to Tunnel.\n");
+ return;
+ }
+
+ mask->vlan_tci_mask = rte_cpu_to_be_16(res->vlan_mask);
+ mask->mac_addr_byte_mask = res->mac_addr_byte_mask;
+ mask->tunnel_id_mask = rte_cpu_to_be_32(res->tunnel_id_mask);
+ mask->tunnel_type_mask = res->tunnel_type_mask;
+ } else {
+ if (strcmp(res->mode_value, "IP")) {
+ printf("Please set mode to IP.\n");
+ return;
+ }
+
+ mask->vlan_tci_mask = rte_cpu_to_be_16(res->vlan_mask);
+ IPV4_ADDR_TO_UINT(res->ipv4_src, mask->ipv4_mask.src_ip);
+ IPV4_ADDR_TO_UINT(res->ipv4_dst, mask->ipv4_mask.dst_ip);
+ IPV6_ADDR_TO_ARRAY(res->ipv6_src, mask->ipv6_mask.src_ip);
+ IPV6_ADDR_TO_ARRAY(res->ipv6_dst, mask->ipv6_mask.dst_ip);
+ mask->src_port_mask = rte_cpu_to_be_16(res->port_src);
+ mask->dst_port_mask = rte_cpu_to_be_16(res->port_dst);
+ }
+
+ cmd_reconfig_device_queue(res->port_id, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_flow_director_mask =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_mask_result,
+ flow_director_mask, "flow_director_mask");
+cmdline_parse_token_num_t cmd_flow_director_mask_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_mask_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_flow_director_mask_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_mask_result,
+ vlan, "vlan");
+cmdline_parse_token_num_t cmd_flow_director_mask_vlan_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_mask_result,
+ vlan_mask, UINT16);
+cmdline_parse_token_string_t cmd_flow_director_mask_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_mask_result,
+ src_mask, "src_mask");
+cmdline_parse_token_ipaddr_t cmd_flow_director_mask_ipv4_src =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_flow_director_mask_result,
+ ipv4_src);
+cmdline_parse_token_ipaddr_t cmd_flow_director_mask_ipv6_src =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_flow_director_mask_result,
+ ipv6_src);
+cmdline_parse_token_num_t cmd_flow_director_mask_port_src =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_mask_result,
+ port_src, UINT16);
+cmdline_parse_token_string_t cmd_flow_director_mask_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_mask_result,
+ dst_mask, "dst_mask");
+cmdline_parse_token_ipaddr_t cmd_flow_director_mask_ipv4_dst =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_flow_director_mask_result,
+ ipv4_dst);
+cmdline_parse_token_ipaddr_t cmd_flow_director_mask_ipv6_dst =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_flow_director_mask_result,
+ ipv6_dst);
+cmdline_parse_token_num_t cmd_flow_director_mask_port_dst =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_mask_result,
+ port_dst, UINT16);
+
+cmdline_parse_token_string_t cmd_flow_director_mask_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_mask_result,
+ mode, "mode");
+cmdline_parse_token_string_t cmd_flow_director_mask_mode_ip =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_mask_result,
+ mode_value, "IP");
+cmdline_parse_token_string_t cmd_flow_director_mask_mode_mac_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_mask_result,
+ mode_value, "MAC-VLAN");
+cmdline_parse_token_string_t cmd_flow_director_mask_mode_tunnel =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_mask_result,
+ mode_value, "Tunnel");
+cmdline_parse_token_string_t cmd_flow_director_mask_mac =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_mask_result,
+ mac, "mac");
+cmdline_parse_token_num_t cmd_flow_director_mask_mac_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_mask_result,
+ mac_addr_byte_mask, UINT8);
+cmdline_parse_token_string_t cmd_flow_director_mask_tunnel_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_mask_result,
+ tunnel_type, "tunnel-type");
+cmdline_parse_token_num_t cmd_flow_director_mask_tunnel_type_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_mask_result,
+ tunnel_type_mask, UINT8);
+cmdline_parse_token_string_t cmd_flow_director_mask_tunnel_id =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_mask_result,
+ tunnel_id, "tunnel-id");
+cmdline_parse_token_num_t cmd_flow_director_mask_tunnel_id_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_mask_result,
+ tunnel_id_mask, UINT32);
+
+cmdline_parse_inst_t cmd_set_flow_director_ip_mask = {
+ .f = cmd_flow_director_mask_parsed,
+ .data = NULL,
+ .help_str = "flow_director_mask ... : "
+ "Set IP mode flow director's mask on NIC",
+ .tokens = {
+ (void *)&cmd_flow_director_mask,
+ (void *)&cmd_flow_director_mask_port_id,
+ (void *)&cmd_flow_director_mask_mode,
+ (void *)&cmd_flow_director_mask_mode_ip,
+ (void *)&cmd_flow_director_mask_vlan,
+ (void *)&cmd_flow_director_mask_vlan_value,
+ (void *)&cmd_flow_director_mask_src,
+ (void *)&cmd_flow_director_mask_ipv4_src,
+ (void *)&cmd_flow_director_mask_ipv6_src,
+ (void *)&cmd_flow_director_mask_port_src,
+ (void *)&cmd_flow_director_mask_dst,
+ (void *)&cmd_flow_director_mask_ipv4_dst,
+ (void *)&cmd_flow_director_mask_ipv6_dst,
+ (void *)&cmd_flow_director_mask_port_dst,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_flow_director_mac_vlan_mask = {
+ .f = cmd_flow_director_mask_parsed,
+ .data = NULL,
+ .help_str = "flow_director_mask ... : Set MAC VLAN mode "
+ "flow director's mask on NIC",
+ .tokens = {
+ (void *)&cmd_flow_director_mask,
+ (void *)&cmd_flow_director_mask_port_id,
+ (void *)&cmd_flow_director_mask_mode,
+ (void *)&cmd_flow_director_mask_mode_mac_vlan,
+ (void *)&cmd_flow_director_mask_vlan,
+ (void *)&cmd_flow_director_mask_vlan_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_flow_director_tunnel_mask = {
+ .f = cmd_flow_director_mask_parsed,
+ .data = NULL,
+ .help_str = "flow_director_mask ... : Set tunnel mode "
+ "flow director's mask on NIC",
+ .tokens = {
+ (void *)&cmd_flow_director_mask,
+ (void *)&cmd_flow_director_mask_port_id,
+ (void *)&cmd_flow_director_mask_mode,
+ (void *)&cmd_flow_director_mask_mode_tunnel,
+ (void *)&cmd_flow_director_mask_vlan,
+ (void *)&cmd_flow_director_mask_vlan_value,
+ (void *)&cmd_flow_director_mask_mac,
+ (void *)&cmd_flow_director_mask_mac_value,
+ (void *)&cmd_flow_director_mask_tunnel_type,
+ (void *)&cmd_flow_director_mask_tunnel_type_value,
+ (void *)&cmd_flow_director_mask_tunnel_id,
+ (void *)&cmd_flow_director_mask_tunnel_id_value,
+ NULL,
+ },
+};
+
+/* *** deal with flow director mask on flexible payload *** */
+struct cmd_flow_director_flex_mask_result {
+ cmdline_fixed_string_t flow_director_flexmask;
+ portid_t port_id;
+ cmdline_fixed_string_t flow;
+ cmdline_fixed_string_t flow_type;
+ cmdline_fixed_string_t mask;
+};
+
+static void
+cmd_flow_director_flex_mask_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_flow_director_flex_mask_result *res = parsed_result;
+ struct rte_eth_fdir_info fdir_info;
+ struct rte_eth_fdir_flex_mask flex_mask;
+ struct rte_port *port;
+ uint64_t flow_type_mask;
+ uint16_t i;
+ int ret;
+
+ port = &ports[res->port_id];
+ /** Check if the port is not started **/
+ if (port->port_status != RTE_PORT_STOPPED) {
+ printf("Please stop port %d first\n", res->port_id);
+ return;
+ }
+
+ memset(&flex_mask, 0, sizeof(struct rte_eth_fdir_flex_mask));
+ ret = parse_flexbytes(res->mask,
+ flex_mask.mask,
+ RTE_ETH_FDIR_MAX_FLEXLEN);
+ if (ret < 0) {
+ printf("error: Cannot parse mask input.\n");
+ return;
+ }
+
+ memset(&fdir_info, 0, sizeof(fdir_info));
+ ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_FDIR,
+ RTE_ETH_FILTER_INFO, &fdir_info);
+ if (ret < 0) {
+ printf("Cannot get FDir filter info\n");
+ return;
+ }
+
+ if (!strcmp(res->flow_type, "none")) {
+ /* means don't specify the flow type */
+ flex_mask.flow_type = RTE_ETH_FLOW_UNKNOWN;
+ for (i = 0; i < RTE_ETH_FLOW_MAX; i++)
+ memset(&port->dev_conf.fdir_conf.flex_conf.flex_mask[i],
+ 0, sizeof(struct rte_eth_fdir_flex_mask));
+ port->dev_conf.fdir_conf.flex_conf.nb_flexmasks = 1;
+ rte_memcpy(&port->dev_conf.fdir_conf.flex_conf.flex_mask[0],
+ &flex_mask,
+ sizeof(struct rte_eth_fdir_flex_mask));
+ cmd_reconfig_device_queue(res->port_id, 1, 1);
+ return;
+ }
+ flow_type_mask = fdir_info.flow_types_mask[0];
+ if (!strcmp(res->flow_type, "all")) {
+ if (!flow_type_mask) {
+ printf("No flow type supported\n");
+ return;
+ }
+ for (i = RTE_ETH_FLOW_UNKNOWN; i < RTE_ETH_FLOW_MAX; i++) {
+ if (flow_type_mask & (1ULL << i)) {
+ flex_mask.flow_type = i;
+ fdir_set_flex_mask(res->port_id, &flex_mask);
+ }
+ }
+ cmd_reconfig_device_queue(res->port_id, 1, 1);
+ return;
+ }
+ flex_mask.flow_type = str2flowtype(res->flow_type);
+ if (!(flow_type_mask & (1ULL << flex_mask.flow_type))) {
+ printf("Flow type %s not supported on port %d\n",
+ res->flow_type, res->port_id);
+ return;
+ }
+ fdir_set_flex_mask(res->port_id, &flex_mask);
+ cmd_reconfig_device_queue(res->port_id, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_flow_director_flexmask =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_flex_mask_result,
+ flow_director_flexmask,
+ "flow_director_flex_mask");
+cmdline_parse_token_num_t cmd_flow_director_flexmask_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_flex_mask_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_flow_director_flexmask_flow =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_flex_mask_result,
+ flow, "flow");
+cmdline_parse_token_string_t cmd_flow_director_flexmask_flow_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_flex_mask_result,
+ flow_type, "none#ipv4-other#ipv4-frag#ipv4-tcp#ipv4-udp#ipv4-sctp#"
+ "ipv6-other#ipv6-frag#ipv6-tcp#ipv6-udp#ipv6-sctp#l2_payload#all");
+cmdline_parse_token_string_t cmd_flow_director_flexmask_mask =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_flex_mask_result,
+ mask, NULL);
+
+cmdline_parse_inst_t cmd_set_flow_director_flex_mask = {
+ .f = cmd_flow_director_flex_mask_parsed,
+ .data = NULL,
+ .help_str = "flow_director_flex_mask ... : "
+ "Set flow director's flex mask on NIC",
+ .tokens = {
+ (void *)&cmd_flow_director_flexmask,
+ (void *)&cmd_flow_director_flexmask_port_id,
+ (void *)&cmd_flow_director_flexmask_flow,
+ (void *)&cmd_flow_director_flexmask_flow_type,
+ (void *)&cmd_flow_director_flexmask_mask,
+ NULL,
+ },
+};
+
+/* *** deal with flow director flexible payload configuration *** */
+struct cmd_flow_director_flexpayload_result {
+ cmdline_fixed_string_t flow_director_flexpayload;
+ portid_t port_id;
+ cmdline_fixed_string_t payload_layer;
+ cmdline_fixed_string_t payload_cfg;
+};
+
+static inline int
+parse_offsets(const char *q_arg, uint16_t *offsets, uint16_t max_num)
+{
+ char s[256];
+ const char *p, *p0 = q_arg;
+ char *end;
+ unsigned long int_fld;
+ char *str_fld[max_num];
+ int i;
+ unsigned size;
+ int ret = -1;
+
+ p = strchr(p0, '(');
+ if (p == NULL)
+ return -1;
+ ++p;
+ p0 = strchr(p, ')');
+ if (p0 == NULL)
+ return -1;
+
+ size = p0 - p;
+ if (size >= sizeof(s))
+ return -1;
+
+ snprintf(s, sizeof(s), "%.*s", size, p);
+ ret = rte_strsplit(s, sizeof(s), str_fld, max_num, ',');
+ if (ret < 0 || ret > max_num)
+ return -1;
+ for (i = 0; i < ret; i++) {
+ errno = 0;
+ int_fld = strtoul(str_fld[i], &end, 0);
+ if (errno != 0 || *end != '\0' || int_fld > UINT16_MAX)
+ return -1;
+ offsets[i] = (uint16_t)int_fld;
+ }
+ return ret;
+}
+
+static void
+cmd_flow_director_flxpld_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_flow_director_flexpayload_result *res = parsed_result;
+ struct rte_eth_flex_payload_cfg flex_cfg;
+ struct rte_port *port;
+ int ret = 0;
+
+ port = &ports[res->port_id];
+ /** Check if the port is not started **/
+ if (port->port_status != RTE_PORT_STOPPED) {
+ printf("Please stop port %d first\n", res->port_id);
+ return;
+ }
+
+ memset(&flex_cfg, 0, sizeof(struct rte_eth_flex_payload_cfg));
+
+ if (!strcmp(res->payload_layer, "raw"))
+ flex_cfg.type = RTE_ETH_RAW_PAYLOAD;
+ else if (!strcmp(res->payload_layer, "l2"))
+ flex_cfg.type = RTE_ETH_L2_PAYLOAD;
+ else if (!strcmp(res->payload_layer, "l3"))
+ flex_cfg.type = RTE_ETH_L3_PAYLOAD;
+ else if (!strcmp(res->payload_layer, "l4"))
+ flex_cfg.type = RTE_ETH_L4_PAYLOAD;
+
+ ret = parse_offsets(res->payload_cfg, flex_cfg.src_offset,
+ RTE_ETH_FDIR_MAX_FLEXLEN);
+ if (ret < 0) {
+ printf("error: Cannot parse flex payload input.\n");
+ return;
+ }
+
+ fdir_set_flex_payload(res->port_id, &flex_cfg);
+ cmd_reconfig_device_queue(res->port_id, 1, 1);
+}
+
+cmdline_parse_token_string_t cmd_flow_director_flexpayload =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_flexpayload_result,
+ flow_director_flexpayload,
+ "flow_director_flex_payload");
+cmdline_parse_token_num_t cmd_flow_director_flexpayload_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_director_flexpayload_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_flow_director_flexpayload_payload_layer =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_flexpayload_result,
+ payload_layer, "raw#l2#l3#l4");
+cmdline_parse_token_string_t cmd_flow_director_flexpayload_payload_cfg =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_director_flexpayload_result,
+ payload_cfg, NULL);
+
+cmdline_parse_inst_t cmd_set_flow_director_flex_payload = {
+ .f = cmd_flow_director_flxpld_parsed,
+ .data = NULL,
+ .help_str = "flow_director_flexpayload ... : "
+ "Set flow director's flex payload on NIC",
+ .tokens = {
+ (void *)&cmd_flow_director_flexpayload,
+ (void *)&cmd_flow_director_flexpayload_port_id,
+ (void *)&cmd_flow_director_flexpayload_payload_layer,
+ (void *)&cmd_flow_director_flexpayload_payload_cfg,
+ NULL,
+ },
+};
+
+/* Generic flow interface command. */
+extern cmdline_parse_inst_t cmd_flow;
+
+/* *** Classification Filters Control *** */
+/* *** Get symmetric hash enable per port *** */
+struct cmd_get_sym_hash_ena_per_port_result {
+ cmdline_fixed_string_t get_sym_hash_ena_per_port;
+ portid_t port_id;
+};
+
+static void
+cmd_get_sym_hash_per_port_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_get_sym_hash_ena_per_port_result *res = parsed_result;
+ struct rte_eth_hash_filter_info info;
+ int ret;
+
+ if (rte_eth_dev_filter_supported(res->port_id,
+ RTE_ETH_FILTER_HASH) < 0) {
+ printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+ res->port_id);
+ return;
+ }
+
+ memset(&info, 0, sizeof(info));
+ info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT;
+ ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+ RTE_ETH_FILTER_GET, &info);
+
+ if (ret < 0) {
+ printf("Cannot get symmetric hash enable per port "
+ "on port %u\n", res->port_id);
+ return;
+ }
+
+ printf("Symmetric hash is %s on port %u\n", info.info.enable ?
+ "enabled" : "disabled", res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_get_sym_hash_ena_per_port_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+ get_sym_hash_ena_per_port, "get_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_port_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_get_sym_hash_ena_per_port = {
+ .f = cmd_get_sym_hash_per_port_parsed,
+ .data = NULL,
+ .help_str = "get_sym_hash_ena_per_port <port_id>",
+ .tokens = {
+ (void *)&cmd_get_sym_hash_ena_per_port_all,
+ (void *)&cmd_get_sym_hash_ena_per_port_port_id,
+ NULL,
+ },
+};
+
+/* *** Set symmetric hash enable per port *** */
+struct cmd_set_sym_hash_ena_per_port_result {
+ cmdline_fixed_string_t set_sym_hash_ena_per_port;
+ cmdline_fixed_string_t enable;
+ portid_t port_id;
+};
+
+static void
+cmd_set_sym_hash_per_port_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_sym_hash_ena_per_port_result *res = parsed_result;
+ struct rte_eth_hash_filter_info info;
+ int ret;
+
+ if (rte_eth_dev_filter_supported(res->port_id,
+ RTE_ETH_FILTER_HASH) < 0) {
+ printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+ res->port_id);
+ return;
+ }
+
+ memset(&info, 0, sizeof(info));
+ info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT;
+ if (!strcmp(res->enable, "enable"))
+ info.info.enable = 1;
+ ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+ RTE_ETH_FILTER_SET, &info);
+ if (ret < 0) {
+ printf("Cannot set symmetric hash enable per port on "
+ "port %u\n", res->port_id);
+ return;
+ }
+ printf("Symmetric hash has been set to %s on port %u\n",
+ res->enable, res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+ set_sym_hash_ena_per_port, "set_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_port_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_enable =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+ enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_sym_hash_ena_per_port = {
+ .f = cmd_set_sym_hash_per_port_parsed,
+ .data = NULL,
+ .help_str = "set_sym_hash_ena_per_port <port_id> enable|disable",
+ .tokens = {
+ (void *)&cmd_set_sym_hash_ena_per_port_all,
+ (void *)&cmd_set_sym_hash_ena_per_port_port_id,
+ (void *)&cmd_set_sym_hash_ena_per_port_enable,
+ NULL,
+ },
+};
+
+/* Get global config of hash function */
+struct cmd_get_hash_global_config_result {
+ cmdline_fixed_string_t get_hash_global_config;
+ portid_t port_id;
+};
+
+static char *
+flowtype_to_str(uint16_t ftype)
+{
+ uint16_t i;
+ static struct {
+ char str[16];
+ uint16_t ftype;
+ } ftype_table[] = {
+ {"ipv4", RTE_ETH_FLOW_IPV4},
+ {"ipv4-frag", RTE_ETH_FLOW_FRAG_IPV4},
+ {"ipv4-tcp", RTE_ETH_FLOW_NONFRAG_IPV4_TCP},
+ {"ipv4-udp", RTE_ETH_FLOW_NONFRAG_IPV4_UDP},
+ {"ipv4-sctp", RTE_ETH_FLOW_NONFRAG_IPV4_SCTP},
+ {"ipv4-other", RTE_ETH_FLOW_NONFRAG_IPV4_OTHER},
+ {"ipv6", RTE_ETH_FLOW_IPV6},
+ {"ipv6-frag", RTE_ETH_FLOW_FRAG_IPV6},
+ {"ipv6-tcp", RTE_ETH_FLOW_NONFRAG_IPV6_TCP},
+ {"ipv6-udp", RTE_ETH_FLOW_NONFRAG_IPV6_UDP},
+ {"ipv6-sctp", RTE_ETH_FLOW_NONFRAG_IPV6_SCTP},
+ {"ipv6-other", RTE_ETH_FLOW_NONFRAG_IPV6_OTHER},
+ {"l2_payload", RTE_ETH_FLOW_L2_PAYLOAD},
+ {"port", RTE_ETH_FLOW_PORT},
+ {"vxlan", RTE_ETH_FLOW_VXLAN},
+ {"geneve", RTE_ETH_FLOW_GENEVE},
+ {"nvgre", RTE_ETH_FLOW_NVGRE},
+ {"vxlan-gpe", RTE_ETH_FLOW_VXLAN_GPE},
+ };
+
+ for (i = 0; i < RTE_DIM(ftype_table); i++) {
+ if (ftype_table[i].ftype == ftype)
+ return ftype_table[i].str;
+ }
+
+ return NULL;
+}
+
+static void
+cmd_get_hash_global_config_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_get_hash_global_config_result *res = parsed_result;
+ struct rte_eth_hash_filter_info info;
+ uint32_t idx, offset;
+ uint16_t i;
+ char *str;
+ int ret;
+
+ if (rte_eth_dev_filter_supported(res->port_id,
+ RTE_ETH_FILTER_HASH) < 0) {
+ printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+ res->port_id);
+ return;
+ }
+
+ memset(&info, 0, sizeof(info));
+ info.info_type = RTE_ETH_HASH_FILTER_GLOBAL_CONFIG;
+ ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+ RTE_ETH_FILTER_GET, &info);
+ if (ret < 0) {
+ printf("Cannot get hash global configurations by port %d\n",
+ res->port_id);
+ return;
+ }
+
+ switch (info.info.global_conf.hash_func) {
+ case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
+ printf("Hash function is Toeplitz\n");
+ break;
+ case RTE_ETH_HASH_FUNCTION_SIMPLE_XOR:
+ printf("Hash function is Simple XOR\n");
+ break;
+ case RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ:
+ printf("Hash function is Symmetric Toeplitz\n");
+ break;
+ default:
+ printf("Unknown hash function\n");
+ break;
+ }
+
+ for (i = 0; i < RTE_ETH_FLOW_MAX; i++) {
+ idx = i / UINT64_BIT;
+ offset = i % UINT64_BIT;
+ if (!(info.info.global_conf.valid_bit_mask[idx] &
+ (1ULL << offset)))
+ continue;
+ str = flowtype_to_str(i);
+ if (!str)
+ continue;
+ printf("Symmetric hash is %s globally for flow type %s "
+ "by port %d\n",
+ ((info.info.global_conf.sym_hash_enable_mask[idx] &
+ (1ULL << offset)) ? "enabled" : "disabled"), str,
+ res->port_id);
+ }
+}
+
+cmdline_parse_token_string_t cmd_get_hash_global_config_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_get_hash_global_config_result,
+ get_hash_global_config, "get_hash_global_config");
+cmdline_parse_token_num_t cmd_get_hash_global_config_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_get_hash_global_config_result,
+ port_id, UINT16);
+
+cmdline_parse_inst_t cmd_get_hash_global_config = {
+ .f = cmd_get_hash_global_config_parsed,
+ .data = NULL,
+ .help_str = "get_hash_global_config <port_id>",
+ .tokens = {
+ (void *)&cmd_get_hash_global_config_all,
+ (void *)&cmd_get_hash_global_config_port_id,
+ NULL,
+ },
+};
+
+/* Set global config of hash function */
+struct cmd_set_hash_global_config_result {
+ cmdline_fixed_string_t set_hash_global_config;
+ portid_t port_id;
+ cmdline_fixed_string_t hash_func;
+ cmdline_fixed_string_t flow_type;
+ cmdline_fixed_string_t enable;
+};
+
+static void
+cmd_set_hash_global_config_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_hash_global_config_result *res = parsed_result;
+ struct rte_eth_hash_filter_info info;
+ uint32_t ftype, idx, offset;
+ int ret;
+
+ if (rte_eth_dev_filter_supported(res->port_id,
+ RTE_ETH_FILTER_HASH) < 0) {
+ printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+ res->port_id);
+ return;
+ }
+ memset(&info, 0, sizeof(info));
+ info.info_type = RTE_ETH_HASH_FILTER_GLOBAL_CONFIG;
+ if (!strcmp(res->hash_func, "toeplitz"))
+ info.info.global_conf.hash_func =
+ RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+ else if (!strcmp(res->hash_func, "simple_xor"))
+ info.info.global_conf.hash_func =
+ RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+ else if (!strcmp(res->hash_func, "symmetric_toeplitz"))
+ info.info.global_conf.hash_func =
+ RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ;
+ else if (!strcmp(res->hash_func, "default"))
+ info.info.global_conf.hash_func =
+ RTE_ETH_HASH_FUNCTION_DEFAULT;
+
+ ftype = str2flowtype(res->flow_type);
+ idx = ftype / UINT64_BIT;
+ offset = ftype % UINT64_BIT;
+ info.info.global_conf.valid_bit_mask[idx] |= (1ULL << offset);
+ if (!strcmp(res->enable, "enable"))
+ info.info.global_conf.sym_hash_enable_mask[idx] |=
+ (1ULL << offset);
+ ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+ RTE_ETH_FILTER_SET, &info);
+ if (ret < 0)
+ printf("Cannot set global hash configurations by port %d\n",
+ res->port_id);
+ else
+ printf("Global hash configurations have been set "
+ "successfully by port %d\n", res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_hash_global_config_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+ set_hash_global_config, "set_hash_global_config");
+cmdline_parse_token_num_t cmd_set_hash_global_config_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_hash_global_config_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_set_hash_global_config_hash_func =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+ hash_func, "toeplitz#simple_xor#symmetric_toeplitz#default");
+cmdline_parse_token_string_t cmd_set_hash_global_config_flow_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+ flow_type,
+ "ipv4#ipv4-frag#ipv4-tcp#ipv4-udp#ipv4-sctp#ipv4-other#ipv6#"
+ "ipv6-frag#ipv6-tcp#ipv6-udp#ipv6-sctp#ipv6-other#l2_payload");
+cmdline_parse_token_string_t cmd_set_hash_global_config_enable =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+ enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_hash_global_config = {
+ .f = cmd_set_hash_global_config_parsed,
+ .data = NULL,
+ .help_str = "set_hash_global_config <port_id> "
+ "toeplitz|simple_xor|symmetric_toeplitz|default "
+ "ipv4|ipv4-frag|ipv4-tcp|ipv4-udp|ipv4-sctp|ipv4-other|"
+ "ipv6|ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|ipv6-other|"
+ "l2_payload enable|disable",
+ .tokens = {
+ (void *)&cmd_set_hash_global_config_all,
+ (void *)&cmd_set_hash_global_config_port_id,
+ (void *)&cmd_set_hash_global_config_hash_func,
+ (void *)&cmd_set_hash_global_config_flow_type,
+ (void *)&cmd_set_hash_global_config_enable,
+ NULL,
+ },
+};
+
+/* Set hash input set */
+struct cmd_set_hash_input_set_result {
+ cmdline_fixed_string_t set_hash_input_set;
+ portid_t port_id;
+ cmdline_fixed_string_t flow_type;
+ cmdline_fixed_string_t inset_field;
+ cmdline_fixed_string_t select;
+};
+
+static enum rte_eth_input_set_field
+str2inset(char *string)
+{
+ uint16_t i;
+
+ static const struct {
+ char str[32];
+ enum rte_eth_input_set_field inset;
+ } inset_table[] = {
+ {"ethertype", RTE_ETH_INPUT_SET_L2_ETHERTYPE},
+ {"ovlan", RTE_ETH_INPUT_SET_L2_OUTER_VLAN},
+ {"ivlan", RTE_ETH_INPUT_SET_L2_INNER_VLAN},
+ {"src-ipv4", RTE_ETH_INPUT_SET_L3_SRC_IP4},
+ {"dst-ipv4", RTE_ETH_INPUT_SET_L3_DST_IP4},
+ {"ipv4-tos", RTE_ETH_INPUT_SET_L3_IP4_TOS},
+ {"ipv4-proto", RTE_ETH_INPUT_SET_L3_IP4_PROTO},
+ {"ipv4-ttl", RTE_ETH_INPUT_SET_L3_IP4_TTL},
+ {"src-ipv6", RTE_ETH_INPUT_SET_L3_SRC_IP6},
+ {"dst-ipv6", RTE_ETH_INPUT_SET_L3_DST_IP6},
+ {"ipv6-tc", RTE_ETH_INPUT_SET_L3_IP6_TC},
+ {"ipv6-next-header", RTE_ETH_INPUT_SET_L3_IP6_NEXT_HEADER},
+ {"ipv6-hop-limits", RTE_ETH_INPUT_SET_L3_IP6_HOP_LIMITS},
+ {"udp-src-port", RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT},
+ {"udp-dst-port", RTE_ETH_INPUT_SET_L4_UDP_DST_PORT},
+ {"tcp-src-port", RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT},
+ {"tcp-dst-port", RTE_ETH_INPUT_SET_L4_TCP_DST_PORT},
+ {"sctp-src-port", RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT},
+ {"sctp-dst-port", RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT},
+ {"sctp-veri-tag", RTE_ETH_INPUT_SET_L4_SCTP_VERIFICATION_TAG},
+ {"udp-key", RTE_ETH_INPUT_SET_TUNNEL_L4_UDP_KEY},
+ {"gre-key", RTE_ETH_INPUT_SET_TUNNEL_GRE_KEY},
+ {"fld-1st", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_1ST_WORD},
+ {"fld-2nd", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_2ND_WORD},
+ {"fld-3rd", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_3RD_WORD},
+ {"fld-4th", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_4TH_WORD},
+ {"fld-5th", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_5TH_WORD},
+ {"fld-6th", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_6TH_WORD},
+ {"fld-7th", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_7TH_WORD},
+ {"fld-8th", RTE_ETH_INPUT_SET_FLEX_PAYLOAD_8TH_WORD},
+ {"none", RTE_ETH_INPUT_SET_NONE},
+ };
+
+ for (i = 0; i < RTE_DIM(inset_table); i++) {
+ if (!strcmp(string, inset_table[i].str))
+ return inset_table[i].inset;
+ }
+
+ return RTE_ETH_INPUT_SET_UNKNOWN;
+}
+
+static void
+cmd_set_hash_input_set_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_hash_input_set_result *res = parsed_result;
+ struct rte_eth_hash_filter_info info;
+
+ memset(&info, 0, sizeof(info));
+ info.info_type = RTE_ETH_HASH_FILTER_INPUT_SET_SELECT;
+ info.info.input_set_conf.flow_type = str2flowtype(res->flow_type);
+ info.info.input_set_conf.field[0] = str2inset(res->inset_field);
+ info.info.input_set_conf.inset_size = 1;
+ if (!strcmp(res->select, "select"))
+ info.info.input_set_conf.op = RTE_ETH_INPUT_SET_SELECT;
+ else if (!strcmp(res->select, "add"))
+ info.info.input_set_conf.op = RTE_ETH_INPUT_SET_ADD;
+ rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+ RTE_ETH_FILTER_SET, &info);
+}
+
+cmdline_parse_token_string_t cmd_set_hash_input_set_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_hash_input_set_result,
+ set_hash_input_set, "set_hash_input_set");
+cmdline_parse_token_num_t cmd_set_hash_input_set_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_hash_input_set_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_set_hash_input_set_flow_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_hash_input_set_result,
+ flow_type, NULL);
+cmdline_parse_token_string_t cmd_set_hash_input_set_field =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_hash_input_set_result,
+ inset_field,
+ "ovlan#ivlan#src-ipv4#dst-ipv4#src-ipv6#dst-ipv6#"
+ "ipv4-tos#ipv4-proto#ipv6-tc#ipv6-next-header#udp-src-port#"
+ "udp-dst-port#tcp-src-port#tcp-dst-port#sctp-src-port#"
+ "sctp-dst-port#sctp-veri-tag#udp-key#gre-key#fld-1st#"
+ "fld-2nd#fld-3rd#fld-4th#fld-5th#fld-6th#fld-7th#"
+ "fld-8th#none");
+cmdline_parse_token_string_t cmd_set_hash_input_set_select =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_hash_input_set_result,
+ select, "select#add");
+
+cmdline_parse_inst_t cmd_set_hash_input_set = {
+ .f = cmd_set_hash_input_set_parsed,
+ .data = NULL,
+ .help_str = "set_hash_input_set <port_id> "
+ "ipv4-frag|ipv4-tcp|ipv4-udp|ipv4-sctp|ipv4-other|"
+ "ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|ipv6-other|l2_payload|<flowtype_id> "
+ "ovlan|ivlan|src-ipv4|dst-ipv4|src-ipv6|dst-ipv6|ipv4-tos|ipv4-proto|"
+ "ipv6-tc|ipv6-next-header|udp-src-port|udp-dst-port|tcp-src-port|"
+ "tcp-dst-port|sctp-src-port|sctp-dst-port|sctp-veri-tag|udp-key|"
+ "gre-key|fld-1st|fld-2nd|fld-3rd|fld-4th|fld-5th|fld-6th|"
+ "fld-7th|fld-8th|none select|add",
+ .tokens = {
+ (void *)&cmd_set_hash_input_set_cmd,
+ (void *)&cmd_set_hash_input_set_port_id,
+ (void *)&cmd_set_hash_input_set_flow_type,
+ (void *)&cmd_set_hash_input_set_field,
+ (void *)&cmd_set_hash_input_set_select,
+ NULL,
+ },
+};
+
+/* Set flow director input set */
+struct cmd_set_fdir_input_set_result {
+ cmdline_fixed_string_t set_fdir_input_set;
+ portid_t port_id;
+ cmdline_fixed_string_t flow_type;
+ cmdline_fixed_string_t inset_field;
+ cmdline_fixed_string_t select;
+};
+
+static void
+cmd_set_fdir_input_set_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_fdir_input_set_result *res = parsed_result;
+ struct rte_eth_fdir_filter_info info;
+
+ memset(&info, 0, sizeof(info));
+ info.info_type = RTE_ETH_FDIR_FILTER_INPUT_SET_SELECT;
+ info.info.input_set_conf.flow_type = str2flowtype(res->flow_type);
+ info.info.input_set_conf.field[0] = str2inset(res->inset_field);
+ info.info.input_set_conf.inset_size = 1;
+ if (!strcmp(res->select, "select"))
+ info.info.input_set_conf.op = RTE_ETH_INPUT_SET_SELECT;
+ else if (!strcmp(res->select, "add"))
+ info.info.input_set_conf.op = RTE_ETH_INPUT_SET_ADD;
+ rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_FDIR,
+ RTE_ETH_FILTER_SET, &info);
+}
+
+cmdline_parse_token_string_t cmd_set_fdir_input_set_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_fdir_input_set_result,
+ set_fdir_input_set, "set_fdir_input_set");
+cmdline_parse_token_num_t cmd_set_fdir_input_set_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_fdir_input_set_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_set_fdir_input_set_flow_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_fdir_input_set_result,
+ flow_type,
+ "ipv4-frag#ipv4-tcp#ipv4-udp#ipv4-sctp#ipv4-other#"
+ "ipv6-frag#ipv6-tcp#ipv6-udp#ipv6-sctp#ipv6-other#l2_payload");
+cmdline_parse_token_string_t cmd_set_fdir_input_set_field =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_fdir_input_set_result,
+ inset_field,
+ "ivlan#ethertype#src-ipv4#dst-ipv4#src-ipv6#dst-ipv6#"
+ "ipv4-tos#ipv4-proto#ipv4-ttl#ipv6-tc#ipv6-next-header#"
+ "ipv6-hop-limits#udp-src-port#udp-dst-port#"
+ "tcp-src-port#tcp-dst-port#sctp-src-port#sctp-dst-port#"
+ "sctp-veri-tag#none");
+cmdline_parse_token_string_t cmd_set_fdir_input_set_select =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_fdir_input_set_result,
+ select, "select#add");
+
+cmdline_parse_inst_t cmd_set_fdir_input_set = {
+ .f = cmd_set_fdir_input_set_parsed,
+ .data = NULL,
+ .help_str = "set_fdir_input_set <port_id> "
+ "ipv4-frag|ipv4-tcp|ipv4-udp|ipv4-sctp|ipv4-other|"
+ "ipv6-frag|ipv6-tcp|ipv6-udp|ipv6-sctp|ipv6-other|l2_payload "
+ "ivlan|ethertype|src-ipv4|dst-ipv4|src-ipv6|dst-ipv6|"
+ "ipv4-tos|ipv4-proto|ipv4-ttl|ipv6-tc|ipv6-next-header|"
+ "ipv6-hop-limits|udp-src-port|udp-dst-port|"
+ "tcp-src-port|tcp-dst-port|sctp-src-port|sctp-dst-port|"
+ "sctp-veri-tag|none select|add",
+ .tokens = {
+ (void *)&cmd_set_fdir_input_set_cmd,
+ (void *)&cmd_set_fdir_input_set_port_id,
+ (void *)&cmd_set_fdir_input_set_flow_type,
+ (void *)&cmd_set_fdir_input_set_field,
+ (void *)&cmd_set_fdir_input_set_select,
+ NULL,
+ },
+};
+
+/* *** ADD/REMOVE A MULTICAST MAC ADDRESS TO/FROM A PORT *** */
+struct cmd_mcast_addr_result {
+ cmdline_fixed_string_t mcast_addr_cmd;
+ cmdline_fixed_string_t what;
+ uint16_t port_num;
+ struct rte_ether_addr mc_addr;
+};
+
+static void cmd_mcast_addr_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_mcast_addr_result *res = parsed_result;
+
+ if (!rte_is_multicast_ether_addr(&res->mc_addr)) {
+ printf("Invalid multicast addr %02X:%02X:%02X:%02X:%02X:%02X\n",
+ res->mc_addr.addr_bytes[0], res->mc_addr.addr_bytes[1],
+ res->mc_addr.addr_bytes[2], res->mc_addr.addr_bytes[3],
+ res->mc_addr.addr_bytes[4], res->mc_addr.addr_bytes[5]);
+ return;
+ }
+ if (strcmp(res->what, "add") == 0)
+ mcast_addr_add(res->port_num, &res->mc_addr);
+ else
+ mcast_addr_remove(res->port_num, &res->mc_addr);
+}
+
+cmdline_parse_token_string_t cmd_mcast_addr_cmd =
+ TOKEN_STRING_INITIALIZER(struct cmd_mcast_addr_result,
+ mcast_addr_cmd, "mcast_addr");
+cmdline_parse_token_string_t cmd_mcast_addr_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_mcast_addr_result, what,
+ "add#remove");
+cmdline_parse_token_num_t cmd_mcast_addr_portnum =
+ TOKEN_NUM_INITIALIZER(struct cmd_mcast_addr_result, port_num, UINT16);
+cmdline_parse_token_etheraddr_t cmd_mcast_addr_addr =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_mac_addr_result, address);
+
+cmdline_parse_inst_t cmd_mcast_addr = {
+ .f = cmd_mcast_addr_parsed,
+ .data = (void *)0,
+ .help_str = "mcast_addr add|remove <port_id> <mcast_addr>: "
+ "Add/Remove multicast MAC address on port_id",
+ .tokens = {
+ (void *)&cmd_mcast_addr_cmd,
+ (void *)&cmd_mcast_addr_what,
+ (void *)&cmd_mcast_addr_portnum,
+ (void *)&cmd_mcast_addr_addr,
+ NULL,
+ },
+};
+
+/* l2 tunnel config
+ * only support E-tag now.
+ */
+
+/* Ether type config */
+struct cmd_config_l2_tunnel_eth_type_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t config;
+ cmdline_fixed_string_t all;
+ portid_t id;
+ cmdline_fixed_string_t l2_tunnel;
+ cmdline_fixed_string_t l2_tunnel_type;
+ cmdline_fixed_string_t eth_type;
+ uint16_t eth_type_val;
+};
+
+cmdline_parse_token_string_t cmd_config_l2_tunnel_eth_type_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_l2_tunnel_eth_type_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_config_l2_tunnel_eth_type_config =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_l2_tunnel_eth_type_result,
+ config, "config");
+cmdline_parse_token_string_t cmd_config_l2_tunnel_eth_type_all_str =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_l2_tunnel_eth_type_result,
+ all, "all");
+cmdline_parse_token_num_t cmd_config_l2_tunnel_eth_type_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_l2_tunnel_eth_type_result,
+ id, UINT16);
+cmdline_parse_token_string_t cmd_config_l2_tunnel_eth_type_l2_tunnel =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_l2_tunnel_eth_type_result,
+ l2_tunnel, "l2-tunnel");
+cmdline_parse_token_string_t cmd_config_l2_tunnel_eth_type_l2_tunnel_type =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_l2_tunnel_eth_type_result,
+ l2_tunnel_type, "E-tag");
+cmdline_parse_token_string_t cmd_config_l2_tunnel_eth_type_eth_type =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_l2_tunnel_eth_type_result,
+ eth_type, "ether-type");
+cmdline_parse_token_num_t cmd_config_l2_tunnel_eth_type_eth_type_val =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_l2_tunnel_eth_type_result,
+ eth_type_val, UINT16);
+
+static enum rte_eth_tunnel_type
+str2fdir_l2_tunnel_type(char *string)
+{
+ uint32_t i = 0;
+
+ static const struct {
+ char str[32];
+ enum rte_eth_tunnel_type type;
+ } l2_tunnel_type_str[] = {
+ {"E-tag", RTE_L2_TUNNEL_TYPE_E_TAG},
+ };
+
+ for (i = 0; i < RTE_DIM(l2_tunnel_type_str); i++) {
+ if (!strcmp(l2_tunnel_type_str[i].str, string))
+ return l2_tunnel_type_str[i].type;
+ }
+ return RTE_TUNNEL_TYPE_NONE;
+}
+
+/* ether type config for all ports */
+static void
+cmd_config_l2_tunnel_eth_type_all_parsed
+ (void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_l2_tunnel_eth_type_result *res = parsed_result;
+ struct rte_eth_l2_tunnel_conf entry;
+ portid_t pid;
+
+ entry.l2_tunnel_type = str2fdir_l2_tunnel_type(res->l2_tunnel_type);
+ entry.ether_type = res->eth_type_val;
+
+ RTE_ETH_FOREACH_DEV(pid) {
+ rte_eth_dev_l2_tunnel_eth_type_conf(pid, &entry);
+ }
+}
+
+cmdline_parse_inst_t cmd_config_l2_tunnel_eth_type_all = {
+ .f = cmd_config_l2_tunnel_eth_type_all_parsed,
+ .data = NULL,
+ .help_str = "port config all l2-tunnel E-tag ether-type <value>",
+ .tokens = {
+ (void *)&cmd_config_l2_tunnel_eth_type_port,
+ (void *)&cmd_config_l2_tunnel_eth_type_config,
+ (void *)&cmd_config_l2_tunnel_eth_type_all_str,
+ (void *)&cmd_config_l2_tunnel_eth_type_l2_tunnel,
+ (void *)&cmd_config_l2_tunnel_eth_type_l2_tunnel_type,
+ (void *)&cmd_config_l2_tunnel_eth_type_eth_type,
+ (void *)&cmd_config_l2_tunnel_eth_type_eth_type_val,
+ NULL,
+ },
+};
+
+/* ether type config for a specific port */
+static void
+cmd_config_l2_tunnel_eth_type_specific_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_l2_tunnel_eth_type_result *res =
+ parsed_result;
+ struct rte_eth_l2_tunnel_conf entry;
+
+ if (port_id_is_invalid(res->id, ENABLED_WARN))
+ return;
+
+ entry.l2_tunnel_type = str2fdir_l2_tunnel_type(res->l2_tunnel_type);
+ entry.ether_type = res->eth_type_val;
+
+ rte_eth_dev_l2_tunnel_eth_type_conf(res->id, &entry);
+}
+
+cmdline_parse_inst_t cmd_config_l2_tunnel_eth_type_specific = {
+ .f = cmd_config_l2_tunnel_eth_type_specific_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> l2-tunnel E-tag ether-type <value>",
+ .tokens = {
+ (void *)&cmd_config_l2_tunnel_eth_type_port,
+ (void *)&cmd_config_l2_tunnel_eth_type_config,
+ (void *)&cmd_config_l2_tunnel_eth_type_id,
+ (void *)&cmd_config_l2_tunnel_eth_type_l2_tunnel,
+ (void *)&cmd_config_l2_tunnel_eth_type_l2_tunnel_type,
+ (void *)&cmd_config_l2_tunnel_eth_type_eth_type,
+ (void *)&cmd_config_l2_tunnel_eth_type_eth_type_val,
+ NULL,
+ },
+};
+
+/* Enable/disable l2 tunnel */
+struct cmd_config_l2_tunnel_en_dis_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t config;
+ cmdline_fixed_string_t all;
+ portid_t id;
+ cmdline_fixed_string_t l2_tunnel;
+ cmdline_fixed_string_t l2_tunnel_type;
+ cmdline_fixed_string_t en_dis;
+};
+
+cmdline_parse_token_string_t cmd_config_l2_tunnel_en_dis_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_l2_tunnel_en_dis_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_config_l2_tunnel_en_dis_config =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_l2_tunnel_en_dis_result,
+ config, "config");
+cmdline_parse_token_string_t cmd_config_l2_tunnel_en_dis_all_str =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_l2_tunnel_en_dis_result,
+ all, "all");
+cmdline_parse_token_num_t cmd_config_l2_tunnel_en_dis_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_l2_tunnel_en_dis_result,
+ id, UINT16);
+cmdline_parse_token_string_t cmd_config_l2_tunnel_en_dis_l2_tunnel =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_l2_tunnel_en_dis_result,
+ l2_tunnel, "l2-tunnel");
+cmdline_parse_token_string_t cmd_config_l2_tunnel_en_dis_l2_tunnel_type =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_l2_tunnel_en_dis_result,
+ l2_tunnel_type, "E-tag");
+cmdline_parse_token_string_t cmd_config_l2_tunnel_en_dis_en_dis =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_l2_tunnel_en_dis_result,
+ en_dis, "enable#disable");
+
+/* enable/disable l2 tunnel for all ports */
+static void
+cmd_config_l2_tunnel_en_dis_all_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_l2_tunnel_en_dis_result *res = parsed_result;
+ struct rte_eth_l2_tunnel_conf entry;
+ portid_t pid;
+ uint8_t en;
+
+ entry.l2_tunnel_type = str2fdir_l2_tunnel_type(res->l2_tunnel_type);
+
+ if (!strcmp("enable", res->en_dis))
+ en = 1;
+ else
+ en = 0;
+
+ RTE_ETH_FOREACH_DEV(pid) {
+ rte_eth_dev_l2_tunnel_offload_set(pid,
+ &entry,
+ ETH_L2_TUNNEL_ENABLE_MASK,
+ en);
+ }
+}
+
+cmdline_parse_inst_t cmd_config_l2_tunnel_en_dis_all = {
+ .f = cmd_config_l2_tunnel_en_dis_all_parsed,
+ .data = NULL,
+ .help_str = "port config all l2-tunnel E-tag enable|disable",
+ .tokens = {
+ (void *)&cmd_config_l2_tunnel_en_dis_port,
+ (void *)&cmd_config_l2_tunnel_en_dis_config,
+ (void *)&cmd_config_l2_tunnel_en_dis_all_str,
+ (void *)&cmd_config_l2_tunnel_en_dis_l2_tunnel,
+ (void *)&cmd_config_l2_tunnel_en_dis_l2_tunnel_type,
+ (void *)&cmd_config_l2_tunnel_en_dis_en_dis,
+ NULL,
+ },
+};
+
+/* enable/disable l2 tunnel for a port */
+static void
+cmd_config_l2_tunnel_en_dis_specific_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_l2_tunnel_en_dis_result *res =
+ parsed_result;
+ struct rte_eth_l2_tunnel_conf entry;
+
+ if (port_id_is_invalid(res->id, ENABLED_WARN))
+ return;
+
+ entry.l2_tunnel_type = str2fdir_l2_tunnel_type(res->l2_tunnel_type);
+
+ if (!strcmp("enable", res->en_dis))
+ rte_eth_dev_l2_tunnel_offload_set(res->id,
+ &entry,
+ ETH_L2_TUNNEL_ENABLE_MASK,
+ 1);
+ else
+ rte_eth_dev_l2_tunnel_offload_set(res->id,
+ &entry,
+ ETH_L2_TUNNEL_ENABLE_MASK,
+ 0);
+}
+
+cmdline_parse_inst_t cmd_config_l2_tunnel_en_dis_specific = {
+ .f = cmd_config_l2_tunnel_en_dis_specific_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> l2-tunnel E-tag enable|disable",
+ .tokens = {
+ (void *)&cmd_config_l2_tunnel_en_dis_port,
+ (void *)&cmd_config_l2_tunnel_en_dis_config,
+ (void *)&cmd_config_l2_tunnel_en_dis_id,
+ (void *)&cmd_config_l2_tunnel_en_dis_l2_tunnel,
+ (void *)&cmd_config_l2_tunnel_en_dis_l2_tunnel_type,
+ (void *)&cmd_config_l2_tunnel_en_dis_en_dis,
+ NULL,
+ },
+};
+
+/* E-tag configuration */
+
+/* Common result structure for all E-tag configuration */
+struct cmd_config_e_tag_result {
+ cmdline_fixed_string_t e_tag;
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t insertion;
+ cmdline_fixed_string_t stripping;
+ cmdline_fixed_string_t forwarding;
+ cmdline_fixed_string_t filter;
+ cmdline_fixed_string_t add;
+ cmdline_fixed_string_t del;
+ cmdline_fixed_string_t on;
+ cmdline_fixed_string_t off;
+ cmdline_fixed_string_t on_off;
+ cmdline_fixed_string_t port_tag_id;
+ uint32_t port_tag_id_val;
+ cmdline_fixed_string_t e_tag_id;
+ uint16_t e_tag_id_val;
+ cmdline_fixed_string_t dst_pool;
+ uint8_t dst_pool_val;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t vf;
+ uint8_t vf_id;
+};
+
+/* Common CLI fields for all E-tag configuration */
+cmdline_parse_token_string_t cmd_config_e_tag_e_tag =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ e_tag, "E-tag");
+cmdline_parse_token_string_t cmd_config_e_tag_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_config_e_tag_insertion =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ insertion, "insertion");
+cmdline_parse_token_string_t cmd_config_e_tag_stripping =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ stripping, "stripping");
+cmdline_parse_token_string_t cmd_config_e_tag_forwarding =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ forwarding, "forwarding");
+cmdline_parse_token_string_t cmd_config_e_tag_filter =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ filter, "filter");
+cmdline_parse_token_string_t cmd_config_e_tag_add =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ add, "add");
+cmdline_parse_token_string_t cmd_config_e_tag_del =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ del, "del");
+cmdline_parse_token_string_t cmd_config_e_tag_on =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ on, "on");
+cmdline_parse_token_string_t cmd_config_e_tag_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ off, "off");
+cmdline_parse_token_string_t cmd_config_e_tag_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ on_off, "on#off");
+cmdline_parse_token_string_t cmd_config_e_tag_port_tag_id =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ port_tag_id, "port-tag-id");
+cmdline_parse_token_num_t cmd_config_e_tag_port_tag_id_val =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ port_tag_id_val, UINT32);
+cmdline_parse_token_string_t cmd_config_e_tag_e_tag_id =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ e_tag_id, "e-tag-id");
+cmdline_parse_token_num_t cmd_config_e_tag_e_tag_id_val =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ e_tag_id_val, UINT16);
+cmdline_parse_token_string_t cmd_config_e_tag_dst_pool =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ dst_pool, "dst-pool");
+cmdline_parse_token_num_t cmd_config_e_tag_dst_pool_val =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ dst_pool_val, UINT8);
+cmdline_parse_token_string_t cmd_config_e_tag_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_config_e_tag_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_config_e_tag_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ vf, "vf");
+cmdline_parse_token_num_t cmd_config_e_tag_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_e_tag_result,
+ vf_id, UINT8);
+
+/* E-tag insertion configuration */
+static void
+cmd_config_e_tag_insertion_en_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_e_tag_result *res =
+ parsed_result;
+ struct rte_eth_l2_tunnel_conf entry;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+ entry.l2_tunnel_type = RTE_L2_TUNNEL_TYPE_E_TAG;
+ entry.tunnel_id = res->port_tag_id_val;
+ entry.vf_id = res->vf_id;
+ rte_eth_dev_l2_tunnel_offload_set(res->port_id,
+ &entry,
+ ETH_L2_TUNNEL_INSERTION_MASK,
+ 1);
+}
+
+static void
+cmd_config_e_tag_insertion_dis_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_e_tag_result *res =
+ parsed_result;
+ struct rte_eth_l2_tunnel_conf entry;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+ entry.l2_tunnel_type = RTE_L2_TUNNEL_TYPE_E_TAG;
+ entry.vf_id = res->vf_id;
+
+ rte_eth_dev_l2_tunnel_offload_set(res->port_id,
+ &entry,
+ ETH_L2_TUNNEL_INSERTION_MASK,
+ 0);
+}
+
+cmdline_parse_inst_t cmd_config_e_tag_insertion_en = {
+ .f = cmd_config_e_tag_insertion_en_parsed,
+ .data = NULL,
+ .help_str = "E-tag ... : E-tag insertion enable",
+ .tokens = {
+ (void *)&cmd_config_e_tag_e_tag,
+ (void *)&cmd_config_e_tag_set,
+ (void *)&cmd_config_e_tag_insertion,
+ (void *)&cmd_config_e_tag_on,
+ (void *)&cmd_config_e_tag_port_tag_id,
+ (void *)&cmd_config_e_tag_port_tag_id_val,
+ (void *)&cmd_config_e_tag_port,
+ (void *)&cmd_config_e_tag_port_id,
+ (void *)&cmd_config_e_tag_vf,
+ (void *)&cmd_config_e_tag_vf_id,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_config_e_tag_insertion_dis = {
+ .f = cmd_config_e_tag_insertion_dis_parsed,
+ .data = NULL,
+ .help_str = "E-tag ... : E-tag insertion disable",
+ .tokens = {
+ (void *)&cmd_config_e_tag_e_tag,
+ (void *)&cmd_config_e_tag_set,
+ (void *)&cmd_config_e_tag_insertion,
+ (void *)&cmd_config_e_tag_off,
+ (void *)&cmd_config_e_tag_port,
+ (void *)&cmd_config_e_tag_port_id,
+ (void *)&cmd_config_e_tag_vf,
+ (void *)&cmd_config_e_tag_vf_id,
+ NULL,
+ },
+};
+
+/* E-tag stripping configuration */
+static void
+cmd_config_e_tag_stripping_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_e_tag_result *res =
+ parsed_result;
+ struct rte_eth_l2_tunnel_conf entry;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+ entry.l2_tunnel_type = RTE_L2_TUNNEL_TYPE_E_TAG;
+
+ if (!strcmp(res->on_off, "on"))
+ rte_eth_dev_l2_tunnel_offload_set
+ (res->port_id,
+ &entry,
+ ETH_L2_TUNNEL_STRIPPING_MASK,
+ 1);
+ else
+ rte_eth_dev_l2_tunnel_offload_set
+ (res->port_id,
+ &entry,
+ ETH_L2_TUNNEL_STRIPPING_MASK,
+ 0);
+}
+
+cmdline_parse_inst_t cmd_config_e_tag_stripping_en_dis = {
+ .f = cmd_config_e_tag_stripping_parsed,
+ .data = NULL,
+ .help_str = "E-tag ... : E-tag stripping enable/disable",
+ .tokens = {
+ (void *)&cmd_config_e_tag_e_tag,
+ (void *)&cmd_config_e_tag_set,
+ (void *)&cmd_config_e_tag_stripping,
+ (void *)&cmd_config_e_tag_on_off,
+ (void *)&cmd_config_e_tag_port,
+ (void *)&cmd_config_e_tag_port_id,
+ NULL,
+ },
+};
+
+/* E-tag forwarding configuration */
+static void
+cmd_config_e_tag_forwarding_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_e_tag_result *res = parsed_result;
+ struct rte_eth_l2_tunnel_conf entry;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+ entry.l2_tunnel_type = RTE_L2_TUNNEL_TYPE_E_TAG;
+
+ if (!strcmp(res->on_off, "on"))
+ rte_eth_dev_l2_tunnel_offload_set
+ (res->port_id,
+ &entry,
+ ETH_L2_TUNNEL_FORWARDING_MASK,
+ 1);
+ else
+ rte_eth_dev_l2_tunnel_offload_set
+ (res->port_id,
+ &entry,
+ ETH_L2_TUNNEL_FORWARDING_MASK,
+ 0);
+}
+
+cmdline_parse_inst_t cmd_config_e_tag_forwarding_en_dis = {
+ .f = cmd_config_e_tag_forwarding_parsed,
+ .data = NULL,
+ .help_str = "E-tag ... : E-tag forwarding enable/disable",
+ .tokens = {
+ (void *)&cmd_config_e_tag_e_tag,
+ (void *)&cmd_config_e_tag_set,
+ (void *)&cmd_config_e_tag_forwarding,
+ (void *)&cmd_config_e_tag_on_off,
+ (void *)&cmd_config_e_tag_port,
+ (void *)&cmd_config_e_tag_port_id,
+ NULL,
+ },
+};
+
+/* E-tag filter configuration */
+static void
+cmd_config_e_tag_filter_add_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_e_tag_result *res = parsed_result;
+ struct rte_eth_l2_tunnel_conf entry;
+ int ret = 0;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+ if (res->e_tag_id_val > 0x3fff) {
+ printf("e-tag-id must be equal or less than 0x3fff.\n");
+ return;
+ }
+
+ ret = rte_eth_dev_filter_supported(res->port_id,
+ RTE_ETH_FILTER_L2_TUNNEL);
+ if (ret < 0) {
+ printf("E-tag filter is not supported on port %u.\n",
+ res->port_id);
+ return;
+ }
+
+ entry.l2_tunnel_type = RTE_L2_TUNNEL_TYPE_E_TAG;
+ entry.tunnel_id = res->e_tag_id_val;
+ entry.pool = res->dst_pool_val;
+
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_L2_TUNNEL,
+ RTE_ETH_FILTER_ADD,
+ &entry);
+ if (ret < 0)
+ printf("E-tag filter programming error: (%s)\n",
+ strerror(-ret));
+}
+
+cmdline_parse_inst_t cmd_config_e_tag_filter_add = {
+ .f = cmd_config_e_tag_filter_add_parsed,
+ .data = NULL,
+ .help_str = "E-tag ... : E-tag filter add",
+ .tokens = {
+ (void *)&cmd_config_e_tag_e_tag,
+ (void *)&cmd_config_e_tag_set,
+ (void *)&cmd_config_e_tag_filter,
+ (void *)&cmd_config_e_tag_add,
+ (void *)&cmd_config_e_tag_e_tag_id,
+ (void *)&cmd_config_e_tag_e_tag_id_val,
+ (void *)&cmd_config_e_tag_dst_pool,
+ (void *)&cmd_config_e_tag_dst_pool_val,
+ (void *)&cmd_config_e_tag_port,
+ (void *)&cmd_config_e_tag_port_id,
+ NULL,
+ },
+};
+
+static void
+cmd_config_e_tag_filter_del_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_e_tag_result *res = parsed_result;
+ struct rte_eth_l2_tunnel_conf entry;
+ int ret = 0;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+ if (res->e_tag_id_val > 0x3fff) {
+ printf("e-tag-id must be less than 0x3fff.\n");
+ return;
+ }
+
+ ret = rte_eth_dev_filter_supported(res->port_id,
+ RTE_ETH_FILTER_L2_TUNNEL);
+ if (ret < 0) {
+ printf("E-tag filter is not supported on port %u.\n",
+ res->port_id);
+ return;
+ }
+
+ entry.l2_tunnel_type = RTE_L2_TUNNEL_TYPE_E_TAG;
+ entry.tunnel_id = res->e_tag_id_val;
+
+ ret = rte_eth_dev_filter_ctrl(res->port_id,
+ RTE_ETH_FILTER_L2_TUNNEL,
+ RTE_ETH_FILTER_DELETE,
+ &entry);
+ if (ret < 0)
+ printf("E-tag filter programming error: (%s)\n",
+ strerror(-ret));
+}
+
+cmdline_parse_inst_t cmd_config_e_tag_filter_del = {
+ .f = cmd_config_e_tag_filter_del_parsed,
+ .data = NULL,
+ .help_str = "E-tag ... : E-tag filter delete",
+ .tokens = {
+ (void *)&cmd_config_e_tag_e_tag,
+ (void *)&cmd_config_e_tag_set,
+ (void *)&cmd_config_e_tag_filter,
+ (void *)&cmd_config_e_tag_del,
+ (void *)&cmd_config_e_tag_e_tag_id,
+ (void *)&cmd_config_e_tag_e_tag_id_val,
+ (void *)&cmd_config_e_tag_port,
+ (void *)&cmd_config_e_tag_port_id,
+ NULL,
+ },
+};
+
+/* vf vlan anti spoof configuration */
+
+/* Common result structure for vf vlan anti spoof */
+struct cmd_vf_vlan_anti_spoof_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t vlan;
+ cmdline_fixed_string_t antispoof;
+ portid_t port_id;
+ uint32_t vf_id;
+ cmdline_fixed_string_t on_off;
+};
+
+/* Common CLI fields for vf vlan anti spoof enable disable */
+cmdline_parse_token_string_t cmd_vf_vlan_anti_spoof_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_vlan_anti_spoof_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_vf_vlan_anti_spoof_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_vlan_anti_spoof_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_vf_vlan_anti_spoof_vlan =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_vlan_anti_spoof_result,
+ vlan, "vlan");
+cmdline_parse_token_string_t cmd_vf_vlan_anti_spoof_antispoof =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_vlan_anti_spoof_result,
+ antispoof, "antispoof");
+cmdline_parse_token_num_t cmd_vf_vlan_anti_spoof_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_vlan_anti_spoof_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_vf_vlan_anti_spoof_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_vlan_anti_spoof_result,
+ vf_id, UINT32);
+cmdline_parse_token_string_t cmd_vf_vlan_anti_spoof_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_vlan_anti_spoof_result,
+ on_off, "on#off");
+
+static void
+cmd_set_vf_vlan_anti_spoof_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_vlan_anti_spoof_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ __rte_unused int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_ixgbe_set_vf_vlan_anti_spoof(res->port_id,
+ res->vf_id, is_on);
+#endif
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_i40e_set_vf_vlan_anti_spoof(res->port_id,
+ res->vf_id, is_on);
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_bnxt_set_vf_vlan_anti_spoof(res->port_id,
+ res->vf_id, is_on);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d\n", res->vf_id);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_vf_vlan_anti_spoof = {
+ .f = cmd_set_vf_vlan_anti_spoof_parsed,
+ .data = NULL,
+ .help_str = "set vf vlan antispoof <port_id> <vf_id> on|off",
+ .tokens = {
+ (void *)&cmd_vf_vlan_anti_spoof_set,
+ (void *)&cmd_vf_vlan_anti_spoof_vf,
+ (void *)&cmd_vf_vlan_anti_spoof_vlan,
+ (void *)&cmd_vf_vlan_anti_spoof_antispoof,
+ (void *)&cmd_vf_vlan_anti_spoof_port_id,
+ (void *)&cmd_vf_vlan_anti_spoof_vf_id,
+ (void *)&cmd_vf_vlan_anti_spoof_on_off,
+ NULL,
+ },
+};
+
+/* vf mac anti spoof configuration */
+
+/* Common result structure for vf mac anti spoof */
+struct cmd_vf_mac_anti_spoof_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t mac;
+ cmdline_fixed_string_t antispoof;
+ portid_t port_id;
+ uint32_t vf_id;
+ cmdline_fixed_string_t on_off;
+};
+
+/* Common CLI fields for vf mac anti spoof enable disable */
+cmdline_parse_token_string_t cmd_vf_mac_anti_spoof_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_mac_anti_spoof_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_vf_mac_anti_spoof_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_mac_anti_spoof_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_vf_mac_anti_spoof_mac =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_mac_anti_spoof_result,
+ mac, "mac");
+cmdline_parse_token_string_t cmd_vf_mac_anti_spoof_antispoof =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_mac_anti_spoof_result,
+ antispoof, "antispoof");
+cmdline_parse_token_num_t cmd_vf_mac_anti_spoof_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_mac_anti_spoof_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_vf_mac_anti_spoof_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_mac_anti_spoof_result,
+ vf_id, UINT32);
+cmdline_parse_token_string_t cmd_vf_mac_anti_spoof_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_mac_anti_spoof_result,
+ on_off, "on#off");
+
+static void
+cmd_set_vf_mac_anti_spoof_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_mac_anti_spoof_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ __rte_unused int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_ixgbe_set_vf_mac_anti_spoof(res->port_id,
+ res->vf_id, is_on);
+#endif
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_i40e_set_vf_mac_anti_spoof(res->port_id,
+ res->vf_id, is_on);
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_bnxt_set_vf_mac_anti_spoof(res->port_id,
+ res->vf_id, is_on);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d or is_on %d\n", res->vf_id, is_on);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_vf_mac_anti_spoof = {
+ .f = cmd_set_vf_mac_anti_spoof_parsed,
+ .data = NULL,
+ .help_str = "set vf mac antispoof <port_id> <vf_id> on|off",
+ .tokens = {
+ (void *)&cmd_vf_mac_anti_spoof_set,
+ (void *)&cmd_vf_mac_anti_spoof_vf,
+ (void *)&cmd_vf_mac_anti_spoof_mac,
+ (void *)&cmd_vf_mac_anti_spoof_antispoof,
+ (void *)&cmd_vf_mac_anti_spoof_port_id,
+ (void *)&cmd_vf_mac_anti_spoof_vf_id,
+ (void *)&cmd_vf_mac_anti_spoof_on_off,
+ NULL,
+ },
+};
+
+/* vf vlan strip queue configuration */
+
+/* Common result structure for vf mac anti spoof */
+struct cmd_vf_vlan_stripq_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t vlan;
+ cmdline_fixed_string_t stripq;
+ portid_t port_id;
+ uint16_t vf_id;
+ cmdline_fixed_string_t on_off;
+};
+
+/* Common CLI fields for vf vlan strip enable disable */
+cmdline_parse_token_string_t cmd_vf_vlan_stripq_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_vlan_stripq_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_vf_vlan_stripq_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_vlan_stripq_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_vf_vlan_stripq_vlan =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_vlan_stripq_result,
+ vlan, "vlan");
+cmdline_parse_token_string_t cmd_vf_vlan_stripq_stripq =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_vlan_stripq_result,
+ stripq, "stripq");
+cmdline_parse_token_num_t cmd_vf_vlan_stripq_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_vlan_stripq_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_vf_vlan_stripq_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_vlan_stripq_result,
+ vf_id, UINT16);
+cmdline_parse_token_string_t cmd_vf_vlan_stripq_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_vlan_stripq_result,
+ on_off, "on#off");
+
+static void
+cmd_set_vf_vlan_stripq_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_vlan_stripq_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ __rte_unused int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_ixgbe_set_vf_vlan_stripq(res->port_id,
+ res->vf_id, is_on);
+#endif
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_i40e_set_vf_vlan_stripq(res->port_id,
+ res->vf_id, is_on);
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_bnxt_set_vf_vlan_stripq(res->port_id,
+ res->vf_id, is_on);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d or is_on %d\n", res->vf_id, is_on);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_vf_vlan_stripq = {
+ .f = cmd_set_vf_vlan_stripq_parsed,
+ .data = NULL,
+ .help_str = "set vf vlan stripq <port_id> <vf_id> on|off",
+ .tokens = {
+ (void *)&cmd_vf_vlan_stripq_set,
+ (void *)&cmd_vf_vlan_stripq_vf,
+ (void *)&cmd_vf_vlan_stripq_vlan,
+ (void *)&cmd_vf_vlan_stripq_stripq,
+ (void *)&cmd_vf_vlan_stripq_port_id,
+ (void *)&cmd_vf_vlan_stripq_vf_id,
+ (void *)&cmd_vf_vlan_stripq_on_off,
+ NULL,
+ },
+};
+
+/* vf vlan insert configuration */
+
+/* Common result structure for vf vlan insert */
+struct cmd_vf_vlan_insert_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t vlan;
+ cmdline_fixed_string_t insert;
+ portid_t port_id;
+ uint16_t vf_id;
+ uint16_t vlan_id;
+};
+
+/* Common CLI fields for vf vlan insert enable disable */
+cmdline_parse_token_string_t cmd_vf_vlan_insert_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_vlan_insert_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_vf_vlan_insert_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_vlan_insert_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_vf_vlan_insert_vlan =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_vlan_insert_result,
+ vlan, "vlan");
+cmdline_parse_token_string_t cmd_vf_vlan_insert_insert =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_vlan_insert_result,
+ insert, "insert");
+cmdline_parse_token_num_t cmd_vf_vlan_insert_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_vlan_insert_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_vf_vlan_insert_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_vlan_insert_result,
+ vf_id, UINT16);
+cmdline_parse_token_num_t cmd_vf_vlan_insert_vlan_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_vlan_insert_result,
+ vlan_id, UINT16);
+
+static void
+cmd_set_vf_vlan_insert_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_vlan_insert_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_ixgbe_set_vf_vlan_insert(res->port_id, res->vf_id,
+ res->vlan_id);
+#endif
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_i40e_set_vf_vlan_insert(res->port_id, res->vf_id,
+ res->vlan_id);
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_bnxt_set_vf_vlan_insert(res->port_id, res->vf_id,
+ res->vlan_id);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d or vlan_id %d\n", res->vf_id, res->vlan_id);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_vf_vlan_insert = {
+ .f = cmd_set_vf_vlan_insert_parsed,
+ .data = NULL,
+ .help_str = "set vf vlan insert <port_id> <vf_id> <vlan_id>",
+ .tokens = {
+ (void *)&cmd_vf_vlan_insert_set,
+ (void *)&cmd_vf_vlan_insert_vf,
+ (void *)&cmd_vf_vlan_insert_vlan,
+ (void *)&cmd_vf_vlan_insert_insert,
+ (void *)&cmd_vf_vlan_insert_port_id,
+ (void *)&cmd_vf_vlan_insert_vf_id,
+ (void *)&cmd_vf_vlan_insert_vlan_id,
+ NULL,
+ },
+};
+
+/* tx loopback configuration */
+
+/* Common result structure for tx loopback */
+struct cmd_tx_loopback_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t tx;
+ cmdline_fixed_string_t loopback;
+ portid_t port_id;
+ cmdline_fixed_string_t on_off;
+};
+
+/* Common CLI fields for tx loopback enable disable */
+cmdline_parse_token_string_t cmd_tx_loopback_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_tx_loopback_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_tx_loopback_tx =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_tx_loopback_result,
+ tx, "tx");
+cmdline_parse_token_string_t cmd_tx_loopback_loopback =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_tx_loopback_result,
+ loopback, "loopback");
+cmdline_parse_token_num_t cmd_tx_loopback_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_tx_loopback_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_tx_loopback_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_tx_loopback_result,
+ on_off, "on#off");
+
+static void
+cmd_set_tx_loopback_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_tx_loopback_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ __rte_unused int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_ixgbe_set_tx_loopback(res->port_id, is_on);
+#endif
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_i40e_set_tx_loopback(res->port_id, is_on);
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_bnxt_set_tx_loopback(res->port_id, is_on);
+#endif
+#if defined RTE_LIBRTE_DPAA_BUS && defined RTE_LIBRTE_DPAA_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_dpaa_set_tx_loopback(res->port_id, is_on);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid is_on %d\n", is_on);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_tx_loopback = {
+ .f = cmd_set_tx_loopback_parsed,
+ .data = NULL,
+ .help_str = "set tx loopback <port_id> on|off",
+ .tokens = {
+ (void *)&cmd_tx_loopback_set,
+ (void *)&cmd_tx_loopback_tx,
+ (void *)&cmd_tx_loopback_loopback,
+ (void *)&cmd_tx_loopback_port_id,
+ (void *)&cmd_tx_loopback_on_off,
+ NULL,
+ },
+};
+
+/* all queues drop enable configuration */
+
+/* Common result structure for all queues drop enable */
+struct cmd_all_queues_drop_en_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t all;
+ cmdline_fixed_string_t queues;
+ cmdline_fixed_string_t drop;
+ portid_t port_id;
+ cmdline_fixed_string_t on_off;
+};
+
+/* Common CLI fields for tx loopback enable disable */
+cmdline_parse_token_string_t cmd_all_queues_drop_en_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_all_queues_drop_en_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_all_queues_drop_en_all =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_all_queues_drop_en_result,
+ all, "all");
+cmdline_parse_token_string_t cmd_all_queues_drop_en_queues =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_all_queues_drop_en_result,
+ queues, "queues");
+cmdline_parse_token_string_t cmd_all_queues_drop_en_drop =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_all_queues_drop_en_result,
+ drop, "drop");
+cmdline_parse_token_num_t cmd_all_queues_drop_en_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_all_queues_drop_en_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_all_queues_drop_en_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_all_queues_drop_en_result,
+ on_off, "on#off");
+
+static void
+cmd_set_all_queues_drop_en_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_all_queues_drop_en_result *res = parsed_result;
+ int ret = -ENOTSUP;
+ int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_ixgbe_set_all_queues_drop_en(res->port_id, is_on);
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_bnxt_set_all_queues_drop_en(res->port_id, is_on);
+#endif
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid is_on %d\n", is_on);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_all_queues_drop_en = {
+ .f = cmd_set_all_queues_drop_en_parsed,
+ .data = NULL,
+ .help_str = "set all queues drop <port_id> on|off",
+ .tokens = {
+ (void *)&cmd_all_queues_drop_en_set,
+ (void *)&cmd_all_queues_drop_en_all,
+ (void *)&cmd_all_queues_drop_en_queues,
+ (void *)&cmd_all_queues_drop_en_drop,
+ (void *)&cmd_all_queues_drop_en_port_id,
+ (void *)&cmd_all_queues_drop_en_on_off,
+ NULL,
+ },
+};
+
+/* vf split drop enable configuration */
+
+/* Common result structure for vf split drop enable */
+struct cmd_vf_split_drop_en_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t split;
+ cmdline_fixed_string_t drop;
+ portid_t port_id;
+ uint16_t vf_id;
+ cmdline_fixed_string_t on_off;
+};
+
+/* Common CLI fields for vf split drop enable disable */
+cmdline_parse_token_string_t cmd_vf_split_drop_en_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_split_drop_en_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_vf_split_drop_en_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_split_drop_en_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_vf_split_drop_en_split =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_split_drop_en_result,
+ split, "split");
+cmdline_parse_token_string_t cmd_vf_split_drop_en_drop =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_split_drop_en_result,
+ drop, "drop");
+cmdline_parse_token_num_t cmd_vf_split_drop_en_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_split_drop_en_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_vf_split_drop_en_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_split_drop_en_result,
+ vf_id, UINT16);
+cmdline_parse_token_string_t cmd_vf_split_drop_en_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_split_drop_en_result,
+ on_off, "on#off");
+
+static void
+cmd_set_vf_split_drop_en_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_split_drop_en_result *res = parsed_result;
+ int ret = -ENOTSUP;
+ int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ ret = rte_pmd_ixgbe_set_vf_split_drop_en(res->port_id, res->vf_id,
+ is_on);
+#endif
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d or is_on %d\n", res->vf_id, is_on);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("not supported on port %d\n", res->port_id);
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_vf_split_drop_en = {
+ .f = cmd_set_vf_split_drop_en_parsed,
+ .data = NULL,
+ .help_str = "set vf split drop <port_id> <vf_id> on|off",
+ .tokens = {
+ (void *)&cmd_vf_split_drop_en_set,
+ (void *)&cmd_vf_split_drop_en_vf,
+ (void *)&cmd_vf_split_drop_en_split,
+ (void *)&cmd_vf_split_drop_en_drop,
+ (void *)&cmd_vf_split_drop_en_port_id,
+ (void *)&cmd_vf_split_drop_en_vf_id,
+ (void *)&cmd_vf_split_drop_en_on_off,
+ NULL,
+ },
+};
+
+/* vf mac address configuration */
+
+/* Common result structure for vf mac address */
+struct cmd_set_vf_mac_addr_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t mac;
+ cmdline_fixed_string_t addr;
+ portid_t port_id;
+ uint16_t vf_id;
+ struct rte_ether_addr mac_addr;
+
+};
+
+/* Common CLI fields for vf split drop enable disable */
+cmdline_parse_token_string_t cmd_set_vf_mac_addr_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_mac_addr_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_set_vf_mac_addr_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_mac_addr_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_set_vf_mac_addr_mac =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_mac_addr_result,
+ mac, "mac");
+cmdline_parse_token_string_t cmd_set_vf_mac_addr_addr =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_mac_addr_result,
+ addr, "addr");
+cmdline_parse_token_num_t cmd_set_vf_mac_addr_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_set_vf_mac_addr_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_vf_mac_addr_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_set_vf_mac_addr_result,
+ vf_id, UINT16);
+cmdline_parse_token_etheraddr_t cmd_set_vf_mac_addr_mac_addr =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_vf_mac_addr_result,
+ mac_addr);
+
+static void
+cmd_set_vf_mac_addr_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_vf_mac_addr_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_ixgbe_set_vf_mac_addr(res->port_id, res->vf_id,
+ &res->mac_addr);
+#endif
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_i40e_set_vf_mac_addr(res->port_id, res->vf_id,
+ &res->mac_addr);
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_bnxt_set_vf_mac_addr(res->port_id, res->vf_id,
+ &res->mac_addr);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d or mac_addr\n", res->vf_id);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_vf_mac_addr = {
+ .f = cmd_set_vf_mac_addr_parsed,
+ .data = NULL,
+ .help_str = "set vf mac addr <port_id> <vf_id> <mac_addr>",
+ .tokens = {
+ (void *)&cmd_set_vf_mac_addr_set,
+ (void *)&cmd_set_vf_mac_addr_vf,
+ (void *)&cmd_set_vf_mac_addr_mac,
+ (void *)&cmd_set_vf_mac_addr_addr,
+ (void *)&cmd_set_vf_mac_addr_port_id,
+ (void *)&cmd_set_vf_mac_addr_vf_id,
+ (void *)&cmd_set_vf_mac_addr_mac_addr,
+ NULL,
+ },
+};
+
+/* MACsec configuration */
+
+/* Common result structure for MACsec offload enable */
+struct cmd_macsec_offload_on_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t macsec;
+ cmdline_fixed_string_t offload;
+ portid_t port_id;
+ cmdline_fixed_string_t on;
+ cmdline_fixed_string_t encrypt;
+ cmdline_fixed_string_t en_on_off;
+ cmdline_fixed_string_t replay_protect;
+ cmdline_fixed_string_t rp_on_off;
+};
+
+/* Common CLI fields for MACsec offload disable */
+cmdline_parse_token_string_t cmd_macsec_offload_on_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_offload_on_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_macsec_offload_on_macsec =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_offload_on_result,
+ macsec, "macsec");
+cmdline_parse_token_string_t cmd_macsec_offload_on_offload =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_offload_on_result,
+ offload, "offload");
+cmdline_parse_token_num_t cmd_macsec_offload_on_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_macsec_offload_on_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_macsec_offload_on_on =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_offload_on_result,
+ on, "on");
+cmdline_parse_token_string_t cmd_macsec_offload_on_encrypt =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_offload_on_result,
+ encrypt, "encrypt");
+cmdline_parse_token_string_t cmd_macsec_offload_on_en_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_offload_on_result,
+ en_on_off, "on#off");
+cmdline_parse_token_string_t cmd_macsec_offload_on_replay_protect =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_offload_on_result,
+ replay_protect, "replay-protect");
+cmdline_parse_token_string_t cmd_macsec_offload_on_rp_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_offload_on_result,
+ rp_on_off, "on#off");
+
+static void
+cmd_set_macsec_offload_on_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_macsec_offload_on_result *res = parsed_result;
+ int ret = -ENOTSUP;
+ portid_t port_id = res->port_id;
+ int en = (strcmp(res->en_on_off, "on") == 0) ? 1 : 0;
+ int rp = (strcmp(res->rp_on_off, "on") == 0) ? 1 : 0;
+ struct rte_eth_dev_info dev_info;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ if (!port_is_stopped(port_id)) {
+ printf("Please stop port %d first\n", port_id);
+ return;
+ }
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MACSEC_INSERT) {
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ ret = rte_pmd_ixgbe_macsec_enable(port_id, en, rp);
+#endif
+ }
+ RTE_SET_USED(en);
+ RTE_SET_USED(rp);
+
+ switch (ret) {
+ case 0:
+ ports[port_id].dev_conf.txmode.offloads |=
+ DEV_TX_OFFLOAD_MACSEC_INSERT;
+ cmd_reconfig_device_queue(port_id, 1, 1);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", port_id);
+ break;
+ case -ENOTSUP:
+ printf("not supported on port %d\n", port_id);
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_macsec_offload_on = {
+ .f = cmd_set_macsec_offload_on_parsed,
+ .data = NULL,
+ .help_str = "set macsec offload <port_id> on "
+ "encrypt on|off replay-protect on|off",
+ .tokens = {
+ (void *)&cmd_macsec_offload_on_set,
+ (void *)&cmd_macsec_offload_on_macsec,
+ (void *)&cmd_macsec_offload_on_offload,
+ (void *)&cmd_macsec_offload_on_port_id,
+ (void *)&cmd_macsec_offload_on_on,
+ (void *)&cmd_macsec_offload_on_encrypt,
+ (void *)&cmd_macsec_offload_on_en_on_off,
+ (void *)&cmd_macsec_offload_on_replay_protect,
+ (void *)&cmd_macsec_offload_on_rp_on_off,
+ NULL,
+ },
+};
+
+/* Common result structure for MACsec offload disable */
+struct cmd_macsec_offload_off_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t macsec;
+ cmdline_fixed_string_t offload;
+ portid_t port_id;
+ cmdline_fixed_string_t off;
+};
+
+/* Common CLI fields for MACsec offload disable */
+cmdline_parse_token_string_t cmd_macsec_offload_off_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_offload_off_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_macsec_offload_off_macsec =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_offload_off_result,
+ macsec, "macsec");
+cmdline_parse_token_string_t cmd_macsec_offload_off_offload =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_offload_off_result,
+ offload, "offload");
+cmdline_parse_token_num_t cmd_macsec_offload_off_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_macsec_offload_off_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_macsec_offload_off_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_offload_off_result,
+ off, "off");
+
+static void
+cmd_set_macsec_offload_off_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_macsec_offload_off_result *res = parsed_result;
+ int ret = -ENOTSUP;
+ struct rte_eth_dev_info dev_info;
+ portid_t port_id = res->port_id;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ if (!port_is_stopped(port_id)) {
+ printf("Please stop port %d first\n", port_id);
+ return;
+ }
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MACSEC_INSERT) {
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ ret = rte_pmd_ixgbe_macsec_disable(port_id);
+#endif
+ }
+ switch (ret) {
+ case 0:
+ ports[port_id].dev_conf.txmode.offloads &=
+ ~DEV_TX_OFFLOAD_MACSEC_INSERT;
+ cmd_reconfig_device_queue(port_id, 1, 1);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", port_id);
+ break;
+ case -ENOTSUP:
+ printf("not supported on port %d\n", port_id);
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_macsec_offload_off = {
+ .f = cmd_set_macsec_offload_off_parsed,
+ .data = NULL,
+ .help_str = "set macsec offload <port_id> off",
+ .tokens = {
+ (void *)&cmd_macsec_offload_off_set,
+ (void *)&cmd_macsec_offload_off_macsec,
+ (void *)&cmd_macsec_offload_off_offload,
+ (void *)&cmd_macsec_offload_off_port_id,
+ (void *)&cmd_macsec_offload_off_off,
+ NULL,
+ },
+};
+
+/* Common result structure for MACsec secure connection configure */
+struct cmd_macsec_sc_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t macsec;
+ cmdline_fixed_string_t sc;
+ cmdline_fixed_string_t tx_rx;
+ portid_t port_id;
+ struct rte_ether_addr mac;
+ uint16_t pi;
+};
+
+/* Common CLI fields for MACsec secure connection configure */
+cmdline_parse_token_string_t cmd_macsec_sc_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_sc_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_macsec_sc_macsec =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_sc_result,
+ macsec, "macsec");
+cmdline_parse_token_string_t cmd_macsec_sc_sc =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_sc_result,
+ sc, "sc");
+cmdline_parse_token_string_t cmd_macsec_sc_tx_rx =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_sc_result,
+ tx_rx, "tx#rx");
+cmdline_parse_token_num_t cmd_macsec_sc_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_macsec_sc_result,
+ port_id, UINT16);
+cmdline_parse_token_etheraddr_t cmd_macsec_sc_mac =
+ TOKEN_ETHERADDR_INITIALIZER
+ (struct cmd_macsec_sc_result,
+ mac);
+cmdline_parse_token_num_t cmd_macsec_sc_pi =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_macsec_sc_result,
+ pi, UINT16);
+
+static void
+cmd_set_macsec_sc_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_macsec_sc_result *res = parsed_result;
+ int ret = -ENOTSUP;
+ int is_tx = (strcmp(res->tx_rx, "tx") == 0) ? 1 : 0;
+
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ ret = is_tx ?
+ rte_pmd_ixgbe_macsec_config_txsc(res->port_id,
+ res->mac.addr_bytes) :
+ rte_pmd_ixgbe_macsec_config_rxsc(res->port_id,
+ res->mac.addr_bytes, res->pi);
+#endif
+ RTE_SET_USED(is_tx);
+
+ switch (ret) {
+ case 0:
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("not supported on port %d\n", res->port_id);
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_macsec_sc = {
+ .f = cmd_set_macsec_sc_parsed,
+ .data = NULL,
+ .help_str = "set macsec sc tx|rx <port_id> <mac> <pi>",
+ .tokens = {
+ (void *)&cmd_macsec_sc_set,
+ (void *)&cmd_macsec_sc_macsec,
+ (void *)&cmd_macsec_sc_sc,
+ (void *)&cmd_macsec_sc_tx_rx,
+ (void *)&cmd_macsec_sc_port_id,
+ (void *)&cmd_macsec_sc_mac,
+ (void *)&cmd_macsec_sc_pi,
+ NULL,
+ },
+};
+
+/* Common result structure for MACsec secure connection configure */
+struct cmd_macsec_sa_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t macsec;
+ cmdline_fixed_string_t sa;
+ cmdline_fixed_string_t tx_rx;
+ portid_t port_id;
+ uint8_t idx;
+ uint8_t an;
+ uint32_t pn;
+ cmdline_fixed_string_t key;
+};
+
+/* Common CLI fields for MACsec secure connection configure */
+cmdline_parse_token_string_t cmd_macsec_sa_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_sa_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_macsec_sa_macsec =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_sa_result,
+ macsec, "macsec");
+cmdline_parse_token_string_t cmd_macsec_sa_sa =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_sa_result,
+ sa, "sa");
+cmdline_parse_token_string_t cmd_macsec_sa_tx_rx =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_sa_result,
+ tx_rx, "tx#rx");
+cmdline_parse_token_num_t cmd_macsec_sa_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_macsec_sa_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_macsec_sa_idx =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_macsec_sa_result,
+ idx, UINT8);
+cmdline_parse_token_num_t cmd_macsec_sa_an =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_macsec_sa_result,
+ an, UINT8);
+cmdline_parse_token_num_t cmd_macsec_sa_pn =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_macsec_sa_result,
+ pn, UINT32);
+cmdline_parse_token_string_t cmd_macsec_sa_key =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_macsec_sa_result,
+ key, NULL);
+
+static void
+cmd_set_macsec_sa_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_macsec_sa_result *res = parsed_result;
+ int ret = -ENOTSUP;
+ int is_tx = (strcmp(res->tx_rx, "tx") == 0) ? 1 : 0;
+ uint8_t key[16] = { 0 };
+ uint8_t xdgt0;
+ uint8_t xdgt1;
+ int key_len;
+ int i;
+
+ key_len = strlen(res->key) / 2;
+ if (key_len > 16)
+ key_len = 16;
+
+ for (i = 0; i < key_len; i++) {
+ xdgt0 = parse_and_check_key_hexa_digit(res->key, (i * 2));
+ if (xdgt0 == 0xFF)
+ return;
+ xdgt1 = parse_and_check_key_hexa_digit(res->key, (i * 2) + 1);
+ if (xdgt1 == 0xFF)
+ return;
+ key[i] = (uint8_t) ((xdgt0 * 16) + xdgt1);
+ }
+
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ ret = is_tx ?
+ rte_pmd_ixgbe_macsec_select_txsa(res->port_id,
+ res->idx, res->an, res->pn, key) :
+ rte_pmd_ixgbe_macsec_select_rxsa(res->port_id,
+ res->idx, res->an, res->pn, key);
+#endif
+ RTE_SET_USED(is_tx);
+ RTE_SET_USED(key);
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid idx %d or an %d\n", res->idx, res->an);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("not supported on port %d\n", res->port_id);
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_macsec_sa = {
+ .f = cmd_set_macsec_sa_parsed,
+ .data = NULL,
+ .help_str = "set macsec sa tx|rx <port_id> <idx> <an> <pn> <key>",
+ .tokens = {
+ (void *)&cmd_macsec_sa_set,
+ (void *)&cmd_macsec_sa_macsec,
+ (void *)&cmd_macsec_sa_sa,
+ (void *)&cmd_macsec_sa_tx_rx,
+ (void *)&cmd_macsec_sa_port_id,
+ (void *)&cmd_macsec_sa_idx,
+ (void *)&cmd_macsec_sa_an,
+ (void *)&cmd_macsec_sa_pn,
+ (void *)&cmd_macsec_sa_key,
+ NULL,
+ },
+};
+
+/* VF unicast promiscuous mode configuration */
+
+/* Common result structure for VF unicast promiscuous mode */
+struct cmd_vf_promisc_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t promisc;
+ portid_t port_id;
+ uint32_t vf_id;
+ cmdline_fixed_string_t on_off;
+};
+
+/* Common CLI fields for VF unicast promiscuous mode enable disable */
+cmdline_parse_token_string_t cmd_vf_promisc_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_promisc_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_vf_promisc_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_promisc_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_vf_promisc_promisc =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_promisc_result,
+ promisc, "promisc");
+cmdline_parse_token_num_t cmd_vf_promisc_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_promisc_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_vf_promisc_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_promisc_result,
+ vf_id, UINT32);
+cmdline_parse_token_string_t cmd_vf_promisc_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_promisc_result,
+ on_off, "on#off");
+
+static void
+cmd_set_vf_promisc_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_promisc_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ __rte_unused int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ ret = rte_pmd_i40e_set_vf_unicast_promisc(res->port_id,
+ res->vf_id, is_on);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d\n", res->vf_id);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_vf_promisc = {
+ .f = cmd_set_vf_promisc_parsed,
+ .data = NULL,
+ .help_str = "set vf promisc <port_id> <vf_id> on|off: "
+ "Set unicast promiscuous mode for a VF from the PF",
+ .tokens = {
+ (void *)&cmd_vf_promisc_set,
+ (void *)&cmd_vf_promisc_vf,
+ (void *)&cmd_vf_promisc_promisc,
+ (void *)&cmd_vf_promisc_port_id,
+ (void *)&cmd_vf_promisc_vf_id,
+ (void *)&cmd_vf_promisc_on_off,
+ NULL,
+ },
+};
+
+/* VF multicast promiscuous mode configuration */
+
+/* Common result structure for VF multicast promiscuous mode */
+struct cmd_vf_allmulti_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t allmulti;
+ portid_t port_id;
+ uint32_t vf_id;
+ cmdline_fixed_string_t on_off;
+};
+
+/* Common CLI fields for VF multicast promiscuous mode enable disable */
+cmdline_parse_token_string_t cmd_vf_allmulti_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_allmulti_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_vf_allmulti_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_allmulti_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_vf_allmulti_allmulti =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_allmulti_result,
+ allmulti, "allmulti");
+cmdline_parse_token_num_t cmd_vf_allmulti_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_allmulti_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_vf_allmulti_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_allmulti_result,
+ vf_id, UINT32);
+cmdline_parse_token_string_t cmd_vf_allmulti_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_allmulti_result,
+ on_off, "on#off");
+
+static void
+cmd_set_vf_allmulti_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_allmulti_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ __rte_unused int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ ret = rte_pmd_i40e_set_vf_multicast_promisc(res->port_id,
+ res->vf_id, is_on);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d\n", res->vf_id);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_vf_allmulti = {
+ .f = cmd_set_vf_allmulti_parsed,
+ .data = NULL,
+ .help_str = "set vf allmulti <port_id> <vf_id> on|off: "
+ "Set multicast promiscuous mode for a VF from the PF",
+ .tokens = {
+ (void *)&cmd_vf_allmulti_set,
+ (void *)&cmd_vf_allmulti_vf,
+ (void *)&cmd_vf_allmulti_allmulti,
+ (void *)&cmd_vf_allmulti_port_id,
+ (void *)&cmd_vf_allmulti_vf_id,
+ (void *)&cmd_vf_allmulti_on_off,
+ NULL,
+ },
+};
+
+/* vf broadcast mode configuration */
+
+/* Common result structure for vf broadcast */
+struct cmd_set_vf_broadcast_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t broadcast;
+ portid_t port_id;
+ uint16_t vf_id;
+ cmdline_fixed_string_t on_off;
+};
+
+/* Common CLI fields for vf broadcast enable disable */
+cmdline_parse_token_string_t cmd_set_vf_broadcast_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_broadcast_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_set_vf_broadcast_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_broadcast_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_set_vf_broadcast_broadcast =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_broadcast_result,
+ broadcast, "broadcast");
+cmdline_parse_token_num_t cmd_set_vf_broadcast_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_set_vf_broadcast_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_vf_broadcast_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_set_vf_broadcast_result,
+ vf_id, UINT16);
+cmdline_parse_token_string_t cmd_set_vf_broadcast_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_broadcast_result,
+ on_off, "on#off");
+
+static void
+cmd_set_vf_broadcast_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_vf_broadcast_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ __rte_unused int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ ret = rte_pmd_i40e_set_vf_broadcast(res->port_id,
+ res->vf_id, is_on);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d or is_on %d\n", res->vf_id, is_on);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_vf_broadcast = {
+ .f = cmd_set_vf_broadcast_parsed,
+ .data = NULL,
+ .help_str = "set vf broadcast <port_id> <vf_id> on|off",
+ .tokens = {
+ (void *)&cmd_set_vf_broadcast_set,
+ (void *)&cmd_set_vf_broadcast_vf,
+ (void *)&cmd_set_vf_broadcast_broadcast,
+ (void *)&cmd_set_vf_broadcast_port_id,
+ (void *)&cmd_set_vf_broadcast_vf_id,
+ (void *)&cmd_set_vf_broadcast_on_off,
+ NULL,
+ },
+};
+
+/* vf vlan tag configuration */
+
+/* Common result structure for vf vlan tag */
+struct cmd_set_vf_vlan_tag_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t vlan;
+ cmdline_fixed_string_t tag;
+ portid_t port_id;
+ uint16_t vf_id;
+ cmdline_fixed_string_t on_off;
+};
+
+/* Common CLI fields for vf vlan tag enable disable */
+cmdline_parse_token_string_t cmd_set_vf_vlan_tag_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_vlan_tag_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_set_vf_vlan_tag_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_vlan_tag_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_set_vf_vlan_tag_vlan =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_vlan_tag_result,
+ vlan, "vlan");
+cmdline_parse_token_string_t cmd_set_vf_vlan_tag_tag =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_vlan_tag_result,
+ tag, "tag");
+cmdline_parse_token_num_t cmd_set_vf_vlan_tag_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_set_vf_vlan_tag_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_vf_vlan_tag_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_set_vf_vlan_tag_result,
+ vf_id, UINT16);
+cmdline_parse_token_string_t cmd_set_vf_vlan_tag_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_vf_vlan_tag_result,
+ on_off, "on#off");
+
+static void
+cmd_set_vf_vlan_tag_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_vf_vlan_tag_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ __rte_unused int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ ret = rte_pmd_i40e_set_vf_vlan_tag(res->port_id,
+ res->vf_id, is_on);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d or is_on %d\n", res->vf_id, is_on);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_set_vf_vlan_tag = {
+ .f = cmd_set_vf_vlan_tag_parsed,
+ .data = NULL,
+ .help_str = "set vf vlan tag <port_id> <vf_id> on|off",
+ .tokens = {
+ (void *)&cmd_set_vf_vlan_tag_set,
+ (void *)&cmd_set_vf_vlan_tag_vf,
+ (void *)&cmd_set_vf_vlan_tag_vlan,
+ (void *)&cmd_set_vf_vlan_tag_tag,
+ (void *)&cmd_set_vf_vlan_tag_port_id,
+ (void *)&cmd_set_vf_vlan_tag_vf_id,
+ (void *)&cmd_set_vf_vlan_tag_on_off,
+ NULL,
+ },
+};
+
+/* Common definition of VF and TC TX bandwidth configuration */
+struct cmd_vf_tc_bw_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t tc;
+ cmdline_fixed_string_t tx;
+ cmdline_fixed_string_t min_bw;
+ cmdline_fixed_string_t max_bw;
+ cmdline_fixed_string_t strict_link_prio;
+ portid_t port_id;
+ uint16_t vf_id;
+ uint8_t tc_no;
+ uint32_t bw;
+ cmdline_fixed_string_t bw_list;
+ uint8_t tc_map;
+};
+
+cmdline_parse_token_string_t cmd_vf_tc_bw_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_tc_bw_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_vf_tc_bw_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_tc_bw_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_vf_tc_bw_tc =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_tc_bw_result,
+ tc, "tc");
+cmdline_parse_token_string_t cmd_vf_tc_bw_tx =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_tc_bw_result,
+ tx, "tx");
+cmdline_parse_token_string_t cmd_vf_tc_bw_strict_link_prio =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_tc_bw_result,
+ strict_link_prio, "strict-link-priority");
+cmdline_parse_token_string_t cmd_vf_tc_bw_min_bw =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_tc_bw_result,
+ min_bw, "min-bandwidth");
+cmdline_parse_token_string_t cmd_vf_tc_bw_max_bw =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_tc_bw_result,
+ max_bw, "max-bandwidth");
+cmdline_parse_token_num_t cmd_vf_tc_bw_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_tc_bw_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_vf_tc_bw_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_tc_bw_result,
+ vf_id, UINT16);
+cmdline_parse_token_num_t cmd_vf_tc_bw_tc_no =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_tc_bw_result,
+ tc_no, UINT8);
+cmdline_parse_token_num_t cmd_vf_tc_bw_bw =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_tc_bw_result,
+ bw, UINT32);
+cmdline_parse_token_string_t cmd_vf_tc_bw_bw_list =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_vf_tc_bw_result,
+ bw_list, NULL);
+cmdline_parse_token_num_t cmd_vf_tc_bw_tc_map =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_vf_tc_bw_result,
+ tc_map, UINT8);
+
+/* VF max bandwidth setting */
+static void
+cmd_vf_max_bw_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_tc_bw_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ ret = rte_pmd_i40e_set_vf_max_bw(res->port_id,
+ res->vf_id, res->bw);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d or bandwidth %d\n",
+ res->vf_id, res->bw);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_vf_max_bw = {
+ .f = cmd_vf_max_bw_parsed,
+ .data = NULL,
+ .help_str = "set vf tx max-bandwidth <port_id> <vf_id> <bandwidth>",
+ .tokens = {
+ (void *)&cmd_vf_tc_bw_set,
+ (void *)&cmd_vf_tc_bw_vf,
+ (void *)&cmd_vf_tc_bw_tx,
+ (void *)&cmd_vf_tc_bw_max_bw,
+ (void *)&cmd_vf_tc_bw_port_id,
+ (void *)&cmd_vf_tc_bw_vf_id,
+ (void *)&cmd_vf_tc_bw_bw,
+ NULL,
+ },
+};
+
+static int
+vf_tc_min_bw_parse_bw_list(uint8_t *bw_list,
+ uint8_t *tc_num,
+ char *str)
+{
+ uint32_t size;
+ const char *p, *p0 = str;
+ char s[256];
+ char *end;
+ char *str_fld[16];
+ uint16_t i;
+ int ret;
+
+ p = strchr(p0, '(');
+ if (p == NULL) {
+ printf("The bandwidth-list should be '(bw1, bw2, ...)'\n");
+ return -1;
+ }
+ p++;
+ p0 = strchr(p, ')');
+ if (p0 == NULL) {
+ printf("The bandwidth-list should be '(bw1, bw2, ...)'\n");
+ return -1;
+ }
+ size = p0 - p;
+ if (size >= sizeof(s)) {
+ printf("The string size exceeds the internal buffer size\n");
+ return -1;
+ }
+ snprintf(s, sizeof(s), "%.*s", size, p);
+ ret = rte_strsplit(s, sizeof(s), str_fld, 16, ',');
+ if (ret <= 0) {
+ printf("Failed to get the bandwidth list. ");
+ return -1;
+ }
+ *tc_num = ret;
+ for (i = 0; i < ret; i++)
+ bw_list[i] = (uint8_t)strtoul(str_fld[i], &end, 0);
+
+ return 0;
+}
+
+/* TC min bandwidth setting */
+static void
+cmd_vf_tc_min_bw_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_tc_bw_result *res = parsed_result;
+ uint8_t tc_num;
+ uint8_t bw[16];
+ int ret = -ENOTSUP;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+ ret = vf_tc_min_bw_parse_bw_list(bw, &tc_num, res->bw_list);
+ if (ret)
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ ret = rte_pmd_i40e_set_vf_tc_bw_alloc(res->port_id, res->vf_id,
+ tc_num, bw);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d or bandwidth\n", res->vf_id);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_vf_tc_min_bw = {
+ .f = cmd_vf_tc_min_bw_parsed,
+ .data = NULL,
+ .help_str = "set vf tc tx min-bandwidth <port_id> <vf_id>"
+ " <bw1, bw2, ...>",
+ .tokens = {
+ (void *)&cmd_vf_tc_bw_set,
+ (void *)&cmd_vf_tc_bw_vf,
+ (void *)&cmd_vf_tc_bw_tc,
+ (void *)&cmd_vf_tc_bw_tx,
+ (void *)&cmd_vf_tc_bw_min_bw,
+ (void *)&cmd_vf_tc_bw_port_id,
+ (void *)&cmd_vf_tc_bw_vf_id,
+ (void *)&cmd_vf_tc_bw_bw_list,
+ NULL,
+ },
+};
+
+static void
+cmd_tc_min_bw_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_tc_bw_result *res = parsed_result;
+ struct rte_port *port;
+ uint8_t tc_num;
+ uint8_t bw[16];
+ int ret = -ENOTSUP;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+ port = &ports[res->port_id];
+ /** Check if the port is not started **/
+ if (port->port_status != RTE_PORT_STOPPED) {
+ printf("Please stop port %d first\n", res->port_id);
+ return;
+ }
+
+ ret = vf_tc_min_bw_parse_bw_list(bw, &tc_num, res->bw_list);
+ if (ret)
+ return;
+
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ ret = rte_pmd_ixgbe_set_tc_bw_alloc(res->port_id, tc_num, bw);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid bandwidth\n");
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_tc_min_bw = {
+ .f = cmd_tc_min_bw_parsed,
+ .data = NULL,
+ .help_str = "set tc tx min-bandwidth <port_id> <bw1, bw2, ...>",
+ .tokens = {
+ (void *)&cmd_vf_tc_bw_set,
+ (void *)&cmd_vf_tc_bw_tc,
+ (void *)&cmd_vf_tc_bw_tx,
+ (void *)&cmd_vf_tc_bw_min_bw,
+ (void *)&cmd_vf_tc_bw_port_id,
+ (void *)&cmd_vf_tc_bw_bw_list,
+ NULL,
+ },
+};
+
+/* TC max bandwidth setting */
+static void
+cmd_vf_tc_max_bw_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_tc_bw_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ ret = rte_pmd_i40e_set_vf_tc_max_bw(res->port_id, res->vf_id,
+ res->tc_no, res->bw);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d, tc_no %d or bandwidth %d\n",
+ res->vf_id, res->tc_no, res->bw);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_vf_tc_max_bw = {
+ .f = cmd_vf_tc_max_bw_parsed,
+ .data = NULL,
+ .help_str = "set vf tc tx max-bandwidth <port_id> <vf_id> <tc_no>"
+ " <bandwidth>",
+ .tokens = {
+ (void *)&cmd_vf_tc_bw_set,
+ (void *)&cmd_vf_tc_bw_vf,
+ (void *)&cmd_vf_tc_bw_tc,
+ (void *)&cmd_vf_tc_bw_tx,
+ (void *)&cmd_vf_tc_bw_max_bw,
+ (void *)&cmd_vf_tc_bw_port_id,
+ (void *)&cmd_vf_tc_bw_vf_id,
+ (void *)&cmd_vf_tc_bw_tc_no,
+ (void *)&cmd_vf_tc_bw_bw,
+ NULL,
+ },
+};
+
+
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+
+/* *** Set Port default Traffic Management Hierarchy *** */
+struct cmd_set_port_tm_hierarchy_default_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t hierarchy;
+ cmdline_fixed_string_t def;
+ portid_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_hierarchy_default_set =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_hierarchy_default_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_hierarchy_default_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_hierarchy_default_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_hierarchy_default_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_hierarchy_default_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_hierarchy_default_hierarchy =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_hierarchy_default_result,
+ hierarchy, "hierarchy");
+cmdline_parse_token_string_t cmd_set_port_tm_hierarchy_default_default =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_hierarchy_default_result,
+ def, "default");
+cmdline_parse_token_num_t cmd_set_port_tm_hierarchy_default_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_set_port_tm_hierarchy_default_result,
+ port_id, UINT16);
+
+static void cmd_set_port_tm_hierarchy_default_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_port_tm_hierarchy_default_result *res = parsed_result;
+ struct rte_port *p;
+ portid_t port_id = res->port_id;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ p = &ports[port_id];
+
+ /* Forward mode: tm */
+ if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnic")) {
+ printf(" softnicfwd mode not enabled(error)\n");
+ return;
+ }
+
+ /* Set the default tm hierarchy */
+ p->softport.default_tm_hierarchy_enable = 1;
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_hierarchy_default = {
+ .f = cmd_set_port_tm_hierarchy_default_parsed,
+ .data = NULL,
+ .help_str = "set port tm hierarchy default <port_id>",
+ .tokens = {
+ (void *)&cmd_set_port_tm_hierarchy_default_set,
+ (void *)&cmd_set_port_tm_hierarchy_default_port,
+ (void *)&cmd_set_port_tm_hierarchy_default_tm,
+ (void *)&cmd_set_port_tm_hierarchy_default_hierarchy,
+ (void *)&cmd_set_port_tm_hierarchy_default_default,
+ (void *)&cmd_set_port_tm_hierarchy_default_port_id,
+ NULL,
+ },
+};
+#endif
+
+/** Set VXLAN encapsulation details */
+struct cmd_set_vxlan_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t vxlan;
+ cmdline_fixed_string_t pos_token;
+ cmdline_fixed_string_t ip_version;
+ uint32_t vlan_present:1;
+ uint32_t vni;
+ uint16_t udp_src;
+ uint16_t udp_dst;
+ cmdline_ipaddr_t ip_src;
+ cmdline_ipaddr_t ip_dst;
+ uint16_t tci;
+ uint8_t tos;
+ uint8_t ttl;
+ struct rte_ether_addr eth_src;
+ struct rte_ether_addr eth_dst;
+};
+
+cmdline_parse_token_string_t cmd_set_vxlan_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, set, "set");
+cmdline_parse_token_string_t cmd_set_vxlan_vxlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, vxlan, "vxlan");
+cmdline_parse_token_string_t cmd_set_vxlan_vxlan_tos_ttl =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, vxlan,
+ "vxlan-tos-ttl");
+cmdline_parse_token_string_t cmd_set_vxlan_vxlan_with_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, vxlan,
+ "vxlan-with-vlan");
+cmdline_parse_token_string_t cmd_set_vxlan_ip_version =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, pos_token,
+ "ip-version");
+cmdline_parse_token_string_t cmd_set_vxlan_ip_version_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, ip_version,
+ "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_set_vxlan_vni =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, pos_token,
+ "vni");
+cmdline_parse_token_num_t cmd_set_vxlan_vni_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_vxlan_result, vni, UINT32);
+cmdline_parse_token_string_t cmd_set_vxlan_udp_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, pos_token,
+ "udp-src");
+cmdline_parse_token_num_t cmd_set_vxlan_udp_src_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_vxlan_result, udp_src, UINT16);
+cmdline_parse_token_string_t cmd_set_vxlan_udp_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, pos_token,
+ "udp-dst");
+cmdline_parse_token_num_t cmd_set_vxlan_udp_dst_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_vxlan_result, udp_dst, UINT16);
+cmdline_parse_token_string_t cmd_set_vxlan_ip_tos =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, pos_token,
+ "ip-tos");
+cmdline_parse_token_num_t cmd_set_vxlan_ip_tos_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_vxlan_result, tos, UINT8);
+cmdline_parse_token_string_t cmd_set_vxlan_ip_ttl =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, pos_token,
+ "ip-ttl");
+cmdline_parse_token_num_t cmd_set_vxlan_ip_ttl_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_vxlan_result, ttl, UINT8);
+cmdline_parse_token_string_t cmd_set_vxlan_ip_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, pos_token,
+ "ip-src");
+cmdline_parse_token_ipaddr_t cmd_set_vxlan_ip_src_value =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_set_vxlan_result, ip_src);
+cmdline_parse_token_string_t cmd_set_vxlan_ip_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, pos_token,
+ "ip-dst");
+cmdline_parse_token_ipaddr_t cmd_set_vxlan_ip_dst_value =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_set_vxlan_result, ip_dst);
+cmdline_parse_token_string_t cmd_set_vxlan_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, pos_token,
+ "vlan-tci");
+cmdline_parse_token_num_t cmd_set_vxlan_vlan_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_vxlan_result, tci, UINT16);
+cmdline_parse_token_string_t cmd_set_vxlan_eth_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, pos_token,
+ "eth-src");
+cmdline_parse_token_etheraddr_t cmd_set_vxlan_eth_src_value =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_vxlan_result, eth_src);
+cmdline_parse_token_string_t cmd_set_vxlan_eth_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_vxlan_result, pos_token,
+ "eth-dst");
+cmdline_parse_token_etheraddr_t cmd_set_vxlan_eth_dst_value =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_vxlan_result, eth_dst);
+
+static void cmd_set_vxlan_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_vxlan_result *res = parsed_result;
+ union {
+ uint32_t vxlan_id;
+ uint8_t vni[4];
+ } id = {
+ .vxlan_id = rte_cpu_to_be_32(res->vni) & RTE_BE32(0x00ffffff),
+ };
+
+ vxlan_encap_conf.select_tos_ttl = 0;
+ if (strcmp(res->vxlan, "vxlan") == 0)
+ vxlan_encap_conf.select_vlan = 0;
+ else if (strcmp(res->vxlan, "vxlan-with-vlan") == 0)
+ vxlan_encap_conf.select_vlan = 1;
+ else if (strcmp(res->vxlan, "vxlan-tos-ttl") == 0) {
+ vxlan_encap_conf.select_vlan = 0;
+ vxlan_encap_conf.select_tos_ttl = 1;
+ }
+ if (strcmp(res->ip_version, "ipv4") == 0)
+ vxlan_encap_conf.select_ipv4 = 1;
+ else if (strcmp(res->ip_version, "ipv6") == 0)
+ vxlan_encap_conf.select_ipv4 = 0;
+ else
+ return;
+ rte_memcpy(vxlan_encap_conf.vni, &id.vni[1], 3);
+ vxlan_encap_conf.udp_src = rte_cpu_to_be_16(res->udp_src);
+ vxlan_encap_conf.udp_dst = rte_cpu_to_be_16(res->udp_dst);
+ vxlan_encap_conf.ip_tos = res->tos;
+ vxlan_encap_conf.ip_ttl = res->ttl;
+ if (vxlan_encap_conf.select_ipv4) {
+ IPV4_ADDR_TO_UINT(res->ip_src, vxlan_encap_conf.ipv4_src);
+ IPV4_ADDR_TO_UINT(res->ip_dst, vxlan_encap_conf.ipv4_dst);
+ } else {
+ IPV6_ADDR_TO_ARRAY(res->ip_src, vxlan_encap_conf.ipv6_src);
+ IPV6_ADDR_TO_ARRAY(res->ip_dst, vxlan_encap_conf.ipv6_dst);
+ }
+ if (vxlan_encap_conf.select_vlan)
+ vxlan_encap_conf.vlan_tci = rte_cpu_to_be_16(res->tci);
+ rte_memcpy(vxlan_encap_conf.eth_src, res->eth_src.addr_bytes,
+ RTE_ETHER_ADDR_LEN);
+ rte_memcpy(vxlan_encap_conf.eth_dst, res->eth_dst.addr_bytes,
+ RTE_ETHER_ADDR_LEN);
+}
+
+cmdline_parse_inst_t cmd_set_vxlan = {
+ .f = cmd_set_vxlan_parsed,
+ .data = NULL,
+ .help_str = "set vxlan ip-version ipv4|ipv6 vni <vni> udp-src"
+ " <udp-src> udp-dst <udp-dst> ip-src <ip-src> ip-dst <ip-dst>"
+ " eth-src <eth-src> eth-dst <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_vxlan_set,
+ (void *)&cmd_set_vxlan_vxlan,
+ (void *)&cmd_set_vxlan_ip_version,
+ (void *)&cmd_set_vxlan_ip_version_value,
+ (void *)&cmd_set_vxlan_vni,
+ (void *)&cmd_set_vxlan_vni_value,
+ (void *)&cmd_set_vxlan_udp_src,
+ (void *)&cmd_set_vxlan_udp_src_value,
+ (void *)&cmd_set_vxlan_udp_dst,
+ (void *)&cmd_set_vxlan_udp_dst_value,
+ (void *)&cmd_set_vxlan_ip_src,
+ (void *)&cmd_set_vxlan_ip_src_value,
+ (void *)&cmd_set_vxlan_ip_dst,
+ (void *)&cmd_set_vxlan_ip_dst_value,
+ (void *)&cmd_set_vxlan_eth_src,
+ (void *)&cmd_set_vxlan_eth_src_value,
+ (void *)&cmd_set_vxlan_eth_dst,
+ (void *)&cmd_set_vxlan_eth_dst_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_vxlan_tos_ttl = {
+ .f = cmd_set_vxlan_parsed,
+ .data = NULL,
+ .help_str = "set vxlan-tos-ttl ip-version ipv4|ipv6 vni <vni> udp-src"
+ " <udp-src> udp-dst <udp-dst> ip-tos <ip-tos> ip-ttl <ip-ttl>"
+ " ip-src <ip-src> ip-dst <ip-dst> eth-src <eth-src>"
+ " eth-dst <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_vxlan_set,
+ (void *)&cmd_set_vxlan_vxlan_tos_ttl,
+ (void *)&cmd_set_vxlan_ip_version,
+ (void *)&cmd_set_vxlan_ip_version_value,
+ (void *)&cmd_set_vxlan_vni,
+ (void *)&cmd_set_vxlan_vni_value,
+ (void *)&cmd_set_vxlan_udp_src,
+ (void *)&cmd_set_vxlan_udp_src_value,
+ (void *)&cmd_set_vxlan_udp_dst,
+ (void *)&cmd_set_vxlan_udp_dst_value,
+ (void *)&cmd_set_vxlan_ip_tos,
+ (void *)&cmd_set_vxlan_ip_tos_value,
+ (void *)&cmd_set_vxlan_ip_ttl,
+ (void *)&cmd_set_vxlan_ip_ttl_value,
+ (void *)&cmd_set_vxlan_ip_src,
+ (void *)&cmd_set_vxlan_ip_src_value,
+ (void *)&cmd_set_vxlan_ip_dst,
+ (void *)&cmd_set_vxlan_ip_dst_value,
+ (void *)&cmd_set_vxlan_eth_src,
+ (void *)&cmd_set_vxlan_eth_src_value,
+ (void *)&cmd_set_vxlan_eth_dst,
+ (void *)&cmd_set_vxlan_eth_dst_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_vxlan_with_vlan = {
+ .f = cmd_set_vxlan_parsed,
+ .data = NULL,
+ .help_str = "set vxlan-with-vlan ip-version ipv4|ipv6 vni <vni>"
+ " udp-src <udp-src> udp-dst <udp-dst> ip-src <ip-src> ip-dst"
+ " <ip-dst> vlan-tci <vlan-tci> eth-src <eth-src> eth-dst"
+ " <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_vxlan_set,
+ (void *)&cmd_set_vxlan_vxlan_with_vlan,
+ (void *)&cmd_set_vxlan_ip_version,
+ (void *)&cmd_set_vxlan_ip_version_value,
+ (void *)&cmd_set_vxlan_vni,
+ (void *)&cmd_set_vxlan_vni_value,
+ (void *)&cmd_set_vxlan_udp_src,
+ (void *)&cmd_set_vxlan_udp_src_value,
+ (void *)&cmd_set_vxlan_udp_dst,
+ (void *)&cmd_set_vxlan_udp_dst_value,
+ (void *)&cmd_set_vxlan_ip_src,
+ (void *)&cmd_set_vxlan_ip_src_value,
+ (void *)&cmd_set_vxlan_ip_dst,
+ (void *)&cmd_set_vxlan_ip_dst_value,
+ (void *)&cmd_set_vxlan_vlan,
+ (void *)&cmd_set_vxlan_vlan_value,
+ (void *)&cmd_set_vxlan_eth_src,
+ (void *)&cmd_set_vxlan_eth_src_value,
+ (void *)&cmd_set_vxlan_eth_dst,
+ (void *)&cmd_set_vxlan_eth_dst_value,
+ NULL,
+ },
+};
+
+/** Set NVGRE encapsulation details */
+struct cmd_set_nvgre_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t nvgre;
+ cmdline_fixed_string_t pos_token;
+ cmdline_fixed_string_t ip_version;
+ uint32_t tni;
+ cmdline_ipaddr_t ip_src;
+ cmdline_ipaddr_t ip_dst;
+ uint16_t tci;
+ struct rte_ether_addr eth_src;
+ struct rte_ether_addr eth_dst;
+};
+
+cmdline_parse_token_string_t cmd_set_nvgre_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_nvgre_result, set, "set");
+cmdline_parse_token_string_t cmd_set_nvgre_nvgre =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_nvgre_result, nvgre, "nvgre");
+cmdline_parse_token_string_t cmd_set_nvgre_nvgre_with_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_nvgre_result, nvgre,
+ "nvgre-with-vlan");
+cmdline_parse_token_string_t cmd_set_nvgre_ip_version =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_nvgre_result, pos_token,
+ "ip-version");
+cmdline_parse_token_string_t cmd_set_nvgre_ip_version_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_nvgre_result, ip_version,
+ "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_set_nvgre_tni =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_nvgre_result, pos_token,
+ "tni");
+cmdline_parse_token_num_t cmd_set_nvgre_tni_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_nvgre_result, tni, UINT32);
+cmdline_parse_token_string_t cmd_set_nvgre_ip_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_nvgre_result, pos_token,
+ "ip-src");
+cmdline_parse_token_num_t cmd_set_nvgre_ip_src_value =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_set_nvgre_result, ip_src);
+cmdline_parse_token_string_t cmd_set_nvgre_ip_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_nvgre_result, pos_token,
+ "ip-dst");
+cmdline_parse_token_ipaddr_t cmd_set_nvgre_ip_dst_value =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_set_nvgre_result, ip_dst);
+cmdline_parse_token_string_t cmd_set_nvgre_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_nvgre_result, pos_token,
+ "vlan-tci");
+cmdline_parse_token_num_t cmd_set_nvgre_vlan_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_nvgre_result, tci, UINT16);
+cmdline_parse_token_string_t cmd_set_nvgre_eth_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_nvgre_result, pos_token,
+ "eth-src");
+cmdline_parse_token_etheraddr_t cmd_set_nvgre_eth_src_value =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_nvgre_result, eth_src);
+cmdline_parse_token_string_t cmd_set_nvgre_eth_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_nvgre_result, pos_token,
+ "eth-dst");
+cmdline_parse_token_etheraddr_t cmd_set_nvgre_eth_dst_value =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_nvgre_result, eth_dst);
+
+static void cmd_set_nvgre_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_nvgre_result *res = parsed_result;
+ union {
+ uint32_t nvgre_tni;
+ uint8_t tni[4];
+ } id = {
+ .nvgre_tni = rte_cpu_to_be_32(res->tni) & RTE_BE32(0x00ffffff),
+ };
+
+ if (strcmp(res->nvgre, "nvgre") == 0)
+ nvgre_encap_conf.select_vlan = 0;
+ else if (strcmp(res->nvgre, "nvgre-with-vlan") == 0)
+ nvgre_encap_conf.select_vlan = 1;
+ if (strcmp(res->ip_version, "ipv4") == 0)
+ nvgre_encap_conf.select_ipv4 = 1;
+ else if (strcmp(res->ip_version, "ipv6") == 0)
+ nvgre_encap_conf.select_ipv4 = 0;
+ else
+ return;
+ rte_memcpy(nvgre_encap_conf.tni, &id.tni[1], 3);
+ if (nvgre_encap_conf.select_ipv4) {
+ IPV4_ADDR_TO_UINT(res->ip_src, nvgre_encap_conf.ipv4_src);
+ IPV4_ADDR_TO_UINT(res->ip_dst, nvgre_encap_conf.ipv4_dst);
+ } else {
+ IPV6_ADDR_TO_ARRAY(res->ip_src, nvgre_encap_conf.ipv6_src);
+ IPV6_ADDR_TO_ARRAY(res->ip_dst, nvgre_encap_conf.ipv6_dst);
+ }
+ if (nvgre_encap_conf.select_vlan)
+ nvgre_encap_conf.vlan_tci = rte_cpu_to_be_16(res->tci);
+ rte_memcpy(nvgre_encap_conf.eth_src, res->eth_src.addr_bytes,
+ RTE_ETHER_ADDR_LEN);
+ rte_memcpy(nvgre_encap_conf.eth_dst, res->eth_dst.addr_bytes,
+ RTE_ETHER_ADDR_LEN);
+}
+
+cmdline_parse_inst_t cmd_set_nvgre = {
+ .f = cmd_set_nvgre_parsed,
+ .data = NULL,
+ .help_str = "set nvgre ip-version <ipv4|ipv6> tni <tni> ip-src"
+ " <ip-src> ip-dst <ip-dst> eth-src <eth-src>"
+ " eth-dst <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_nvgre_set,
+ (void *)&cmd_set_nvgre_nvgre,
+ (void *)&cmd_set_nvgre_ip_version,
+ (void *)&cmd_set_nvgre_ip_version_value,
+ (void *)&cmd_set_nvgre_tni,
+ (void *)&cmd_set_nvgre_tni_value,
+ (void *)&cmd_set_nvgre_ip_src,
+ (void *)&cmd_set_nvgre_ip_src_value,
+ (void *)&cmd_set_nvgre_ip_dst,
+ (void *)&cmd_set_nvgre_ip_dst_value,
+ (void *)&cmd_set_nvgre_eth_src,
+ (void *)&cmd_set_nvgre_eth_src_value,
+ (void *)&cmd_set_nvgre_eth_dst,
+ (void *)&cmd_set_nvgre_eth_dst_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_nvgre_with_vlan = {
+ .f = cmd_set_nvgre_parsed,
+ .data = NULL,
+ .help_str = "set nvgre-with-vlan ip-version <ipv4|ipv6> tni <tni>"
+ " ip-src <ip-src> ip-dst <ip-dst> vlan-tci <vlan-tci>"
+ " eth-src <eth-src> eth-dst <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_nvgre_set,
+ (void *)&cmd_set_nvgre_nvgre_with_vlan,
+ (void *)&cmd_set_nvgre_ip_version,
+ (void *)&cmd_set_nvgre_ip_version_value,
+ (void *)&cmd_set_nvgre_tni,
+ (void *)&cmd_set_nvgre_tni_value,
+ (void *)&cmd_set_nvgre_ip_src,
+ (void *)&cmd_set_nvgre_ip_src_value,
+ (void *)&cmd_set_nvgre_ip_dst,
+ (void *)&cmd_set_nvgre_ip_dst_value,
+ (void *)&cmd_set_nvgre_vlan,
+ (void *)&cmd_set_nvgre_vlan_value,
+ (void *)&cmd_set_nvgre_eth_src,
+ (void *)&cmd_set_nvgre_eth_src_value,
+ (void *)&cmd_set_nvgre_eth_dst,
+ (void *)&cmd_set_nvgre_eth_dst_value,
+ NULL,
+ },
+};
+
+/** Set L2 encapsulation details */
+struct cmd_set_l2_encap_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t l2_encap;
+ cmdline_fixed_string_t pos_token;
+ cmdline_fixed_string_t ip_version;
+ uint32_t vlan_present:1;
+ uint16_t tci;
+ struct rte_ether_addr eth_src;
+ struct rte_ether_addr eth_dst;
+};
+
+cmdline_parse_token_string_t cmd_set_l2_encap_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_l2_encap_result, set, "set");
+cmdline_parse_token_string_t cmd_set_l2_encap_l2_encap =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_l2_encap_result, l2_encap, "l2_encap");
+cmdline_parse_token_string_t cmd_set_l2_encap_l2_encap_with_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_l2_encap_result, l2_encap,
+ "l2_encap-with-vlan");
+cmdline_parse_token_string_t cmd_set_l2_encap_ip_version =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_l2_encap_result, pos_token,
+ "ip-version");
+cmdline_parse_token_string_t cmd_set_l2_encap_ip_version_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_l2_encap_result, ip_version,
+ "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_set_l2_encap_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_l2_encap_result, pos_token,
+ "vlan-tci");
+cmdline_parse_token_num_t cmd_set_l2_encap_vlan_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_l2_encap_result, tci, UINT16);
+cmdline_parse_token_string_t cmd_set_l2_encap_eth_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_l2_encap_result, pos_token,
+ "eth-src");
+cmdline_parse_token_etheraddr_t cmd_set_l2_encap_eth_src_value =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_l2_encap_result, eth_src);
+cmdline_parse_token_string_t cmd_set_l2_encap_eth_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_l2_encap_result, pos_token,
+ "eth-dst");
+cmdline_parse_token_etheraddr_t cmd_set_l2_encap_eth_dst_value =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_l2_encap_result, eth_dst);
+
+static void cmd_set_l2_encap_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_l2_encap_result *res = parsed_result;
+
+ if (strcmp(res->l2_encap, "l2_encap") == 0)
+ l2_encap_conf.select_vlan = 0;
+ else if (strcmp(res->l2_encap, "l2_encap-with-vlan") == 0)
+ l2_encap_conf.select_vlan = 1;
+ if (strcmp(res->ip_version, "ipv4") == 0)
+ l2_encap_conf.select_ipv4 = 1;
+ else if (strcmp(res->ip_version, "ipv6") == 0)
+ l2_encap_conf.select_ipv4 = 0;
+ else
+ return;
+ if (l2_encap_conf.select_vlan)
+ l2_encap_conf.vlan_tci = rte_cpu_to_be_16(res->tci);
+ rte_memcpy(l2_encap_conf.eth_src, res->eth_src.addr_bytes,
+ RTE_ETHER_ADDR_LEN);
+ rte_memcpy(l2_encap_conf.eth_dst, res->eth_dst.addr_bytes,
+ RTE_ETHER_ADDR_LEN);
+}
+
+cmdline_parse_inst_t cmd_set_l2_encap = {
+ .f = cmd_set_l2_encap_parsed,
+ .data = NULL,
+ .help_str = "set l2_encap ip-version ipv4|ipv6"
+ " eth-src <eth-src> eth-dst <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_l2_encap_set,
+ (void *)&cmd_set_l2_encap_l2_encap,
+ (void *)&cmd_set_l2_encap_ip_version,
+ (void *)&cmd_set_l2_encap_ip_version_value,
+ (void *)&cmd_set_l2_encap_eth_src,
+ (void *)&cmd_set_l2_encap_eth_src_value,
+ (void *)&cmd_set_l2_encap_eth_dst,
+ (void *)&cmd_set_l2_encap_eth_dst_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_l2_encap_with_vlan = {
+ .f = cmd_set_l2_encap_parsed,
+ .data = NULL,
+ .help_str = "set l2_encap-with-vlan ip-version ipv4|ipv6"
+ " vlan-tci <vlan-tci> eth-src <eth-src> eth-dst <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_l2_encap_set,
+ (void *)&cmd_set_l2_encap_l2_encap_with_vlan,
+ (void *)&cmd_set_l2_encap_ip_version,
+ (void *)&cmd_set_l2_encap_ip_version_value,
+ (void *)&cmd_set_l2_encap_vlan,
+ (void *)&cmd_set_l2_encap_vlan_value,
+ (void *)&cmd_set_l2_encap_eth_src,
+ (void *)&cmd_set_l2_encap_eth_src_value,
+ (void *)&cmd_set_l2_encap_eth_dst,
+ (void *)&cmd_set_l2_encap_eth_dst_value,
+ NULL,
+ },
+};
+
+/** Set L2 decapsulation details */
+struct cmd_set_l2_decap_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t l2_decap;
+ cmdline_fixed_string_t pos_token;
+ uint32_t vlan_present:1;
+};
+
+cmdline_parse_token_string_t cmd_set_l2_decap_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_l2_decap_result, set, "set");
+cmdline_parse_token_string_t cmd_set_l2_decap_l2_decap =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_l2_decap_result, l2_decap,
+ "l2_decap");
+cmdline_parse_token_string_t cmd_set_l2_decap_l2_decap_with_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_l2_decap_result, l2_decap,
+ "l2_decap-with-vlan");
+
+static void cmd_set_l2_decap_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_l2_decap_result *res = parsed_result;
+
+ if (strcmp(res->l2_decap, "l2_decap") == 0)
+ l2_decap_conf.select_vlan = 0;
+ else if (strcmp(res->l2_decap, "l2_decap-with-vlan") == 0)
+ l2_decap_conf.select_vlan = 1;
+}
+
+cmdline_parse_inst_t cmd_set_l2_decap = {
+ .f = cmd_set_l2_decap_parsed,
+ .data = NULL,
+ .help_str = "set l2_decap",
+ .tokens = {
+ (void *)&cmd_set_l2_decap_set,
+ (void *)&cmd_set_l2_decap_l2_decap,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_l2_decap_with_vlan = {
+ .f = cmd_set_l2_decap_parsed,
+ .data = NULL,
+ .help_str = "set l2_decap-with-vlan",
+ .tokens = {
+ (void *)&cmd_set_l2_decap_set,
+ (void *)&cmd_set_l2_decap_l2_decap_with_vlan,
+ NULL,
+ },
+};
+
+/** Set MPLSoGRE encapsulation details */
+struct cmd_set_mplsogre_encap_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t mplsogre;
+ cmdline_fixed_string_t pos_token;
+ cmdline_fixed_string_t ip_version;
+ uint32_t vlan_present:1;
+ uint32_t label;
+ cmdline_ipaddr_t ip_src;
+ cmdline_ipaddr_t ip_dst;
+ uint16_t tci;
+ struct rte_ether_addr eth_src;
+ struct rte_ether_addr eth_dst;
+};
+
+cmdline_parse_token_string_t cmd_set_mplsogre_encap_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_encap_result, set,
+ "set");
+cmdline_parse_token_string_t cmd_set_mplsogre_encap_mplsogre_encap =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_encap_result, mplsogre,
+ "mplsogre_encap");
+cmdline_parse_token_string_t cmd_set_mplsogre_encap_mplsogre_encap_with_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_encap_result,
+ mplsogre, "mplsogre_encap-with-vlan");
+cmdline_parse_token_string_t cmd_set_mplsogre_encap_ip_version =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_encap_result,
+ pos_token, "ip-version");
+cmdline_parse_token_string_t cmd_set_mplsogre_encap_ip_version_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_encap_result,
+ ip_version, "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_set_mplsogre_encap_label =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_encap_result,
+ pos_token, "label");
+cmdline_parse_token_num_t cmd_set_mplsogre_encap_label_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mplsogre_encap_result, label,
+ UINT32);
+cmdline_parse_token_string_t cmd_set_mplsogre_encap_ip_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_encap_result,
+ pos_token, "ip-src");
+cmdline_parse_token_ipaddr_t cmd_set_mplsogre_encap_ip_src_value =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_set_mplsogre_encap_result, ip_src);
+cmdline_parse_token_string_t cmd_set_mplsogre_encap_ip_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_encap_result,
+ pos_token, "ip-dst");
+cmdline_parse_token_ipaddr_t cmd_set_mplsogre_encap_ip_dst_value =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_set_mplsogre_encap_result, ip_dst);
+cmdline_parse_token_string_t cmd_set_mplsogre_encap_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_encap_result,
+ pos_token, "vlan-tci");
+cmdline_parse_token_num_t cmd_set_mplsogre_encap_vlan_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mplsogre_encap_result, tci,
+ UINT16);
+cmdline_parse_token_string_t cmd_set_mplsogre_encap_eth_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_encap_result,
+ pos_token, "eth-src");
+cmdline_parse_token_etheraddr_t cmd_set_mplsogre_encap_eth_src_value =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_mplsogre_encap_result,
+ eth_src);
+cmdline_parse_token_string_t cmd_set_mplsogre_encap_eth_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_encap_result,
+ pos_token, "eth-dst");
+cmdline_parse_token_etheraddr_t cmd_set_mplsogre_encap_eth_dst_value =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_mplsogre_encap_result,
+ eth_dst);
+
+static void cmd_set_mplsogre_encap_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_mplsogre_encap_result *res = parsed_result;
+ union {
+ uint32_t mplsogre_label;
+ uint8_t label[4];
+ } id = {
+ .mplsogre_label = rte_cpu_to_be_32(res->label<<12),
+ };
+
+ if (strcmp(res->mplsogre, "mplsogre_encap") == 0)
+ mplsogre_encap_conf.select_vlan = 0;
+ else if (strcmp(res->mplsogre, "mplsogre_encap-with-vlan") == 0)
+ mplsogre_encap_conf.select_vlan = 1;
+ if (strcmp(res->ip_version, "ipv4") == 0)
+ mplsogre_encap_conf.select_ipv4 = 1;
+ else if (strcmp(res->ip_version, "ipv6") == 0)
+ mplsogre_encap_conf.select_ipv4 = 0;
+ else
+ return;
+ rte_memcpy(mplsogre_encap_conf.label, &id.label, 3);
+ if (mplsogre_encap_conf.select_ipv4) {
+ IPV4_ADDR_TO_UINT(res->ip_src, mplsogre_encap_conf.ipv4_src);
+ IPV4_ADDR_TO_UINT(res->ip_dst, mplsogre_encap_conf.ipv4_dst);
+ } else {
+ IPV6_ADDR_TO_ARRAY(res->ip_src, mplsogre_encap_conf.ipv6_src);
+ IPV6_ADDR_TO_ARRAY(res->ip_dst, mplsogre_encap_conf.ipv6_dst);
+ }
+ if (mplsogre_encap_conf.select_vlan)
+ mplsogre_encap_conf.vlan_tci = rte_cpu_to_be_16(res->tci);
+ rte_memcpy(mplsogre_encap_conf.eth_src, res->eth_src.addr_bytes,
+ RTE_ETHER_ADDR_LEN);
+ rte_memcpy(mplsogre_encap_conf.eth_dst, res->eth_dst.addr_bytes,
+ RTE_ETHER_ADDR_LEN);
+}
+
+cmdline_parse_inst_t cmd_set_mplsogre_encap = {
+ .f = cmd_set_mplsogre_encap_parsed,
+ .data = NULL,
+ .help_str = "set mplsogre_encap ip-version ipv4|ipv6 label <label>"
+ " ip-src <ip-src> ip-dst <ip-dst> eth-src <eth-src>"
+ " eth-dst <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_mplsogre_encap_set,
+ (void *)&cmd_set_mplsogre_encap_mplsogre_encap,
+ (void *)&cmd_set_mplsogre_encap_ip_version,
+ (void *)&cmd_set_mplsogre_encap_ip_version_value,
+ (void *)&cmd_set_mplsogre_encap_label,
+ (void *)&cmd_set_mplsogre_encap_label_value,
+ (void *)&cmd_set_mplsogre_encap_ip_src,
+ (void *)&cmd_set_mplsogre_encap_ip_src_value,
+ (void *)&cmd_set_mplsogre_encap_ip_dst,
+ (void *)&cmd_set_mplsogre_encap_ip_dst_value,
+ (void *)&cmd_set_mplsogre_encap_eth_src,
+ (void *)&cmd_set_mplsogre_encap_eth_src_value,
+ (void *)&cmd_set_mplsogre_encap_eth_dst,
+ (void *)&cmd_set_mplsogre_encap_eth_dst_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_mplsogre_encap_with_vlan = {
+ .f = cmd_set_mplsogre_encap_parsed,
+ .data = NULL,
+ .help_str = "set mplsogre_encap-with-vlan ip-version ipv4|ipv6"
+ " label <label> ip-src <ip-src> ip-dst <ip-dst>"
+ " vlan-tci <vlan-tci> eth-src <eth-src> eth-dst <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_mplsogre_encap_set,
+ (void *)&cmd_set_mplsogre_encap_mplsogre_encap_with_vlan,
+ (void *)&cmd_set_mplsogre_encap_ip_version,
+ (void *)&cmd_set_mplsogre_encap_ip_version_value,
+ (void *)&cmd_set_mplsogre_encap_label,
+ (void *)&cmd_set_mplsogre_encap_label_value,
+ (void *)&cmd_set_mplsogre_encap_ip_src,
+ (void *)&cmd_set_mplsogre_encap_ip_src_value,
+ (void *)&cmd_set_mplsogre_encap_ip_dst,
+ (void *)&cmd_set_mplsogre_encap_ip_dst_value,
+ (void *)&cmd_set_mplsogre_encap_vlan,
+ (void *)&cmd_set_mplsogre_encap_vlan_value,
+ (void *)&cmd_set_mplsogre_encap_eth_src,
+ (void *)&cmd_set_mplsogre_encap_eth_src_value,
+ (void *)&cmd_set_mplsogre_encap_eth_dst,
+ (void *)&cmd_set_mplsogre_encap_eth_dst_value,
+ NULL,
+ },
+};
+
+/** Set MPLSoGRE decapsulation details */
+struct cmd_set_mplsogre_decap_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t mplsogre;
+ cmdline_fixed_string_t pos_token;
+ cmdline_fixed_string_t ip_version;
+ uint32_t vlan_present:1;
+};
+
+cmdline_parse_token_string_t cmd_set_mplsogre_decap_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_decap_result, set,
+ "set");
+cmdline_parse_token_string_t cmd_set_mplsogre_decap_mplsogre_decap =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_decap_result, mplsogre,
+ "mplsogre_decap");
+cmdline_parse_token_string_t cmd_set_mplsogre_decap_mplsogre_decap_with_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_decap_result,
+ mplsogre, "mplsogre_decap-with-vlan");
+cmdline_parse_token_string_t cmd_set_mplsogre_decap_ip_version =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_decap_result,
+ pos_token, "ip-version");
+cmdline_parse_token_string_t cmd_set_mplsogre_decap_ip_version_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_decap_result,
+ ip_version, "ipv4#ipv6");
+
+static void cmd_set_mplsogre_decap_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_mplsogre_decap_result *res = parsed_result;
+
+ if (strcmp(res->mplsogre, "mplsogre_decap") == 0)
+ mplsogre_decap_conf.select_vlan = 0;
+ else if (strcmp(res->mplsogre, "mplsogre_decap-with-vlan") == 0)
+ mplsogre_decap_conf.select_vlan = 1;
+ if (strcmp(res->ip_version, "ipv4") == 0)
+ mplsogre_decap_conf.select_ipv4 = 1;
+ else if (strcmp(res->ip_version, "ipv6") == 0)
+ mplsogre_decap_conf.select_ipv4 = 0;
+}
+
+cmdline_parse_inst_t cmd_set_mplsogre_decap = {
+ .f = cmd_set_mplsogre_decap_parsed,
+ .data = NULL,
+ .help_str = "set mplsogre_decap ip-version ipv4|ipv6",
+ .tokens = {
+ (void *)&cmd_set_mplsogre_decap_set,
+ (void *)&cmd_set_mplsogre_decap_mplsogre_decap,
+ (void *)&cmd_set_mplsogre_decap_ip_version,
+ (void *)&cmd_set_mplsogre_decap_ip_version_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_mplsogre_decap_with_vlan = {
+ .f = cmd_set_mplsogre_decap_parsed,
+ .data = NULL,
+ .help_str = "set mplsogre_decap-with-vlan ip-version ipv4|ipv6",
+ .tokens = {
+ (void *)&cmd_set_mplsogre_decap_set,
+ (void *)&cmd_set_mplsogre_decap_mplsogre_decap_with_vlan,
+ (void *)&cmd_set_mplsogre_decap_ip_version,
+ (void *)&cmd_set_mplsogre_decap_ip_version_value,
+ NULL,
+ },
+};
+
+/** Set MPLSoUDP encapsulation details */
+struct cmd_set_mplsoudp_encap_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t mplsoudp;
+ cmdline_fixed_string_t pos_token;
+ cmdline_fixed_string_t ip_version;
+ uint32_t vlan_present:1;
+ uint32_t label;
+ uint16_t udp_src;
+ uint16_t udp_dst;
+ cmdline_ipaddr_t ip_src;
+ cmdline_ipaddr_t ip_dst;
+ uint16_t tci;
+ struct rte_ether_addr eth_src;
+ struct rte_ether_addr eth_dst;
+};
+
+cmdline_parse_token_string_t cmd_set_mplsoudp_encap_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_encap_result, set,
+ "set");
+cmdline_parse_token_string_t cmd_set_mplsoudp_encap_mplsoudp_encap =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_encap_result, mplsoudp,
+ "mplsoudp_encap");
+cmdline_parse_token_string_t cmd_set_mplsoudp_encap_mplsoudp_encap_with_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_encap_result,
+ mplsoudp, "mplsoudp_encap-with-vlan");
+cmdline_parse_token_string_t cmd_set_mplsoudp_encap_ip_version =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_encap_result,
+ pos_token, "ip-version");
+cmdline_parse_token_string_t cmd_set_mplsoudp_encap_ip_version_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_encap_result,
+ ip_version, "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_set_mplsoudp_encap_label =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_encap_result,
+ pos_token, "label");
+cmdline_parse_token_num_t cmd_set_mplsoudp_encap_label_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_encap_result, label,
+ UINT32);
+cmdline_parse_token_string_t cmd_set_mplsoudp_encap_udp_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_encap_result,
+ pos_token, "udp-src");
+cmdline_parse_token_num_t cmd_set_mplsoudp_encap_udp_src_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_encap_result, udp_src,
+ UINT16);
+cmdline_parse_token_string_t cmd_set_mplsoudp_encap_udp_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_encap_result,
+ pos_token, "udp-dst");
+cmdline_parse_token_num_t cmd_set_mplsoudp_encap_udp_dst_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_encap_result, udp_dst,
+ UINT16);
+cmdline_parse_token_string_t cmd_set_mplsoudp_encap_ip_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_encap_result,
+ pos_token, "ip-src");
+cmdline_parse_token_ipaddr_t cmd_set_mplsoudp_encap_ip_src_value =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_set_mplsoudp_encap_result, ip_src);
+cmdline_parse_token_string_t cmd_set_mplsoudp_encap_ip_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_encap_result,
+ pos_token, "ip-dst");
+cmdline_parse_token_ipaddr_t cmd_set_mplsoudp_encap_ip_dst_value =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_set_mplsoudp_encap_result, ip_dst);
+cmdline_parse_token_string_t cmd_set_mplsoudp_encap_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_encap_result,
+ pos_token, "vlan-tci");
+cmdline_parse_token_num_t cmd_set_mplsoudp_encap_vlan_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_encap_result, tci,
+ UINT16);
+cmdline_parse_token_string_t cmd_set_mplsoudp_encap_eth_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_encap_result,
+ pos_token, "eth-src");
+cmdline_parse_token_etheraddr_t cmd_set_mplsoudp_encap_eth_src_value =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_mplsoudp_encap_result,
+ eth_src);
+cmdline_parse_token_string_t cmd_set_mplsoudp_encap_eth_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_encap_result,
+ pos_token, "eth-dst");
+cmdline_parse_token_etheraddr_t cmd_set_mplsoudp_encap_eth_dst_value =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_mplsoudp_encap_result,
+ eth_dst);
+
+static void cmd_set_mplsoudp_encap_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_mplsoudp_encap_result *res = parsed_result;
+ union {
+ uint32_t mplsoudp_label;
+ uint8_t label[4];
+ } id = {
+ .mplsoudp_label = rte_cpu_to_be_32(res->label<<12),
+ };
+
+ if (strcmp(res->mplsoudp, "mplsoudp_encap") == 0)
+ mplsoudp_encap_conf.select_vlan = 0;
+ else if (strcmp(res->mplsoudp, "mplsoudp_encap-with-vlan") == 0)
+ mplsoudp_encap_conf.select_vlan = 1;
+ if (strcmp(res->ip_version, "ipv4") == 0)
+ mplsoudp_encap_conf.select_ipv4 = 1;
+ else if (strcmp(res->ip_version, "ipv6") == 0)
+ mplsoudp_encap_conf.select_ipv4 = 0;
+ else
+ return;
+ rte_memcpy(mplsoudp_encap_conf.label, &id.label, 3);
+ mplsoudp_encap_conf.udp_src = rte_cpu_to_be_16(res->udp_src);
+ mplsoudp_encap_conf.udp_dst = rte_cpu_to_be_16(res->udp_dst);
+ if (mplsoudp_encap_conf.select_ipv4) {
+ IPV4_ADDR_TO_UINT(res->ip_src, mplsoudp_encap_conf.ipv4_src);
+ IPV4_ADDR_TO_UINT(res->ip_dst, mplsoudp_encap_conf.ipv4_dst);
+ } else {
+ IPV6_ADDR_TO_ARRAY(res->ip_src, mplsoudp_encap_conf.ipv6_src);
+ IPV6_ADDR_TO_ARRAY(res->ip_dst, mplsoudp_encap_conf.ipv6_dst);
+ }
+ if (mplsoudp_encap_conf.select_vlan)
+ mplsoudp_encap_conf.vlan_tci = rte_cpu_to_be_16(res->tci);
+ rte_memcpy(mplsoudp_encap_conf.eth_src, res->eth_src.addr_bytes,
+ RTE_ETHER_ADDR_LEN);
+ rte_memcpy(mplsoudp_encap_conf.eth_dst, res->eth_dst.addr_bytes,
+ RTE_ETHER_ADDR_LEN);
+}
+
+cmdline_parse_inst_t cmd_set_mplsoudp_encap = {
+ .f = cmd_set_mplsoudp_encap_parsed,
+ .data = NULL,
+ .help_str = "set mplsoudp_encap ip-version ipv4|ipv6 label <label>"
+ " udp-src <udp-src> udp-dst <udp-dst> ip-src <ip-src>"
+ " ip-dst <ip-dst> eth-src <eth-src> eth-dst <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_mplsoudp_encap_set,
+ (void *)&cmd_set_mplsoudp_encap_mplsoudp_encap,
+ (void *)&cmd_set_mplsoudp_encap_ip_version,
+ (void *)&cmd_set_mplsoudp_encap_ip_version_value,
+ (void *)&cmd_set_mplsoudp_encap_label,
+ (void *)&cmd_set_mplsoudp_encap_label_value,
+ (void *)&cmd_set_mplsoudp_encap_udp_src,
+ (void *)&cmd_set_mplsoudp_encap_udp_src_value,
+ (void *)&cmd_set_mplsoudp_encap_udp_dst,
+ (void *)&cmd_set_mplsoudp_encap_udp_dst_value,
+ (void *)&cmd_set_mplsoudp_encap_ip_src,
+ (void *)&cmd_set_mplsoudp_encap_ip_src_value,
+ (void *)&cmd_set_mplsoudp_encap_ip_dst,
+ (void *)&cmd_set_mplsoudp_encap_ip_dst_value,
+ (void *)&cmd_set_mplsoudp_encap_eth_src,
+ (void *)&cmd_set_mplsoudp_encap_eth_src_value,
+ (void *)&cmd_set_mplsoudp_encap_eth_dst,
+ (void *)&cmd_set_mplsoudp_encap_eth_dst_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_mplsoudp_encap_with_vlan = {
+ .f = cmd_set_mplsoudp_encap_parsed,
+ .data = NULL,
+ .help_str = "set mplsoudp_encap-with-vlan ip-version ipv4|ipv6"
+ " label <label> udp-src <udp-src> udp-dst <udp-dst>"
+ " ip-src <ip-src> ip-dst <ip-dst> vlan-tci <vlan-tci>"
+ " eth-src <eth-src> eth-dst <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_mplsoudp_encap_set,
+ (void *)&cmd_set_mplsoudp_encap_mplsoudp_encap_with_vlan,
+ (void *)&cmd_set_mplsoudp_encap_ip_version,
+ (void *)&cmd_set_mplsoudp_encap_ip_version_value,
+ (void *)&cmd_set_mplsoudp_encap_label,
+ (void *)&cmd_set_mplsoudp_encap_label_value,
+ (void *)&cmd_set_mplsoudp_encap_udp_src,
+ (void *)&cmd_set_mplsoudp_encap_udp_src_value,
+ (void *)&cmd_set_mplsoudp_encap_udp_dst,
+ (void *)&cmd_set_mplsoudp_encap_udp_dst_value,
+ (void *)&cmd_set_mplsoudp_encap_ip_src,
+ (void *)&cmd_set_mplsoudp_encap_ip_src_value,
+ (void *)&cmd_set_mplsoudp_encap_ip_dst,
+ (void *)&cmd_set_mplsoudp_encap_ip_dst_value,
+ (void *)&cmd_set_mplsoudp_encap_vlan,
+ (void *)&cmd_set_mplsoudp_encap_vlan_value,
+ (void *)&cmd_set_mplsoudp_encap_eth_src,
+ (void *)&cmd_set_mplsoudp_encap_eth_src_value,
+ (void *)&cmd_set_mplsoudp_encap_eth_dst,
+ (void *)&cmd_set_mplsoudp_encap_eth_dst_value,
+ NULL,
+ },
+};
+
+/** Set MPLSoUDP decapsulation details */
+struct cmd_set_mplsoudp_decap_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t mplsoudp;
+ cmdline_fixed_string_t pos_token;
+ cmdline_fixed_string_t ip_version;
+ uint32_t vlan_present:1;
+};
+
+cmdline_parse_token_string_t cmd_set_mplsoudp_decap_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_decap_result, set,
+ "set");
+cmdline_parse_token_string_t cmd_set_mplsoudp_decap_mplsoudp_decap =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_decap_result, mplsoudp,
+ "mplsoudp_decap");
+cmdline_parse_token_string_t cmd_set_mplsoudp_decap_mplsoudp_decap_with_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_decap_result,
+ mplsoudp, "mplsoudp_decap-with-vlan");
+cmdline_parse_token_string_t cmd_set_mplsoudp_decap_ip_version =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_decap_result,
+ pos_token, "ip-version");
+cmdline_parse_token_string_t cmd_set_mplsoudp_decap_ip_version_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_decap_result,
+ ip_version, "ipv4#ipv6");
+
+static void cmd_set_mplsoudp_decap_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_mplsoudp_decap_result *res = parsed_result;
+
+ if (strcmp(res->mplsoudp, "mplsoudp_decap") == 0)
+ mplsoudp_decap_conf.select_vlan = 0;
+ else if (strcmp(res->mplsoudp, "mplsoudp_decap-with-vlan") == 0)
+ mplsoudp_decap_conf.select_vlan = 1;
+ if (strcmp(res->ip_version, "ipv4") == 0)
+ mplsoudp_decap_conf.select_ipv4 = 1;
+ else if (strcmp(res->ip_version, "ipv6") == 0)
+ mplsoudp_decap_conf.select_ipv4 = 0;
+}
+
+cmdline_parse_inst_t cmd_set_mplsoudp_decap = {
+ .f = cmd_set_mplsoudp_decap_parsed,
+ .data = NULL,
+ .help_str = "set mplsoudp_decap ip-version ipv4|ipv6",
+ .tokens = {
+ (void *)&cmd_set_mplsoudp_decap_set,
+ (void *)&cmd_set_mplsoudp_decap_mplsoudp_decap,
+ (void *)&cmd_set_mplsoudp_decap_ip_version,
+ (void *)&cmd_set_mplsoudp_decap_ip_version_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_mplsoudp_decap_with_vlan = {
+ .f = cmd_set_mplsoudp_decap_parsed,
+ .data = NULL,
+ .help_str = "set mplsoudp_decap-with-vlan ip-version ipv4|ipv6",
+ .tokens = {
+ (void *)&cmd_set_mplsoudp_decap_set,
+ (void *)&cmd_set_mplsoudp_decap_mplsoudp_decap_with_vlan,
+ (void *)&cmd_set_mplsoudp_decap_ip_version,
+ (void *)&cmd_set_mplsoudp_decap_ip_version_value,
+ NULL,
+ },
+};
+
+/* Strict link priority scheduling mode setting */
+static void
+cmd_strict_link_prio_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_vf_tc_bw_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ ret = rte_pmd_i40e_set_tc_strict_prio(res->port_id, res->tc_map);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid tc_bitmap 0x%x\n", res->tc_map);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_strict_link_prio = {
+ .f = cmd_strict_link_prio_parsed,
+ .data = NULL,
+ .help_str = "set tx strict-link-priority <port_id> <tc_bitmap>",
+ .tokens = {
+ (void *)&cmd_vf_tc_bw_set,
+ (void *)&cmd_vf_tc_bw_tx,
+ (void *)&cmd_vf_tc_bw_strict_link_prio,
+ (void *)&cmd_vf_tc_bw_port_id,
+ (void *)&cmd_vf_tc_bw_tc_map,
+ NULL,
+ },
+};
+
+/* Load dynamic device personalization*/
+struct cmd_ddp_add_result {
+ cmdline_fixed_string_t ddp;
+ cmdline_fixed_string_t add;
+ portid_t port_id;
+ char filepath[];
+};
+
+cmdline_parse_token_string_t cmd_ddp_add_ddp =
+ TOKEN_STRING_INITIALIZER(struct cmd_ddp_add_result, ddp, "ddp");
+cmdline_parse_token_string_t cmd_ddp_add_add =
+ TOKEN_STRING_INITIALIZER(struct cmd_ddp_add_result, add, "add");
+cmdline_parse_token_num_t cmd_ddp_add_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_ddp_add_result, port_id, UINT16);
+cmdline_parse_token_string_t cmd_ddp_add_filepath =
+ TOKEN_STRING_INITIALIZER(struct cmd_ddp_add_result, filepath, NULL);
+
+static void
+cmd_ddp_add_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_ddp_add_result *res = parsed_result;
+ uint8_t *buff;
+ uint32_t size;
+ char *filepath;
+ char *file_fld[2];
+ int file_num;
+ int ret = -ENOTSUP;
+
+ if (!all_ports_stopped()) {
+ printf("Please stop all ports first\n");
+ return;
+ }
+
+ filepath = strdup(res->filepath);
+ if (filepath == NULL) {
+ printf("Failed to allocate memory\n");
+ return;
+ }
+ file_num = rte_strsplit(filepath, strlen(filepath), file_fld, 2, ',');
+
+ buff = open_file(file_fld[0], &size);
+ if (!buff) {
+ free((void *)filepath);
+ return;
+ }
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_i40e_process_ddp_package(res->port_id,
+ buff, size,
+ RTE_PMD_I40E_PKG_OP_WR_ADD);
+#endif
+
+ if (ret == -EEXIST)
+ printf("Profile has already existed.\n");
+ else if (ret < 0)
+ printf("Failed to load profile.\n");
+ else if (file_num == 2)
+ save_file(file_fld[1], buff, size);
+
+ close_file(buff);
+ free((void *)filepath);
+}
+
+cmdline_parse_inst_t cmd_ddp_add = {
+ .f = cmd_ddp_add_parsed,
+ .data = NULL,
+ .help_str = "ddp add <port_id> <profile_path[,backup_profile_path]>",
+ .tokens = {
+ (void *)&cmd_ddp_add_ddp,
+ (void *)&cmd_ddp_add_add,
+ (void *)&cmd_ddp_add_port_id,
+ (void *)&cmd_ddp_add_filepath,
+ NULL,
+ },
+};
+
+/* Delete dynamic device personalization*/
+struct cmd_ddp_del_result {
+ cmdline_fixed_string_t ddp;
+ cmdline_fixed_string_t del;
+ portid_t port_id;
+ char filepath[];
+};
+
+cmdline_parse_token_string_t cmd_ddp_del_ddp =
+ TOKEN_STRING_INITIALIZER(struct cmd_ddp_del_result, ddp, "ddp");
+cmdline_parse_token_string_t cmd_ddp_del_del =
+ TOKEN_STRING_INITIALIZER(struct cmd_ddp_del_result, del, "del");
+cmdline_parse_token_num_t cmd_ddp_del_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_ddp_del_result, port_id, UINT16);
+cmdline_parse_token_string_t cmd_ddp_del_filepath =
+ TOKEN_STRING_INITIALIZER(struct cmd_ddp_del_result, filepath, NULL);
+
+static void
+cmd_ddp_del_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_ddp_del_result *res = parsed_result;
+ uint8_t *buff;
+ uint32_t size;
+ int ret = -ENOTSUP;
+
+ if (!all_ports_stopped()) {
+ printf("Please stop all ports first\n");
+ return;
+ }
+
+ buff = open_file(res->filepath, &size);
+ if (!buff)
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_i40e_process_ddp_package(res->port_id,
+ buff, size,
+ RTE_PMD_I40E_PKG_OP_WR_DEL);
+#endif
+
+ if (ret == -EACCES)
+ printf("Profile does not exist.\n");
+ else if (ret < 0)
+ printf("Failed to delete profile.\n");
+
+ close_file(buff);
+}
+
+cmdline_parse_inst_t cmd_ddp_del = {
+ .f = cmd_ddp_del_parsed,
+ .data = NULL,
+ .help_str = "ddp del <port_id> <backup_profile_path>",
+ .tokens = {
+ (void *)&cmd_ddp_del_ddp,
+ (void *)&cmd_ddp_del_del,
+ (void *)&cmd_ddp_del_port_id,
+ (void *)&cmd_ddp_del_filepath,
+ NULL,
+ },
+};
+
+/* Get dynamic device personalization profile info */
+struct cmd_ddp_info_result {
+ cmdline_fixed_string_t ddp;
+ cmdline_fixed_string_t get;
+ cmdline_fixed_string_t info;
+ char filepath[];
+};
+
+cmdline_parse_token_string_t cmd_ddp_info_ddp =
+ TOKEN_STRING_INITIALIZER(struct cmd_ddp_info_result, ddp, "ddp");
+cmdline_parse_token_string_t cmd_ddp_info_get =
+ TOKEN_STRING_INITIALIZER(struct cmd_ddp_info_result, get, "get");
+cmdline_parse_token_string_t cmd_ddp_info_info =
+ TOKEN_STRING_INITIALIZER(struct cmd_ddp_info_result, info, "info");
+cmdline_parse_token_string_t cmd_ddp_info_filepath =
+ TOKEN_STRING_INITIALIZER(struct cmd_ddp_info_result, filepath, NULL);
+
+static void
+cmd_ddp_info_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_ddp_info_result *res = parsed_result;
+ uint8_t *pkg;
+ uint32_t pkg_size;
+ int ret = -ENOTSUP;
+#ifdef RTE_LIBRTE_I40E_PMD
+ uint32_t i, j, n;
+ uint8_t *buff;
+ uint32_t buff_size = 0;
+ struct rte_pmd_i40e_profile_info info;
+ uint32_t dev_num = 0;
+ struct rte_pmd_i40e_ddp_device_id *devs;
+ uint32_t proto_num = 0;
+ struct rte_pmd_i40e_proto_info *proto = NULL;
+ uint32_t pctype_num = 0;
+ struct rte_pmd_i40e_ptype_info *pctype;
+ uint32_t ptype_num = 0;
+ struct rte_pmd_i40e_ptype_info *ptype;
+ uint8_t proto_id;
+
+#endif
+
+ pkg = open_file(res->filepath, &pkg_size);
+ if (!pkg)
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+ (uint8_t *)&info, sizeof(info),
+ RTE_PMD_I40E_PKG_INFO_GLOBAL_HEADER);
+ if (!ret) {
+ printf("Global Track id: 0x%x\n", info.track_id);
+ printf("Global Version: %d.%d.%d.%d\n",
+ info.version.major,
+ info.version.minor,
+ info.version.update,
+ info.version.draft);
+ printf("Global Package name: %s\n\n", info.name);
+ }
+
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+ (uint8_t *)&info, sizeof(info),
+ RTE_PMD_I40E_PKG_INFO_HEADER);
+ if (!ret) {
+ printf("i40e Profile Track id: 0x%x\n", info.track_id);
+ printf("i40e Profile Version: %d.%d.%d.%d\n",
+ info.version.major,
+ info.version.minor,
+ info.version.update,
+ info.version.draft);
+ printf("i40e Profile name: %s\n\n", info.name);
+ }
+
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+ (uint8_t *)&buff_size, sizeof(buff_size),
+ RTE_PMD_I40E_PKG_INFO_GLOBAL_NOTES_SIZE);
+ if (!ret && buff_size) {
+ buff = (uint8_t *)malloc(buff_size);
+ if (buff) {
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+ buff, buff_size,
+ RTE_PMD_I40E_PKG_INFO_GLOBAL_NOTES);
+ if (!ret)
+ printf("Package Notes:\n%s\n\n", buff);
+ free(buff);
+ }
+ }
+
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+ (uint8_t *)&dev_num, sizeof(dev_num),
+ RTE_PMD_I40E_PKG_INFO_DEVID_NUM);
+ if (!ret && dev_num) {
+ buff_size = dev_num * sizeof(struct rte_pmd_i40e_ddp_device_id);
+ devs = (struct rte_pmd_i40e_ddp_device_id *)malloc(buff_size);
+ if (devs) {
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+ (uint8_t *)devs, buff_size,
+ RTE_PMD_I40E_PKG_INFO_DEVID_LIST);
+ if (!ret) {
+ printf("List of supported devices:\n");
+ for (i = 0; i < dev_num; i++) {
+ printf(" %04X:%04X %04X:%04X\n",
+ devs[i].vendor_dev_id >> 16,
+ devs[i].vendor_dev_id & 0xFFFF,
+ devs[i].sub_vendor_dev_id >> 16,
+ devs[i].sub_vendor_dev_id & 0xFFFF);
+ }
+ printf("\n");
+ }
+ free(devs);
+ }
+ }
+
+ /* get information about protocols and packet types */
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+ (uint8_t *)&proto_num, sizeof(proto_num),
+ RTE_PMD_I40E_PKG_INFO_PROTOCOL_NUM);
+ if (ret || !proto_num)
+ goto no_print_return;
+
+ buff_size = proto_num * sizeof(struct rte_pmd_i40e_proto_info);
+ proto = (struct rte_pmd_i40e_proto_info *)malloc(buff_size);
+ if (!proto)
+ goto no_print_return;
+
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size, (uint8_t *)proto,
+ buff_size,
+ RTE_PMD_I40E_PKG_INFO_PROTOCOL_LIST);
+ if (!ret) {
+ printf("List of used protocols:\n");
+ for (i = 0; i < proto_num; i++)
+ printf(" %2u: %s\n", proto[i].proto_id,
+ proto[i].name);
+ printf("\n");
+ }
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+ (uint8_t *)&pctype_num, sizeof(pctype_num),
+ RTE_PMD_I40E_PKG_INFO_PCTYPE_NUM);
+ if (ret || !pctype_num)
+ goto no_print_pctypes;
+
+ buff_size = pctype_num * sizeof(struct rte_pmd_i40e_ptype_info);
+ pctype = (struct rte_pmd_i40e_ptype_info *)malloc(buff_size);
+ if (!pctype)
+ goto no_print_pctypes;
+
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size, (uint8_t *)pctype,
+ buff_size,
+ RTE_PMD_I40E_PKG_INFO_PCTYPE_LIST);
+ if (ret) {
+ free(pctype);
+ goto no_print_pctypes;
+ }
+
+ printf("List of defined packet classification types:\n");
+ for (i = 0; i < pctype_num; i++) {
+ printf(" %2u:", pctype[i].ptype_id);
+ for (j = 0; j < RTE_PMD_I40E_PROTO_NUM; j++) {
+ proto_id = pctype[i].protocols[j];
+ if (proto_id != RTE_PMD_I40E_PROTO_UNUSED) {
+ for (n = 0; n < proto_num; n++) {
+ if (proto[n].proto_id == proto_id) {
+ printf(" %s", proto[n].name);
+ break;
+ }
+ }
+ }
+ }
+ printf("\n");
+ }
+ printf("\n");
+ free(pctype);
+
+no_print_pctypes:
+
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size, (uint8_t *)&ptype_num,
+ sizeof(ptype_num),
+ RTE_PMD_I40E_PKG_INFO_PTYPE_NUM);
+ if (ret || !ptype_num)
+ goto no_print_return;
+
+ buff_size = ptype_num * sizeof(struct rte_pmd_i40e_ptype_info);
+ ptype = (struct rte_pmd_i40e_ptype_info *)malloc(buff_size);
+ if (!ptype)
+ goto no_print_return;
+
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size, (uint8_t *)ptype,
+ buff_size,
+ RTE_PMD_I40E_PKG_INFO_PTYPE_LIST);
+ if (ret) {
+ free(ptype);
+ goto no_print_return;
+ }
+ printf("List of defined packet types:\n");
+ for (i = 0; i < ptype_num; i++) {
+ printf(" %2u:", ptype[i].ptype_id);
+ for (j = 0; j < RTE_PMD_I40E_PROTO_NUM; j++) {
+ proto_id = ptype[i].protocols[j];
+ if (proto_id != RTE_PMD_I40E_PROTO_UNUSED) {
+ for (n = 0; n < proto_num; n++) {
+ if (proto[n].proto_id == proto_id) {
+ printf(" %s", proto[n].name);
+ break;
+ }
+ }
+ }
+ }
+ printf("\n");
+ }
+ free(ptype);
+ printf("\n");
+
+ ret = 0;
+no_print_return:
+ if (proto)
+ free(proto);
+#endif
+ if (ret == -ENOTSUP)
+ printf("Function not supported in PMD driver\n");
+ close_file(pkg);
+}
+
+cmdline_parse_inst_t cmd_ddp_get_info = {
+ .f = cmd_ddp_info_parsed,
+ .data = NULL,
+ .help_str = "ddp get info <profile_path>",
+ .tokens = {
+ (void *)&cmd_ddp_info_ddp,
+ (void *)&cmd_ddp_info_get,
+ (void *)&cmd_ddp_info_info,
+ (void *)&cmd_ddp_info_filepath,
+ NULL,
+ },
+};
+
+/* Get dynamic device personalization profile info list*/
+#define PROFILE_INFO_SIZE 48
+#define MAX_PROFILE_NUM 16
+
+struct cmd_ddp_get_list_result {
+ cmdline_fixed_string_t ddp;
+ cmdline_fixed_string_t get;
+ cmdline_fixed_string_t list;
+ portid_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_ddp_get_list_ddp =
+ TOKEN_STRING_INITIALIZER(struct cmd_ddp_get_list_result, ddp, "ddp");
+cmdline_parse_token_string_t cmd_ddp_get_list_get =
+ TOKEN_STRING_INITIALIZER(struct cmd_ddp_get_list_result, get, "get");
+cmdline_parse_token_string_t cmd_ddp_get_list_list =
+ TOKEN_STRING_INITIALIZER(struct cmd_ddp_get_list_result, list, "list");
+cmdline_parse_token_num_t cmd_ddp_get_list_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_ddp_get_list_result, port_id, UINT16);
+
+static void
+cmd_ddp_get_list_parsed(
+ __rte_unused void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+#ifdef RTE_LIBRTE_I40E_PMD
+ struct cmd_ddp_get_list_result *res = parsed_result;
+ struct rte_pmd_i40e_profile_list *p_list;
+ struct rte_pmd_i40e_profile_info *p_info;
+ uint32_t p_num;
+ uint32_t size;
+ uint32_t i;
+#endif
+ int ret = -ENOTSUP;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ size = PROFILE_INFO_SIZE * MAX_PROFILE_NUM + 4;
+ p_list = (struct rte_pmd_i40e_profile_list *)malloc(size);
+ if (!p_list) {
+ printf("%s: Failed to malloc buffer\n", __func__);
+ return;
+ }
+
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_i40e_get_ddp_list(res->port_id,
+ (uint8_t *)p_list, size);
+
+ if (!ret) {
+ p_num = p_list->p_count;
+ printf("Profile number is: %d\n\n", p_num);
+
+ for (i = 0; i < p_num; i++) {
+ p_info = &p_list->p_info[i];
+ printf("Profile %d:\n", i);
+ printf("Track id: 0x%x\n", p_info->track_id);
+ printf("Version: %d.%d.%d.%d\n",
+ p_info->version.major,
+ p_info->version.minor,
+ p_info->version.update,
+ p_info->version.draft);
+ printf("Profile name: %s\n\n", p_info->name);
+ }
+ }
+
+ free(p_list);
+#endif
+
+ if (ret < 0)
+ printf("Failed to get ddp list\n");
+}
+
+cmdline_parse_inst_t cmd_ddp_get_list = {
+ .f = cmd_ddp_get_list_parsed,
+ .data = NULL,
+ .help_str = "ddp get list <port_id>",
+ .tokens = {
+ (void *)&cmd_ddp_get_list_ddp,
+ (void *)&cmd_ddp_get_list_get,
+ (void *)&cmd_ddp_get_list_list,
+ (void *)&cmd_ddp_get_list_port_id,
+ NULL,
+ },
+};
+
+/* Configure input set */
+struct cmd_cfg_input_set_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t cfg;
+ portid_t port_id;
+ cmdline_fixed_string_t pctype;
+ uint8_t pctype_id;
+ cmdline_fixed_string_t inset_type;
+ cmdline_fixed_string_t opt;
+ cmdline_fixed_string_t field;
+ uint8_t field_idx;
+};
+
+static void
+cmd_cfg_input_set_parsed(
+ __rte_unused void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+#ifdef RTE_LIBRTE_I40E_PMD
+ struct cmd_cfg_input_set_result *res = parsed_result;
+ enum rte_pmd_i40e_inset_type inset_type = INSET_NONE;
+ struct rte_pmd_i40e_inset inset;
+#endif
+ int ret = -ENOTSUP;
+
+ if (!all_ports_stopped()) {
+ printf("Please stop all ports first\n");
+ return;
+ }
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (!strcmp(res->inset_type, "hash_inset"))
+ inset_type = INSET_HASH;
+ else if (!strcmp(res->inset_type, "fdir_inset"))
+ inset_type = INSET_FDIR;
+ else if (!strcmp(res->inset_type, "fdir_flx_inset"))
+ inset_type = INSET_FDIR_FLX;
+ ret = rte_pmd_i40e_inset_get(res->port_id, res->pctype_id,
+ &inset, inset_type);
+ if (ret) {
+ printf("Failed to get input set.\n");
+ return;
+ }
+
+ if (!strcmp(res->opt, "get")) {
+ ret = rte_pmd_i40e_inset_field_get(inset.inset,
+ res->field_idx);
+ if (ret)
+ printf("Field index %d is enabled.\n", res->field_idx);
+ else
+ printf("Field index %d is disabled.\n", res->field_idx);
+ return;
+ } else if (!strcmp(res->opt, "set"))
+ ret = rte_pmd_i40e_inset_field_set(&inset.inset,
+ res->field_idx);
+ else if (!strcmp(res->opt, "clear"))
+ ret = rte_pmd_i40e_inset_field_clear(&inset.inset,
+ res->field_idx);
+ if (ret) {
+ printf("Failed to configure input set field.\n");
+ return;
+ }
+
+ ret = rte_pmd_i40e_inset_set(res->port_id, res->pctype_id,
+ &inset, inset_type);
+ if (ret) {
+ printf("Failed to set input set.\n");
+ return;
+ }
+#endif
+
+ if (ret == -ENOTSUP)
+ printf("Function not supported\n");
+}
+
+cmdline_parse_token_string_t cmd_cfg_input_set_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_cfg_input_set_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_cfg_input_set_cfg =
+ TOKEN_STRING_INITIALIZER(struct cmd_cfg_input_set_result,
+ cfg, "config");
+cmdline_parse_token_num_t cmd_cfg_input_set_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_cfg_input_set_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_cfg_input_set_pctype =
+ TOKEN_STRING_INITIALIZER(struct cmd_cfg_input_set_result,
+ pctype, "pctype");
+cmdline_parse_token_num_t cmd_cfg_input_set_pctype_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_cfg_input_set_result,
+ pctype_id, UINT8);
+cmdline_parse_token_string_t cmd_cfg_input_set_inset_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_cfg_input_set_result,
+ inset_type,
+ "hash_inset#fdir_inset#fdir_flx_inset");
+cmdline_parse_token_string_t cmd_cfg_input_set_opt =
+ TOKEN_STRING_INITIALIZER(struct cmd_cfg_input_set_result,
+ opt, "get#set#clear");
+cmdline_parse_token_string_t cmd_cfg_input_set_field =
+ TOKEN_STRING_INITIALIZER(struct cmd_cfg_input_set_result,
+ field, "field");
+cmdline_parse_token_num_t cmd_cfg_input_set_field_idx =
+ TOKEN_NUM_INITIALIZER(struct cmd_cfg_input_set_result,
+ field_idx, UINT8);
+
+cmdline_parse_inst_t cmd_cfg_input_set = {
+ .f = cmd_cfg_input_set_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> pctype <pctype_id> hash_inset|"
+ "fdir_inset|fdir_flx_inset get|set|clear field <field_idx>",
+ .tokens = {
+ (void *)&cmd_cfg_input_set_port,
+ (void *)&cmd_cfg_input_set_cfg,
+ (void *)&cmd_cfg_input_set_port_id,
+ (void *)&cmd_cfg_input_set_pctype,
+ (void *)&cmd_cfg_input_set_pctype_id,
+ (void *)&cmd_cfg_input_set_inset_type,
+ (void *)&cmd_cfg_input_set_opt,
+ (void *)&cmd_cfg_input_set_field,
+ (void *)&cmd_cfg_input_set_field_idx,
+ NULL,
+ },
+};
+
+/* Clear input set */
+struct cmd_clear_input_set_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t cfg;
+ portid_t port_id;
+ cmdline_fixed_string_t pctype;
+ uint8_t pctype_id;
+ cmdline_fixed_string_t inset_type;
+ cmdline_fixed_string_t clear;
+ cmdline_fixed_string_t all;
+};
+
+static void
+cmd_clear_input_set_parsed(
+ __rte_unused void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+#ifdef RTE_LIBRTE_I40E_PMD
+ struct cmd_clear_input_set_result *res = parsed_result;
+ enum rte_pmd_i40e_inset_type inset_type = INSET_NONE;
+ struct rte_pmd_i40e_inset inset;
+#endif
+ int ret = -ENOTSUP;
+
+ if (!all_ports_stopped()) {
+ printf("Please stop all ports first\n");
+ return;
+ }
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (!strcmp(res->inset_type, "hash_inset"))
+ inset_type = INSET_HASH;
+ else if (!strcmp(res->inset_type, "fdir_inset"))
+ inset_type = INSET_FDIR;
+ else if (!strcmp(res->inset_type, "fdir_flx_inset"))
+ inset_type = INSET_FDIR_FLX;
+
+ memset(&inset, 0, sizeof(inset));
+
+ ret = rte_pmd_i40e_inset_set(res->port_id, res->pctype_id,
+ &inset, inset_type);
+ if (ret) {
+ printf("Failed to clear input set.\n");
+ return;
+ }
+
+#endif
+
+ if (ret == -ENOTSUP)
+ printf("Function not supported\n");
+}
+
+cmdline_parse_token_string_t cmd_clear_input_set_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_clear_input_set_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_clear_input_set_cfg =
+ TOKEN_STRING_INITIALIZER(struct cmd_clear_input_set_result,
+ cfg, "config");
+cmdline_parse_token_num_t cmd_clear_input_set_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_clear_input_set_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_clear_input_set_pctype =
+ TOKEN_STRING_INITIALIZER(struct cmd_clear_input_set_result,
+ pctype, "pctype");
+cmdline_parse_token_num_t cmd_clear_input_set_pctype_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_clear_input_set_result,
+ pctype_id, UINT8);
+cmdline_parse_token_string_t cmd_clear_input_set_inset_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_clear_input_set_result,
+ inset_type,
+ "hash_inset#fdir_inset#fdir_flx_inset");
+cmdline_parse_token_string_t cmd_clear_input_set_clear =
+ TOKEN_STRING_INITIALIZER(struct cmd_clear_input_set_result,
+ clear, "clear");
+cmdline_parse_token_string_t cmd_clear_input_set_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_clear_input_set_result,
+ all, "all");
+
+cmdline_parse_inst_t cmd_clear_input_set = {
+ .f = cmd_clear_input_set_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> pctype <pctype_id> hash_inset|"
+ "fdir_inset|fdir_flx_inset clear all",
+ .tokens = {
+ (void *)&cmd_clear_input_set_port,
+ (void *)&cmd_clear_input_set_cfg,
+ (void *)&cmd_clear_input_set_port_id,
+ (void *)&cmd_clear_input_set_pctype,
+ (void *)&cmd_clear_input_set_pctype_id,
+ (void *)&cmd_clear_input_set_inset_type,
+ (void *)&cmd_clear_input_set_clear,
+ (void *)&cmd_clear_input_set_all,
+ NULL,
+ },
+};
+
+/* show vf stats */
+
+/* Common result structure for show vf stats */
+struct cmd_show_vf_stats_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t stats;
+ portid_t port_id;
+ uint16_t vf_id;
+};
+
+/* Common CLI fields show vf stats*/
+cmdline_parse_token_string_t cmd_show_vf_stats_show =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_show_vf_stats_result,
+ show, "show");
+cmdline_parse_token_string_t cmd_show_vf_stats_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_show_vf_stats_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_show_vf_stats_stats =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_show_vf_stats_result,
+ stats, "stats");
+cmdline_parse_token_num_t cmd_show_vf_stats_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_show_vf_stats_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_vf_stats_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_show_vf_stats_result,
+ vf_id, UINT16);
+
+static void
+cmd_show_vf_stats_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_vf_stats_result *res = parsed_result;
+ struct rte_eth_stats stats;
+ int ret = -ENOTSUP;
+ static const char *nic_stats_border = "########################";
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+ memset(&stats, 0, sizeof(stats));
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_i40e_get_vf_stats(res->port_id,
+ res->vf_id,
+ &stats);
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_bnxt_get_vf_stats(res->port_id,
+ res->vf_id,
+ &stats);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d\n", res->vf_id);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+
+ printf("\n %s NIC statistics for port %-2d vf %-2d %s\n",
+ nic_stats_border, res->port_id, res->vf_id, nic_stats_border);
+
+ printf(" RX-packets: %-10"PRIu64" RX-missed: %-10"PRIu64" RX-bytes: "
+ "%-"PRIu64"\n",
+ stats.ipackets, stats.imissed, stats.ibytes);
+ printf(" RX-errors: %-"PRIu64"\n", stats.ierrors);
+ printf(" RX-nombuf: %-10"PRIu64"\n",
+ stats.rx_nombuf);
+ printf(" TX-packets: %-10"PRIu64" TX-errors: %-10"PRIu64" TX-bytes: "
+ "%-"PRIu64"\n",
+ stats.opackets, stats.oerrors, stats.obytes);
+
+ printf(" %s############################%s\n",
+ nic_stats_border, nic_stats_border);
+}
+
+cmdline_parse_inst_t cmd_show_vf_stats = {
+ .f = cmd_show_vf_stats_parsed,
+ .data = NULL,
+ .help_str = "show vf stats <port_id> <vf_id>",
+ .tokens = {
+ (void *)&cmd_show_vf_stats_show,
+ (void *)&cmd_show_vf_stats_vf,
+ (void *)&cmd_show_vf_stats_stats,
+ (void *)&cmd_show_vf_stats_port_id,
+ (void *)&cmd_show_vf_stats_vf_id,
+ NULL,
+ },
+};
+
+/* clear vf stats */
+
+/* Common result structure for clear vf stats */
+struct cmd_clear_vf_stats_result {
+ cmdline_fixed_string_t clear;
+ cmdline_fixed_string_t vf;
+ cmdline_fixed_string_t stats;
+ portid_t port_id;
+ uint16_t vf_id;
+};
+
+/* Common CLI fields clear vf stats*/
+cmdline_parse_token_string_t cmd_clear_vf_stats_clear =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_clear_vf_stats_result,
+ clear, "clear");
+cmdline_parse_token_string_t cmd_clear_vf_stats_vf =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_clear_vf_stats_result,
+ vf, "vf");
+cmdline_parse_token_string_t cmd_clear_vf_stats_stats =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_clear_vf_stats_result,
+ stats, "stats");
+cmdline_parse_token_num_t cmd_clear_vf_stats_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_clear_vf_stats_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_clear_vf_stats_vf_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_clear_vf_stats_result,
+ vf_id, UINT16);
+
+static void
+cmd_clear_vf_stats_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_clear_vf_stats_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_i40e_reset_vf_stats(res->port_id,
+ res->vf_id);
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+ if (ret == -ENOTSUP)
+ ret = rte_pmd_bnxt_reset_vf_stats(res->port_id,
+ res->vf_id);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid vf_id %d\n", res->vf_id);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_clear_vf_stats = {
+ .f = cmd_clear_vf_stats_parsed,
+ .data = NULL,
+ .help_str = "clear vf stats <port_id> <vf_id>",
+ .tokens = {
+ (void *)&cmd_clear_vf_stats_clear,
+ (void *)&cmd_clear_vf_stats_vf,
+ (void *)&cmd_clear_vf_stats_stats,
+ (void *)&cmd_clear_vf_stats_port_id,
+ (void *)&cmd_clear_vf_stats_vf_id,
+ NULL,
+ },
+};
+
+/* port config pctype mapping reset */
+
+/* Common result structure for port config pctype mapping reset */
+struct cmd_pctype_mapping_reset_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t config;
+ portid_t port_id;
+ cmdline_fixed_string_t pctype;
+ cmdline_fixed_string_t mapping;
+ cmdline_fixed_string_t reset;
+};
+
+/* Common CLI fields for port config pctype mapping reset*/
+cmdline_parse_token_string_t cmd_pctype_mapping_reset_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_reset_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_pctype_mapping_reset_config =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_reset_result,
+ config, "config");
+cmdline_parse_token_num_t cmd_pctype_mapping_reset_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_pctype_mapping_reset_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_pctype_mapping_reset_pctype =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_reset_result,
+ pctype, "pctype");
+cmdline_parse_token_string_t cmd_pctype_mapping_reset_mapping =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_reset_result,
+ mapping, "mapping");
+cmdline_parse_token_string_t cmd_pctype_mapping_reset_reset =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_reset_result,
+ reset, "reset");
+
+static void
+cmd_pctype_mapping_reset_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_pctype_mapping_reset_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ ret = rte_pmd_i40e_flow_type_mapping_reset(res->port_id);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_pctype_mapping_reset = {
+ .f = cmd_pctype_mapping_reset_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> pctype mapping reset",
+ .tokens = {
+ (void *)&cmd_pctype_mapping_reset_port,
+ (void *)&cmd_pctype_mapping_reset_config,
+ (void *)&cmd_pctype_mapping_reset_port_id,
+ (void *)&cmd_pctype_mapping_reset_pctype,
+ (void *)&cmd_pctype_mapping_reset_mapping,
+ (void *)&cmd_pctype_mapping_reset_reset,
+ NULL,
+ },
+};
+
+/* show port pctype mapping */
+
+/* Common result structure for show port pctype mapping */
+struct cmd_pctype_mapping_get_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t pctype;
+ cmdline_fixed_string_t mapping;
+};
+
+/* Common CLI fields for pctype mapping get */
+cmdline_parse_token_string_t cmd_pctype_mapping_get_show =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_get_result,
+ show, "show");
+cmdline_parse_token_string_t cmd_pctype_mapping_get_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_get_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_pctype_mapping_get_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_pctype_mapping_get_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_pctype_mapping_get_pctype =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_get_result,
+ pctype, "pctype");
+cmdline_parse_token_string_t cmd_pctype_mapping_get_mapping =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_get_result,
+ mapping, "mapping");
+
+static void
+cmd_pctype_mapping_get_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_pctype_mapping_get_result *res = parsed_result;
+ int ret = -ENOTSUP;
+#ifdef RTE_LIBRTE_I40E_PMD
+ struct rte_pmd_i40e_flow_type_mapping
+ mapping[RTE_PMD_I40E_FLOW_TYPE_MAX];
+ int i, j, first_pctype;
+#endif
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ ret = rte_pmd_i40e_flow_type_mapping_get(res->port_id, mapping);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ return;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ return;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ return;
+ }
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ for (i = 0; i < RTE_PMD_I40E_FLOW_TYPE_MAX; i++) {
+ if (mapping[i].pctype != 0ULL) {
+ first_pctype = 1;
+
+ printf("pctype: ");
+ for (j = 0; j < RTE_PMD_I40E_PCTYPE_MAX; j++) {
+ if (mapping[i].pctype & (1ULL << j)) {
+ printf(first_pctype ?
+ "%02d" : ",%02d", j);
+ first_pctype = 0;
+ }
+ }
+ printf(" -> flowtype: %02d\n", mapping[i].flow_type);
+ }
+ }
+#endif
+}
+
+cmdline_parse_inst_t cmd_pctype_mapping_get = {
+ .f = cmd_pctype_mapping_get_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> pctype mapping",
+ .tokens = {
+ (void *)&cmd_pctype_mapping_get_show,
+ (void *)&cmd_pctype_mapping_get_port,
+ (void *)&cmd_pctype_mapping_get_port_id,
+ (void *)&cmd_pctype_mapping_get_pctype,
+ (void *)&cmd_pctype_mapping_get_mapping,
+ NULL,
+ },
+};
+
+/* port config pctype mapping update */
+
+/* Common result structure for port config pctype mapping update */
+struct cmd_pctype_mapping_update_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t config;
+ portid_t port_id;
+ cmdline_fixed_string_t pctype;
+ cmdline_fixed_string_t mapping;
+ cmdline_fixed_string_t update;
+ cmdline_fixed_string_t pctype_list;
+ uint16_t flow_type;
+};
+
+/* Common CLI fields for pctype mapping update*/
+cmdline_parse_token_string_t cmd_pctype_mapping_update_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_update_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_pctype_mapping_update_config =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_update_result,
+ config, "config");
+cmdline_parse_token_num_t cmd_pctype_mapping_update_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_pctype_mapping_update_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_pctype_mapping_update_pctype =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_update_result,
+ pctype, "pctype");
+cmdline_parse_token_string_t cmd_pctype_mapping_update_mapping =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_update_result,
+ mapping, "mapping");
+cmdline_parse_token_string_t cmd_pctype_mapping_update_update =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_update_result,
+ update, "update");
+cmdline_parse_token_string_t cmd_pctype_mapping_update_pc_type =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_pctype_mapping_update_result,
+ pctype_list, NULL);
+cmdline_parse_token_num_t cmd_pctype_mapping_update_flow_type =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_pctype_mapping_update_result,
+ flow_type, UINT16);
+
+static void
+cmd_pctype_mapping_update_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_pctype_mapping_update_result *res = parsed_result;
+ int ret = -ENOTSUP;
+#ifdef RTE_LIBRTE_I40E_PMD
+ struct rte_pmd_i40e_flow_type_mapping mapping;
+ unsigned int i;
+ unsigned int nb_item;
+ unsigned int pctype_list[RTE_PMD_I40E_PCTYPE_MAX];
+#endif
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ nb_item = parse_item_list(res->pctype_list, "pctypes",
+ RTE_PMD_I40E_PCTYPE_MAX, pctype_list, 1);
+ mapping.flow_type = res->flow_type;
+ for (i = 0, mapping.pctype = 0ULL; i < nb_item; i++)
+ mapping.pctype |= (1ULL << pctype_list[i]);
+ ret = rte_pmd_i40e_flow_type_mapping_update(res->port_id,
+ &mapping,
+ 1,
+ 0);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid pctype or flow type\n");
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_pctype_mapping_update = {
+ .f = cmd_pctype_mapping_update_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> pctype mapping update"
+ " <pctype_id_0,[pctype_id_1]*> <flowtype_id>",
+ .tokens = {
+ (void *)&cmd_pctype_mapping_update_port,
+ (void *)&cmd_pctype_mapping_update_config,
+ (void *)&cmd_pctype_mapping_update_port_id,
+ (void *)&cmd_pctype_mapping_update_pctype,
+ (void *)&cmd_pctype_mapping_update_mapping,
+ (void *)&cmd_pctype_mapping_update_update,
+ (void *)&cmd_pctype_mapping_update_pc_type,
+ (void *)&cmd_pctype_mapping_update_flow_type,
+ NULL,
+ },
+};
+
+/* ptype mapping get */
+
+/* Common result structure for ptype mapping get */
+struct cmd_ptype_mapping_get_result {
+ cmdline_fixed_string_t ptype;
+ cmdline_fixed_string_t mapping;
+ cmdline_fixed_string_t get;
+ portid_t port_id;
+ uint8_t valid_only;
+};
+
+/* Common CLI fields for ptype mapping get */
+cmdline_parse_token_string_t cmd_ptype_mapping_get_ptype =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_ptype_mapping_get_result,
+ ptype, "ptype");
+cmdline_parse_token_string_t cmd_ptype_mapping_get_mapping =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_ptype_mapping_get_result,
+ mapping, "mapping");
+cmdline_parse_token_string_t cmd_ptype_mapping_get_get =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_ptype_mapping_get_result,
+ get, "get");
+cmdline_parse_token_num_t cmd_ptype_mapping_get_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_ptype_mapping_get_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_ptype_mapping_get_valid_only =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_ptype_mapping_get_result,
+ valid_only, UINT8);
+
+static void
+cmd_ptype_mapping_get_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_ptype_mapping_get_result *res = parsed_result;
+ int ret = -ENOTSUP;
+#ifdef RTE_LIBRTE_I40E_PMD
+ int max_ptype_num = 256;
+ struct rte_pmd_i40e_ptype_mapping mapping[max_ptype_num];
+ uint16_t count;
+ int i;
+#endif
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ ret = rte_pmd_i40e_ptype_mapping_get(res->port_id,
+ mapping,
+ max_ptype_num,
+ &count,
+ res->valid_only);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ if (!ret) {
+ for (i = 0; i < count; i++)
+ printf("%3d\t0x%08x\n",
+ mapping[i].hw_ptype, mapping[i].sw_ptype);
+ }
+#endif
+}
+
+cmdline_parse_inst_t cmd_ptype_mapping_get = {
+ .f = cmd_ptype_mapping_get_parsed,
+ .data = NULL,
+ .help_str = "ptype mapping get <port_id> <valid_only>",
+ .tokens = {
+ (void *)&cmd_ptype_mapping_get_ptype,
+ (void *)&cmd_ptype_mapping_get_mapping,
+ (void *)&cmd_ptype_mapping_get_get,
+ (void *)&cmd_ptype_mapping_get_port_id,
+ (void *)&cmd_ptype_mapping_get_valid_only,
+ NULL,
+ },
+};
+
+/* ptype mapping replace */
+
+/* Common result structure for ptype mapping replace */
+struct cmd_ptype_mapping_replace_result {
+ cmdline_fixed_string_t ptype;
+ cmdline_fixed_string_t mapping;
+ cmdline_fixed_string_t replace;
+ portid_t port_id;
+ uint32_t target;
+ uint8_t mask;
+ uint32_t pkt_type;
+};
+
+/* Common CLI fields for ptype mapping replace */
+cmdline_parse_token_string_t cmd_ptype_mapping_replace_ptype =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_ptype_mapping_replace_result,
+ ptype, "ptype");
+cmdline_parse_token_string_t cmd_ptype_mapping_replace_mapping =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_ptype_mapping_replace_result,
+ mapping, "mapping");
+cmdline_parse_token_string_t cmd_ptype_mapping_replace_replace =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_ptype_mapping_replace_result,
+ replace, "replace");
+cmdline_parse_token_num_t cmd_ptype_mapping_replace_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_ptype_mapping_replace_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_ptype_mapping_replace_target =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_ptype_mapping_replace_result,
+ target, UINT32);
+cmdline_parse_token_num_t cmd_ptype_mapping_replace_mask =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_ptype_mapping_replace_result,
+ mask, UINT8);
+cmdline_parse_token_num_t cmd_ptype_mapping_replace_pkt_type =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_ptype_mapping_replace_result,
+ pkt_type, UINT32);
+
+static void
+cmd_ptype_mapping_replace_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_ptype_mapping_replace_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ ret = rte_pmd_i40e_ptype_mapping_replace(res->port_id,
+ res->target,
+ res->mask,
+ res->pkt_type);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid ptype 0x%8x or 0x%8x\n",
+ res->target, res->pkt_type);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_ptype_mapping_replace = {
+ .f = cmd_ptype_mapping_replace_parsed,
+ .data = NULL,
+ .help_str =
+ "ptype mapping replace <port_id> <target> <mask> <pkt_type>",
+ .tokens = {
+ (void *)&cmd_ptype_mapping_replace_ptype,
+ (void *)&cmd_ptype_mapping_replace_mapping,
+ (void *)&cmd_ptype_mapping_replace_replace,
+ (void *)&cmd_ptype_mapping_replace_port_id,
+ (void *)&cmd_ptype_mapping_replace_target,
+ (void *)&cmd_ptype_mapping_replace_mask,
+ (void *)&cmd_ptype_mapping_replace_pkt_type,
+ NULL,
+ },
+};
+
+/* ptype mapping reset */
+
+/* Common result structure for ptype mapping reset */
+struct cmd_ptype_mapping_reset_result {
+ cmdline_fixed_string_t ptype;
+ cmdline_fixed_string_t mapping;
+ cmdline_fixed_string_t reset;
+ portid_t port_id;
+};
+
+/* Common CLI fields for ptype mapping reset*/
+cmdline_parse_token_string_t cmd_ptype_mapping_reset_ptype =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_ptype_mapping_reset_result,
+ ptype, "ptype");
+cmdline_parse_token_string_t cmd_ptype_mapping_reset_mapping =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_ptype_mapping_reset_result,
+ mapping, "mapping");
+cmdline_parse_token_string_t cmd_ptype_mapping_reset_reset =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_ptype_mapping_reset_result,
+ reset, "reset");
+cmdline_parse_token_num_t cmd_ptype_mapping_reset_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_ptype_mapping_reset_result,
+ port_id, UINT16);
+
+static void
+cmd_ptype_mapping_reset_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_ptype_mapping_reset_result *res = parsed_result;
+ int ret = -ENOTSUP;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ ret = rte_pmd_i40e_ptype_mapping_reset(res->port_id);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_ptype_mapping_reset = {
+ .f = cmd_ptype_mapping_reset_parsed,
+ .data = NULL,
+ .help_str = "ptype mapping reset <port_id>",
+ .tokens = {
+ (void *)&cmd_ptype_mapping_reset_ptype,
+ (void *)&cmd_ptype_mapping_reset_mapping,
+ (void *)&cmd_ptype_mapping_reset_reset,
+ (void *)&cmd_ptype_mapping_reset_port_id,
+ NULL,
+ },
+};
+
+/* ptype mapping update */
+
+/* Common result structure for ptype mapping update */
+struct cmd_ptype_mapping_update_result {
+ cmdline_fixed_string_t ptype;
+ cmdline_fixed_string_t mapping;
+ cmdline_fixed_string_t reset;
+ portid_t port_id;
+ uint8_t hw_ptype;
+ uint32_t sw_ptype;
+};
+
+/* Common CLI fields for ptype mapping update*/
+cmdline_parse_token_string_t cmd_ptype_mapping_update_ptype =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_ptype_mapping_update_result,
+ ptype, "ptype");
+cmdline_parse_token_string_t cmd_ptype_mapping_update_mapping =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_ptype_mapping_update_result,
+ mapping, "mapping");
+cmdline_parse_token_string_t cmd_ptype_mapping_update_update =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_ptype_mapping_update_result,
+ reset, "update");
+cmdline_parse_token_num_t cmd_ptype_mapping_update_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_ptype_mapping_update_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_ptype_mapping_update_hw_ptype =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_ptype_mapping_update_result,
+ hw_ptype, UINT8);
+cmdline_parse_token_num_t cmd_ptype_mapping_update_sw_ptype =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_ptype_mapping_update_result,
+ sw_ptype, UINT32);
+
+static void
+cmd_ptype_mapping_update_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_ptype_mapping_update_result *res = parsed_result;
+ int ret = -ENOTSUP;
+#ifdef RTE_LIBRTE_I40E_PMD
+ struct rte_pmd_i40e_ptype_mapping mapping;
+#endif
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+#ifdef RTE_LIBRTE_I40E_PMD
+ mapping.hw_ptype = res->hw_ptype;
+ mapping.sw_ptype = res->sw_ptype;
+ ret = rte_pmd_i40e_ptype_mapping_update(res->port_id,
+ &mapping,
+ 1,
+ 0);
+#endif
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ printf("invalid ptype 0x%8x\n", res->sw_ptype);
+ break;
+ case -ENODEV:
+ printf("invalid port_id %d\n", res->port_id);
+ break;
+ case -ENOTSUP:
+ printf("function not implemented\n");
+ break;
+ default:
+ printf("programming error: (%s)\n", strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_ptype_mapping_update = {
+ .f = cmd_ptype_mapping_update_parsed,
+ .data = NULL,
+ .help_str = "ptype mapping update <port_id> <hw_ptype> <sw_ptype>",
+ .tokens = {
+ (void *)&cmd_ptype_mapping_update_ptype,
+ (void *)&cmd_ptype_mapping_update_mapping,
+ (void *)&cmd_ptype_mapping_update_update,
+ (void *)&cmd_ptype_mapping_update_port_id,
+ (void *)&cmd_ptype_mapping_update_hw_ptype,
+ (void *)&cmd_ptype_mapping_update_sw_ptype,
+ NULL,
+ },
+};
+
+/* Common result structure for file commands */
+struct cmd_cmdfile_result {
+ cmdline_fixed_string_t load;
+ cmdline_fixed_string_t filename;
+};
+
+/* Common CLI fields for file commands */
+cmdline_parse_token_string_t cmd_load_cmdfile =
+ TOKEN_STRING_INITIALIZER(struct cmd_cmdfile_result, load, "load");
+cmdline_parse_token_string_t cmd_load_cmdfile_filename =
+ TOKEN_STRING_INITIALIZER(struct cmd_cmdfile_result, filename, NULL);
+
+static void
+cmd_load_from_file_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_cmdfile_result *res = parsed_result;
+
+ cmdline_read_from_file(res->filename);
+}
+
+cmdline_parse_inst_t cmd_load_from_file = {
+ .f = cmd_load_from_file_parsed,
+ .data = NULL,
+ .help_str = "load <filename>",
+ .tokens = {
+ (void *)&cmd_load_cmdfile,
+ (void *)&cmd_load_cmdfile_filename,
+ NULL,
+ },
+};
+
+/* Get Rx offloads capabilities */
+struct cmd_rx_offload_get_capa_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t rx_offload;
+ cmdline_fixed_string_t capabilities;
+};
+
+cmdline_parse_token_string_t cmd_rx_offload_get_capa_show =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_rx_offload_get_capa_result,
+ show, "show");
+cmdline_parse_token_string_t cmd_rx_offload_get_capa_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_rx_offload_get_capa_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_rx_offload_get_capa_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_rx_offload_get_capa_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_rx_offload_get_capa_rx_offload =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_rx_offload_get_capa_result,
+ rx_offload, "rx_offload");
+cmdline_parse_token_string_t cmd_rx_offload_get_capa_capabilities =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_rx_offload_get_capa_result,
+ capabilities, "capabilities");
+
+static void
+print_rx_offloads(uint64_t offloads)
+{
+ uint64_t single_offload;
+ int begin;
+ int end;
+ int bit;
+
+ if (offloads == 0)
+ return;
+
+ begin = __builtin_ctzll(offloads);
+ end = sizeof(offloads) * CHAR_BIT - __builtin_clzll(offloads);
+
+ single_offload = 1ULL << begin;
+ for (bit = begin; bit < end; bit++) {
+ if (offloads & single_offload)
+ printf(" %s",
+ rte_eth_dev_rx_offload_name(single_offload));
+ single_offload <<= 1;
+ }
+}
+
+static void
+cmd_rx_offload_get_capa_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_rx_offload_get_capa_result *res = parsed_result;
+ struct rte_eth_dev_info dev_info;
+ portid_t port_id = res->port_id;
+ uint64_t queue_offloads;
+ uint64_t port_offloads;
+ int ret;
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ queue_offloads = dev_info.rx_queue_offload_capa;
+ port_offloads = dev_info.rx_offload_capa ^ queue_offloads;
+
+ printf("Rx Offloading Capabilities of port %d :\n", port_id);
+ printf(" Per Queue :");
+ print_rx_offloads(queue_offloads);
+
+ printf("\n");
+ printf(" Per Port :");
+ print_rx_offloads(port_offloads);
+ printf("\n\n");
+}
+
+cmdline_parse_inst_t cmd_rx_offload_get_capa = {
+ .f = cmd_rx_offload_get_capa_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> rx_offload capabilities",
+ .tokens = {
+ (void *)&cmd_rx_offload_get_capa_show,
+ (void *)&cmd_rx_offload_get_capa_port,
+ (void *)&cmd_rx_offload_get_capa_port_id,
+ (void *)&cmd_rx_offload_get_capa_rx_offload,
+ (void *)&cmd_rx_offload_get_capa_capabilities,
+ NULL,
+ }
+};
+
+/* Get Rx offloads configuration */
+struct cmd_rx_offload_get_configuration_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t rx_offload;
+ cmdline_fixed_string_t configuration;
+};
+
+cmdline_parse_token_string_t cmd_rx_offload_get_configuration_show =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_rx_offload_get_configuration_result,
+ show, "show");
+cmdline_parse_token_string_t cmd_rx_offload_get_configuration_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_rx_offload_get_configuration_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_rx_offload_get_configuration_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_rx_offload_get_configuration_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_rx_offload_get_configuration_rx_offload =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_rx_offload_get_configuration_result,
+ rx_offload, "rx_offload");
+cmdline_parse_token_string_t cmd_rx_offload_get_configuration_configuration =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_rx_offload_get_configuration_result,
+ configuration, "configuration");
+
+static void
+cmd_rx_offload_get_configuration_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_rx_offload_get_configuration_result *res = parsed_result;
+ struct rte_eth_dev_info dev_info;
+ portid_t port_id = res->port_id;
+ struct rte_port *port = &ports[port_id];
+ uint64_t port_offloads;
+ uint64_t queue_offloads;
+ uint16_t nb_rx_queues;
+ int q;
+ int ret;
+
+ printf("Rx Offloading Configuration of port %d :\n", port_id);
+
+ port_offloads = port->dev_conf.rxmode.offloads;
+ printf(" Port :");
+ print_rx_offloads(port_offloads);
+ printf("\n");
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ nb_rx_queues = dev_info.nb_rx_queues;
+ for (q = 0; q < nb_rx_queues; q++) {
+ queue_offloads = port->rx_conf[q].offloads;
+ printf(" Queue[%2d] :", q);
+ print_rx_offloads(queue_offloads);
+ printf("\n");
+ }
+ printf("\n");
+}
+
+cmdline_parse_inst_t cmd_rx_offload_get_configuration = {
+ .f = cmd_rx_offload_get_configuration_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> rx_offload configuration",
+ .tokens = {
+ (void *)&cmd_rx_offload_get_configuration_show,
+ (void *)&cmd_rx_offload_get_configuration_port,
+ (void *)&cmd_rx_offload_get_configuration_port_id,
+ (void *)&cmd_rx_offload_get_configuration_rx_offload,
+ (void *)&cmd_rx_offload_get_configuration_configuration,
+ NULL,
+ }
+};
+
+/* Enable/Disable a per port offloading */
+struct cmd_config_per_port_rx_offload_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t config;
+ portid_t port_id;
+ cmdline_fixed_string_t rx_offload;
+ cmdline_fixed_string_t offload;
+ cmdline_fixed_string_t on_off;
+};
+
+cmdline_parse_token_string_t cmd_config_per_port_rx_offload_result_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_port_rx_offload_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_config_per_port_rx_offload_result_config =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_port_rx_offload_result,
+ config, "config");
+cmdline_parse_token_num_t cmd_config_per_port_rx_offload_result_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_per_port_rx_offload_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_config_per_port_rx_offload_result_rx_offload =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_port_rx_offload_result,
+ rx_offload, "rx_offload");
+cmdline_parse_token_string_t cmd_config_per_port_rx_offload_result_offload =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_port_rx_offload_result,
+ offload, "vlan_strip#ipv4_cksum#udp_cksum#tcp_cksum#tcp_lro#"
+ "qinq_strip#outer_ipv4_cksum#macsec_strip#"
+ "header_split#vlan_filter#vlan_extend#jumbo_frame#"
+ "scatter#timestamp#security#keep_crc#rss_hash");
+cmdline_parse_token_string_t cmd_config_per_port_rx_offload_result_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_port_rx_offload_result,
+ on_off, "on#off");
+
+static uint64_t
+search_rx_offload(const char *name)
+{
+ uint64_t single_offload;
+ const char *single_name;
+ int found = 0;
+ unsigned int bit;
+
+ single_offload = 1;
+ for (bit = 0; bit < sizeof(single_offload) * CHAR_BIT; bit++) {
+ single_name = rte_eth_dev_rx_offload_name(single_offload);
+ if (!strcasecmp(single_name, name)) {
+ found = 1;
+ break;
+ }
+ single_offload <<= 1;
+ }
+
+ if (found)
+ return single_offload;
+
+ return 0;
+}
+
+static void
+cmd_config_per_port_rx_offload_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_per_port_rx_offload_result *res = parsed_result;
+ portid_t port_id = res->port_id;
+ struct rte_eth_dev_info dev_info;
+ struct rte_port *port = &ports[port_id];
+ uint64_t single_offload;
+ uint16_t nb_rx_queues;
+ int q;
+ int ret;
+
+ if (port->port_status != RTE_PORT_STOPPED) {
+ printf("Error: Can't config offload when Port %d "
+ "is not stopped\n", port_id);
+ return;
+ }
+
+ single_offload = search_rx_offload(res->offload);
+ if (single_offload == 0) {
+ printf("Unknown offload name: %s\n", res->offload);
+ return;
+ }
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ nb_rx_queues = dev_info.nb_rx_queues;
+ if (!strcmp(res->on_off, "on")) {
+ port->dev_conf.rxmode.offloads |= single_offload;
+ for (q = 0; q < nb_rx_queues; q++)
+ port->rx_conf[q].offloads |= single_offload;
+ } else {
+ port->dev_conf.rxmode.offloads &= ~single_offload;
+ for (q = 0; q < nb_rx_queues; q++)
+ port->rx_conf[q].offloads &= ~single_offload;
+ }
+
+ cmd_reconfig_device_queue(port_id, 1, 1);
+}
+
+cmdline_parse_inst_t cmd_config_per_port_rx_offload = {
+ .f = cmd_config_per_port_rx_offload_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> rx_offload vlan_strip|ipv4_cksum|"
+ "udp_cksum|tcp_cksum|tcp_lro|qinq_strip|outer_ipv4_cksum|"
+ "macsec_strip|header_split|vlan_filter|vlan_extend|"
+ "jumbo_frame|scatter|timestamp|security|keep_crc|rss_hash "
+ "on|off",
+ .tokens = {
+ (void *)&cmd_config_per_port_rx_offload_result_port,
+ (void *)&cmd_config_per_port_rx_offload_result_config,
+ (void *)&cmd_config_per_port_rx_offload_result_port_id,
+ (void *)&cmd_config_per_port_rx_offload_result_rx_offload,
+ (void *)&cmd_config_per_port_rx_offload_result_offload,
+ (void *)&cmd_config_per_port_rx_offload_result_on_off,
+ NULL,
+ }
+};
+
+/* Enable/Disable a per queue offloading */
+struct cmd_config_per_queue_rx_offload_result {
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t rxq;
+ uint16_t queue_id;
+ cmdline_fixed_string_t rx_offload;
+ cmdline_fixed_string_t offload;
+ cmdline_fixed_string_t on_off;
+};
+
+cmdline_parse_token_string_t cmd_config_per_queue_rx_offload_result_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_queue_rx_offload_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_config_per_queue_rx_offload_result_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_per_queue_rx_offload_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_config_per_queue_rx_offload_result_rxq =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_queue_rx_offload_result,
+ rxq, "rxq");
+cmdline_parse_token_num_t cmd_config_per_queue_rx_offload_result_queue_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_per_queue_rx_offload_result,
+ queue_id, UINT16);
+cmdline_parse_token_string_t cmd_config_per_queue_rx_offload_result_rxoffload =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_queue_rx_offload_result,
+ rx_offload, "rx_offload");
+cmdline_parse_token_string_t cmd_config_per_queue_rx_offload_result_offload =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_queue_rx_offload_result,
+ offload, "vlan_strip#ipv4_cksum#udp_cksum#tcp_cksum#tcp_lro#"
+ "qinq_strip#outer_ipv4_cksum#macsec_strip#"
+ "header_split#vlan_filter#vlan_extend#jumbo_frame#"
+ "scatter#timestamp#security#keep_crc");
+cmdline_parse_token_string_t cmd_config_per_queue_rx_offload_result_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_queue_rx_offload_result,
+ on_off, "on#off");
+
+static void
+cmd_config_per_queue_rx_offload_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_per_queue_rx_offload_result *res = parsed_result;
+ struct rte_eth_dev_info dev_info;
+ portid_t port_id = res->port_id;
+ uint16_t queue_id = res->queue_id;
+ struct rte_port *port = &ports[port_id];
+ uint64_t single_offload;
+ int ret;
+
+ if (port->port_status != RTE_PORT_STOPPED) {
+ printf("Error: Can't config offload when Port %d "
+ "is not stopped\n", port_id);
+ return;
+ }
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if (queue_id >= dev_info.nb_rx_queues) {
+ printf("Error: input queue_id should be 0 ... "
+ "%d\n", dev_info.nb_rx_queues - 1);
+ return;
+ }
+
+ single_offload = search_rx_offload(res->offload);
+ if (single_offload == 0) {
+ printf("Unknown offload name: %s\n", res->offload);
+ return;
+ }
+
+ if (!strcmp(res->on_off, "on"))
+ port->rx_conf[queue_id].offloads |= single_offload;
+ else
+ port->rx_conf[queue_id].offloads &= ~single_offload;
+
+ cmd_reconfig_device_queue(port_id, 1, 1);
+}
+
+cmdline_parse_inst_t cmd_config_per_queue_rx_offload = {
+ .f = cmd_config_per_queue_rx_offload_parsed,
+ .data = NULL,
+ .help_str = "port <port_id> rxq <queue_id> rx_offload "
+ "vlan_strip|ipv4_cksum|"
+ "udp_cksum|tcp_cksum|tcp_lro|qinq_strip|outer_ipv4_cksum|"
+ "macsec_strip|header_split|vlan_filter|vlan_extend|"
+ "jumbo_frame|scatter|timestamp|security|keep_crc "
+ "on|off",
+ .tokens = {
+ (void *)&cmd_config_per_queue_rx_offload_result_port,
+ (void *)&cmd_config_per_queue_rx_offload_result_port_id,
+ (void *)&cmd_config_per_queue_rx_offload_result_rxq,
+ (void *)&cmd_config_per_queue_rx_offload_result_queue_id,
+ (void *)&cmd_config_per_queue_rx_offload_result_rxoffload,
+ (void *)&cmd_config_per_queue_rx_offload_result_offload,
+ (void *)&cmd_config_per_queue_rx_offload_result_on_off,
+ NULL,
+ }
+};
+
+/* Get Tx offloads capabilities */
+struct cmd_tx_offload_get_capa_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t tx_offload;
+ cmdline_fixed_string_t capabilities;
+};
+
+cmdline_parse_token_string_t cmd_tx_offload_get_capa_show =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_tx_offload_get_capa_result,
+ show, "show");
+cmdline_parse_token_string_t cmd_tx_offload_get_capa_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_tx_offload_get_capa_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_tx_offload_get_capa_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_tx_offload_get_capa_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_tx_offload_get_capa_tx_offload =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_tx_offload_get_capa_result,
+ tx_offload, "tx_offload");
+cmdline_parse_token_string_t cmd_tx_offload_get_capa_capabilities =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_tx_offload_get_capa_result,
+ capabilities, "capabilities");
+
+static void
+print_tx_offloads(uint64_t offloads)
+{
+ uint64_t single_offload;
+ int begin;
+ int end;
+ int bit;
+
+ if (offloads == 0)
+ return;
+
+ begin = __builtin_ctzll(offloads);
+ end = sizeof(offloads) * CHAR_BIT - __builtin_clzll(offloads);
+
+ single_offload = 1ULL << begin;
+ for (bit = begin; bit < end; bit++) {
+ if (offloads & single_offload)
+ printf(" %s",
+ rte_eth_dev_tx_offload_name(single_offload));
+ single_offload <<= 1;
+ }
+}
+
+static void
+cmd_tx_offload_get_capa_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_tx_offload_get_capa_result *res = parsed_result;
+ struct rte_eth_dev_info dev_info;
+ portid_t port_id = res->port_id;
+ uint64_t queue_offloads;
+ uint64_t port_offloads;
+ int ret;
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ queue_offloads = dev_info.tx_queue_offload_capa;
+ port_offloads = dev_info.tx_offload_capa ^ queue_offloads;
+
+ printf("Tx Offloading Capabilities of port %d :\n", port_id);
+ printf(" Per Queue :");
+ print_tx_offloads(queue_offloads);
+
+ printf("\n");
+ printf(" Per Port :");
+ print_tx_offloads(port_offloads);
+ printf("\n\n");
+}
+
+cmdline_parse_inst_t cmd_tx_offload_get_capa = {
+ .f = cmd_tx_offload_get_capa_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> tx_offload capabilities",
+ .tokens = {
+ (void *)&cmd_tx_offload_get_capa_show,
+ (void *)&cmd_tx_offload_get_capa_port,
+ (void *)&cmd_tx_offload_get_capa_port_id,
+ (void *)&cmd_tx_offload_get_capa_tx_offload,
+ (void *)&cmd_tx_offload_get_capa_capabilities,
+ NULL,
+ }
+};
+
+/* Get Tx offloads configuration */
+struct cmd_tx_offload_get_configuration_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t tx_offload;
+ cmdline_fixed_string_t configuration;
+};
+
+cmdline_parse_token_string_t cmd_tx_offload_get_configuration_show =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_tx_offload_get_configuration_result,
+ show, "show");
+cmdline_parse_token_string_t cmd_tx_offload_get_configuration_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_tx_offload_get_configuration_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_tx_offload_get_configuration_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_tx_offload_get_configuration_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_tx_offload_get_configuration_tx_offload =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_tx_offload_get_configuration_result,
+ tx_offload, "tx_offload");
+cmdline_parse_token_string_t cmd_tx_offload_get_configuration_configuration =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_tx_offload_get_configuration_result,
+ configuration, "configuration");
+
+static void
+cmd_tx_offload_get_configuration_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_tx_offload_get_configuration_result *res = parsed_result;
+ struct rte_eth_dev_info dev_info;
+ portid_t port_id = res->port_id;
+ struct rte_port *port = &ports[port_id];
+ uint64_t port_offloads;
+ uint64_t queue_offloads;
+ uint16_t nb_tx_queues;
+ int q;
+ int ret;
+
+ printf("Tx Offloading Configuration of port %d :\n", port_id);
+
+ port_offloads = port->dev_conf.txmode.offloads;
+ printf(" Port :");
+ print_tx_offloads(port_offloads);
+ printf("\n");
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ nb_tx_queues = dev_info.nb_tx_queues;
+ for (q = 0; q < nb_tx_queues; q++) {
+ queue_offloads = port->tx_conf[q].offloads;
+ printf(" Queue[%2d] :", q);
+ print_tx_offloads(queue_offloads);
+ printf("\n");
+ }
+ printf("\n");
+}
+
+cmdline_parse_inst_t cmd_tx_offload_get_configuration = {
+ .f = cmd_tx_offload_get_configuration_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> tx_offload configuration",
+ .tokens = {
+ (void *)&cmd_tx_offload_get_configuration_show,
+ (void *)&cmd_tx_offload_get_configuration_port,
+ (void *)&cmd_tx_offload_get_configuration_port_id,
+ (void *)&cmd_tx_offload_get_configuration_tx_offload,
+ (void *)&cmd_tx_offload_get_configuration_configuration,
+ NULL,
+ }
+};
+
+/* Enable/Disable a per port offloading */
+struct cmd_config_per_port_tx_offload_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t config;
+ portid_t port_id;
+ cmdline_fixed_string_t tx_offload;
+ cmdline_fixed_string_t offload;
+ cmdline_fixed_string_t on_off;
+};
+
+cmdline_parse_token_string_t cmd_config_per_port_tx_offload_result_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_port_tx_offload_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_config_per_port_tx_offload_result_config =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_port_tx_offload_result,
+ config, "config");
+cmdline_parse_token_num_t cmd_config_per_port_tx_offload_result_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_per_port_tx_offload_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_config_per_port_tx_offload_result_tx_offload =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_port_tx_offload_result,
+ tx_offload, "tx_offload");
+cmdline_parse_token_string_t cmd_config_per_port_tx_offload_result_offload =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_port_tx_offload_result,
+ offload, "vlan_insert#ipv4_cksum#udp_cksum#tcp_cksum#"
+ "sctp_cksum#tcp_tso#udp_tso#outer_ipv4_cksum#"
+ "qinq_insert#vxlan_tnl_tso#gre_tnl_tso#"
+ "ipip_tnl_tso#geneve_tnl_tso#macsec_insert#"
+ "mt_lockfree#multi_segs#mbuf_fast_free#security");
+cmdline_parse_token_string_t cmd_config_per_port_tx_offload_result_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_port_tx_offload_result,
+ on_off, "on#off");
+
+static uint64_t
+search_tx_offload(const char *name)
+{
+ uint64_t single_offload;
+ const char *single_name;
+ int found = 0;
+ unsigned int bit;
+
+ single_offload = 1;
+ for (bit = 0; bit < sizeof(single_offload) * CHAR_BIT; bit++) {
+ single_name = rte_eth_dev_tx_offload_name(single_offload);
+ if (single_name == NULL)
+ break;
+ if (!strcasecmp(single_name, name)) {
+ found = 1;
+ break;
+ } else if (!strcasecmp(single_name, "UNKNOWN"))
+ break;
+ single_offload <<= 1;
+ }
+
+ if (found)
+ return single_offload;
+
+ return 0;
+}
+
+static void
+cmd_config_per_port_tx_offload_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_per_port_tx_offload_result *res = parsed_result;
+ portid_t port_id = res->port_id;
+ struct rte_eth_dev_info dev_info;
+ struct rte_port *port = &ports[port_id];
+ uint64_t single_offload;
+ uint16_t nb_tx_queues;
+ int q;
+ int ret;
+
+ if (port->port_status != RTE_PORT_STOPPED) {
+ printf("Error: Can't config offload when Port %d "
+ "is not stopped\n", port_id);
+ return;
+ }
+
+ single_offload = search_tx_offload(res->offload);
+ if (single_offload == 0) {
+ printf("Unknown offload name: %s\n", res->offload);
+ return;
+ }
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ nb_tx_queues = dev_info.nb_tx_queues;
+ if (!strcmp(res->on_off, "on")) {
+ port->dev_conf.txmode.offloads |= single_offload;
+ for (q = 0; q < nb_tx_queues; q++)
+ port->tx_conf[q].offloads |= single_offload;
+ } else {
+ port->dev_conf.txmode.offloads &= ~single_offload;
+ for (q = 0; q < nb_tx_queues; q++)
+ port->tx_conf[q].offloads &= ~single_offload;
+ }
+
+ cmd_reconfig_device_queue(port_id, 1, 1);
+}
+
+cmdline_parse_inst_t cmd_config_per_port_tx_offload = {
+ .f = cmd_config_per_port_tx_offload_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> tx_offload "
+ "vlan_insert|ipv4_cksum|udp_cksum|tcp_cksum|"
+ "sctp_cksum|tcp_tso|udp_tso|outer_ipv4_cksum|"
+ "qinq_insert|vxlan_tnl_tso|gre_tnl_tso|"
+ "ipip_tnl_tso|geneve_tnl_tso|macsec_insert|"
+ "mt_lockfree|multi_segs|mbuf_fast_free|security on|off",
+ .tokens = {
+ (void *)&cmd_config_per_port_tx_offload_result_port,
+ (void *)&cmd_config_per_port_tx_offload_result_config,
+ (void *)&cmd_config_per_port_tx_offload_result_port_id,
+ (void *)&cmd_config_per_port_tx_offload_result_tx_offload,
+ (void *)&cmd_config_per_port_tx_offload_result_offload,
+ (void *)&cmd_config_per_port_tx_offload_result_on_off,
+ NULL,
+ }
+};
+
+/* Enable/Disable a per queue offloading */
+struct cmd_config_per_queue_tx_offload_result {
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t txq;
+ uint16_t queue_id;
+ cmdline_fixed_string_t tx_offload;
+ cmdline_fixed_string_t offload;
+ cmdline_fixed_string_t on_off;
+};
+
+cmdline_parse_token_string_t cmd_config_per_queue_tx_offload_result_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_queue_tx_offload_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_config_per_queue_tx_offload_result_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_per_queue_tx_offload_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_config_per_queue_tx_offload_result_txq =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_queue_tx_offload_result,
+ txq, "txq");
+cmdline_parse_token_num_t cmd_config_per_queue_tx_offload_result_queue_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_per_queue_tx_offload_result,
+ queue_id, UINT16);
+cmdline_parse_token_string_t cmd_config_per_queue_tx_offload_result_txoffload =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_queue_tx_offload_result,
+ tx_offload, "tx_offload");
+cmdline_parse_token_string_t cmd_config_per_queue_tx_offload_result_offload =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_queue_tx_offload_result,
+ offload, "vlan_insert#ipv4_cksum#udp_cksum#tcp_cksum#"
+ "sctp_cksum#tcp_tso#udp_tso#outer_ipv4_cksum#"
+ "qinq_insert#vxlan_tnl_tso#gre_tnl_tso#"
+ "ipip_tnl_tso#geneve_tnl_tso#macsec_insert#"
+ "mt_lockfree#multi_segs#mbuf_fast_free#security");
+cmdline_parse_token_string_t cmd_config_per_queue_tx_offload_result_on_off =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_per_queue_tx_offload_result,
+ on_off, "on#off");
+
+static void
+cmd_config_per_queue_tx_offload_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_per_queue_tx_offload_result *res = parsed_result;
+ struct rte_eth_dev_info dev_info;
+ portid_t port_id = res->port_id;
+ uint16_t queue_id = res->queue_id;
+ struct rte_port *port = &ports[port_id];
+ uint64_t single_offload;
+ int ret;
+
+ if (port->port_status != RTE_PORT_STOPPED) {
+ printf("Error: Can't config offload when Port %d "
+ "is not stopped\n", port_id);
+ return;
+ }
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if (queue_id >= dev_info.nb_tx_queues) {
+ printf("Error: input queue_id should be 0 ... "
+ "%d\n", dev_info.nb_tx_queues - 1);
+ return;
+ }
+
+ single_offload = search_tx_offload(res->offload);
+ if (single_offload == 0) {
+ printf("Unknown offload name: %s\n", res->offload);
+ return;
+ }
+
+ if (!strcmp(res->on_off, "on"))
+ port->tx_conf[queue_id].offloads |= single_offload;
+ else
+ port->tx_conf[queue_id].offloads &= ~single_offload;
+
+ cmd_reconfig_device_queue(port_id, 1, 1);
+}
+
+cmdline_parse_inst_t cmd_config_per_queue_tx_offload = {
+ .f = cmd_config_per_queue_tx_offload_parsed,
+ .data = NULL,
+ .help_str = "port <port_id> txq <queue_id> tx_offload "
+ "vlan_insert|ipv4_cksum|udp_cksum|tcp_cksum|"
+ "sctp_cksum|tcp_tso|udp_tso|outer_ipv4_cksum|"
+ "qinq_insert|vxlan_tnl_tso|gre_tnl_tso|"
+ "ipip_tnl_tso|geneve_tnl_tso|macsec_insert|"
+ "mt_lockfree|multi_segs|mbuf_fast_free|security "
+ "on|off",
+ .tokens = {
+ (void *)&cmd_config_per_queue_tx_offload_result_port,
+ (void *)&cmd_config_per_queue_tx_offload_result_port_id,
+ (void *)&cmd_config_per_queue_tx_offload_result_txq,
+ (void *)&cmd_config_per_queue_tx_offload_result_queue_id,
+ (void *)&cmd_config_per_queue_tx_offload_result_txoffload,
+ (void *)&cmd_config_per_queue_tx_offload_result_offload,
+ (void *)&cmd_config_per_queue_tx_offload_result_on_off,
+ NULL,
+ }
+};
+
+/* *** configure tx_metadata for specific port *** */
+struct cmd_config_tx_metadata_specific_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ uint16_t port_id;
+ cmdline_fixed_string_t item;
+ uint32_t value;
+};
+
+static void
+cmd_config_tx_metadata_specific_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_tx_metadata_specific_result *res = parsed_result;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+ ports[res->port_id].tx_metadata = res->value;
+ /* Add/remove callback to insert valid metadata in every Tx packet. */
+ if (ports[res->port_id].tx_metadata)
+ add_tx_md_callback(res->port_id);
+ else
+ remove_tx_md_callback(res->port_id);
+ rte_flow_dynf_metadata_register();
+}
+
+cmdline_parse_token_string_t cmd_config_tx_metadata_specific_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_tx_metadata_specific_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_config_tx_metadata_specific_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_tx_metadata_specific_result,
+ keyword, "config");
+cmdline_parse_token_num_t cmd_config_tx_metadata_specific_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_tx_metadata_specific_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_config_tx_metadata_specific_item =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_tx_metadata_specific_result,
+ item, "tx_metadata");
+cmdline_parse_token_num_t cmd_config_tx_metadata_specific_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_tx_metadata_specific_result,
+ value, UINT32);
+
+cmdline_parse_inst_t cmd_config_tx_metadata_specific = {
+ .f = cmd_config_tx_metadata_specific_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> tx_metadata <value>",
+ .tokens = {
+ (void *)&cmd_config_tx_metadata_specific_port,
+ (void *)&cmd_config_tx_metadata_specific_keyword,
+ (void *)&cmd_config_tx_metadata_specific_id,
+ (void *)&cmd_config_tx_metadata_specific_item,
+ (void *)&cmd_config_tx_metadata_specific_value,
+ NULL,
+ },
+};
+
+/* *** set dynf *** */
+struct cmd_config_tx_dynf_specific_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ uint16_t port_id;
+ cmdline_fixed_string_t item;
+ cmdline_fixed_string_t name;
+ cmdline_fixed_string_t value;
+};
+
+static void
+cmd_config_dynf_specific_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_tx_dynf_specific_result *res = parsed_result;
+ struct rte_mbuf_dynflag desc_flag;
+ int flag;
+ uint64_t old_port_flags;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+ flag = rte_mbuf_dynflag_lookup(res->name, NULL);
+ if (flag <= 0) {
+ if (strlcpy(desc_flag.name, res->name,
+ RTE_MBUF_DYN_NAMESIZE) >= RTE_MBUF_DYN_NAMESIZE) {
+ printf("Flag name too long\n");
+ return;
+ }
+ desc_flag.flags = 0;
+ flag = rte_mbuf_dynflag_register(&desc_flag);
+ if (flag < 0) {
+ printf("Can't register flag\n");
+ return;
+ }
+ strcpy(dynf_names[flag], desc_flag.name);
+ }
+ old_port_flags = ports[res->port_id].mbuf_dynf;
+ if (!strcmp(res->value, "set")) {
+ ports[res->port_id].mbuf_dynf |= 1UL << flag;
+ if (old_port_flags == 0)
+ add_tx_dynf_callback(res->port_id);
+ } else {
+ ports[res->port_id].mbuf_dynf &= ~(1UL << flag);
+ if (ports[res->port_id].mbuf_dynf == 0)
+ remove_tx_dynf_callback(res->port_id);
+ }
+}
+
+cmdline_parse_token_string_t cmd_config_tx_dynf_specific_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_tx_dynf_specific_result,
+ keyword, "port");
+cmdline_parse_token_string_t cmd_config_tx_dynf_specific_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_tx_dynf_specific_result,
+ keyword, "config");
+cmdline_parse_token_num_t cmd_config_tx_dynf_specific_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_tx_dynf_specific_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_config_tx_dynf_specific_item =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_tx_dynf_specific_result,
+ item, "dynf");
+cmdline_parse_token_string_t cmd_config_tx_dynf_specific_name =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_tx_dynf_specific_result,
+ name, NULL);
+cmdline_parse_token_string_t cmd_config_tx_dynf_specific_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_tx_dynf_specific_result,
+ value, "set#clear");
+
+cmdline_parse_inst_t cmd_config_tx_dynf_specific = {
+ .f = cmd_config_dynf_specific_parsed,
+ .data = NULL,
+ .help_str = "port config <port id> dynf <name> set|clear",
+ .tokens = {
+ (void *)&cmd_config_tx_dynf_specific_port,
+ (void *)&cmd_config_tx_dynf_specific_keyword,
+ (void *)&cmd_config_tx_dynf_specific_port_id,
+ (void *)&cmd_config_tx_dynf_specific_item,
+ (void *)&cmd_config_tx_dynf_specific_name,
+ (void *)&cmd_config_tx_dynf_specific_value,
+ NULL,
+ },
+};
+
+/* *** display tx_metadata per port configuration *** */
+struct cmd_show_tx_metadata_result {
+ cmdline_fixed_string_t cmd_show;
+ cmdline_fixed_string_t cmd_port;
+ cmdline_fixed_string_t cmd_keyword;
+ portid_t cmd_pid;
+};
+
+static void
+cmd_show_tx_metadata_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_tx_metadata_result *res = parsed_result;
+
+ if (!rte_eth_dev_is_valid_port(res->cmd_pid)) {
+ printf("invalid port id %u\n", res->cmd_pid);
+ return;
+ }
+ if (!strcmp(res->cmd_keyword, "tx_metadata")) {
+ printf("Port %u tx_metadata: %u\n", res->cmd_pid,
+ ports[res->cmd_pid].tx_metadata);
+ }
+}
+
+cmdline_parse_token_string_t cmd_show_tx_metadata_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_tx_metadata_result,
+ cmd_show, "show");
+cmdline_parse_token_string_t cmd_show_tx_metadata_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_tx_metadata_result,
+ cmd_port, "port");
+cmdline_parse_token_num_t cmd_show_tx_metadata_pid =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_tx_metadata_result,
+ cmd_pid, UINT16);
+cmdline_parse_token_string_t cmd_show_tx_metadata_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_tx_metadata_result,
+ cmd_keyword, "tx_metadata");
+
+cmdline_parse_inst_t cmd_show_tx_metadata = {
+ .f = cmd_show_tx_metadata_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> tx_metadata",
+ .tokens = {
+ (void *)&cmd_show_tx_metadata_show,
+ (void *)&cmd_show_tx_metadata_port,
+ (void *)&cmd_show_tx_metadata_pid,
+ (void *)&cmd_show_tx_metadata_keyword,
+ NULL,
+ },
+};
+
+/* show port supported ptypes */
+
+/* Common result structure for show port ptypes */
+struct cmd_show_port_supported_ptypes_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t ptypes;
+};
+
+/* Common CLI fields for show port ptypes */
+cmdline_parse_token_string_t cmd_show_port_supported_ptypes_show =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_show_port_supported_ptypes_result,
+ show, "show");
+cmdline_parse_token_string_t cmd_show_port_supported_ptypes_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_show_port_supported_ptypes_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_show_port_supported_ptypes_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_show_port_supported_ptypes_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_show_port_supported_ptypes_ptypes =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_show_port_supported_ptypes_result,
+ ptypes, "ptypes");
+
+static void
+cmd_show_port_supported_ptypes_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+#define RSVD_PTYPE_MASK 0xf0000000
+#define MAX_PTYPES_PER_LAYER 16
+#define LTYPE_NAMESIZE 32
+#define PTYPE_NAMESIZE 256
+ struct cmd_show_port_supported_ptypes_result *res = parsed_result;
+ char buf[PTYPE_NAMESIZE], ltype[LTYPE_NAMESIZE];
+ uint32_t ptype_mask = RTE_PTYPE_L2_MASK;
+ uint32_t ptypes[MAX_PTYPES_PER_LAYER];
+ uint16_t port_id = res->port_id;
+ int ret, i;
+
+ ret = rte_eth_dev_get_supported_ptypes(port_id, ptype_mask, NULL, 0);
+ if (ret < 0)
+ return;
+
+ while (ptype_mask != RSVD_PTYPE_MASK) {
+
+ switch (ptype_mask) {
+ case RTE_PTYPE_L2_MASK:
+ strlcpy(ltype, "L2", sizeof(ltype));
+ break;
+ case RTE_PTYPE_L3_MASK:
+ strlcpy(ltype, "L3", sizeof(ltype));
+ break;
+ case RTE_PTYPE_L4_MASK:
+ strlcpy(ltype, "L4", sizeof(ltype));
+ break;
+ case RTE_PTYPE_TUNNEL_MASK:
+ strlcpy(ltype, "Tunnel", sizeof(ltype));
+ break;
+ case RTE_PTYPE_INNER_L2_MASK:
+ strlcpy(ltype, "Inner L2", sizeof(ltype));
+ break;
+ case RTE_PTYPE_INNER_L3_MASK:
+ strlcpy(ltype, "Inner L3", sizeof(ltype));
+ break;
+ case RTE_PTYPE_INNER_L4_MASK:
+ strlcpy(ltype, "Inner L4", sizeof(ltype));
+ break;
+ default:
+ return;
+ }
+
+ ret = rte_eth_dev_get_supported_ptypes(res->port_id,
+ ptype_mask, ptypes,
+ MAX_PTYPES_PER_LAYER);
+
+ if (ret > 0)
+ printf("Supported %s ptypes:\n", ltype);
+ else
+ printf("%s ptypes unsupported\n", ltype);
+
+ for (i = 0; i < ret; ++i) {
+ rte_get_ptype_name(ptypes[i], buf, sizeof(buf));
+ printf("%s\n", buf);
+ }
+
+ ptype_mask <<= 4;
+ }
+}
+
+cmdline_parse_inst_t cmd_show_port_supported_ptypes = {
+ .f = cmd_show_port_supported_ptypes_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> ptypes",
+ .tokens = {
+ (void *)&cmd_show_port_supported_ptypes_show,
+ (void *)&cmd_show_port_supported_ptypes_port,
+ (void *)&cmd_show_port_supported_ptypes_port_id,
+ (void *)&cmd_show_port_supported_ptypes_ptypes,
+ NULL,
+ },
+};
+
+/* *** display rx/tx descriptor status *** */
+struct cmd_show_rx_tx_desc_status_result {
+ cmdline_fixed_string_t cmd_show;
+ cmdline_fixed_string_t cmd_port;
+ cmdline_fixed_string_t cmd_keyword;
+ cmdline_fixed_string_t cmd_desc;
+ cmdline_fixed_string_t cmd_status;
+ portid_t cmd_pid;
+ portid_t cmd_qid;
+ portid_t cmd_did;
+};
+
+static void
+cmd_show_rx_tx_desc_status_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_rx_tx_desc_status_result *res = parsed_result;
+ int rc;
+
+ if (!rte_eth_dev_is_valid_port(res->cmd_pid)) {
+ printf("invalid port id %u\n", res->cmd_pid);
+ return;
+ }
+
+ if (!strcmp(res->cmd_keyword, "rxq")) {
+ rc = rte_eth_rx_descriptor_status(res->cmd_pid, res->cmd_qid,
+ res->cmd_did);
+ if (rc < 0) {
+ printf("Invalid queueid = %d\n", res->cmd_qid);
+ return;
+ }
+ if (rc == RTE_ETH_RX_DESC_AVAIL)
+ printf("Desc status = AVAILABLE\n");
+ else if (rc == RTE_ETH_RX_DESC_DONE)
+ printf("Desc status = DONE\n");
+ else
+ printf("Desc status = UNAVAILABLE\n");
+ } else if (!strcmp(res->cmd_keyword, "txq")) {
+ rc = rte_eth_tx_descriptor_status(res->cmd_pid, res->cmd_qid,
+ res->cmd_did);
+ if (rc < 0) {
+ printf("Invalid queueid = %d\n", res->cmd_qid);
+ return;
+ }
+ if (rc == RTE_ETH_TX_DESC_FULL)
+ printf("Desc status = FULL\n");
+ else if (rc == RTE_ETH_TX_DESC_DONE)
+ printf("Desc status = DONE\n");
+ else
+ printf("Desc status = UNAVAILABLE\n");
+ }
+}
+
+cmdline_parse_token_string_t cmd_show_rx_tx_desc_status_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_rx_tx_desc_status_result,
+ cmd_show, "show");
+cmdline_parse_token_string_t cmd_show_rx_tx_desc_status_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_rx_tx_desc_status_result,
+ cmd_port, "port");
+cmdline_parse_token_num_t cmd_show_rx_tx_desc_status_pid =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_rx_tx_desc_status_result,
+ cmd_pid, UINT16);
+cmdline_parse_token_string_t cmd_show_rx_tx_desc_status_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_rx_tx_desc_status_result,
+ cmd_keyword, "rxq#txq");
+cmdline_parse_token_num_t cmd_show_rx_tx_desc_status_qid =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_rx_tx_desc_status_result,
+ cmd_qid, UINT16);
+cmdline_parse_token_string_t cmd_show_rx_tx_desc_status_desc =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_rx_tx_desc_status_result,
+ cmd_desc, "desc");
+cmdline_parse_token_num_t cmd_show_rx_tx_desc_status_did =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_rx_tx_desc_status_result,
+ cmd_did, UINT16);
+cmdline_parse_token_string_t cmd_show_rx_tx_desc_status_status =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_rx_tx_desc_status_result,
+ cmd_status, "status");
+cmdline_parse_inst_t cmd_show_rx_tx_desc_status = {
+ .f = cmd_show_rx_tx_desc_status_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> rxq|txq <queue_id> desc <desc_id> "
+ "status",
+ .tokens = {
+ (void *)&cmd_show_rx_tx_desc_status_show,
+ (void *)&cmd_show_rx_tx_desc_status_port,
+ (void *)&cmd_show_rx_tx_desc_status_pid,
+ (void *)&cmd_show_rx_tx_desc_status_keyword,
+ (void *)&cmd_show_rx_tx_desc_status_qid,
+ (void *)&cmd_show_rx_tx_desc_status_desc,
+ (void *)&cmd_show_rx_tx_desc_status_did,
+ (void *)&cmd_show_rx_tx_desc_status_status,
+ NULL,
+ },
+};
+
+/* Common result structure for set port ptypes */
+struct cmd_set_port_ptypes_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ portid_t port_id;
+ cmdline_fixed_string_t ptype_mask;
+ uint32_t mask;
+};
+
+/* Common CLI fields for set port ptypes */
+cmdline_parse_token_string_t cmd_set_port_ptypes_set =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_port_ptypes_result,
+ set, "set");
+cmdline_parse_token_string_t cmd_set_port_ptypes_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_port_ptypes_result,
+ port, "port");
+cmdline_parse_token_num_t cmd_set_port_ptypes_port_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_set_port_ptypes_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_set_port_ptypes_mask_str =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_set_port_ptypes_result,
+ ptype_mask, "ptype_mask");
+cmdline_parse_token_num_t cmd_set_port_ptypes_mask_u32 =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_set_port_ptypes_result,
+ mask, UINT32);
+
+static void
+cmd_set_port_ptypes_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_port_ptypes_result *res = parsed_result;
+#define PTYPE_NAMESIZE 256
+ char ptype_name[PTYPE_NAMESIZE];
+ uint16_t port_id = res->port_id;
+ uint32_t ptype_mask = res->mask;
+ int ret, i;
+
+ ret = rte_eth_dev_get_supported_ptypes(port_id, RTE_PTYPE_ALL_MASK,
+ NULL, 0);
+ if (ret <= 0) {
+ printf("Port %d doesn't support any ptypes.\n", port_id);
+ return;
+ }
+
+ uint32_t ptypes[ret];
+
+ ret = rte_eth_dev_set_ptypes(port_id, ptype_mask, ptypes, ret);
+ if (ret < 0) {
+ printf("Unable to set requested ptypes for Port %d\n", port_id);
+ return;
+ }
+
+ printf("Successfully set following ptypes for Port %d\n", port_id);
+ for (i = 0; i < ret && ptypes[i] != RTE_PTYPE_UNKNOWN; i++) {
+ rte_get_ptype_name(ptypes[i], ptype_name, sizeof(ptype_name));
+ printf("%s\n", ptype_name);
+ }
+
+ clear_ptypes = false;
+}
+
+cmdline_parse_inst_t cmd_set_port_ptypes = {
+ .f = cmd_set_port_ptypes_parsed,
+ .data = NULL,
+ .help_str = "set port <port_id> ptype_mask <mask>",
+ .tokens = {
+ (void *)&cmd_set_port_ptypes_set,
+ (void *)&cmd_set_port_ptypes_port,
+ (void *)&cmd_set_port_ptypes_port_id,
+ (void *)&cmd_set_port_ptypes_mask_str,
+ (void *)&cmd_set_port_ptypes_mask_u32,
+ NULL,
+ },
+};
+
+/* *** display mac addresses added to a port *** */
+struct cmd_showport_macs_result {
+ cmdline_fixed_string_t cmd_show;
+ cmdline_fixed_string_t cmd_port;
+ cmdline_fixed_string_t cmd_keyword;
+ portid_t cmd_pid;
+};
+
+static void
+cmd_showport_macs_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_showport_macs_result *res = parsed_result;
+
+ if (port_id_is_invalid(res->cmd_pid, ENABLED_WARN))
+ return;
+
+ if (!strcmp(res->cmd_keyword, "macs"))
+ show_macs(res->cmd_pid);
+ else if (!strcmp(res->cmd_keyword, "mcast_macs"))
+ show_mcast_macs(res->cmd_pid);
+}
+
+cmdline_parse_token_string_t cmd_showport_macs_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_macs_result,
+ cmd_show, "show");
+cmdline_parse_token_string_t cmd_showport_macs_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_macs_result,
+ cmd_port, "port");
+cmdline_parse_token_num_t cmd_showport_macs_pid =
+ TOKEN_NUM_INITIALIZER(struct cmd_showport_macs_result,
+ cmd_pid, UINT16);
+cmdline_parse_token_string_t cmd_showport_macs_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_showport_macs_result,
+ cmd_keyword, "macs#mcast_macs");
+
+cmdline_parse_inst_t cmd_showport_macs = {
+ .f = cmd_showport_macs_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> macs|mcast_macs",
+ .tokens = {
+ (void *)&cmd_showport_macs_show,
+ (void *)&cmd_showport_macs_port,
+ (void *)&cmd_showport_macs_pid,
+ (void *)&cmd_showport_macs_keyword,
+ NULL,
+ },
+};
+
+/* ******************************************************************************** */
+
+/* list of instructions */
+cmdline_parse_ctx_t main_ctx[] = {
+ (cmdline_parse_inst_t *)&cmd_help_brief,
+ (cmdline_parse_inst_t *)&cmd_help_long,
+ (cmdline_parse_inst_t *)&cmd_quit,
+ (cmdline_parse_inst_t *)&cmd_load_from_file,
+ (cmdline_parse_inst_t *)&cmd_showport,
+ (cmdline_parse_inst_t *)&cmd_showqueue,
+ (cmdline_parse_inst_t *)&cmd_showportall,
+ (cmdline_parse_inst_t *)&cmd_showdevice,
+ (cmdline_parse_inst_t *)&cmd_showcfg,
+ (cmdline_parse_inst_t *)&cmd_showfwdall,
+ (cmdline_parse_inst_t *)&cmd_start,
+ (cmdline_parse_inst_t *)&cmd_start_tx_first,
+ (cmdline_parse_inst_t *)&cmd_start_tx_first_n,
+ (cmdline_parse_inst_t *)&cmd_set_link_up,
+ (cmdline_parse_inst_t *)&cmd_set_link_down,
+ (cmdline_parse_inst_t *)&cmd_reset,
+ (cmdline_parse_inst_t *)&cmd_set_numbers,
+ (cmdline_parse_inst_t *)&cmd_set_log,
+ (cmdline_parse_inst_t *)&cmd_set_txpkts,
+ (cmdline_parse_inst_t *)&cmd_set_txsplit,
+ (cmdline_parse_inst_t *)&cmd_set_fwd_list,
+ (cmdline_parse_inst_t *)&cmd_set_fwd_mask,
+ (cmdline_parse_inst_t *)&cmd_set_fwd_mode,
+ (cmdline_parse_inst_t *)&cmd_set_fwd_retry_mode,
+ (cmdline_parse_inst_t *)&cmd_set_burst_tx_retry,
+ (cmdline_parse_inst_t *)&cmd_set_promisc_mode_one,
+ (cmdline_parse_inst_t *)&cmd_set_promisc_mode_all,
+ (cmdline_parse_inst_t *)&cmd_set_allmulti_mode_one,
+ (cmdline_parse_inst_t *)&cmd_set_allmulti_mode_all,
+ (cmdline_parse_inst_t *)&cmd_set_flush_rx,
+ (cmdline_parse_inst_t *)&cmd_set_link_check,
+ (cmdline_parse_inst_t *)&cmd_set_bypass_mode,
+ (cmdline_parse_inst_t *)&cmd_set_bypass_event,
+ (cmdline_parse_inst_t *)&cmd_set_bypass_timeout,
+ (cmdline_parse_inst_t *)&cmd_show_bypass_config,
+#ifdef RTE_LIBRTE_PMD_BOND
+ (cmdline_parse_inst_t *) &cmd_set_bonding_mode,
+ (cmdline_parse_inst_t *) &cmd_show_bonding_config,
+ (cmdline_parse_inst_t *) &cmd_set_bonding_primary,
+ (cmdline_parse_inst_t *) &cmd_add_bonding_slave,
+ (cmdline_parse_inst_t *) &cmd_remove_bonding_slave,
+ (cmdline_parse_inst_t *) &cmd_create_bonded_device,
+ (cmdline_parse_inst_t *) &cmd_set_bond_mac_addr,
+ (cmdline_parse_inst_t *) &cmd_set_balance_xmit_policy,
+ (cmdline_parse_inst_t *) &cmd_set_bond_mon_period,
+ (cmdline_parse_inst_t *) &cmd_set_lacp_dedicated_queues,
+ (cmdline_parse_inst_t *) &cmd_set_bonding_agg_mode_policy,
+#endif
+ (cmdline_parse_inst_t *)&cmd_vlan_offload,
+ (cmdline_parse_inst_t *)&cmd_vlan_tpid,
+ (cmdline_parse_inst_t *)&cmd_rx_vlan_filter_all,
+ (cmdline_parse_inst_t *)&cmd_rx_vlan_filter,
+ (cmdline_parse_inst_t *)&cmd_tx_vlan_set,
+ (cmdline_parse_inst_t *)&cmd_tx_vlan_set_qinq,
+ (cmdline_parse_inst_t *)&cmd_tx_vlan_reset,
+ (cmdline_parse_inst_t *)&cmd_tx_vlan_set_pvid,
+ (cmdline_parse_inst_t *)&cmd_csum_set,
+ (cmdline_parse_inst_t *)&cmd_csum_show,
+ (cmdline_parse_inst_t *)&cmd_csum_tunnel,
+ (cmdline_parse_inst_t *)&cmd_tso_set,
+ (cmdline_parse_inst_t *)&cmd_tso_show,
+ (cmdline_parse_inst_t *)&cmd_tunnel_tso_set,
+ (cmdline_parse_inst_t *)&cmd_tunnel_tso_show,
+ (cmdline_parse_inst_t *)&cmd_gro_enable,
+ (cmdline_parse_inst_t *)&cmd_gro_flush,
+ (cmdline_parse_inst_t *)&cmd_gro_show,
+ (cmdline_parse_inst_t *)&cmd_gso_enable,
+ (cmdline_parse_inst_t *)&cmd_gso_size,
+ (cmdline_parse_inst_t *)&cmd_gso_show,
+ (cmdline_parse_inst_t *)&cmd_link_flow_control_set,
+ (cmdline_parse_inst_t *)&cmd_link_flow_control_set_rx,
+ (cmdline_parse_inst_t *)&cmd_link_flow_control_set_tx,
+ (cmdline_parse_inst_t *)&cmd_link_flow_control_set_hw,
+ (cmdline_parse_inst_t *)&cmd_link_flow_control_set_lw,
+ (cmdline_parse_inst_t *)&cmd_link_flow_control_set_pt,
+ (cmdline_parse_inst_t *)&cmd_link_flow_control_set_xon,
+ (cmdline_parse_inst_t *)&cmd_link_flow_control_set_macfwd,
+ (cmdline_parse_inst_t *)&cmd_link_flow_control_set_autoneg,
+ (cmdline_parse_inst_t *)&cmd_priority_flow_control_set,
+ (cmdline_parse_inst_t *)&cmd_config_dcb,
+ (cmdline_parse_inst_t *)&cmd_read_reg,
+ (cmdline_parse_inst_t *)&cmd_read_reg_bit_field,
+ (cmdline_parse_inst_t *)&cmd_read_reg_bit,
+ (cmdline_parse_inst_t *)&cmd_write_reg,
+ (cmdline_parse_inst_t *)&cmd_write_reg_bit_field,
+ (cmdline_parse_inst_t *)&cmd_write_reg_bit,
+ (cmdline_parse_inst_t *)&cmd_read_rxd_txd,
+ (cmdline_parse_inst_t *)&cmd_stop,
+ (cmdline_parse_inst_t *)&cmd_mac_addr,
+ (cmdline_parse_inst_t *)&cmd_set_fwd_eth_peer,
+ (cmdline_parse_inst_t *)&cmd_set_qmap,
+ (cmdline_parse_inst_t *)&cmd_set_xstats_hide_zero,
+ (cmdline_parse_inst_t *)&cmd_operate_port,
+ (cmdline_parse_inst_t *)&cmd_operate_specific_port,
+ (cmdline_parse_inst_t *)&cmd_operate_attach_port,
+ (cmdline_parse_inst_t *)&cmd_operate_detach_port,
+ (cmdline_parse_inst_t *)&cmd_operate_detach_device,
+ (cmdline_parse_inst_t *)&cmd_set_port_setup_on,
+ (cmdline_parse_inst_t *)&cmd_config_speed_all,
+ (cmdline_parse_inst_t *)&cmd_config_speed_specific,
+ (cmdline_parse_inst_t *)&cmd_config_loopback_all,
+ (cmdline_parse_inst_t *)&cmd_config_loopback_specific,
+ (cmdline_parse_inst_t *)&cmd_config_rx_tx,
+ (cmdline_parse_inst_t *)&cmd_config_mtu,
+ (cmdline_parse_inst_t *)&cmd_config_max_pkt_len,
+ (cmdline_parse_inst_t *)&cmd_config_max_lro_pkt_size,
+ (cmdline_parse_inst_t *)&cmd_config_rx_mode_flag,
+ (cmdline_parse_inst_t *)&cmd_config_rss,
+ (cmdline_parse_inst_t *)&cmd_config_rxtx_ring_size,
+ (cmdline_parse_inst_t *)&cmd_config_rxtx_queue,
+ (cmdline_parse_inst_t *)&cmd_config_deferred_start_rxtx_queue,
+ (cmdline_parse_inst_t *)&cmd_setup_rxtx_queue,
+ (cmdline_parse_inst_t *)&cmd_config_rss_reta,
+ (cmdline_parse_inst_t *)&cmd_showport_reta,
+ (cmdline_parse_inst_t *)&cmd_showport_macs,
+ (cmdline_parse_inst_t *)&cmd_config_burst,
+ (cmdline_parse_inst_t *)&cmd_config_thresh,
+ (cmdline_parse_inst_t *)&cmd_config_threshold,
+ (cmdline_parse_inst_t *)&cmd_set_uc_hash_filter,
+ (cmdline_parse_inst_t *)&cmd_set_uc_all_hash_filter,
+ (cmdline_parse_inst_t *)&cmd_vf_mac_addr_filter,
+ (cmdline_parse_inst_t *)&cmd_set_vf_macvlan_filter,
+ (cmdline_parse_inst_t *)&cmd_queue_rate_limit,
+ (cmdline_parse_inst_t *)&cmd_tunnel_filter,
+ (cmdline_parse_inst_t *)&cmd_tunnel_udp_config,
+ (cmdline_parse_inst_t *)&cmd_global_config,
+ (cmdline_parse_inst_t *)&cmd_set_mirror_mask,
+ (cmdline_parse_inst_t *)&cmd_set_mirror_link,
+ (cmdline_parse_inst_t *)&cmd_reset_mirror_rule,
+ (cmdline_parse_inst_t *)&cmd_showport_rss_hash,
+ (cmdline_parse_inst_t *)&cmd_showport_rss_hash_key,
+ (cmdline_parse_inst_t *)&cmd_config_rss_hash_key,
+ (cmdline_parse_inst_t *)&cmd_dump,
+ (cmdline_parse_inst_t *)&cmd_dump_one,
+ (cmdline_parse_inst_t *)&cmd_ethertype_filter,
+ (cmdline_parse_inst_t *)&cmd_syn_filter,
+ (cmdline_parse_inst_t *)&cmd_2tuple_filter,
+ (cmdline_parse_inst_t *)&cmd_5tuple_filter,
+ (cmdline_parse_inst_t *)&cmd_flex_filter,
+ (cmdline_parse_inst_t *)&cmd_add_del_ip_flow_director,
+ (cmdline_parse_inst_t *)&cmd_add_del_udp_flow_director,
+ (cmdline_parse_inst_t *)&cmd_add_del_sctp_flow_director,
+ (cmdline_parse_inst_t *)&cmd_add_del_l2_flow_director,
+ (cmdline_parse_inst_t *)&cmd_add_del_mac_vlan_flow_director,
+ (cmdline_parse_inst_t *)&cmd_add_del_tunnel_flow_director,
+ (cmdline_parse_inst_t *)&cmd_add_del_raw_flow_director,
+ (cmdline_parse_inst_t *)&cmd_flush_flow_director,
+ (cmdline_parse_inst_t *)&cmd_set_flow_director_ip_mask,
+ (cmdline_parse_inst_t *)&cmd_set_flow_director_mac_vlan_mask,
+ (cmdline_parse_inst_t *)&cmd_set_flow_director_tunnel_mask,
+ (cmdline_parse_inst_t *)&cmd_set_flow_director_flex_mask,
+ (cmdline_parse_inst_t *)&cmd_set_flow_director_flex_payload,
+ (cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_port,
+ (cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_port,
+ (cmdline_parse_inst_t *)&cmd_get_hash_global_config,
+ (cmdline_parse_inst_t *)&cmd_set_hash_global_config,
+ (cmdline_parse_inst_t *)&cmd_set_hash_input_set,
+ (cmdline_parse_inst_t *)&cmd_set_fdir_input_set,
+ (cmdline_parse_inst_t *)&cmd_flow,
+ (cmdline_parse_inst_t *)&cmd_show_port_meter_cap,
+ (cmdline_parse_inst_t *)&cmd_add_port_meter_profile_srtcm,
+ (cmdline_parse_inst_t *)&cmd_add_port_meter_profile_trtcm,
+ (cmdline_parse_inst_t *)&cmd_del_port_meter_profile,
+ (cmdline_parse_inst_t *)&cmd_create_port_meter,
+ (cmdline_parse_inst_t *)&cmd_enable_port_meter,
+ (cmdline_parse_inst_t *)&cmd_disable_port_meter,
+ (cmdline_parse_inst_t *)&cmd_del_port_meter,
+ (cmdline_parse_inst_t *)&cmd_set_port_meter_profile,
+ (cmdline_parse_inst_t *)&cmd_set_port_meter_dscp_table,
+ (cmdline_parse_inst_t *)&cmd_set_port_meter_policer_action,
+ (cmdline_parse_inst_t *)&cmd_set_port_meter_stats_mask,
+ (cmdline_parse_inst_t *)&cmd_show_port_meter_stats,
+ (cmdline_parse_inst_t *)&cmd_mcast_addr,
+ (cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_all,
+ (cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_specific,
+ (cmdline_parse_inst_t *)&cmd_config_l2_tunnel_en_dis_all,
+ (cmdline_parse_inst_t *)&cmd_config_l2_tunnel_en_dis_specific,
+ (cmdline_parse_inst_t *)&cmd_config_e_tag_insertion_en,
+ (cmdline_parse_inst_t *)&cmd_config_e_tag_insertion_dis,
+ (cmdline_parse_inst_t *)&cmd_config_e_tag_stripping_en_dis,
+ (cmdline_parse_inst_t *)&cmd_config_e_tag_forwarding_en_dis,
+ (cmdline_parse_inst_t *)&cmd_config_e_tag_filter_add,
+ (cmdline_parse_inst_t *)&cmd_config_e_tag_filter_del,
+ (cmdline_parse_inst_t *)&cmd_set_vf_vlan_anti_spoof,
+ (cmdline_parse_inst_t *)&cmd_set_vf_mac_anti_spoof,
+ (cmdline_parse_inst_t *)&cmd_set_vf_vlan_stripq,
+ (cmdline_parse_inst_t *)&cmd_set_vf_vlan_insert,
+ (cmdline_parse_inst_t *)&cmd_set_tx_loopback,
+ (cmdline_parse_inst_t *)&cmd_set_all_queues_drop_en,
+ (cmdline_parse_inst_t *)&cmd_set_vf_split_drop_en,
+ (cmdline_parse_inst_t *)&cmd_set_macsec_offload_on,
+ (cmdline_parse_inst_t *)&cmd_set_macsec_offload_off,
+ (cmdline_parse_inst_t *)&cmd_set_macsec_sc,
+ (cmdline_parse_inst_t *)&cmd_set_macsec_sa,
+ (cmdline_parse_inst_t *)&cmd_set_vf_traffic,
+ (cmdline_parse_inst_t *)&cmd_set_vf_rxmode,
+ (cmdline_parse_inst_t *)&cmd_vf_rate_limit,
+ (cmdline_parse_inst_t *)&cmd_vf_rxvlan_filter,
+ (cmdline_parse_inst_t *)&cmd_set_vf_mac_addr,
+ (cmdline_parse_inst_t *)&cmd_set_vf_promisc,
+ (cmdline_parse_inst_t *)&cmd_set_vf_allmulti,
+ (cmdline_parse_inst_t *)&cmd_set_vf_broadcast,
+ (cmdline_parse_inst_t *)&cmd_set_vf_vlan_tag,
+ (cmdline_parse_inst_t *)&cmd_vf_max_bw,
+ (cmdline_parse_inst_t *)&cmd_vf_tc_min_bw,
+ (cmdline_parse_inst_t *)&cmd_vf_tc_max_bw,
+ (cmdline_parse_inst_t *)&cmd_strict_link_prio,
+ (cmdline_parse_inst_t *)&cmd_tc_min_bw,
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+ (cmdline_parse_inst_t *)&cmd_set_port_tm_hierarchy_default,
+#endif
+ (cmdline_parse_inst_t *)&cmd_set_vxlan,
+ (cmdline_parse_inst_t *)&cmd_set_vxlan_tos_ttl,
+ (cmdline_parse_inst_t *)&cmd_set_vxlan_with_vlan,
+ (cmdline_parse_inst_t *)&cmd_set_nvgre,
+ (cmdline_parse_inst_t *)&cmd_set_nvgre_with_vlan,
+ (cmdline_parse_inst_t *)&cmd_set_l2_encap,
+ (cmdline_parse_inst_t *)&cmd_set_l2_encap_with_vlan,
+ (cmdline_parse_inst_t *)&cmd_set_l2_decap,
+ (cmdline_parse_inst_t *)&cmd_set_l2_decap_with_vlan,
+ (cmdline_parse_inst_t *)&cmd_set_mplsogre_encap,
+ (cmdline_parse_inst_t *)&cmd_set_mplsogre_encap_with_vlan,
+ (cmdline_parse_inst_t *)&cmd_set_mplsogre_decap,
+ (cmdline_parse_inst_t *)&cmd_set_mplsogre_decap_with_vlan,
+ (cmdline_parse_inst_t *)&cmd_set_mplsoudp_encap,
+ (cmdline_parse_inst_t *)&cmd_set_mplsoudp_encap_with_vlan,
+ (cmdline_parse_inst_t *)&cmd_set_mplsoudp_decap,
+ (cmdline_parse_inst_t *)&cmd_set_mplsoudp_decap_with_vlan,
+ (cmdline_parse_inst_t *)&cmd_ddp_add,
+ (cmdline_parse_inst_t *)&cmd_ddp_del,
+ (cmdline_parse_inst_t *)&cmd_ddp_get_list,
+ (cmdline_parse_inst_t *)&cmd_ddp_get_info,
+ (cmdline_parse_inst_t *)&cmd_cfg_input_set,
+ (cmdline_parse_inst_t *)&cmd_clear_input_set,
+ (cmdline_parse_inst_t *)&cmd_show_vf_stats,
+ (cmdline_parse_inst_t *)&cmd_clear_vf_stats,
+ (cmdline_parse_inst_t *)&cmd_show_port_supported_ptypes,
+ (cmdline_parse_inst_t *)&cmd_set_port_ptypes,
+ (cmdline_parse_inst_t *)&cmd_ptype_mapping_get,
+ (cmdline_parse_inst_t *)&cmd_ptype_mapping_replace,
+ (cmdline_parse_inst_t *)&cmd_ptype_mapping_reset,
+ (cmdline_parse_inst_t *)&cmd_ptype_mapping_update,
+
+ (cmdline_parse_inst_t *)&cmd_pctype_mapping_get,
+ (cmdline_parse_inst_t *)&cmd_pctype_mapping_reset,
+ (cmdline_parse_inst_t *)&cmd_pctype_mapping_update,
+ (cmdline_parse_inst_t *)&cmd_queue_region,
+ (cmdline_parse_inst_t *)&cmd_region_flowtype,
+ (cmdline_parse_inst_t *)&cmd_user_priority_region,
+ (cmdline_parse_inst_t *)&cmd_flush_queue_region,
+ (cmdline_parse_inst_t *)&cmd_show_queue_region_info_all,
+ (cmdline_parse_inst_t *)&cmd_show_port_tm_cap,
+ (cmdline_parse_inst_t *)&cmd_show_port_tm_level_cap,
+ (cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
+ (cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
+ (cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
+ (cmdline_parse_inst_t *)&cmd_add_port_tm_node_shaper_profile,
+ (cmdline_parse_inst_t *)&cmd_del_port_tm_node_shaper_profile,
+ (cmdline_parse_inst_t *)&cmd_add_port_tm_node_shared_shaper,
+ (cmdline_parse_inst_t *)&cmd_del_port_tm_node_shared_shaper,
+ (cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
+ (cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
+ (cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
+ (cmdline_parse_inst_t *)&cmd_add_port_tm_nonleaf_node,
+ (cmdline_parse_inst_t *)&cmd_add_port_tm_leaf_node,
+ (cmdline_parse_inst_t *)&cmd_del_port_tm_node,
+ (cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
+ (cmdline_parse_inst_t *)&cmd_suspend_port_tm_node,
+ (cmdline_parse_inst_t *)&cmd_resume_port_tm_node,
+ (cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
+ (cmdline_parse_inst_t *)&cmd_port_tm_mark_ip_ecn,
+ (cmdline_parse_inst_t *)&cmd_port_tm_mark_ip_dscp,
+ (cmdline_parse_inst_t *)&cmd_port_tm_mark_vlan_dei,
+ (cmdline_parse_inst_t *)&cmd_cfg_tunnel_udp_port,
+ (cmdline_parse_inst_t *)&cmd_rx_offload_get_capa,
+ (cmdline_parse_inst_t *)&cmd_rx_offload_get_configuration,
+ (cmdline_parse_inst_t *)&cmd_config_per_port_rx_offload,
+ (cmdline_parse_inst_t *)&cmd_config_per_queue_rx_offload,
+ (cmdline_parse_inst_t *)&cmd_tx_offload_get_capa,
+ (cmdline_parse_inst_t *)&cmd_tx_offload_get_configuration,
+ (cmdline_parse_inst_t *)&cmd_config_per_port_tx_offload,
+ (cmdline_parse_inst_t *)&cmd_config_per_queue_tx_offload,
+#ifdef RTE_LIBRTE_BPF
+ (cmdline_parse_inst_t *)&cmd_operate_bpf_ld_parse,
+ (cmdline_parse_inst_t *)&cmd_operate_bpf_unld_parse,
+#endif
+ (cmdline_parse_inst_t *)&cmd_config_tx_metadata_specific,
+ (cmdline_parse_inst_t *)&cmd_show_tx_metadata,
+ (cmdline_parse_inst_t *)&cmd_show_rx_tx_desc_status,
+ (cmdline_parse_inst_t *)&cmd_set_raw,
+ (cmdline_parse_inst_t *)&cmd_show_set_raw,
+ (cmdline_parse_inst_t *)&cmd_show_set_raw_all,
+ (cmdline_parse_inst_t *)&cmd_config_tx_dynf_specific,
+ NULL,
+};
+
+/* read cmdline commands from file */
+void
+cmdline_read_from_file(const char *filename)
+{
+ struct cmdline *cl;
+
+ cl = cmdline_file_new(main_ctx, "testpmd> ", filename);
+ if (cl == NULL) {
+ printf("Failed to create file based cmdline context: %s\n",
+ filename);
+ return;
+ }
+
+ cmdline_interact(cl);
+ cmdline_quit(cl);
+
+ cmdline_free(cl);
+
+ printf("Read CLI commands from %s\n", filename);
+}
+
+/* prompt function, called from main on MASTER lcore */
+void
+prompt(void)
+{
+ /* initialize non-constant commands */
+ cmd_set_fwd_mode_init();
+ cmd_set_fwd_retry_mode_init();
+
+ testpmd_cl = cmdline_stdin_new(main_ctx, "testpmd> ");
+ if (testpmd_cl == NULL)
+ return;
+ cmdline_interact(testpmd_cl);
+ cmdline_stdin_exit(testpmd_cl);
+}
+
+void
+prompt_exit(void)
+{
+ if (testpmd_cl != NULL)
+ cmdline_quit(testpmd_cl);
+}
+
+static void
+cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue)
+{
+ if (id == (portid_t)RTE_PORT_ALL) {
+ portid_t pid;
+
+ RTE_ETH_FOREACH_DEV(pid) {
+ /* check if need_reconfig has been set to 1 */
+ if (ports[pid].need_reconfig == 0)
+ ports[pid].need_reconfig = dev;
+ /* check if need_reconfig_queues has been set to 1 */
+ if (ports[pid].need_reconfig_queues == 0)
+ ports[pid].need_reconfig_queues = queue;
+ }
+ } else if (!port_id_is_invalid(id, DISABLED_WARN)) {
+ /* check if need_reconfig has been set to 1 */
+ if (ports[id].need_reconfig == 0)
+ ports[id].need_reconfig = dev;
+ /* check if need_reconfig_queues has been set to 1 */
+ if (ports[id].need_reconfig_queues == 0)
+ ports[id].need_reconfig_queues = queue;
+ }
+}
diff --git a/src/spdk/dpdk/app/test-pmd/cmdline_flow.c b/src/spdk/dpdk/app/test-pmd/cmdline_flow.c
new file mode 100644
index 000000000..4e2006c54
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/cmdline_flow.c
@@ -0,0 +1,6888 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2016 6WIND S.A.
+ * Copyright 2016 Mellanox Technologies, Ltd
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include <rte_string_fns.h>
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_byteorder.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_num.h>
+#include <rte_flow.h>
+#include <rte_hexdump.h>
+
+#include "testpmd.h"
+
+/** Parser token indices. */
+enum index {
+ /* Special tokens. */
+ ZERO = 0,
+ END,
+ START_SET,
+ END_SET,
+
+ /* Common tokens. */
+ INTEGER,
+ UNSIGNED,
+ PREFIX,
+ BOOLEAN,
+ STRING,
+ HEX,
+ FILE_PATH,
+ MAC_ADDR,
+ IPV4_ADDR,
+ IPV6_ADDR,
+ RULE_ID,
+ PORT_ID,
+ GROUP_ID,
+ PRIORITY_LEVEL,
+
+ /* Top-level command. */
+ SET,
+ /* Sub-leve commands. */
+ SET_RAW_ENCAP,
+ SET_RAW_DECAP,
+ SET_RAW_INDEX,
+
+ /* Top-level command. */
+ FLOW,
+ /* Sub-level commands. */
+ VALIDATE,
+ CREATE,
+ DESTROY,
+ FLUSH,
+ DUMP,
+ QUERY,
+ LIST,
+ AGED,
+ ISOLATE,
+
+ /* Destroy arguments. */
+ DESTROY_RULE,
+
+ /* Query arguments. */
+ QUERY_ACTION,
+
+ /* List arguments. */
+ LIST_GROUP,
+
+ /* Destroy aged flow arguments. */
+ AGED_DESTROY,
+
+ /* Validate/create arguments. */
+ GROUP,
+ PRIORITY,
+ INGRESS,
+ EGRESS,
+ TRANSFER,
+
+ /* Validate/create pattern. */
+ PATTERN,
+ ITEM_PARAM_IS,
+ ITEM_PARAM_SPEC,
+ ITEM_PARAM_LAST,
+ ITEM_PARAM_MASK,
+ ITEM_PARAM_PREFIX,
+ ITEM_NEXT,
+ ITEM_END,
+ ITEM_VOID,
+ ITEM_INVERT,
+ ITEM_ANY,
+ ITEM_ANY_NUM,
+ ITEM_PF,
+ ITEM_VF,
+ ITEM_VF_ID,
+ ITEM_PHY_PORT,
+ ITEM_PHY_PORT_INDEX,
+ ITEM_PORT_ID,
+ ITEM_PORT_ID_ID,
+ ITEM_MARK,
+ ITEM_MARK_ID,
+ ITEM_RAW,
+ ITEM_RAW_RELATIVE,
+ ITEM_RAW_SEARCH,
+ ITEM_RAW_OFFSET,
+ ITEM_RAW_LIMIT,
+ ITEM_RAW_PATTERN,
+ ITEM_ETH,
+ ITEM_ETH_DST,
+ ITEM_ETH_SRC,
+ ITEM_ETH_TYPE,
+ ITEM_VLAN,
+ ITEM_VLAN_TCI,
+ ITEM_VLAN_PCP,
+ ITEM_VLAN_DEI,
+ ITEM_VLAN_VID,
+ ITEM_VLAN_INNER_TYPE,
+ ITEM_IPV4,
+ ITEM_IPV4_TOS,
+ ITEM_IPV4_TTL,
+ ITEM_IPV4_PROTO,
+ ITEM_IPV4_SRC,
+ ITEM_IPV4_DST,
+ ITEM_IPV6,
+ ITEM_IPV6_TC,
+ ITEM_IPV6_FLOW,
+ ITEM_IPV6_PROTO,
+ ITEM_IPV6_HOP,
+ ITEM_IPV6_SRC,
+ ITEM_IPV6_DST,
+ ITEM_ICMP,
+ ITEM_ICMP_TYPE,
+ ITEM_ICMP_CODE,
+ ITEM_UDP,
+ ITEM_UDP_SRC,
+ ITEM_UDP_DST,
+ ITEM_TCP,
+ ITEM_TCP_SRC,
+ ITEM_TCP_DST,
+ ITEM_TCP_FLAGS,
+ ITEM_SCTP,
+ ITEM_SCTP_SRC,
+ ITEM_SCTP_DST,
+ ITEM_SCTP_TAG,
+ ITEM_SCTP_CKSUM,
+ ITEM_VXLAN,
+ ITEM_VXLAN_VNI,
+ ITEM_E_TAG,
+ ITEM_E_TAG_GRP_ECID_B,
+ ITEM_NVGRE,
+ ITEM_NVGRE_TNI,
+ ITEM_MPLS,
+ ITEM_MPLS_LABEL,
+ ITEM_MPLS_TC,
+ ITEM_MPLS_S,
+ ITEM_GRE,
+ ITEM_GRE_PROTO,
+ ITEM_GRE_C_RSVD0_VER,
+ ITEM_GRE_C_BIT,
+ ITEM_GRE_K_BIT,
+ ITEM_GRE_S_BIT,
+ ITEM_FUZZY,
+ ITEM_FUZZY_THRESH,
+ ITEM_GTP,
+ ITEM_GTP_FLAGS,
+ ITEM_GTP_MSG_TYPE,
+ ITEM_GTP_TEID,
+ ITEM_GTPC,
+ ITEM_GTPU,
+ ITEM_GENEVE,
+ ITEM_GENEVE_VNI,
+ ITEM_GENEVE_PROTO,
+ ITEM_VXLAN_GPE,
+ ITEM_VXLAN_GPE_VNI,
+ ITEM_ARP_ETH_IPV4,
+ ITEM_ARP_ETH_IPV4_SHA,
+ ITEM_ARP_ETH_IPV4_SPA,
+ ITEM_ARP_ETH_IPV4_THA,
+ ITEM_ARP_ETH_IPV4_TPA,
+ ITEM_IPV6_EXT,
+ ITEM_IPV6_EXT_NEXT_HDR,
+ ITEM_ICMP6,
+ ITEM_ICMP6_TYPE,
+ ITEM_ICMP6_CODE,
+ ITEM_ICMP6_ND_NS,
+ ITEM_ICMP6_ND_NS_TARGET_ADDR,
+ ITEM_ICMP6_ND_NA,
+ ITEM_ICMP6_ND_NA_TARGET_ADDR,
+ ITEM_ICMP6_ND_OPT,
+ ITEM_ICMP6_ND_OPT_TYPE,
+ ITEM_ICMP6_ND_OPT_SLA_ETH,
+ ITEM_ICMP6_ND_OPT_SLA_ETH_SLA,
+ ITEM_ICMP6_ND_OPT_TLA_ETH,
+ ITEM_ICMP6_ND_OPT_TLA_ETH_TLA,
+ ITEM_META,
+ ITEM_META_DATA,
+ ITEM_GRE_KEY,
+ ITEM_GRE_KEY_VALUE,
+ ITEM_GTP_PSC,
+ ITEM_GTP_PSC_QFI,
+ ITEM_GTP_PSC_PDU_T,
+ ITEM_PPPOES,
+ ITEM_PPPOED,
+ ITEM_PPPOE_SEID,
+ ITEM_PPPOE_PROTO_ID,
+ ITEM_HIGIG2,
+ ITEM_HIGIG2_CLASSIFICATION,
+ ITEM_HIGIG2_VID,
+ ITEM_TAG,
+ ITEM_TAG_DATA,
+ ITEM_TAG_INDEX,
+ ITEM_L2TPV3OIP,
+ ITEM_L2TPV3OIP_SESSION_ID,
+ ITEM_ESP,
+ ITEM_ESP_SPI,
+ ITEM_AH,
+ ITEM_AH_SPI,
+ ITEM_PFCP,
+ ITEM_PFCP_S_FIELD,
+ ITEM_PFCP_SEID,
+
+ /* Validate/create actions. */
+ ACTIONS,
+ ACTION_NEXT,
+ ACTION_END,
+ ACTION_VOID,
+ ACTION_PASSTHRU,
+ ACTION_JUMP,
+ ACTION_JUMP_GROUP,
+ ACTION_MARK,
+ ACTION_MARK_ID,
+ ACTION_FLAG,
+ ACTION_QUEUE,
+ ACTION_QUEUE_INDEX,
+ ACTION_DROP,
+ ACTION_COUNT,
+ ACTION_COUNT_SHARED,
+ ACTION_COUNT_ID,
+ ACTION_RSS,
+ ACTION_RSS_FUNC,
+ ACTION_RSS_LEVEL,
+ ACTION_RSS_FUNC_DEFAULT,
+ ACTION_RSS_FUNC_TOEPLITZ,
+ ACTION_RSS_FUNC_SIMPLE_XOR,
+ ACTION_RSS_FUNC_SYMMETRIC_TOEPLITZ,
+ ACTION_RSS_TYPES,
+ ACTION_RSS_TYPE,
+ ACTION_RSS_KEY,
+ ACTION_RSS_KEY_LEN,
+ ACTION_RSS_QUEUES,
+ ACTION_RSS_QUEUE,
+ ACTION_PF,
+ ACTION_VF,
+ ACTION_VF_ORIGINAL,
+ ACTION_VF_ID,
+ ACTION_PHY_PORT,
+ ACTION_PHY_PORT_ORIGINAL,
+ ACTION_PHY_PORT_INDEX,
+ ACTION_PORT_ID,
+ ACTION_PORT_ID_ORIGINAL,
+ ACTION_PORT_ID_ID,
+ ACTION_METER,
+ ACTION_METER_ID,
+ ACTION_OF_SET_MPLS_TTL,
+ ACTION_OF_SET_MPLS_TTL_MPLS_TTL,
+ ACTION_OF_DEC_MPLS_TTL,
+ ACTION_OF_SET_NW_TTL,
+ ACTION_OF_SET_NW_TTL_NW_TTL,
+ ACTION_OF_DEC_NW_TTL,
+ ACTION_OF_COPY_TTL_OUT,
+ ACTION_OF_COPY_TTL_IN,
+ ACTION_OF_POP_VLAN,
+ ACTION_OF_PUSH_VLAN,
+ ACTION_OF_PUSH_VLAN_ETHERTYPE,
+ ACTION_OF_SET_VLAN_VID,
+ ACTION_OF_SET_VLAN_VID_VLAN_VID,
+ ACTION_OF_SET_VLAN_PCP,
+ ACTION_OF_SET_VLAN_PCP_VLAN_PCP,
+ ACTION_OF_POP_MPLS,
+ ACTION_OF_POP_MPLS_ETHERTYPE,
+ ACTION_OF_PUSH_MPLS,
+ ACTION_OF_PUSH_MPLS_ETHERTYPE,
+ ACTION_VXLAN_ENCAP,
+ ACTION_VXLAN_DECAP,
+ ACTION_NVGRE_ENCAP,
+ ACTION_NVGRE_DECAP,
+ ACTION_L2_ENCAP,
+ ACTION_L2_DECAP,
+ ACTION_MPLSOGRE_ENCAP,
+ ACTION_MPLSOGRE_DECAP,
+ ACTION_MPLSOUDP_ENCAP,
+ ACTION_MPLSOUDP_DECAP,
+ ACTION_SET_IPV4_SRC,
+ ACTION_SET_IPV4_SRC_IPV4_SRC,
+ ACTION_SET_IPV4_DST,
+ ACTION_SET_IPV4_DST_IPV4_DST,
+ ACTION_SET_IPV6_SRC,
+ ACTION_SET_IPV6_SRC_IPV6_SRC,
+ ACTION_SET_IPV6_DST,
+ ACTION_SET_IPV6_DST_IPV6_DST,
+ ACTION_SET_TP_SRC,
+ ACTION_SET_TP_SRC_TP_SRC,
+ ACTION_SET_TP_DST,
+ ACTION_SET_TP_DST_TP_DST,
+ ACTION_MAC_SWAP,
+ ACTION_DEC_TTL,
+ ACTION_SET_TTL,
+ ACTION_SET_TTL_TTL,
+ ACTION_SET_MAC_SRC,
+ ACTION_SET_MAC_SRC_MAC_SRC,
+ ACTION_SET_MAC_DST,
+ ACTION_SET_MAC_DST_MAC_DST,
+ ACTION_INC_TCP_SEQ,
+ ACTION_INC_TCP_SEQ_VALUE,
+ ACTION_DEC_TCP_SEQ,
+ ACTION_DEC_TCP_SEQ_VALUE,
+ ACTION_INC_TCP_ACK,
+ ACTION_INC_TCP_ACK_VALUE,
+ ACTION_DEC_TCP_ACK,
+ ACTION_DEC_TCP_ACK_VALUE,
+ ACTION_RAW_ENCAP,
+ ACTION_RAW_DECAP,
+ ACTION_RAW_ENCAP_INDEX,
+ ACTION_RAW_ENCAP_INDEX_VALUE,
+ ACTION_RAW_DECAP_INDEX,
+ ACTION_RAW_DECAP_INDEX_VALUE,
+ ACTION_SET_TAG,
+ ACTION_SET_TAG_DATA,
+ ACTION_SET_TAG_INDEX,
+ ACTION_SET_TAG_MASK,
+ ACTION_SET_META,
+ ACTION_SET_META_DATA,
+ ACTION_SET_META_MASK,
+ ACTION_SET_IPV4_DSCP,
+ ACTION_SET_IPV4_DSCP_VALUE,
+ ACTION_SET_IPV6_DSCP,
+ ACTION_SET_IPV6_DSCP_VALUE,
+ ACTION_AGE,
+ ACTION_AGE_TIMEOUT,
+};
+
+/** Maximum size for pattern in struct rte_flow_item_raw. */
+#define ITEM_RAW_PATTERN_SIZE 40
+
+/** Storage size for struct rte_flow_item_raw including pattern. */
+#define ITEM_RAW_SIZE \
+ (sizeof(struct rte_flow_item_raw) + ITEM_RAW_PATTERN_SIZE)
+
+/** Maximum number of queue indices in struct rte_flow_action_rss. */
+#define ACTION_RSS_QUEUE_NUM 128
+
+/** Storage for struct rte_flow_action_rss including external data. */
+struct action_rss_data {
+ struct rte_flow_action_rss conf;
+ uint8_t key[RSS_HASH_KEY_LENGTH];
+ uint16_t queue[ACTION_RSS_QUEUE_NUM];
+};
+
+/** Maximum data size in struct rte_flow_action_raw_encap. */
+#define ACTION_RAW_ENCAP_MAX_DATA 128
+#define RAW_ENCAP_CONFS_MAX_NUM 8
+
+/** Storage for struct rte_flow_action_raw_encap. */
+struct raw_encap_conf {
+ uint8_t data[ACTION_RAW_ENCAP_MAX_DATA];
+ uint8_t preserve[ACTION_RAW_ENCAP_MAX_DATA];
+ size_t size;
+};
+
+struct raw_encap_conf raw_encap_confs[RAW_ENCAP_CONFS_MAX_NUM];
+
+/** Storage for struct rte_flow_action_raw_encap including external data. */
+struct action_raw_encap_data {
+ struct rte_flow_action_raw_encap conf;
+ uint8_t data[ACTION_RAW_ENCAP_MAX_DATA];
+ uint8_t preserve[ACTION_RAW_ENCAP_MAX_DATA];
+ uint16_t idx;
+};
+
+/** Storage for struct rte_flow_action_raw_decap. */
+struct raw_decap_conf {
+ uint8_t data[ACTION_RAW_ENCAP_MAX_DATA];
+ size_t size;
+};
+
+struct raw_decap_conf raw_decap_confs[RAW_ENCAP_CONFS_MAX_NUM];
+
+/** Storage for struct rte_flow_action_raw_decap including external data. */
+struct action_raw_decap_data {
+ struct rte_flow_action_raw_decap conf;
+ uint8_t data[ACTION_RAW_ENCAP_MAX_DATA];
+ uint16_t idx;
+};
+
+struct vxlan_encap_conf vxlan_encap_conf = {
+ .select_ipv4 = 1,
+ .select_vlan = 0,
+ .select_tos_ttl = 0,
+ .vni = "\x00\x00\x00",
+ .udp_src = 0,
+ .udp_dst = RTE_BE16(4789),
+ .ipv4_src = RTE_IPV4(127, 0, 0, 1),
+ .ipv4_dst = RTE_IPV4(255, 255, 255, 255),
+ .ipv6_src = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x01",
+ .ipv6_dst = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x11\x11",
+ .vlan_tci = 0,
+ .ip_tos = 0,
+ .ip_ttl = 255,
+ .eth_src = "\x00\x00\x00\x00\x00\x00",
+ .eth_dst = "\xff\xff\xff\xff\xff\xff",
+};
+
+/** Maximum number of items in struct rte_flow_action_vxlan_encap. */
+#define ACTION_VXLAN_ENCAP_ITEMS_NUM 6
+
+/** Storage for struct rte_flow_action_vxlan_encap including external data. */
+struct action_vxlan_encap_data {
+ struct rte_flow_action_vxlan_encap conf;
+ struct rte_flow_item items[ACTION_VXLAN_ENCAP_ITEMS_NUM];
+ struct rte_flow_item_eth item_eth;
+ struct rte_flow_item_vlan item_vlan;
+ union {
+ struct rte_flow_item_ipv4 item_ipv4;
+ struct rte_flow_item_ipv6 item_ipv6;
+ };
+ struct rte_flow_item_udp item_udp;
+ struct rte_flow_item_vxlan item_vxlan;
+};
+
+struct nvgre_encap_conf nvgre_encap_conf = {
+ .select_ipv4 = 1,
+ .select_vlan = 0,
+ .tni = "\x00\x00\x00",
+ .ipv4_src = RTE_IPV4(127, 0, 0, 1),
+ .ipv4_dst = RTE_IPV4(255, 255, 255, 255),
+ .ipv6_src = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x01",
+ .ipv6_dst = "\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x11\x11",
+ .vlan_tci = 0,
+ .eth_src = "\x00\x00\x00\x00\x00\x00",
+ .eth_dst = "\xff\xff\xff\xff\xff\xff",
+};
+
+/** Maximum number of items in struct rte_flow_action_nvgre_encap. */
+#define ACTION_NVGRE_ENCAP_ITEMS_NUM 5
+
+/** Storage for struct rte_flow_action_nvgre_encap including external data. */
+struct action_nvgre_encap_data {
+ struct rte_flow_action_nvgre_encap conf;
+ struct rte_flow_item items[ACTION_NVGRE_ENCAP_ITEMS_NUM];
+ struct rte_flow_item_eth item_eth;
+ struct rte_flow_item_vlan item_vlan;
+ union {
+ struct rte_flow_item_ipv4 item_ipv4;
+ struct rte_flow_item_ipv6 item_ipv6;
+ };
+ struct rte_flow_item_nvgre item_nvgre;
+};
+
+struct l2_encap_conf l2_encap_conf;
+
+struct l2_decap_conf l2_decap_conf;
+
+struct mplsogre_encap_conf mplsogre_encap_conf;
+
+struct mplsogre_decap_conf mplsogre_decap_conf;
+
+struct mplsoudp_encap_conf mplsoudp_encap_conf;
+
+struct mplsoudp_decap_conf mplsoudp_decap_conf;
+
+/** Maximum number of subsequent tokens and arguments on the stack. */
+#define CTX_STACK_SIZE 16
+
+/** Parser context. */
+struct context {
+ /** Stack of subsequent token lists to process. */
+ const enum index *next[CTX_STACK_SIZE];
+ /** Arguments for stacked tokens. */
+ const void *args[CTX_STACK_SIZE];
+ enum index curr; /**< Current token index. */
+ enum index prev; /**< Index of the last token seen. */
+ int next_num; /**< Number of entries in next[]. */
+ int args_num; /**< Number of entries in args[]. */
+ uint32_t eol:1; /**< EOL has been detected. */
+ uint32_t last:1; /**< No more arguments. */
+ portid_t port; /**< Current port ID (for completions). */
+ uint32_t objdata; /**< Object-specific data. */
+ void *object; /**< Address of current object for relative offsets. */
+ void *objmask; /**< Object a full mask must be written to. */
+};
+
+/** Token argument. */
+struct arg {
+ uint32_t hton:1; /**< Use network byte ordering. */
+ uint32_t sign:1; /**< Value is signed. */
+ uint32_t bounded:1; /**< Value is bounded. */
+ uintmax_t min; /**< Minimum value if bounded. */
+ uintmax_t max; /**< Maximum value if bounded. */
+ uint32_t offset; /**< Relative offset from ctx->object. */
+ uint32_t size; /**< Field size. */
+ const uint8_t *mask; /**< Bit-mask to use instead of offset/size. */
+};
+
+/** Parser token definition. */
+struct token {
+ /** Type displayed during completion (defaults to "TOKEN"). */
+ const char *type;
+ /** Help displayed during completion (defaults to token name). */
+ const char *help;
+ /** Private data used by parser functions. */
+ const void *priv;
+ /**
+ * Lists of subsequent tokens to push on the stack. Each call to the
+ * parser consumes the last entry of that stack.
+ */
+ const enum index *const *next;
+ /** Arguments stack for subsequent tokens that need them. */
+ const struct arg *const *args;
+ /**
+ * Token-processing callback, returns -1 in case of error, the
+ * length of the matched string otherwise. If NULL, attempts to
+ * match the token name.
+ *
+ * If buf is not NULL, the result should be stored in it according
+ * to context. An error is returned if not large enough.
+ */
+ int (*call)(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size);
+ /**
+ * Callback that provides possible values for this token, used for
+ * completion. Returns -1 in case of error, the number of possible
+ * values otherwise. If NULL, the token name is used.
+ *
+ * If buf is not NULL, entry index ent is written to buf and the
+ * full length of the entry is returned (same behavior as
+ * snprintf()).
+ */
+ int (*comp)(struct context *ctx, const struct token *token,
+ unsigned int ent, char *buf, unsigned int size);
+ /** Mandatory token name, no default value. */
+ const char *name;
+};
+
+/** Static initializer for the next field. */
+#define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, }
+
+/** Static initializer for a NEXT() entry. */
+#define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, }
+
+/** Static initializer for the args field. */
+#define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
+
+/** Static initializer for ARGS() to target a field. */
+#define ARGS_ENTRY(s, f) \
+ (&(const struct arg){ \
+ .offset = offsetof(s, f), \
+ .size = sizeof(((s *)0)->f), \
+ })
+
+/** Static initializer for ARGS() to target a bit-field. */
+#define ARGS_ENTRY_BF(s, f, b) \
+ (&(const struct arg){ \
+ .size = sizeof(s), \
+ .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \
+ })
+
+/** Static initializer for ARGS() to target an arbitrary bit-mask. */
+#define ARGS_ENTRY_MASK(s, f, m) \
+ (&(const struct arg){ \
+ .offset = offsetof(s, f), \
+ .size = sizeof(((s *)0)->f), \
+ .mask = (const void *)(m), \
+ })
+
+/** Same as ARGS_ENTRY_MASK() using network byte ordering for the value. */
+#define ARGS_ENTRY_MASK_HTON(s, f, m) \
+ (&(const struct arg){ \
+ .hton = 1, \
+ .offset = offsetof(s, f), \
+ .size = sizeof(((s *)0)->f), \
+ .mask = (const void *)(m), \
+ })
+
+/** Static initializer for ARGS() to target a pointer. */
+#define ARGS_ENTRY_PTR(s, f) \
+ (&(const struct arg){ \
+ .size = sizeof(*((s *)0)->f), \
+ })
+
+/** Static initializer for ARGS() with arbitrary offset and size. */
+#define ARGS_ENTRY_ARB(o, s) \
+ (&(const struct arg){ \
+ .offset = (o), \
+ .size = (s), \
+ })
+
+/** Same as ARGS_ENTRY_ARB() with bounded values. */
+#define ARGS_ENTRY_ARB_BOUNDED(o, s, i, a) \
+ (&(const struct arg){ \
+ .bounded = 1, \
+ .min = (i), \
+ .max = (a), \
+ .offset = (o), \
+ .size = (s), \
+ })
+
+/** Same as ARGS_ENTRY() using network byte ordering. */
+#define ARGS_ENTRY_HTON(s, f) \
+ (&(const struct arg){ \
+ .hton = 1, \
+ .offset = offsetof(s, f), \
+ .size = sizeof(((s *)0)->f), \
+ })
+
+/** Same as ARGS_ENTRY_HTON() for a single argument, without structure. */
+#define ARG_ENTRY_HTON(s) \
+ (&(const struct arg){ \
+ .hton = 1, \
+ .offset = 0, \
+ .size = sizeof(s), \
+ })
+
+/** Parser output buffer layout expected by cmd_flow_parsed(). */
+struct buffer {
+ enum index command; /**< Flow command. */
+ portid_t port; /**< Affected port ID. */
+ union {
+ struct {
+ struct rte_flow_attr attr;
+ struct rte_flow_item *pattern;
+ struct rte_flow_action *actions;
+ uint32_t pattern_n;
+ uint32_t actions_n;
+ uint8_t *data;
+ } vc; /**< Validate/create arguments. */
+ struct {
+ uint32_t *rule;
+ uint32_t rule_n;
+ } destroy; /**< Destroy arguments. */
+ struct {
+ char file[128];
+ } dump; /**< Dump arguments. */
+ struct {
+ uint32_t rule;
+ struct rte_flow_action action;
+ } query; /**< Query arguments. */
+ struct {
+ uint32_t *group;
+ uint32_t group_n;
+ } list; /**< List arguments. */
+ struct {
+ int set;
+ } isolate; /**< Isolated mode arguments. */
+ struct {
+ int destroy;
+ } aged; /**< Aged arguments. */
+ } args; /**< Command arguments. */
+};
+
+/** Private data for pattern items. */
+struct parse_item_priv {
+ enum rte_flow_item_type type; /**< Item type. */
+ uint32_t size; /**< Size of item specification structure. */
+};
+
+#define PRIV_ITEM(t, s) \
+ (&(const struct parse_item_priv){ \
+ .type = RTE_FLOW_ITEM_TYPE_ ## t, \
+ .size = s, \
+ })
+
+/** Private data for actions. */
+struct parse_action_priv {
+ enum rte_flow_action_type type; /**< Action type. */
+ uint32_t size; /**< Size of action configuration structure. */
+};
+
+#define PRIV_ACTION(t, s) \
+ (&(const struct parse_action_priv){ \
+ .type = RTE_FLOW_ACTION_TYPE_ ## t, \
+ .size = s, \
+ })
+
+static const enum index next_vc_attr[] = {
+ GROUP,
+ PRIORITY,
+ INGRESS,
+ EGRESS,
+ TRANSFER,
+ PATTERN,
+ ZERO,
+};
+
+static const enum index next_destroy_attr[] = {
+ DESTROY_RULE,
+ END,
+ ZERO,
+};
+
+static const enum index next_dump_attr[] = {
+ FILE_PATH,
+ END,
+ ZERO,
+};
+
+static const enum index next_list_attr[] = {
+ LIST_GROUP,
+ END,
+ ZERO,
+};
+
+static const enum index next_aged_attr[] = {
+ AGED_DESTROY,
+ END,
+ ZERO,
+};
+
+static const enum index item_param[] = {
+ ITEM_PARAM_IS,
+ ITEM_PARAM_SPEC,
+ ITEM_PARAM_LAST,
+ ITEM_PARAM_MASK,
+ ITEM_PARAM_PREFIX,
+ ZERO,
+};
+
+static const enum index next_item[] = {
+ ITEM_END,
+ ITEM_VOID,
+ ITEM_INVERT,
+ ITEM_ANY,
+ ITEM_PF,
+ ITEM_VF,
+ ITEM_PHY_PORT,
+ ITEM_PORT_ID,
+ ITEM_MARK,
+ ITEM_RAW,
+ ITEM_ETH,
+ ITEM_VLAN,
+ ITEM_IPV4,
+ ITEM_IPV6,
+ ITEM_ICMP,
+ ITEM_UDP,
+ ITEM_TCP,
+ ITEM_SCTP,
+ ITEM_VXLAN,
+ ITEM_E_TAG,
+ ITEM_NVGRE,
+ ITEM_MPLS,
+ ITEM_GRE,
+ ITEM_FUZZY,
+ ITEM_GTP,
+ ITEM_GTPC,
+ ITEM_GTPU,
+ ITEM_GENEVE,
+ ITEM_VXLAN_GPE,
+ ITEM_ARP_ETH_IPV4,
+ ITEM_IPV6_EXT,
+ ITEM_ICMP6,
+ ITEM_ICMP6_ND_NS,
+ ITEM_ICMP6_ND_NA,
+ ITEM_ICMP6_ND_OPT,
+ ITEM_ICMP6_ND_OPT_SLA_ETH,
+ ITEM_ICMP6_ND_OPT_TLA_ETH,
+ ITEM_META,
+ ITEM_GRE_KEY,
+ ITEM_GTP_PSC,
+ ITEM_PPPOES,
+ ITEM_PPPOED,
+ ITEM_PPPOE_PROTO_ID,
+ ITEM_HIGIG2,
+ ITEM_TAG,
+ ITEM_L2TPV3OIP,
+ ITEM_ESP,
+ ITEM_AH,
+ ITEM_PFCP,
+ END_SET,
+ ZERO,
+};
+
+static const enum index item_fuzzy[] = {
+ ITEM_FUZZY_THRESH,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_any[] = {
+ ITEM_ANY_NUM,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_vf[] = {
+ ITEM_VF_ID,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_phy_port[] = {
+ ITEM_PHY_PORT_INDEX,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_port_id[] = {
+ ITEM_PORT_ID_ID,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_mark[] = {
+ ITEM_MARK_ID,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_raw[] = {
+ ITEM_RAW_RELATIVE,
+ ITEM_RAW_SEARCH,
+ ITEM_RAW_OFFSET,
+ ITEM_RAW_LIMIT,
+ ITEM_RAW_PATTERN,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_eth[] = {
+ ITEM_ETH_DST,
+ ITEM_ETH_SRC,
+ ITEM_ETH_TYPE,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_vlan[] = {
+ ITEM_VLAN_TCI,
+ ITEM_VLAN_PCP,
+ ITEM_VLAN_DEI,
+ ITEM_VLAN_VID,
+ ITEM_VLAN_INNER_TYPE,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_ipv4[] = {
+ ITEM_IPV4_TOS,
+ ITEM_IPV4_TTL,
+ ITEM_IPV4_PROTO,
+ ITEM_IPV4_SRC,
+ ITEM_IPV4_DST,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_ipv6[] = {
+ ITEM_IPV6_TC,
+ ITEM_IPV6_FLOW,
+ ITEM_IPV6_PROTO,
+ ITEM_IPV6_HOP,
+ ITEM_IPV6_SRC,
+ ITEM_IPV6_DST,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_icmp[] = {
+ ITEM_ICMP_TYPE,
+ ITEM_ICMP_CODE,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_udp[] = {
+ ITEM_UDP_SRC,
+ ITEM_UDP_DST,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_tcp[] = {
+ ITEM_TCP_SRC,
+ ITEM_TCP_DST,
+ ITEM_TCP_FLAGS,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_sctp[] = {
+ ITEM_SCTP_SRC,
+ ITEM_SCTP_DST,
+ ITEM_SCTP_TAG,
+ ITEM_SCTP_CKSUM,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_vxlan[] = {
+ ITEM_VXLAN_VNI,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_e_tag[] = {
+ ITEM_E_TAG_GRP_ECID_B,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_nvgre[] = {
+ ITEM_NVGRE_TNI,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_mpls[] = {
+ ITEM_MPLS_LABEL,
+ ITEM_MPLS_TC,
+ ITEM_MPLS_S,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_gre[] = {
+ ITEM_GRE_PROTO,
+ ITEM_GRE_C_RSVD0_VER,
+ ITEM_GRE_C_BIT,
+ ITEM_GRE_K_BIT,
+ ITEM_GRE_S_BIT,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_gre_key[] = {
+ ITEM_GRE_KEY_VALUE,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_gtp[] = {
+ ITEM_GTP_FLAGS,
+ ITEM_GTP_MSG_TYPE,
+ ITEM_GTP_TEID,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_geneve[] = {
+ ITEM_GENEVE_VNI,
+ ITEM_GENEVE_PROTO,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_vxlan_gpe[] = {
+ ITEM_VXLAN_GPE_VNI,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_arp_eth_ipv4[] = {
+ ITEM_ARP_ETH_IPV4_SHA,
+ ITEM_ARP_ETH_IPV4_SPA,
+ ITEM_ARP_ETH_IPV4_THA,
+ ITEM_ARP_ETH_IPV4_TPA,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_ipv6_ext[] = {
+ ITEM_IPV6_EXT_NEXT_HDR,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_icmp6[] = {
+ ITEM_ICMP6_TYPE,
+ ITEM_ICMP6_CODE,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_icmp6_nd_ns[] = {
+ ITEM_ICMP6_ND_NS_TARGET_ADDR,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_icmp6_nd_na[] = {
+ ITEM_ICMP6_ND_NA_TARGET_ADDR,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_icmp6_nd_opt[] = {
+ ITEM_ICMP6_ND_OPT_TYPE,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_icmp6_nd_opt_sla_eth[] = {
+ ITEM_ICMP6_ND_OPT_SLA_ETH_SLA,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_icmp6_nd_opt_tla_eth[] = {
+ ITEM_ICMP6_ND_OPT_TLA_ETH_TLA,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_meta[] = {
+ ITEM_META_DATA,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_gtp_psc[] = {
+ ITEM_GTP_PSC_QFI,
+ ITEM_GTP_PSC_PDU_T,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_pppoed[] = {
+ ITEM_PPPOE_SEID,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_pppoes[] = {
+ ITEM_PPPOE_SEID,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_pppoe_proto_id[] = {
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_higig2[] = {
+ ITEM_HIGIG2_CLASSIFICATION,
+ ITEM_HIGIG2_VID,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_esp[] = {
+ ITEM_ESP_SPI,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_ah[] = {
+ ITEM_AH_SPI,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_pfcp[] = {
+ ITEM_PFCP_S_FIELD,
+ ITEM_PFCP_SEID,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index next_set_raw[] = {
+ SET_RAW_INDEX,
+ ITEM_ETH,
+ ZERO,
+};
+
+static const enum index item_tag[] = {
+ ITEM_TAG_DATA,
+ ITEM_TAG_INDEX,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_l2tpv3oip[] = {
+ ITEM_L2TPV3OIP_SESSION_ID,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index next_action[] = {
+ ACTION_END,
+ ACTION_VOID,
+ ACTION_PASSTHRU,
+ ACTION_JUMP,
+ ACTION_MARK,
+ ACTION_FLAG,
+ ACTION_QUEUE,
+ ACTION_DROP,
+ ACTION_COUNT,
+ ACTION_RSS,
+ ACTION_PF,
+ ACTION_VF,
+ ACTION_PHY_PORT,
+ ACTION_PORT_ID,
+ ACTION_METER,
+ ACTION_OF_SET_MPLS_TTL,
+ ACTION_OF_DEC_MPLS_TTL,
+ ACTION_OF_SET_NW_TTL,
+ ACTION_OF_DEC_NW_TTL,
+ ACTION_OF_COPY_TTL_OUT,
+ ACTION_OF_COPY_TTL_IN,
+ ACTION_OF_POP_VLAN,
+ ACTION_OF_PUSH_VLAN,
+ ACTION_OF_SET_VLAN_VID,
+ ACTION_OF_SET_VLAN_PCP,
+ ACTION_OF_POP_MPLS,
+ ACTION_OF_PUSH_MPLS,
+ ACTION_VXLAN_ENCAP,
+ ACTION_VXLAN_DECAP,
+ ACTION_NVGRE_ENCAP,
+ ACTION_NVGRE_DECAP,
+ ACTION_L2_ENCAP,
+ ACTION_L2_DECAP,
+ ACTION_MPLSOGRE_ENCAP,
+ ACTION_MPLSOGRE_DECAP,
+ ACTION_MPLSOUDP_ENCAP,
+ ACTION_MPLSOUDP_DECAP,
+ ACTION_SET_IPV4_SRC,
+ ACTION_SET_IPV4_DST,
+ ACTION_SET_IPV6_SRC,
+ ACTION_SET_IPV6_DST,
+ ACTION_SET_TP_SRC,
+ ACTION_SET_TP_DST,
+ ACTION_MAC_SWAP,
+ ACTION_DEC_TTL,
+ ACTION_SET_TTL,
+ ACTION_SET_MAC_SRC,
+ ACTION_SET_MAC_DST,
+ ACTION_INC_TCP_SEQ,
+ ACTION_DEC_TCP_SEQ,
+ ACTION_INC_TCP_ACK,
+ ACTION_DEC_TCP_ACK,
+ ACTION_RAW_ENCAP,
+ ACTION_RAW_DECAP,
+ ACTION_SET_TAG,
+ ACTION_SET_META,
+ ACTION_SET_IPV4_DSCP,
+ ACTION_SET_IPV6_DSCP,
+ ACTION_AGE,
+ ZERO,
+};
+
+static const enum index action_mark[] = {
+ ACTION_MARK_ID,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_queue[] = {
+ ACTION_QUEUE_INDEX,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_count[] = {
+ ACTION_COUNT_ID,
+ ACTION_COUNT_SHARED,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_rss[] = {
+ ACTION_RSS_FUNC,
+ ACTION_RSS_LEVEL,
+ ACTION_RSS_TYPES,
+ ACTION_RSS_KEY,
+ ACTION_RSS_KEY_LEN,
+ ACTION_RSS_QUEUES,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_vf[] = {
+ ACTION_VF_ORIGINAL,
+ ACTION_VF_ID,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_phy_port[] = {
+ ACTION_PHY_PORT_ORIGINAL,
+ ACTION_PHY_PORT_INDEX,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_port_id[] = {
+ ACTION_PORT_ID_ORIGINAL,
+ ACTION_PORT_ID_ID,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_meter[] = {
+ ACTION_METER_ID,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_of_set_mpls_ttl[] = {
+ ACTION_OF_SET_MPLS_TTL_MPLS_TTL,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_of_set_nw_ttl[] = {
+ ACTION_OF_SET_NW_TTL_NW_TTL,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_of_push_vlan[] = {
+ ACTION_OF_PUSH_VLAN_ETHERTYPE,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_of_set_vlan_vid[] = {
+ ACTION_OF_SET_VLAN_VID_VLAN_VID,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_of_set_vlan_pcp[] = {
+ ACTION_OF_SET_VLAN_PCP_VLAN_PCP,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_of_pop_mpls[] = {
+ ACTION_OF_POP_MPLS_ETHERTYPE,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_of_push_mpls[] = {
+ ACTION_OF_PUSH_MPLS_ETHERTYPE,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_set_ipv4_src[] = {
+ ACTION_SET_IPV4_SRC_IPV4_SRC,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_set_mac_src[] = {
+ ACTION_SET_MAC_SRC_MAC_SRC,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_set_ipv4_dst[] = {
+ ACTION_SET_IPV4_DST_IPV4_DST,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_set_ipv6_src[] = {
+ ACTION_SET_IPV6_SRC_IPV6_SRC,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_set_ipv6_dst[] = {
+ ACTION_SET_IPV6_DST_IPV6_DST,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_set_tp_src[] = {
+ ACTION_SET_TP_SRC_TP_SRC,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_set_tp_dst[] = {
+ ACTION_SET_TP_DST_TP_DST,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_set_ttl[] = {
+ ACTION_SET_TTL_TTL,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_jump[] = {
+ ACTION_JUMP_GROUP,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_set_mac_dst[] = {
+ ACTION_SET_MAC_DST_MAC_DST,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_inc_tcp_seq[] = {
+ ACTION_INC_TCP_SEQ_VALUE,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_dec_tcp_seq[] = {
+ ACTION_DEC_TCP_SEQ_VALUE,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_inc_tcp_ack[] = {
+ ACTION_INC_TCP_ACK_VALUE,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_dec_tcp_ack[] = {
+ ACTION_DEC_TCP_ACK_VALUE,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_raw_encap[] = {
+ ACTION_RAW_ENCAP_INDEX,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_raw_decap[] = {
+ ACTION_RAW_DECAP_INDEX,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_set_tag[] = {
+ ACTION_SET_TAG_DATA,
+ ACTION_SET_TAG_INDEX,
+ ACTION_SET_TAG_MASK,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_set_meta[] = {
+ ACTION_SET_META_DATA,
+ ACTION_SET_META_MASK,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_set_ipv4_dscp[] = {
+ ACTION_SET_IPV4_DSCP_VALUE,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_set_ipv6_dscp[] = {
+ ACTION_SET_IPV6_DSCP_VALUE,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static const enum index action_age[] = {
+ ACTION_AGE,
+ ACTION_AGE_TIMEOUT,
+ ACTION_NEXT,
+ ZERO,
+};
+
+static int parse_set_raw_encap_decap(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_set_init(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_init(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_vc(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_vc_spec(struct context *, const struct token *,
+ const char *, unsigned int, void *, unsigned int);
+static int parse_vc_conf(struct context *, const struct token *,
+ const char *, unsigned int, void *, unsigned int);
+static int parse_vc_action_rss(struct context *, const struct token *,
+ const char *, unsigned int, void *,
+ unsigned int);
+static int parse_vc_action_rss_func(struct context *, const struct token *,
+ const char *, unsigned int, void *,
+ unsigned int);
+static int parse_vc_action_rss_type(struct context *, const struct token *,
+ const char *, unsigned int, void *,
+ unsigned int);
+static int parse_vc_action_rss_queue(struct context *, const struct token *,
+ const char *, unsigned int, void *,
+ unsigned int);
+static int parse_vc_action_vxlan_encap(struct context *, const struct token *,
+ const char *, unsigned int, void *,
+ unsigned int);
+static int parse_vc_action_nvgre_encap(struct context *, const struct token *,
+ const char *, unsigned int, void *,
+ unsigned int);
+static int parse_vc_action_l2_encap(struct context *, const struct token *,
+ const char *, unsigned int, void *,
+ unsigned int);
+static int parse_vc_action_l2_decap(struct context *, const struct token *,
+ const char *, unsigned int, void *,
+ unsigned int);
+static int parse_vc_action_mplsogre_encap(struct context *,
+ const struct token *, const char *,
+ unsigned int, void *, unsigned int);
+static int parse_vc_action_mplsogre_decap(struct context *,
+ const struct token *, const char *,
+ unsigned int, void *, unsigned int);
+static int parse_vc_action_mplsoudp_encap(struct context *,
+ const struct token *, const char *,
+ unsigned int, void *, unsigned int);
+static int parse_vc_action_mplsoudp_decap(struct context *,
+ const struct token *, const char *,
+ unsigned int, void *, unsigned int);
+static int parse_vc_action_raw_encap(struct context *,
+ const struct token *, const char *,
+ unsigned int, void *, unsigned int);
+static int parse_vc_action_raw_decap(struct context *,
+ const struct token *, const char *,
+ unsigned int, void *, unsigned int);
+static int parse_vc_action_raw_encap_index(struct context *,
+ const struct token *, const char *,
+ unsigned int, void *, unsigned int);
+static int parse_vc_action_raw_decap_index(struct context *,
+ const struct token *, const char *,
+ unsigned int, void *, unsigned int);
+static int parse_vc_action_set_meta(struct context *ctx,
+ const struct token *token, const char *str,
+ unsigned int len, void *buf,
+ unsigned int size);
+static int parse_destroy(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_flush(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_dump(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_query(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_action(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_list(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_aged(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_isolate(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_int(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_prefix(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_boolean(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_string(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_hex(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size);
+static int parse_string0(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_mac_addr(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_ipv4_addr(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_ipv6_addr(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int parse_port(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
+static int comp_none(struct context *, const struct token *,
+ unsigned int, char *, unsigned int);
+static int comp_boolean(struct context *, const struct token *,
+ unsigned int, char *, unsigned int);
+static int comp_action(struct context *, const struct token *,
+ unsigned int, char *, unsigned int);
+static int comp_port(struct context *, const struct token *,
+ unsigned int, char *, unsigned int);
+static int comp_rule_id(struct context *, const struct token *,
+ unsigned int, char *, unsigned int);
+static int comp_vc_action_rss_type(struct context *, const struct token *,
+ unsigned int, char *, unsigned int);
+static int comp_vc_action_rss_queue(struct context *, const struct token *,
+ unsigned int, char *, unsigned int);
+static int comp_set_raw_index(struct context *, const struct token *,
+ unsigned int, char *, unsigned int);
+
+/** Token definitions. */
+static const struct token token_list[] = {
+ /* Special tokens. */
+ [ZERO] = {
+ .name = "ZERO",
+ .help = "null entry, abused as the entry point",
+ .next = NEXT(NEXT_ENTRY(FLOW)),
+ },
+ [END] = {
+ .name = "",
+ .type = "RETURN",
+ .help = "command may end here",
+ },
+ [START_SET] = {
+ .name = "START_SET",
+ .help = "null entry, abused as the entry point for set",
+ .next = NEXT(NEXT_ENTRY(SET)),
+ },
+ [END_SET] = {
+ .name = "end_set",
+ .type = "RETURN",
+ .help = "set command may end here",
+ },
+ /* Common tokens. */
+ [INTEGER] = {
+ .name = "{int}",
+ .type = "INTEGER",
+ .help = "integer value",
+ .call = parse_int,
+ .comp = comp_none,
+ },
+ [UNSIGNED] = {
+ .name = "{unsigned}",
+ .type = "UNSIGNED",
+ .help = "unsigned integer value",
+ .call = parse_int,
+ .comp = comp_none,
+ },
+ [PREFIX] = {
+ .name = "{prefix}",
+ .type = "PREFIX",
+ .help = "prefix length for bit-mask",
+ .call = parse_prefix,
+ .comp = comp_none,
+ },
+ [BOOLEAN] = {
+ .name = "{boolean}",
+ .type = "BOOLEAN",
+ .help = "any boolean value",
+ .call = parse_boolean,
+ .comp = comp_boolean,
+ },
+ [STRING] = {
+ .name = "{string}",
+ .type = "STRING",
+ .help = "fixed string",
+ .call = parse_string,
+ .comp = comp_none,
+ },
+ [HEX] = {
+ .name = "{hex}",
+ .type = "HEX",
+ .help = "fixed string",
+ .call = parse_hex,
+ },
+ [FILE_PATH] = {
+ .name = "{file path}",
+ .type = "STRING",
+ .help = "file path",
+ .call = parse_string0,
+ .comp = comp_none,
+ },
+ [MAC_ADDR] = {
+ .name = "{MAC address}",
+ .type = "MAC-48",
+ .help = "standard MAC address notation",
+ .call = parse_mac_addr,
+ .comp = comp_none,
+ },
+ [IPV4_ADDR] = {
+ .name = "{IPv4 address}",
+ .type = "IPV4 ADDRESS",
+ .help = "standard IPv4 address notation",
+ .call = parse_ipv4_addr,
+ .comp = comp_none,
+ },
+ [IPV6_ADDR] = {
+ .name = "{IPv6 address}",
+ .type = "IPV6 ADDRESS",
+ .help = "standard IPv6 address notation",
+ .call = parse_ipv6_addr,
+ .comp = comp_none,
+ },
+ [RULE_ID] = {
+ .name = "{rule id}",
+ .type = "RULE ID",
+ .help = "rule identifier",
+ .call = parse_int,
+ .comp = comp_rule_id,
+ },
+ [PORT_ID] = {
+ .name = "{port_id}",
+ .type = "PORT ID",
+ .help = "port identifier",
+ .call = parse_port,
+ .comp = comp_port,
+ },
+ [GROUP_ID] = {
+ .name = "{group_id}",
+ .type = "GROUP ID",
+ .help = "group identifier",
+ .call = parse_int,
+ .comp = comp_none,
+ },
+ [PRIORITY_LEVEL] = {
+ .name = "{level}",
+ .type = "PRIORITY",
+ .help = "priority level",
+ .call = parse_int,
+ .comp = comp_none,
+ },
+ /* Top-level command. */
+ [FLOW] = {
+ .name = "flow",
+ .type = "{command} {port_id} [{arg} [...]]",
+ .help = "manage ingress/egress flow rules",
+ .next = NEXT(NEXT_ENTRY
+ (VALIDATE,
+ CREATE,
+ DESTROY,
+ FLUSH,
+ DUMP,
+ LIST,
+ AGED,
+ QUERY,
+ ISOLATE)),
+ .call = parse_init,
+ },
+ /* Sub-level commands. */
+ [VALIDATE] = {
+ .name = "validate",
+ .help = "check whether a flow rule can be created",
+ .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+ .call = parse_vc,
+ },
+ [CREATE] = {
+ .name = "create",
+ .help = "create a flow rule",
+ .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+ .call = parse_vc,
+ },
+ [DESTROY] = {
+ .name = "destroy",
+ .help = "destroy specific flow rules",
+ .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+ .call = parse_destroy,
+ },
+ [FLUSH] = {
+ .name = "flush",
+ .help = "destroy all flow rules",
+ .next = NEXT(NEXT_ENTRY(PORT_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+ .call = parse_flush,
+ },
+ [DUMP] = {
+ .name = "dump",
+ .help = "dump all flow rules to file",
+ .next = NEXT(next_dump_attr, NEXT_ENTRY(PORT_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, args.dump.file),
+ ARGS_ENTRY(struct buffer, port)),
+ .call = parse_dump,
+ },
+ [QUERY] = {
+ .name = "query",
+ .help = "query an existing flow rule",
+ .next = NEXT(NEXT_ENTRY(QUERY_ACTION),
+ NEXT_ENTRY(RULE_ID),
+ NEXT_ENTRY(PORT_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action.type),
+ ARGS_ENTRY(struct buffer, args.query.rule),
+ ARGS_ENTRY(struct buffer, port)),
+ .call = parse_query,
+ },
+ [LIST] = {
+ .name = "list",
+ .help = "list existing flow rules",
+ .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+ .call = parse_list,
+ },
+ [AGED] = {
+ .name = "aged",
+ .help = "list and destroy aged flows",
+ .next = NEXT(next_aged_attr, NEXT_ENTRY(PORT_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+ .call = parse_aged,
+ },
+ [ISOLATE] = {
+ .name = "isolate",
+ .help = "restrict ingress traffic to the defined flow rules",
+ .next = NEXT(NEXT_ENTRY(BOOLEAN),
+ NEXT_ENTRY(PORT_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, args.isolate.set),
+ ARGS_ENTRY(struct buffer, port)),
+ .call = parse_isolate,
+ },
+ /* Destroy arguments. */
+ [DESTROY_RULE] = {
+ .name = "rule",
+ .help = "specify a rule identifier",
+ .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)),
+ .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)),
+ .call = parse_destroy,
+ },
+ /* Query arguments. */
+ [QUERY_ACTION] = {
+ .name = "{action}",
+ .type = "ACTION",
+ .help = "action to query, must be part of the rule",
+ .call = parse_action,
+ .comp = comp_action,
+ },
+ /* List arguments. */
+ [LIST_GROUP] = {
+ .name = "group",
+ .help = "specify a group",
+ .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)),
+ .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
+ .call = parse_list,
+ },
+ [AGED_DESTROY] = {
+ .name = "destroy",
+ .help = "specify aged flows need be destroyed",
+ .call = parse_aged,
+ .comp = comp_none,
+ },
+ /* Validate/create attributes. */
+ [GROUP] = {
+ .name = "group",
+ .help = "specify a group",
+ .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)),
+ .call = parse_vc,
+ },
+ [PRIORITY] = {
+ .name = "priority",
+ .help = "specify a priority level",
+ .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)),
+ .call = parse_vc,
+ },
+ [INGRESS] = {
+ .name = "ingress",
+ .help = "affect rule to ingress",
+ .next = NEXT(next_vc_attr),
+ .call = parse_vc,
+ },
+ [EGRESS] = {
+ .name = "egress",
+ .help = "affect rule to egress",
+ .next = NEXT(next_vc_attr),
+ .call = parse_vc,
+ },
+ [TRANSFER] = {
+ .name = "transfer",
+ .help = "apply rule directly to endpoints found in pattern",
+ .next = NEXT(next_vc_attr),
+ .call = parse_vc,
+ },
+ /* Validate/create pattern. */
+ [PATTERN] = {
+ .name = "pattern",
+ .help = "submit a list of pattern items",
+ .next = NEXT(next_item),
+ .call = parse_vc,
+ },
+ [ITEM_PARAM_IS] = {
+ .name = "is",
+ .help = "match value perfectly (with full bit-mask)",
+ .call = parse_vc_spec,
+ },
+ [ITEM_PARAM_SPEC] = {
+ .name = "spec",
+ .help = "match value according to configured bit-mask",
+ .call = parse_vc_spec,
+ },
+ [ITEM_PARAM_LAST] = {
+ .name = "last",
+ .help = "specify upper bound to establish a range",
+ .call = parse_vc_spec,
+ },
+ [ITEM_PARAM_MASK] = {
+ .name = "mask",
+ .help = "specify bit-mask with relevant bits set to one",
+ .call = parse_vc_spec,
+ },
+ [ITEM_PARAM_PREFIX] = {
+ .name = "prefix",
+ .help = "generate bit-mask from a prefix length",
+ .call = parse_vc_spec,
+ },
+ [ITEM_NEXT] = {
+ .name = "/",
+ .help = "specify next pattern item",
+ .next = NEXT(next_item),
+ },
+ [ITEM_END] = {
+ .name = "end",
+ .help = "end list of pattern items",
+ .priv = PRIV_ITEM(END, 0),
+ .next = NEXT(NEXT_ENTRY(ACTIONS)),
+ .call = parse_vc,
+ },
+ [ITEM_VOID] = {
+ .name = "void",
+ .help = "no-op pattern item",
+ .priv = PRIV_ITEM(VOID, 0),
+ .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
+ .call = parse_vc,
+ },
+ [ITEM_INVERT] = {
+ .name = "invert",
+ .help = "perform actions when pattern does not match",
+ .priv = PRIV_ITEM(INVERT, 0),
+ .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
+ .call = parse_vc,
+ },
+ [ITEM_ANY] = {
+ .name = "any",
+ .help = "match any protocol for the current layer",
+ .priv = PRIV_ITEM(ANY, sizeof(struct rte_flow_item_any)),
+ .next = NEXT(item_any),
+ .call = parse_vc,
+ },
+ [ITEM_ANY_NUM] = {
+ .name = "num",
+ .help = "number of layers covered",
+ .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)),
+ },
+ [ITEM_PF] = {
+ .name = "pf",
+ .help = "match traffic from/to the physical function",
+ .priv = PRIV_ITEM(PF, 0),
+ .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
+ .call = parse_vc,
+ },
+ [ITEM_VF] = {
+ .name = "vf",
+ .help = "match traffic from/to a virtual function ID",
+ .priv = PRIV_ITEM(VF, sizeof(struct rte_flow_item_vf)),
+ .next = NEXT(item_vf),
+ .call = parse_vc,
+ },
+ [ITEM_VF_ID] = {
+ .name = "id",
+ .help = "VF ID",
+ .next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_vf, id)),
+ },
+ [ITEM_PHY_PORT] = {
+ .name = "phy_port",
+ .help = "match traffic from/to a specific physical port",
+ .priv = PRIV_ITEM(PHY_PORT,
+ sizeof(struct rte_flow_item_phy_port)),
+ .next = NEXT(item_phy_port),
+ .call = parse_vc,
+ },
+ [ITEM_PHY_PORT_INDEX] = {
+ .name = "index",
+ .help = "physical port index",
+ .next = NEXT(item_phy_port, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_phy_port, index)),
+ },
+ [ITEM_PORT_ID] = {
+ .name = "port_id",
+ .help = "match traffic from/to a given DPDK port ID",
+ .priv = PRIV_ITEM(PORT_ID,
+ sizeof(struct rte_flow_item_port_id)),
+ .next = NEXT(item_port_id),
+ .call = parse_vc,
+ },
+ [ITEM_PORT_ID_ID] = {
+ .name = "id",
+ .help = "DPDK port ID",
+ .next = NEXT(item_port_id, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port_id, id)),
+ },
+ [ITEM_MARK] = {
+ .name = "mark",
+ .help = "match traffic against value set in previously matched rule",
+ .priv = PRIV_ITEM(MARK, sizeof(struct rte_flow_item_mark)),
+ .next = NEXT(item_mark),
+ .call = parse_vc,
+ },
+ [ITEM_MARK_ID] = {
+ .name = "id",
+ .help = "Integer value to match against",
+ .next = NEXT(item_mark, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_mark, id)),
+ },
+ [ITEM_RAW] = {
+ .name = "raw",
+ .help = "match an arbitrary byte string",
+ .priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE),
+ .next = NEXT(item_raw),
+ .call = parse_vc,
+ },
+ [ITEM_RAW_RELATIVE] = {
+ .name = "relative",
+ .help = "look for pattern after the previous item",
+ .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
+ .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
+ relative, 1)),
+ },
+ [ITEM_RAW_SEARCH] = {
+ .name = "search",
+ .help = "search pattern from offset (see also limit)",
+ .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
+ .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
+ search, 1)),
+ },
+ [ITEM_RAW_OFFSET] = {
+ .name = "offset",
+ .help = "absolute or relative offset for pattern",
+ .next = NEXT(item_raw, NEXT_ENTRY(INTEGER), item_param),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, offset)),
+ },
+ [ITEM_RAW_LIMIT] = {
+ .name = "limit",
+ .help = "search area limit for start of pattern",
+ .next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, limit)),
+ },
+ [ITEM_RAW_PATTERN] = {
+ .name = "pattern",
+ .help = "byte string to look for",
+ .next = NEXT(item_raw,
+ NEXT_ENTRY(STRING),
+ NEXT_ENTRY(ITEM_PARAM_IS,
+ ITEM_PARAM_SPEC,
+ ITEM_PARAM_MASK)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, pattern),
+ ARGS_ENTRY(struct rte_flow_item_raw, length),
+ ARGS_ENTRY_ARB(sizeof(struct rte_flow_item_raw),
+ ITEM_RAW_PATTERN_SIZE)),
+ },
+ [ITEM_ETH] = {
+ .name = "eth",
+ .help = "match Ethernet header",
+ .priv = PRIV_ITEM(ETH, sizeof(struct rte_flow_item_eth)),
+ .next = NEXT(item_eth),
+ .call = parse_vc,
+ },
+ [ITEM_ETH_DST] = {
+ .name = "dst",
+ .help = "destination MAC",
+ .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, dst)),
+ },
+ [ITEM_ETH_SRC] = {
+ .name = "src",
+ .help = "source MAC",
+ .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, src)),
+ },
+ [ITEM_ETH_TYPE] = {
+ .name = "type",
+ .help = "EtherType",
+ .next = NEXT(item_eth, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, type)),
+ },
+ [ITEM_VLAN] = {
+ .name = "vlan",
+ .help = "match 802.1Q/ad VLAN tag",
+ .priv = PRIV_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)),
+ .next = NEXT(item_vlan),
+ .call = parse_vc,
+ },
+ [ITEM_VLAN_TCI] = {
+ .name = "tci",
+ .help = "tag control information",
+ .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)),
+ },
+ [ITEM_VLAN_PCP] = {
+ .name = "pcp",
+ .help = "priority code point",
+ .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
+ tci, "\xe0\x00")),
+ },
+ [ITEM_VLAN_DEI] = {
+ .name = "dei",
+ .help = "drop eligible indicator",
+ .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
+ tci, "\x10\x00")),
+ },
+ [ITEM_VLAN_VID] = {
+ .name = "vid",
+ .help = "VLAN identifier",
+ .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
+ tci, "\x0f\xff")),
+ },
+ [ITEM_VLAN_INNER_TYPE] = {
+ .name = "inner_type",
+ .help = "inner EtherType",
+ .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan,
+ inner_type)),
+ },
+ [ITEM_IPV4] = {
+ .name = "ipv4",
+ .help = "match IPv4 header",
+ .priv = PRIV_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)),
+ .next = NEXT(item_ipv4),
+ .call = parse_vc,
+ },
+ [ITEM_IPV4_TOS] = {
+ .name = "tos",
+ .help = "type of service",
+ .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+ hdr.type_of_service)),
+ },
+ [ITEM_IPV4_TTL] = {
+ .name = "ttl",
+ .help = "time to live",
+ .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+ hdr.time_to_live)),
+ },
+ [ITEM_IPV4_PROTO] = {
+ .name = "proto",
+ .help = "next protocol ID",
+ .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+ hdr.next_proto_id)),
+ },
+ [ITEM_IPV4_SRC] = {
+ .name = "src",
+ .help = "source address",
+ .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+ hdr.src_addr)),
+ },
+ [ITEM_IPV4_DST] = {
+ .name = "dst",
+ .help = "destination address",
+ .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+ hdr.dst_addr)),
+ },
+ [ITEM_IPV6] = {
+ .name = "ipv6",
+ .help = "match IPv6 header",
+ .priv = PRIV_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)),
+ .next = NEXT(item_ipv6),
+ .call = parse_vc,
+ },
+ [ITEM_IPV6_TC] = {
+ .name = "tc",
+ .help = "traffic class",
+ .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6,
+ hdr.vtc_flow,
+ "\x0f\xf0\x00\x00")),
+ },
+ [ITEM_IPV6_FLOW] = {
+ .name = "flow",
+ .help = "flow label",
+ .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6,
+ hdr.vtc_flow,
+ "\x00\x0f\xff\xff")),
+ },
+ [ITEM_IPV6_PROTO] = {
+ .name = "proto",
+ .help = "protocol (next header)",
+ .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
+ hdr.proto)),
+ },
+ [ITEM_IPV6_HOP] = {
+ .name = "hop",
+ .help = "hop limit",
+ .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
+ hdr.hop_limits)),
+ },
+ [ITEM_IPV6_SRC] = {
+ .name = "src",
+ .help = "source address",
+ .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
+ hdr.src_addr)),
+ },
+ [ITEM_IPV6_DST] = {
+ .name = "dst",
+ .help = "destination address",
+ .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
+ hdr.dst_addr)),
+ },
+ [ITEM_ICMP] = {
+ .name = "icmp",
+ .help = "match ICMP header",
+ .priv = PRIV_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)),
+ .next = NEXT(item_icmp),
+ .call = parse_vc,
+ },
+ [ITEM_ICMP_TYPE] = {
+ .name = "type",
+ .help = "ICMP packet type",
+ .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp,
+ hdr.icmp_type)),
+ },
+ [ITEM_ICMP_CODE] = {
+ .name = "code",
+ .help = "ICMP packet code",
+ .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp,
+ hdr.icmp_code)),
+ },
+ [ITEM_UDP] = {
+ .name = "udp",
+ .help = "match UDP header",
+ .priv = PRIV_ITEM(UDP, sizeof(struct rte_flow_item_udp)),
+ .next = NEXT(item_udp),
+ .call = parse_vc,
+ },
+ [ITEM_UDP_SRC] = {
+ .name = "src",
+ .help = "UDP source port",
+ .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp,
+ hdr.src_port)),
+ },
+ [ITEM_UDP_DST] = {
+ .name = "dst",
+ .help = "UDP destination port",
+ .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp,
+ hdr.dst_port)),
+ },
+ [ITEM_TCP] = {
+ .name = "tcp",
+ .help = "match TCP header",
+ .priv = PRIV_ITEM(TCP, sizeof(struct rte_flow_item_tcp)),
+ .next = NEXT(item_tcp),
+ .call = parse_vc,
+ },
+ [ITEM_TCP_SRC] = {
+ .name = "src",
+ .help = "TCP source port",
+ .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
+ hdr.src_port)),
+ },
+ [ITEM_TCP_DST] = {
+ .name = "dst",
+ .help = "TCP destination port",
+ .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
+ hdr.dst_port)),
+ },
+ [ITEM_TCP_FLAGS] = {
+ .name = "flags",
+ .help = "TCP flags",
+ .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
+ hdr.tcp_flags)),
+ },
+ [ITEM_SCTP] = {
+ .name = "sctp",
+ .help = "match SCTP header",
+ .priv = PRIV_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)),
+ .next = NEXT(item_sctp),
+ .call = parse_vc,
+ },
+ [ITEM_SCTP_SRC] = {
+ .name = "src",
+ .help = "SCTP source port",
+ .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
+ hdr.src_port)),
+ },
+ [ITEM_SCTP_DST] = {
+ .name = "dst",
+ .help = "SCTP destination port",
+ .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
+ hdr.dst_port)),
+ },
+ [ITEM_SCTP_TAG] = {
+ .name = "tag",
+ .help = "validation tag",
+ .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
+ hdr.tag)),
+ },
+ [ITEM_SCTP_CKSUM] = {
+ .name = "cksum",
+ .help = "checksum",
+ .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
+ hdr.cksum)),
+ },
+ [ITEM_VXLAN] = {
+ .name = "vxlan",
+ .help = "match VXLAN header",
+ .priv = PRIV_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)),
+ .next = NEXT(item_vxlan),
+ .call = parse_vc,
+ },
+ [ITEM_VXLAN_VNI] = {
+ .name = "vni",
+ .help = "VXLAN identifier",
+ .next = NEXT(item_vxlan, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan, vni)),
+ },
+ [ITEM_E_TAG] = {
+ .name = "e_tag",
+ .help = "match E-Tag header",
+ .priv = PRIV_ITEM(E_TAG, sizeof(struct rte_flow_item_e_tag)),
+ .next = NEXT(item_e_tag),
+ .call = parse_vc,
+ },
+ [ITEM_E_TAG_GRP_ECID_B] = {
+ .name = "grp_ecid_b",
+ .help = "GRP and E-CID base",
+ .next = NEXT(item_e_tag, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_e_tag,
+ rsvd_grp_ecid_b,
+ "\x3f\xff")),
+ },
+ [ITEM_NVGRE] = {
+ .name = "nvgre",
+ .help = "match NVGRE header",
+ .priv = PRIV_ITEM(NVGRE, sizeof(struct rte_flow_item_nvgre)),
+ .next = NEXT(item_nvgre),
+ .call = parse_vc,
+ },
+ [ITEM_NVGRE_TNI] = {
+ .name = "tni",
+ .help = "virtual subnet ID",
+ .next = NEXT(item_nvgre, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_nvgre, tni)),
+ },
+ [ITEM_MPLS] = {
+ .name = "mpls",
+ .help = "match MPLS header",
+ .priv = PRIV_ITEM(MPLS, sizeof(struct rte_flow_item_mpls)),
+ .next = NEXT(item_mpls),
+ .call = parse_vc,
+ },
+ [ITEM_MPLS_LABEL] = {
+ .name = "label",
+ .help = "MPLS label",
+ .next = NEXT(item_mpls, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_mpls,
+ label_tc_s,
+ "\xff\xff\xf0")),
+ },
+ [ITEM_MPLS_TC] = {
+ .name = "tc",
+ .help = "MPLS Traffic Class",
+ .next = NEXT(item_mpls, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_mpls,
+ label_tc_s,
+ "\x00\x00\x0e")),
+ },
+ [ITEM_MPLS_S] = {
+ .name = "s",
+ .help = "MPLS Bottom-of-Stack",
+ .next = NEXT(item_mpls, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_mpls,
+ label_tc_s,
+ "\x00\x00\x01")),
+ },
+ [ITEM_GRE] = {
+ .name = "gre",
+ .help = "match GRE header",
+ .priv = PRIV_ITEM(GRE, sizeof(struct rte_flow_item_gre)),
+ .next = NEXT(item_gre),
+ .call = parse_vc,
+ },
+ [ITEM_GRE_PROTO] = {
+ .name = "protocol",
+ .help = "GRE protocol type",
+ .next = NEXT(item_gre, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gre,
+ protocol)),
+ },
+ [ITEM_GRE_C_RSVD0_VER] = {
+ .name = "c_rsvd0_ver",
+ .help =
+ "checksum (1b), undefined (1b), key bit (1b),"
+ " sequence number (1b), reserved 0 (9b),"
+ " version (3b)",
+ .next = NEXT(item_gre, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gre,
+ c_rsvd0_ver)),
+ },
+ [ITEM_GRE_C_BIT] = {
+ .name = "c_bit",
+ .help = "checksum bit (C)",
+ .next = NEXT(item_gre, NEXT_ENTRY(BOOLEAN), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_gre,
+ c_rsvd0_ver,
+ "\x80\x00\x00\x00")),
+ },
+ [ITEM_GRE_S_BIT] = {
+ .name = "s_bit",
+ .help = "sequence number bit (S)",
+ .next = NEXT(item_gre, NEXT_ENTRY(BOOLEAN), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_gre,
+ c_rsvd0_ver,
+ "\x10\x00\x00\x00")),
+ },
+ [ITEM_GRE_K_BIT] = {
+ .name = "k_bit",
+ .help = "key bit (K)",
+ .next = NEXT(item_gre, NEXT_ENTRY(BOOLEAN), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_gre,
+ c_rsvd0_ver,
+ "\x20\x00\x00\x00")),
+ },
+ [ITEM_FUZZY] = {
+ .name = "fuzzy",
+ .help = "fuzzy pattern match, expect faster than default",
+ .priv = PRIV_ITEM(FUZZY,
+ sizeof(struct rte_flow_item_fuzzy)),
+ .next = NEXT(item_fuzzy),
+ .call = parse_vc,
+ },
+ [ITEM_FUZZY_THRESH] = {
+ .name = "thresh",
+ .help = "match accuracy threshold",
+ .next = NEXT(item_fuzzy, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_fuzzy,
+ thresh)),
+ },
+ [ITEM_GTP] = {
+ .name = "gtp",
+ .help = "match GTP header",
+ .priv = PRIV_ITEM(GTP, sizeof(struct rte_flow_item_gtp)),
+ .next = NEXT(item_gtp),
+ .call = parse_vc,
+ },
+ [ITEM_GTP_FLAGS] = {
+ .name = "v_pt_rsv_flags",
+ .help = "GTP flags",
+ .next = NEXT(item_gtp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_gtp,
+ v_pt_rsv_flags)),
+ },
+ [ITEM_GTP_MSG_TYPE] = {
+ .name = "msg_type",
+ .help = "GTP message type",
+ .next = NEXT(item_gtp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_gtp, msg_type)),
+ },
+ [ITEM_GTP_TEID] = {
+ .name = "teid",
+ .help = "tunnel endpoint identifier",
+ .next = NEXT(item_gtp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gtp, teid)),
+ },
+ [ITEM_GTPC] = {
+ .name = "gtpc",
+ .help = "match GTP header",
+ .priv = PRIV_ITEM(GTPC, sizeof(struct rte_flow_item_gtp)),
+ .next = NEXT(item_gtp),
+ .call = parse_vc,
+ },
+ [ITEM_GTPU] = {
+ .name = "gtpu",
+ .help = "match GTP header",
+ .priv = PRIV_ITEM(GTPU, sizeof(struct rte_flow_item_gtp)),
+ .next = NEXT(item_gtp),
+ .call = parse_vc,
+ },
+ [ITEM_GENEVE] = {
+ .name = "geneve",
+ .help = "match GENEVE header",
+ .priv = PRIV_ITEM(GENEVE, sizeof(struct rte_flow_item_geneve)),
+ .next = NEXT(item_geneve),
+ .call = parse_vc,
+ },
+ [ITEM_GENEVE_VNI] = {
+ .name = "vni",
+ .help = "virtual network identifier",
+ .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve, vni)),
+ },
+ [ITEM_GENEVE_PROTO] = {
+ .name = "protocol",
+ .help = "GENEVE protocol type",
+ .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve,
+ protocol)),
+ },
+ [ITEM_VXLAN_GPE] = {
+ .name = "vxlan-gpe",
+ .help = "match VXLAN-GPE header",
+ .priv = PRIV_ITEM(VXLAN_GPE,
+ sizeof(struct rte_flow_item_vxlan_gpe)),
+ .next = NEXT(item_vxlan_gpe),
+ .call = parse_vc,
+ },
+ [ITEM_VXLAN_GPE_VNI] = {
+ .name = "vni",
+ .help = "VXLAN-GPE identifier",
+ .next = NEXT(item_vxlan_gpe, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan_gpe,
+ vni)),
+ },
+ [ITEM_ARP_ETH_IPV4] = {
+ .name = "arp_eth_ipv4",
+ .help = "match ARP header for Ethernet/IPv4",
+ .priv = PRIV_ITEM(ARP_ETH_IPV4,
+ sizeof(struct rte_flow_item_arp_eth_ipv4)),
+ .next = NEXT(item_arp_eth_ipv4),
+ .call = parse_vc,
+ },
+ [ITEM_ARP_ETH_IPV4_SHA] = {
+ .name = "sha",
+ .help = "sender hardware address",
+ .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(MAC_ADDR),
+ item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
+ sha)),
+ },
+ [ITEM_ARP_ETH_IPV4_SPA] = {
+ .name = "spa",
+ .help = "sender IPv4 address",
+ .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(IPV4_ADDR),
+ item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
+ spa)),
+ },
+ [ITEM_ARP_ETH_IPV4_THA] = {
+ .name = "tha",
+ .help = "target hardware address",
+ .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(MAC_ADDR),
+ item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
+ tha)),
+ },
+ [ITEM_ARP_ETH_IPV4_TPA] = {
+ .name = "tpa",
+ .help = "target IPv4 address",
+ .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(IPV4_ADDR),
+ item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
+ tpa)),
+ },
+ [ITEM_IPV6_EXT] = {
+ .name = "ipv6_ext",
+ .help = "match presence of any IPv6 extension header",
+ .priv = PRIV_ITEM(IPV6_EXT,
+ sizeof(struct rte_flow_item_ipv6_ext)),
+ .next = NEXT(item_ipv6_ext),
+ .call = parse_vc,
+ },
+ [ITEM_IPV6_EXT_NEXT_HDR] = {
+ .name = "next_hdr",
+ .help = "next header",
+ .next = NEXT(item_ipv6_ext, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6_ext,
+ next_hdr)),
+ },
+ [ITEM_ICMP6] = {
+ .name = "icmp6",
+ .help = "match any ICMPv6 header",
+ .priv = PRIV_ITEM(ICMP6, sizeof(struct rte_flow_item_icmp6)),
+ .next = NEXT(item_icmp6),
+ .call = parse_vc,
+ },
+ [ITEM_ICMP6_TYPE] = {
+ .name = "type",
+ .help = "ICMPv6 type",
+ .next = NEXT(item_icmp6, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6,
+ type)),
+ },
+ [ITEM_ICMP6_CODE] = {
+ .name = "code",
+ .help = "ICMPv6 code",
+ .next = NEXT(item_icmp6, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6,
+ code)),
+ },
+ [ITEM_ICMP6_ND_NS] = {
+ .name = "icmp6_nd_ns",
+ .help = "match ICMPv6 neighbor discovery solicitation",
+ .priv = PRIV_ITEM(ICMP6_ND_NS,
+ sizeof(struct rte_flow_item_icmp6_nd_ns)),
+ .next = NEXT(item_icmp6_nd_ns),
+ .call = parse_vc,
+ },
+ [ITEM_ICMP6_ND_NS_TARGET_ADDR] = {
+ .name = "target_addr",
+ .help = "target address",
+ .next = NEXT(item_icmp6_nd_ns, NEXT_ENTRY(IPV6_ADDR),
+ item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_ns,
+ target_addr)),
+ },
+ [ITEM_ICMP6_ND_NA] = {
+ .name = "icmp6_nd_na",
+ .help = "match ICMPv6 neighbor discovery advertisement",
+ .priv = PRIV_ITEM(ICMP6_ND_NA,
+ sizeof(struct rte_flow_item_icmp6_nd_na)),
+ .next = NEXT(item_icmp6_nd_na),
+ .call = parse_vc,
+ },
+ [ITEM_ICMP6_ND_NA_TARGET_ADDR] = {
+ .name = "target_addr",
+ .help = "target address",
+ .next = NEXT(item_icmp6_nd_na, NEXT_ENTRY(IPV6_ADDR),
+ item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_na,
+ target_addr)),
+ },
+ [ITEM_ICMP6_ND_OPT] = {
+ .name = "icmp6_nd_opt",
+ .help = "match presence of any ICMPv6 neighbor discovery"
+ " option",
+ .priv = PRIV_ITEM(ICMP6_ND_OPT,
+ sizeof(struct rte_flow_item_icmp6_nd_opt)),
+ .next = NEXT(item_icmp6_nd_opt),
+ .call = parse_vc,
+ },
+ [ITEM_ICMP6_ND_OPT_TYPE] = {
+ .name = "type",
+ .help = "ND option type",
+ .next = NEXT(item_icmp6_nd_opt, NEXT_ENTRY(UNSIGNED),
+ item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_opt,
+ type)),
+ },
+ [ITEM_ICMP6_ND_OPT_SLA_ETH] = {
+ .name = "icmp6_nd_opt_sla_eth",
+ .help = "match ICMPv6 neighbor discovery source Ethernet"
+ " link-layer address option",
+ .priv = PRIV_ITEM
+ (ICMP6_ND_OPT_SLA_ETH,
+ sizeof(struct rte_flow_item_icmp6_nd_opt_sla_eth)),
+ .next = NEXT(item_icmp6_nd_opt_sla_eth),
+ .call = parse_vc,
+ },
+ [ITEM_ICMP6_ND_OPT_SLA_ETH_SLA] = {
+ .name = "sla",
+ .help = "source Ethernet LLA",
+ .next = NEXT(item_icmp6_nd_opt_sla_eth, NEXT_ENTRY(MAC_ADDR),
+ item_param),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_item_icmp6_nd_opt_sla_eth, sla)),
+ },
+ [ITEM_ICMP6_ND_OPT_TLA_ETH] = {
+ .name = "icmp6_nd_opt_tla_eth",
+ .help = "match ICMPv6 neighbor discovery target Ethernet"
+ " link-layer address option",
+ .priv = PRIV_ITEM
+ (ICMP6_ND_OPT_TLA_ETH,
+ sizeof(struct rte_flow_item_icmp6_nd_opt_tla_eth)),
+ .next = NEXT(item_icmp6_nd_opt_tla_eth),
+ .call = parse_vc,
+ },
+ [ITEM_ICMP6_ND_OPT_TLA_ETH_TLA] = {
+ .name = "tla",
+ .help = "target Ethernet LLA",
+ .next = NEXT(item_icmp6_nd_opt_tla_eth, NEXT_ENTRY(MAC_ADDR),
+ item_param),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_item_icmp6_nd_opt_tla_eth, tla)),
+ },
+ [ITEM_META] = {
+ .name = "meta",
+ .help = "match metadata header",
+ .priv = PRIV_ITEM(META, sizeof(struct rte_flow_item_meta)),
+ .next = NEXT(item_meta),
+ .call = parse_vc,
+ },
+ [ITEM_META_DATA] = {
+ .name = "data",
+ .help = "metadata value",
+ .next = NEXT(item_meta, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK(struct rte_flow_item_meta,
+ data, "\xff\xff\xff\xff")),
+ },
+ [ITEM_GRE_KEY] = {
+ .name = "gre_key",
+ .help = "match GRE key",
+ .priv = PRIV_ITEM(GRE_KEY, sizeof(rte_be32_t)),
+ .next = NEXT(item_gre_key),
+ .call = parse_vc,
+ },
+ [ITEM_GRE_KEY_VALUE] = {
+ .name = "value",
+ .help = "key value",
+ .next = NEXT(item_gre_key, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARG_ENTRY_HTON(rte_be32_t)),
+ },
+ [ITEM_GTP_PSC] = {
+ .name = "gtp_psc",
+ .help = "match GTP extension header with type 0x85",
+ .priv = PRIV_ITEM(GTP_PSC,
+ sizeof(struct rte_flow_item_gtp_psc)),
+ .next = NEXT(item_gtp_psc),
+ .call = parse_vc,
+ },
+ [ITEM_GTP_PSC_QFI] = {
+ .name = "qfi",
+ .help = "QoS flow identifier",
+ .next = NEXT(item_gtp_psc, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gtp_psc,
+ qfi)),
+ },
+ [ITEM_GTP_PSC_PDU_T] = {
+ .name = "pdu_t",
+ .help = "PDU type",
+ .next = NEXT(item_gtp_psc, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gtp_psc,
+ pdu_type)),
+ },
+ [ITEM_PPPOES] = {
+ .name = "pppoes",
+ .help = "match PPPoE session header",
+ .priv = PRIV_ITEM(PPPOES, sizeof(struct rte_flow_item_pppoe)),
+ .next = NEXT(item_pppoes),
+ .call = parse_vc,
+ },
+ [ITEM_PPPOED] = {
+ .name = "pppoed",
+ .help = "match PPPoE discovery header",
+ .priv = PRIV_ITEM(PPPOED, sizeof(struct rte_flow_item_pppoe)),
+ .next = NEXT(item_pppoed),
+ .call = parse_vc,
+ },
+ [ITEM_PPPOE_SEID] = {
+ .name = "seid",
+ .help = "session identifier",
+ .next = NEXT(item_pppoes, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_pppoe,
+ session_id)),
+ },
+ [ITEM_PPPOE_PROTO_ID] = {
+ .name = "pppoe_proto_id",
+ .help = "match PPPoE session protocol identifier",
+ .priv = PRIV_ITEM(PPPOE_PROTO_ID,
+ sizeof(struct rte_flow_item_pppoe_proto_id)),
+ .next = NEXT(item_pppoe_proto_id, NEXT_ENTRY(UNSIGNED),
+ item_param),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_item_pppoe_proto_id, proto_id)),
+ .call = parse_vc,
+ },
+ [ITEM_HIGIG2] = {
+ .name = "higig2",
+ .help = "matches higig2 header",
+ .priv = PRIV_ITEM(HIGIG2,
+ sizeof(struct rte_flow_item_higig2_hdr)),
+ .next = NEXT(item_higig2),
+ .call = parse_vc,
+ },
+ [ITEM_HIGIG2_CLASSIFICATION] = {
+ .name = "classification",
+ .help = "matches classification of higig2 header",
+ .next = NEXT(item_higig2, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_higig2_hdr,
+ hdr.ppt1.classification)),
+ },
+ [ITEM_HIGIG2_VID] = {
+ .name = "vid",
+ .help = "matches vid of higig2 header",
+ .next = NEXT(item_higig2, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_higig2_hdr,
+ hdr.ppt1.vid)),
+ },
+ [ITEM_TAG] = {
+ .name = "tag",
+ .help = "match tag value",
+ .priv = PRIV_ITEM(TAG, sizeof(struct rte_flow_item_tag)),
+ .next = NEXT(item_tag),
+ .call = parse_vc,
+ },
+ [ITEM_TAG_DATA] = {
+ .name = "data",
+ .help = "tag value to match",
+ .next = NEXT(item_tag, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_tag, data)),
+ },
+ [ITEM_TAG_INDEX] = {
+ .name = "index",
+ .help = "index of tag array to match",
+ .next = NEXT(item_tag, NEXT_ENTRY(UNSIGNED),
+ NEXT_ENTRY(ITEM_PARAM_IS)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_tag, index)),
+ },
+ [ITEM_L2TPV3OIP] = {
+ .name = "l2tpv3oip",
+ .help = "match L2TPv3 over IP header",
+ .priv = PRIV_ITEM(L2TPV3OIP,
+ sizeof(struct rte_flow_item_l2tpv3oip)),
+ .next = NEXT(item_l2tpv3oip),
+ .call = parse_vc,
+ },
+ [ITEM_L2TPV3OIP_SESSION_ID] = {
+ .name = "session_id",
+ .help = "session identifier",
+ .next = NEXT(item_l2tpv3oip, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_l2tpv3oip,
+ session_id)),
+ },
+ [ITEM_ESP] = {
+ .name = "esp",
+ .help = "match ESP header",
+ .priv = PRIV_ITEM(ESP, sizeof(struct rte_flow_item_esp)),
+ .next = NEXT(item_esp),
+ .call = parse_vc,
+ },
+ [ITEM_ESP_SPI] = {
+ .name = "spi",
+ .help = "security policy index",
+ .next = NEXT(item_esp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_esp,
+ hdr.spi)),
+ },
+ [ITEM_AH] = {
+ .name = "ah",
+ .help = "match AH header",
+ .priv = PRIV_ITEM(AH, sizeof(struct rte_flow_item_ah)),
+ .next = NEXT(item_ah),
+ .call = parse_vc,
+ },
+ [ITEM_AH_SPI] = {
+ .name = "spi",
+ .help = "security parameters index",
+ .next = NEXT(item_ah, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ah, spi)),
+ },
+ [ITEM_PFCP] = {
+ .name = "pfcp",
+ .help = "match pfcp header",
+ .priv = PRIV_ITEM(PFCP, sizeof(struct rte_flow_item_pfcp)),
+ .next = NEXT(item_pfcp),
+ .call = parse_vc,
+ },
+ [ITEM_PFCP_S_FIELD] = {
+ .name = "s_field",
+ .help = "S field",
+ .next = NEXT(item_pfcp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_pfcp,
+ s_field)),
+ },
+ [ITEM_PFCP_SEID] = {
+ .name = "seid",
+ .help = "session endpoint identifier",
+ .next = NEXT(item_pfcp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_pfcp, seid)),
+ },
+ /* Validate/create actions. */
+ [ACTIONS] = {
+ .name = "actions",
+ .help = "submit a list of associated actions",
+ .next = NEXT(next_action),
+ .call = parse_vc,
+ },
+ [ACTION_NEXT] = {
+ .name = "/",
+ .help = "specify next action",
+ .next = NEXT(next_action),
+ },
+ [ACTION_END] = {
+ .name = "end",
+ .help = "end list of actions",
+ .priv = PRIV_ACTION(END, 0),
+ .call = parse_vc,
+ },
+ [ACTION_VOID] = {
+ .name = "void",
+ .help = "no-op action",
+ .priv = PRIV_ACTION(VOID, 0),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc,
+ },
+ [ACTION_PASSTHRU] = {
+ .name = "passthru",
+ .help = "let subsequent rule process matched packets",
+ .priv = PRIV_ACTION(PASSTHRU, 0),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc,
+ },
+ [ACTION_JUMP] = {
+ .name = "jump",
+ .help = "redirect traffic to a given group",
+ .priv = PRIV_ACTION(JUMP, sizeof(struct rte_flow_action_jump)),
+ .next = NEXT(action_jump),
+ .call = parse_vc,
+ },
+ [ACTION_JUMP_GROUP] = {
+ .name = "group",
+ .help = "group to redirect traffic to",
+ .next = NEXT(action_jump, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_jump, group)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_MARK] = {
+ .name = "mark",
+ .help = "attach 32 bit value to packets",
+ .priv = PRIV_ACTION(MARK, sizeof(struct rte_flow_action_mark)),
+ .next = NEXT(action_mark),
+ .call = parse_vc,
+ },
+ [ACTION_MARK_ID] = {
+ .name = "id",
+ .help = "32 bit value to return with packets",
+ .next = NEXT(action_mark, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_mark, id)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_FLAG] = {
+ .name = "flag",
+ .help = "flag packets",
+ .priv = PRIV_ACTION(FLAG, 0),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc,
+ },
+ [ACTION_QUEUE] = {
+ .name = "queue",
+ .help = "assign packets to a given queue index",
+ .priv = PRIV_ACTION(QUEUE,
+ sizeof(struct rte_flow_action_queue)),
+ .next = NEXT(action_queue),
+ .call = parse_vc,
+ },
+ [ACTION_QUEUE_INDEX] = {
+ .name = "index",
+ .help = "queue index to use",
+ .next = NEXT(action_queue, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_queue, index)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_DROP] = {
+ .name = "drop",
+ .help = "drop packets (note: passthru has priority)",
+ .priv = PRIV_ACTION(DROP, 0),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc,
+ },
+ [ACTION_COUNT] = {
+ .name = "count",
+ .help = "enable counters for this rule",
+ .priv = PRIV_ACTION(COUNT,
+ sizeof(struct rte_flow_action_count)),
+ .next = NEXT(action_count),
+ .call = parse_vc,
+ },
+ [ACTION_COUNT_ID] = {
+ .name = "identifier",
+ .help = "counter identifier to use",
+ .next = NEXT(action_count, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_count, id)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_COUNT_SHARED] = {
+ .name = "shared",
+ .help = "shared counter",
+ .next = NEXT(action_count, NEXT_ENTRY(BOOLEAN)),
+ .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_count,
+ shared, 1)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_RSS] = {
+ .name = "rss",
+ .help = "spread packets among several queues",
+ .priv = PRIV_ACTION(RSS, sizeof(struct action_rss_data)),
+ .next = NEXT(action_rss),
+ .call = parse_vc_action_rss,
+ },
+ [ACTION_RSS_FUNC] = {
+ .name = "func",
+ .help = "RSS hash function to apply",
+ .next = NEXT(action_rss,
+ NEXT_ENTRY(ACTION_RSS_FUNC_DEFAULT,
+ ACTION_RSS_FUNC_TOEPLITZ,
+ ACTION_RSS_FUNC_SIMPLE_XOR,
+ ACTION_RSS_FUNC_SYMMETRIC_TOEPLITZ)),
+ },
+ [ACTION_RSS_FUNC_DEFAULT] = {
+ .name = "default",
+ .help = "default hash function",
+ .call = parse_vc_action_rss_func,
+ },
+ [ACTION_RSS_FUNC_TOEPLITZ] = {
+ .name = "toeplitz",
+ .help = "Toeplitz hash function",
+ .call = parse_vc_action_rss_func,
+ },
+ [ACTION_RSS_FUNC_SIMPLE_XOR] = {
+ .name = "simple_xor",
+ .help = "simple XOR hash function",
+ .call = parse_vc_action_rss_func,
+ },
+ [ACTION_RSS_FUNC_SYMMETRIC_TOEPLITZ] = {
+ .name = "symmetric_toeplitz",
+ .help = "Symmetric Toeplitz hash function",
+ .call = parse_vc_action_rss_func,
+ },
+ [ACTION_RSS_LEVEL] = {
+ .name = "level",
+ .help = "encapsulation level for \"types\"",
+ .next = NEXT(action_rss, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY_ARB
+ (offsetof(struct action_rss_data, conf) +
+ offsetof(struct rte_flow_action_rss, level),
+ sizeof(((struct rte_flow_action_rss *)0)->
+ level))),
+ },
+ [ACTION_RSS_TYPES] = {
+ .name = "types",
+ .help = "specific RSS hash types",
+ .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_TYPE)),
+ },
+ [ACTION_RSS_TYPE] = {
+ .name = "{type}",
+ .help = "RSS hash type",
+ .call = parse_vc_action_rss_type,
+ .comp = comp_vc_action_rss_type,
+ },
+ [ACTION_RSS_KEY] = {
+ .name = "key",
+ .help = "RSS hash key",
+ .next = NEXT(action_rss, NEXT_ENTRY(HEX)),
+ .args = ARGS(ARGS_ENTRY_ARB(0, 0),
+ ARGS_ENTRY_ARB
+ (offsetof(struct action_rss_data, conf) +
+ offsetof(struct rte_flow_action_rss, key_len),
+ sizeof(((struct rte_flow_action_rss *)0)->
+ key_len)),
+ ARGS_ENTRY(struct action_rss_data, key)),
+ },
+ [ACTION_RSS_KEY_LEN] = {
+ .name = "key_len",
+ .help = "RSS hash key length in bytes",
+ .next = NEXT(action_rss, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY_ARB_BOUNDED
+ (offsetof(struct action_rss_data, conf) +
+ offsetof(struct rte_flow_action_rss, key_len),
+ sizeof(((struct rte_flow_action_rss *)0)->
+ key_len),
+ 0,
+ RSS_HASH_KEY_LENGTH)),
+ },
+ [ACTION_RSS_QUEUES] = {
+ .name = "queues",
+ .help = "queue indices to use",
+ .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_QUEUE)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_RSS_QUEUE] = {
+ .name = "{queue}",
+ .help = "queue index",
+ .call = parse_vc_action_rss_queue,
+ .comp = comp_vc_action_rss_queue,
+ },
+ [ACTION_PF] = {
+ .name = "pf",
+ .help = "direct traffic to physical function",
+ .priv = PRIV_ACTION(PF, 0),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc,
+ },
+ [ACTION_VF] = {
+ .name = "vf",
+ .help = "direct traffic to a virtual function ID",
+ .priv = PRIV_ACTION(VF, sizeof(struct rte_flow_action_vf)),
+ .next = NEXT(action_vf),
+ .call = parse_vc,
+ },
+ [ACTION_VF_ORIGINAL] = {
+ .name = "original",
+ .help = "use original VF ID if possible",
+ .next = NEXT(action_vf, NEXT_ENTRY(BOOLEAN)),
+ .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_vf,
+ original, 1)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_VF_ID] = {
+ .name = "id",
+ .help = "VF ID",
+ .next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_PHY_PORT] = {
+ .name = "phy_port",
+ .help = "direct packets to physical port index",
+ .priv = PRIV_ACTION(PHY_PORT,
+ sizeof(struct rte_flow_action_phy_port)),
+ .next = NEXT(action_phy_port),
+ .call = parse_vc,
+ },
+ [ACTION_PHY_PORT_ORIGINAL] = {
+ .name = "original",
+ .help = "use original port index if possible",
+ .next = NEXT(action_phy_port, NEXT_ENTRY(BOOLEAN)),
+ .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_phy_port,
+ original, 1)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_PHY_PORT_INDEX] = {
+ .name = "index",
+ .help = "physical port index",
+ .next = NEXT(action_phy_port, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_phy_port,
+ index)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_PORT_ID] = {
+ .name = "port_id",
+ .help = "direct matching traffic to a given DPDK port ID",
+ .priv = PRIV_ACTION(PORT_ID,
+ sizeof(struct rte_flow_action_port_id)),
+ .next = NEXT(action_port_id),
+ .call = parse_vc,
+ },
+ [ACTION_PORT_ID_ORIGINAL] = {
+ .name = "original",
+ .help = "use original DPDK port ID if possible",
+ .next = NEXT(action_port_id, NEXT_ENTRY(BOOLEAN)),
+ .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_port_id,
+ original, 1)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_PORT_ID_ID] = {
+ .name = "id",
+ .help = "DPDK port ID",
+ .next = NEXT(action_port_id, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_port_id, id)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_METER] = {
+ .name = "meter",
+ .help = "meter the directed packets at given id",
+ .priv = PRIV_ACTION(METER,
+ sizeof(struct rte_flow_action_meter)),
+ .next = NEXT(action_meter),
+ .call = parse_vc,
+ },
+ [ACTION_METER_ID] = {
+ .name = "mtr_id",
+ .help = "meter id to use",
+ .next = NEXT(action_meter, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_meter, mtr_id)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_OF_SET_MPLS_TTL] = {
+ .name = "of_set_mpls_ttl",
+ .help = "OpenFlow's OFPAT_SET_MPLS_TTL",
+ .priv = PRIV_ACTION
+ (OF_SET_MPLS_TTL,
+ sizeof(struct rte_flow_action_of_set_mpls_ttl)),
+ .next = NEXT(action_of_set_mpls_ttl),
+ .call = parse_vc,
+ },
+ [ACTION_OF_SET_MPLS_TTL_MPLS_TTL] = {
+ .name = "mpls_ttl",
+ .help = "MPLS TTL",
+ .next = NEXT(action_of_set_mpls_ttl, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_of_set_mpls_ttl,
+ mpls_ttl)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_OF_DEC_MPLS_TTL] = {
+ .name = "of_dec_mpls_ttl",
+ .help = "OpenFlow's OFPAT_DEC_MPLS_TTL",
+ .priv = PRIV_ACTION(OF_DEC_MPLS_TTL, 0),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc,
+ },
+ [ACTION_OF_SET_NW_TTL] = {
+ .name = "of_set_nw_ttl",
+ .help = "OpenFlow's OFPAT_SET_NW_TTL",
+ .priv = PRIV_ACTION
+ (OF_SET_NW_TTL,
+ sizeof(struct rte_flow_action_of_set_nw_ttl)),
+ .next = NEXT(action_of_set_nw_ttl),
+ .call = parse_vc,
+ },
+ [ACTION_OF_SET_NW_TTL_NW_TTL] = {
+ .name = "nw_ttl",
+ .help = "IP TTL",
+ .next = NEXT(action_of_set_nw_ttl, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_of_set_nw_ttl,
+ nw_ttl)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_OF_DEC_NW_TTL] = {
+ .name = "of_dec_nw_ttl",
+ .help = "OpenFlow's OFPAT_DEC_NW_TTL",
+ .priv = PRIV_ACTION(OF_DEC_NW_TTL, 0),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc,
+ },
+ [ACTION_OF_COPY_TTL_OUT] = {
+ .name = "of_copy_ttl_out",
+ .help = "OpenFlow's OFPAT_COPY_TTL_OUT",
+ .priv = PRIV_ACTION(OF_COPY_TTL_OUT, 0),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc,
+ },
+ [ACTION_OF_COPY_TTL_IN] = {
+ .name = "of_copy_ttl_in",
+ .help = "OpenFlow's OFPAT_COPY_TTL_IN",
+ .priv = PRIV_ACTION(OF_COPY_TTL_IN, 0),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc,
+ },
+ [ACTION_OF_POP_VLAN] = {
+ .name = "of_pop_vlan",
+ .help = "OpenFlow's OFPAT_POP_VLAN",
+ .priv = PRIV_ACTION(OF_POP_VLAN, 0),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc,
+ },
+ [ACTION_OF_PUSH_VLAN] = {
+ .name = "of_push_vlan",
+ .help = "OpenFlow's OFPAT_PUSH_VLAN",
+ .priv = PRIV_ACTION
+ (OF_PUSH_VLAN,
+ sizeof(struct rte_flow_action_of_push_vlan)),
+ .next = NEXT(action_of_push_vlan),
+ .call = parse_vc,
+ },
+ [ACTION_OF_PUSH_VLAN_ETHERTYPE] = {
+ .name = "ethertype",
+ .help = "EtherType",
+ .next = NEXT(action_of_push_vlan, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_action_of_push_vlan,
+ ethertype)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_OF_SET_VLAN_VID] = {
+ .name = "of_set_vlan_vid",
+ .help = "OpenFlow's OFPAT_SET_VLAN_VID",
+ .priv = PRIV_ACTION
+ (OF_SET_VLAN_VID,
+ sizeof(struct rte_flow_action_of_set_vlan_vid)),
+ .next = NEXT(action_of_set_vlan_vid),
+ .call = parse_vc,
+ },
+ [ACTION_OF_SET_VLAN_VID_VLAN_VID] = {
+ .name = "vlan_vid",
+ .help = "VLAN id",
+ .next = NEXT(action_of_set_vlan_vid, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_action_of_set_vlan_vid,
+ vlan_vid)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_OF_SET_VLAN_PCP] = {
+ .name = "of_set_vlan_pcp",
+ .help = "OpenFlow's OFPAT_SET_VLAN_PCP",
+ .priv = PRIV_ACTION
+ (OF_SET_VLAN_PCP,
+ sizeof(struct rte_flow_action_of_set_vlan_pcp)),
+ .next = NEXT(action_of_set_vlan_pcp),
+ .call = parse_vc,
+ },
+ [ACTION_OF_SET_VLAN_PCP_VLAN_PCP] = {
+ .name = "vlan_pcp",
+ .help = "VLAN priority",
+ .next = NEXT(action_of_set_vlan_pcp, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_action_of_set_vlan_pcp,
+ vlan_pcp)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_OF_POP_MPLS] = {
+ .name = "of_pop_mpls",
+ .help = "OpenFlow's OFPAT_POP_MPLS",
+ .priv = PRIV_ACTION(OF_POP_MPLS,
+ sizeof(struct rte_flow_action_of_pop_mpls)),
+ .next = NEXT(action_of_pop_mpls),
+ .call = parse_vc,
+ },
+ [ACTION_OF_POP_MPLS_ETHERTYPE] = {
+ .name = "ethertype",
+ .help = "EtherType",
+ .next = NEXT(action_of_pop_mpls, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_action_of_pop_mpls,
+ ethertype)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_OF_PUSH_MPLS] = {
+ .name = "of_push_mpls",
+ .help = "OpenFlow's OFPAT_PUSH_MPLS",
+ .priv = PRIV_ACTION
+ (OF_PUSH_MPLS,
+ sizeof(struct rte_flow_action_of_push_mpls)),
+ .next = NEXT(action_of_push_mpls),
+ .call = parse_vc,
+ },
+ [ACTION_OF_PUSH_MPLS_ETHERTYPE] = {
+ .name = "ethertype",
+ .help = "EtherType",
+ .next = NEXT(action_of_push_mpls, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_action_of_push_mpls,
+ ethertype)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_VXLAN_ENCAP] = {
+ .name = "vxlan_encap",
+ .help = "VXLAN encapsulation, uses configuration set by \"set"
+ " vxlan\"",
+ .priv = PRIV_ACTION(VXLAN_ENCAP,
+ sizeof(struct action_vxlan_encap_data)),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_vxlan_encap,
+ },
+ [ACTION_VXLAN_DECAP] = {
+ .name = "vxlan_decap",
+ .help = "Performs a decapsulation action by stripping all"
+ " headers of the VXLAN tunnel network overlay from the"
+ " matched flow.",
+ .priv = PRIV_ACTION(VXLAN_DECAP, 0),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc,
+ },
+ [ACTION_NVGRE_ENCAP] = {
+ .name = "nvgre_encap",
+ .help = "NVGRE encapsulation, uses configuration set by \"set"
+ " nvgre\"",
+ .priv = PRIV_ACTION(NVGRE_ENCAP,
+ sizeof(struct action_nvgre_encap_data)),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_nvgre_encap,
+ },
+ [ACTION_NVGRE_DECAP] = {
+ .name = "nvgre_decap",
+ .help = "Performs a decapsulation action by stripping all"
+ " headers of the NVGRE tunnel network overlay from the"
+ " matched flow.",
+ .priv = PRIV_ACTION(NVGRE_DECAP, 0),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc,
+ },
+ [ACTION_L2_ENCAP] = {
+ .name = "l2_encap",
+ .help = "l2 encap, uses configuration set by"
+ " \"set l2_encap\"",
+ .priv = PRIV_ACTION(RAW_ENCAP,
+ sizeof(struct action_raw_encap_data)),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_l2_encap,
+ },
+ [ACTION_L2_DECAP] = {
+ .name = "l2_decap",
+ .help = "l2 decap, uses configuration set by"
+ " \"set l2_decap\"",
+ .priv = PRIV_ACTION(RAW_DECAP,
+ sizeof(struct action_raw_decap_data)),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_l2_decap,
+ },
+ [ACTION_MPLSOGRE_ENCAP] = {
+ .name = "mplsogre_encap",
+ .help = "mplsogre encapsulation, uses configuration set by"
+ " \"set mplsogre_encap\"",
+ .priv = PRIV_ACTION(RAW_ENCAP,
+ sizeof(struct action_raw_encap_data)),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_mplsogre_encap,
+ },
+ [ACTION_MPLSOGRE_DECAP] = {
+ .name = "mplsogre_decap",
+ .help = "mplsogre decapsulation, uses configuration set by"
+ " \"set mplsogre_decap\"",
+ .priv = PRIV_ACTION(RAW_DECAP,
+ sizeof(struct action_raw_decap_data)),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_mplsogre_decap,
+ },
+ [ACTION_MPLSOUDP_ENCAP] = {
+ .name = "mplsoudp_encap",
+ .help = "mplsoudp encapsulation, uses configuration set by"
+ " \"set mplsoudp_encap\"",
+ .priv = PRIV_ACTION(RAW_ENCAP,
+ sizeof(struct action_raw_encap_data)),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_mplsoudp_encap,
+ },
+ [ACTION_MPLSOUDP_DECAP] = {
+ .name = "mplsoudp_decap",
+ .help = "mplsoudp decapsulation, uses configuration set by"
+ " \"set mplsoudp_decap\"",
+ .priv = PRIV_ACTION(RAW_DECAP,
+ sizeof(struct action_raw_decap_data)),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_mplsoudp_decap,
+ },
+ [ACTION_SET_IPV4_SRC] = {
+ .name = "set_ipv4_src",
+ .help = "Set a new IPv4 source address in the outermost"
+ " IPv4 header",
+ .priv = PRIV_ACTION(SET_IPV4_SRC,
+ sizeof(struct rte_flow_action_set_ipv4)),
+ .next = NEXT(action_set_ipv4_src),
+ .call = parse_vc,
+ },
+ [ACTION_SET_IPV4_SRC_IPV4_SRC] = {
+ .name = "ipv4_addr",
+ .help = "new IPv4 source address to set",
+ .next = NEXT(action_set_ipv4_src, NEXT_ENTRY(IPV4_ADDR)),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_action_set_ipv4, ipv4_addr)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_IPV4_DST] = {
+ .name = "set_ipv4_dst",
+ .help = "Set a new IPv4 destination address in the outermost"
+ " IPv4 header",
+ .priv = PRIV_ACTION(SET_IPV4_DST,
+ sizeof(struct rte_flow_action_set_ipv4)),
+ .next = NEXT(action_set_ipv4_dst),
+ .call = parse_vc,
+ },
+ [ACTION_SET_IPV4_DST_IPV4_DST] = {
+ .name = "ipv4_addr",
+ .help = "new IPv4 destination address to set",
+ .next = NEXT(action_set_ipv4_dst, NEXT_ENTRY(IPV4_ADDR)),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_action_set_ipv4, ipv4_addr)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_IPV6_SRC] = {
+ .name = "set_ipv6_src",
+ .help = "Set a new IPv6 source address in the outermost"
+ " IPv6 header",
+ .priv = PRIV_ACTION(SET_IPV6_SRC,
+ sizeof(struct rte_flow_action_set_ipv6)),
+ .next = NEXT(action_set_ipv6_src),
+ .call = parse_vc,
+ },
+ [ACTION_SET_IPV6_SRC_IPV6_SRC] = {
+ .name = "ipv6_addr",
+ .help = "new IPv6 source address to set",
+ .next = NEXT(action_set_ipv6_src, NEXT_ENTRY(IPV6_ADDR)),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_action_set_ipv6, ipv6_addr)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_IPV6_DST] = {
+ .name = "set_ipv6_dst",
+ .help = "Set a new IPv6 destination address in the outermost"
+ " IPv6 header",
+ .priv = PRIV_ACTION(SET_IPV6_DST,
+ sizeof(struct rte_flow_action_set_ipv6)),
+ .next = NEXT(action_set_ipv6_dst),
+ .call = parse_vc,
+ },
+ [ACTION_SET_IPV6_DST_IPV6_DST] = {
+ .name = "ipv6_addr",
+ .help = "new IPv6 destination address to set",
+ .next = NEXT(action_set_ipv6_dst, NEXT_ENTRY(IPV6_ADDR)),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_action_set_ipv6, ipv6_addr)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_TP_SRC] = {
+ .name = "set_tp_src",
+ .help = "set a new source port number in the outermost"
+ " TCP/UDP header",
+ .priv = PRIV_ACTION(SET_TP_SRC,
+ sizeof(struct rte_flow_action_set_tp)),
+ .next = NEXT(action_set_tp_src),
+ .call = parse_vc,
+ },
+ [ACTION_SET_TP_SRC_TP_SRC] = {
+ .name = "port",
+ .help = "new source port number to set",
+ .next = NEXT(action_set_tp_src, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_action_set_tp, port)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_TP_DST] = {
+ .name = "set_tp_dst",
+ .help = "set a new destination port number in the outermost"
+ " TCP/UDP header",
+ .priv = PRIV_ACTION(SET_TP_DST,
+ sizeof(struct rte_flow_action_set_tp)),
+ .next = NEXT(action_set_tp_dst),
+ .call = parse_vc,
+ },
+ [ACTION_SET_TP_DST_TP_DST] = {
+ .name = "port",
+ .help = "new destination port number to set",
+ .next = NEXT(action_set_tp_dst, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_action_set_tp, port)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_MAC_SWAP] = {
+ .name = "mac_swap",
+ .help = "Swap the source and destination MAC addresses"
+ " in the outermost Ethernet header",
+ .priv = PRIV_ACTION(MAC_SWAP, 0),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc,
+ },
+ [ACTION_DEC_TTL] = {
+ .name = "dec_ttl",
+ .help = "decrease network TTL if available",
+ .priv = PRIV_ACTION(DEC_TTL, 0),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc,
+ },
+ [ACTION_SET_TTL] = {
+ .name = "set_ttl",
+ .help = "set ttl value",
+ .priv = PRIV_ACTION(SET_TTL,
+ sizeof(struct rte_flow_action_set_ttl)),
+ .next = NEXT(action_set_ttl),
+ .call = parse_vc,
+ },
+ [ACTION_SET_TTL_TTL] = {
+ .name = "ttl_value",
+ .help = "new ttl value to set",
+ .next = NEXT(action_set_ttl, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_action_set_ttl, ttl_value)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_MAC_SRC] = {
+ .name = "set_mac_src",
+ .help = "set source mac address",
+ .priv = PRIV_ACTION(SET_MAC_SRC,
+ sizeof(struct rte_flow_action_set_mac)),
+ .next = NEXT(action_set_mac_src),
+ .call = parse_vc,
+ },
+ [ACTION_SET_MAC_SRC_MAC_SRC] = {
+ .name = "mac_addr",
+ .help = "new source mac address",
+ .next = NEXT(action_set_mac_src, NEXT_ENTRY(MAC_ADDR)),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_action_set_mac, mac_addr)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_MAC_DST] = {
+ .name = "set_mac_dst",
+ .help = "set destination mac address",
+ .priv = PRIV_ACTION(SET_MAC_DST,
+ sizeof(struct rte_flow_action_set_mac)),
+ .next = NEXT(action_set_mac_dst),
+ .call = parse_vc,
+ },
+ [ACTION_SET_MAC_DST_MAC_DST] = {
+ .name = "mac_addr",
+ .help = "new destination mac address to set",
+ .next = NEXT(action_set_mac_dst, NEXT_ENTRY(MAC_ADDR)),
+ .args = ARGS(ARGS_ENTRY_HTON
+ (struct rte_flow_action_set_mac, mac_addr)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_INC_TCP_SEQ] = {
+ .name = "inc_tcp_seq",
+ .help = "increase TCP sequence number",
+ .priv = PRIV_ACTION(INC_TCP_SEQ, sizeof(rte_be32_t)),
+ .next = NEXT(action_inc_tcp_seq),
+ .call = parse_vc,
+ },
+ [ACTION_INC_TCP_SEQ_VALUE] = {
+ .name = "value",
+ .help = "the value to increase TCP sequence number by",
+ .next = NEXT(action_inc_tcp_seq, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARG_ENTRY_HTON(rte_be32_t)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_DEC_TCP_SEQ] = {
+ .name = "dec_tcp_seq",
+ .help = "decrease TCP sequence number",
+ .priv = PRIV_ACTION(DEC_TCP_SEQ, sizeof(rte_be32_t)),
+ .next = NEXT(action_dec_tcp_seq),
+ .call = parse_vc,
+ },
+ [ACTION_DEC_TCP_SEQ_VALUE] = {
+ .name = "value",
+ .help = "the value to decrease TCP sequence number by",
+ .next = NEXT(action_dec_tcp_seq, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARG_ENTRY_HTON(rte_be32_t)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_INC_TCP_ACK] = {
+ .name = "inc_tcp_ack",
+ .help = "increase TCP acknowledgment number",
+ .priv = PRIV_ACTION(INC_TCP_ACK, sizeof(rte_be32_t)),
+ .next = NEXT(action_inc_tcp_ack),
+ .call = parse_vc,
+ },
+ [ACTION_INC_TCP_ACK_VALUE] = {
+ .name = "value",
+ .help = "the value to increase TCP acknowledgment number by",
+ .next = NEXT(action_inc_tcp_ack, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARG_ENTRY_HTON(rte_be32_t)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_DEC_TCP_ACK] = {
+ .name = "dec_tcp_ack",
+ .help = "decrease TCP acknowledgment number",
+ .priv = PRIV_ACTION(DEC_TCP_ACK, sizeof(rte_be32_t)),
+ .next = NEXT(action_dec_tcp_ack),
+ .call = parse_vc,
+ },
+ [ACTION_DEC_TCP_ACK_VALUE] = {
+ .name = "value",
+ .help = "the value to decrease TCP acknowledgment number by",
+ .next = NEXT(action_dec_tcp_ack, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARG_ENTRY_HTON(rte_be32_t)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_RAW_ENCAP] = {
+ .name = "raw_encap",
+ .help = "encapsulation data, defined by set raw_encap",
+ .priv = PRIV_ACTION(RAW_ENCAP,
+ sizeof(struct action_raw_encap_data)),
+ .next = NEXT(action_raw_encap),
+ .call = parse_vc_action_raw_encap,
+ },
+ [ACTION_RAW_ENCAP_INDEX] = {
+ .name = "index",
+ .help = "the index of raw_encap_confs",
+ .next = NEXT(NEXT_ENTRY(ACTION_RAW_ENCAP_INDEX_VALUE)),
+ },
+ [ACTION_RAW_ENCAP_INDEX_VALUE] = {
+ .name = "{index}",
+ .type = "UNSIGNED",
+ .help = "unsigned integer value",
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_raw_encap_index,
+ .comp = comp_set_raw_index,
+ },
+ [ACTION_RAW_DECAP] = {
+ .name = "raw_decap",
+ .help = "decapsulation data, defined by set raw_encap",
+ .priv = PRIV_ACTION(RAW_DECAP,
+ sizeof(struct action_raw_decap_data)),
+ .next = NEXT(action_raw_decap),
+ .call = parse_vc_action_raw_decap,
+ },
+ [ACTION_RAW_DECAP_INDEX] = {
+ .name = "index",
+ .help = "the index of raw_encap_confs",
+ .next = NEXT(NEXT_ENTRY(ACTION_RAW_DECAP_INDEX_VALUE)),
+ },
+ [ACTION_RAW_DECAP_INDEX_VALUE] = {
+ .name = "{index}",
+ .type = "UNSIGNED",
+ .help = "unsigned integer value",
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_raw_decap_index,
+ .comp = comp_set_raw_index,
+ },
+ /* Top level command. */
+ [SET] = {
+ .name = "set",
+ .help = "set raw encap/decap data",
+ .type = "set raw_encap|raw_decap <index> <pattern>",
+ .next = NEXT(NEXT_ENTRY
+ (SET_RAW_ENCAP,
+ SET_RAW_DECAP)),
+ .call = parse_set_init,
+ },
+ /* Sub-level commands. */
+ [SET_RAW_ENCAP] = {
+ .name = "raw_encap",
+ .help = "set raw encap data",
+ .next = NEXT(next_set_raw),
+ .args = ARGS(ARGS_ENTRY_ARB_BOUNDED
+ (offsetof(struct buffer, port),
+ sizeof(((struct buffer *)0)->port),
+ 0, RAW_ENCAP_CONFS_MAX_NUM - 1)),
+ .call = parse_set_raw_encap_decap,
+ },
+ [SET_RAW_DECAP] = {
+ .name = "raw_decap",
+ .help = "set raw decap data",
+ .next = NEXT(next_set_raw),
+ .args = ARGS(ARGS_ENTRY_ARB_BOUNDED
+ (offsetof(struct buffer, port),
+ sizeof(((struct buffer *)0)->port),
+ 0, RAW_ENCAP_CONFS_MAX_NUM - 1)),
+ .call = parse_set_raw_encap_decap,
+ },
+ [SET_RAW_INDEX] = {
+ .name = "{index}",
+ .type = "UNSIGNED",
+ .help = "index of raw_encap/raw_decap data",
+ .next = NEXT(next_item),
+ .call = parse_port,
+ },
+ [ACTION_SET_TAG] = {
+ .name = "set_tag",
+ .help = "set tag",
+ .priv = PRIV_ACTION(SET_TAG,
+ sizeof(struct rte_flow_action_set_tag)),
+ .next = NEXT(action_set_tag),
+ .call = parse_vc,
+ },
+ [ACTION_SET_TAG_INDEX] = {
+ .name = "index",
+ .help = "index of tag array",
+ .next = NEXT(action_set_tag, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_set_tag, index)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_TAG_DATA] = {
+ .name = "data",
+ .help = "tag value",
+ .next = NEXT(action_set_tag, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY
+ (struct rte_flow_action_set_tag, data)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_TAG_MASK] = {
+ .name = "mask",
+ .help = "mask for tag value",
+ .next = NEXT(action_set_tag, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY
+ (struct rte_flow_action_set_tag, mask)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_META] = {
+ .name = "set_meta",
+ .help = "set metadata",
+ .priv = PRIV_ACTION(SET_META,
+ sizeof(struct rte_flow_action_set_meta)),
+ .next = NEXT(action_set_meta),
+ .call = parse_vc_action_set_meta,
+ },
+ [ACTION_SET_META_DATA] = {
+ .name = "data",
+ .help = "metadata value",
+ .next = NEXT(action_set_meta, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY
+ (struct rte_flow_action_set_meta, data)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_META_MASK] = {
+ .name = "mask",
+ .help = "mask for metadata value",
+ .next = NEXT(action_set_meta, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY
+ (struct rte_flow_action_set_meta, mask)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_IPV4_DSCP] = {
+ .name = "set_ipv4_dscp",
+ .help = "set DSCP value",
+ .priv = PRIV_ACTION(SET_IPV4_DSCP,
+ sizeof(struct rte_flow_action_set_dscp)),
+ .next = NEXT(action_set_ipv4_dscp),
+ .call = parse_vc,
+ },
+ [ACTION_SET_IPV4_DSCP_VALUE] = {
+ .name = "dscp_value",
+ .help = "new IPv4 DSCP value to set",
+ .next = NEXT(action_set_ipv4_dscp, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY
+ (struct rte_flow_action_set_dscp, dscp)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_IPV6_DSCP] = {
+ .name = "set_ipv6_dscp",
+ .help = "set DSCP value",
+ .priv = PRIV_ACTION(SET_IPV6_DSCP,
+ sizeof(struct rte_flow_action_set_dscp)),
+ .next = NEXT(action_set_ipv6_dscp),
+ .call = parse_vc,
+ },
+ [ACTION_SET_IPV6_DSCP_VALUE] = {
+ .name = "dscp_value",
+ .help = "new IPv6 DSCP value to set",
+ .next = NEXT(action_set_ipv6_dscp, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY
+ (struct rte_flow_action_set_dscp, dscp)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_AGE] = {
+ .name = "age",
+ .help = "set a specific metadata header",
+ .next = NEXT(action_age),
+ .priv = PRIV_ACTION(AGE,
+ sizeof(struct rte_flow_action_age)),
+ .call = parse_vc,
+ },
+ [ACTION_AGE_TIMEOUT] = {
+ .name = "timeout",
+ .help = "flow age timeout value",
+ .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_age,
+ timeout, 24)),
+ .next = NEXT(action_age, NEXT_ENTRY(UNSIGNED)),
+ .call = parse_vc_conf,
+ },
+};
+
+/** Remove and return last entry from argument stack. */
+static const struct arg *
+pop_args(struct context *ctx)
+{
+ return ctx->args_num ? ctx->args[--ctx->args_num] : NULL;
+}
+
+/** Add entry on top of the argument stack. */
+static int
+push_args(struct context *ctx, const struct arg *arg)
+{
+ if (ctx->args_num == CTX_STACK_SIZE)
+ return -1;
+ ctx->args[ctx->args_num++] = arg;
+ return 0;
+}
+
+/** Spread value into buffer according to bit-mask. */
+static size_t
+arg_entry_bf_fill(void *dst, uintmax_t val, const struct arg *arg)
+{
+ uint32_t i = arg->size;
+ uint32_t end = 0;
+ int sub = 1;
+ int add = 0;
+ size_t len = 0;
+
+ if (!arg->mask)
+ return 0;
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+ if (!arg->hton) {
+ i = 0;
+ end = arg->size;
+ sub = 0;
+ add = 1;
+ }
+#endif
+ while (i != end) {
+ unsigned int shift = 0;
+ uint8_t *buf = (uint8_t *)dst + arg->offset + (i -= sub);
+
+ for (shift = 0; arg->mask[i] >> shift; ++shift) {
+ if (!(arg->mask[i] & (1 << shift)))
+ continue;
+ ++len;
+ if (!dst)
+ continue;
+ *buf &= ~(1 << shift);
+ *buf |= (val & 1) << shift;
+ val >>= 1;
+ }
+ i += add;
+ }
+ return len;
+}
+
+/** Compare a string with a partial one of a given length. */
+static int
+strcmp_partial(const char *full, const char *partial, size_t partial_len)
+{
+ int r = strncmp(full, partial, partial_len);
+
+ if (r)
+ return r;
+ if (strlen(full) <= partial_len)
+ return 0;
+ return full[partial_len];
+}
+
+/**
+ * Parse a prefix length and generate a bit-mask.
+ *
+ * Last argument (ctx->args) is retrieved to determine mask size, storage
+ * location and whether the result must use network byte ordering.
+ */
+static int
+parse_prefix(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ const struct arg *arg = pop_args(ctx);
+ static const uint8_t conv[] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff";
+ char *end;
+ uintmax_t u;
+ unsigned int bytes;
+ unsigned int extra;
+
+ (void)token;
+ /* Argument is expected. */
+ if (!arg)
+ return -1;
+ errno = 0;
+ u = strtoumax(str, &end, 0);
+ if (errno || (size_t)(end - str) != len)
+ goto error;
+ if (arg->mask) {
+ uintmax_t v = 0;
+
+ extra = arg_entry_bf_fill(NULL, 0, arg);
+ if (u > extra)
+ goto error;
+ if (!ctx->object)
+ return len;
+ extra -= u;
+ while (u--)
+ (v <<= 1, v |= 1);
+ v <<= extra;
+ if (!arg_entry_bf_fill(ctx->object, v, arg) ||
+ !arg_entry_bf_fill(ctx->objmask, -1, arg))
+ goto error;
+ return len;
+ }
+ bytes = u / 8;
+ extra = u % 8;
+ size = arg->size;
+ if (bytes > size || bytes + !!extra > size)
+ goto error;
+ if (!ctx->object)
+ return len;
+ buf = (uint8_t *)ctx->object + arg->offset;
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+ if (!arg->hton) {
+ memset((uint8_t *)buf + size - bytes, 0xff, bytes);
+ memset(buf, 0x00, size - bytes);
+ if (extra)
+ ((uint8_t *)buf)[size - bytes - 1] = conv[extra];
+ } else
+#endif
+ {
+ memset(buf, 0xff, bytes);
+ memset((uint8_t *)buf + bytes, 0x00, size - bytes);
+ if (extra)
+ ((uint8_t *)buf)[bytes] = conv[extra];
+ }
+ if (ctx->objmask)
+ memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
+ return len;
+error:
+ push_args(ctx, arg);
+ return -1;
+}
+
+/** Default parsing function for token name matching. */
+static int
+parse_default(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ (void)ctx;
+ (void)buf;
+ (void)size;
+ if (strcmp_partial(token->name, str, len))
+ return -1;
+ return len;
+}
+
+/** Parse flow command, initialize output buffer for subsequent tokens. */
+static int
+parse_init(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ /* Make sure buffer is large enough. */
+ if (size < sizeof(*out))
+ return -1;
+ /* Initialize buffer. */
+ memset(out, 0x00, sizeof(*out));
+ memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ return len;
+}
+
+/** Parse tokens for validate/create commands. */
+static int
+parse_vc(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ uint8_t *data;
+ uint32_t data_size;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->command) {
+ if (ctx->curr != VALIDATE && ctx->curr != CREATE)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ out->args.vc.data = (uint8_t *)out + size;
+ return len;
+ }
+ ctx->objdata = 0;
+ ctx->object = &out->args.vc.attr;
+ ctx->objmask = NULL;
+ switch (ctx->curr) {
+ case GROUP:
+ case PRIORITY:
+ return len;
+ case INGRESS:
+ out->args.vc.attr.ingress = 1;
+ return len;
+ case EGRESS:
+ out->args.vc.attr.egress = 1;
+ return len;
+ case TRANSFER:
+ out->args.vc.attr.transfer = 1;
+ return len;
+ case PATTERN:
+ out->args.vc.pattern =
+ (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+ sizeof(double));
+ ctx->object = out->args.vc.pattern;
+ ctx->objmask = NULL;
+ return len;
+ case ACTIONS:
+ out->args.vc.actions =
+ (void *)RTE_ALIGN_CEIL((uintptr_t)
+ (out->args.vc.pattern +
+ out->args.vc.pattern_n),
+ sizeof(double));
+ ctx->object = out->args.vc.actions;
+ ctx->objmask = NULL;
+ return len;
+ default:
+ if (!token->priv)
+ return -1;
+ break;
+ }
+ if (!out->args.vc.actions) {
+ const struct parse_item_priv *priv = token->priv;
+ struct rte_flow_item *item =
+ out->args.vc.pattern + out->args.vc.pattern_n;
+
+ data_size = priv->size * 3; /* spec, last, mask */
+ data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
+ (out->args.vc.data - data_size),
+ sizeof(double));
+ if ((uint8_t *)item + sizeof(*item) > data)
+ return -1;
+ *item = (struct rte_flow_item){
+ .type = priv->type,
+ };
+ ++out->args.vc.pattern_n;
+ ctx->object = item;
+ ctx->objmask = NULL;
+ } else {
+ const struct parse_action_priv *priv = token->priv;
+ struct rte_flow_action *action =
+ out->args.vc.actions + out->args.vc.actions_n;
+
+ data_size = priv->size; /* configuration */
+ data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
+ (out->args.vc.data - data_size),
+ sizeof(double));
+ if ((uint8_t *)action + sizeof(*action) > data)
+ return -1;
+ *action = (struct rte_flow_action){
+ .type = priv->type,
+ .conf = data_size ? data : NULL,
+ };
+ ++out->args.vc.actions_n;
+ ctx->object = action;
+ ctx->objmask = NULL;
+ }
+ memset(data, 0, data_size);
+ out->args.vc.data = data;
+ ctx->objdata = data_size;
+ return len;
+}
+
+/** Parse pattern item parameter type. */
+static int
+parse_vc_spec(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_item *item;
+ uint32_t data_size;
+ int index;
+ int objmask = 0;
+
+ (void)size;
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Parse parameter types. */
+ switch (ctx->curr) {
+ static const enum index prefix[] = NEXT_ENTRY(PREFIX);
+
+ case ITEM_PARAM_IS:
+ index = 0;
+ objmask = 1;
+ break;
+ case ITEM_PARAM_SPEC:
+ index = 0;
+ break;
+ case ITEM_PARAM_LAST:
+ index = 1;
+ break;
+ case ITEM_PARAM_PREFIX:
+ /* Modify next token to expect a prefix. */
+ if (ctx->next_num < 2)
+ return -1;
+ ctx->next[ctx->next_num - 2] = prefix;
+ /* Fall through. */
+ case ITEM_PARAM_MASK:
+ index = 2;
+ break;
+ default:
+ return -1;
+ }
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->args.vc.pattern_n)
+ return -1;
+ item = &out->args.vc.pattern[out->args.vc.pattern_n - 1];
+ data_size = ctx->objdata / 3; /* spec, last, mask */
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data + (data_size * index);
+ if (objmask) {
+ ctx->objmask = out->args.vc.data + (data_size * 2); /* mask */
+ item->mask = ctx->objmask;
+ } else
+ ctx->objmask = NULL;
+ /* Update relevant item pointer. */
+ *((const void **[]){ &item->spec, &item->last, &item->mask })[index] =
+ ctx->object;
+ return len;
+}
+
+/** Parse action configuration field. */
+static int
+parse_vc_conf(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ (void)size;
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ return len;
+}
+
+/** Parse RSS action. */
+static int
+parse_vc_action_rss(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_rss_data *action_rss_data;
+ unsigned int i;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Set up default configuration. */
+ action_rss_data = ctx->object;
+ *action_rss_data = (struct action_rss_data){
+ .conf = (struct rte_flow_action_rss){
+ .func = RTE_ETH_HASH_FUNCTION_DEFAULT,
+ .level = 0,
+ .types = rss_hf,
+ .key_len = sizeof(action_rss_data->key),
+ .queue_num = RTE_MIN(nb_rxq, ACTION_RSS_QUEUE_NUM),
+ .key = action_rss_data->key,
+ .queue = action_rss_data->queue,
+ },
+ .key = "testpmd's default RSS hash key, "
+ "override it for better balancing",
+ .queue = { 0 },
+ };
+ for (i = 0; i < action_rss_data->conf.queue_num; ++i)
+ action_rss_data->queue[i] = i;
+ if (!port_id_is_invalid(ctx->port, DISABLED_WARN) &&
+ ctx->port != (portid_t)RTE_PORT_ALL) {
+ struct rte_eth_dev_info info;
+ int ret2;
+
+ ret2 = rte_eth_dev_info_get(ctx->port, &info);
+ if (ret2 != 0)
+ return ret2;
+
+ action_rss_data->conf.key_len =
+ RTE_MIN(sizeof(action_rss_data->key),
+ info.hash_key_size);
+ }
+ action->conf = &action_rss_data->conf;
+ return ret;
+}
+
+/**
+ * Parse func field for RSS action.
+ *
+ * The RTE_ETH_HASH_FUNCTION_* value to assign is derived from the
+ * ACTION_RSS_FUNC_* index that called this function.
+ */
+static int
+parse_vc_action_rss_func(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct action_rss_data *action_rss_data;
+ enum rte_eth_hash_function func;
+
+ (void)buf;
+ (void)size;
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ switch (ctx->curr) {
+ case ACTION_RSS_FUNC_DEFAULT:
+ func = RTE_ETH_HASH_FUNCTION_DEFAULT;
+ break;
+ case ACTION_RSS_FUNC_TOEPLITZ:
+ func = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+ break;
+ case ACTION_RSS_FUNC_SIMPLE_XOR:
+ func = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+ break;
+ case ACTION_RSS_FUNC_SYMMETRIC_TOEPLITZ:
+ func = RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ;
+ break;
+ default:
+ return -1;
+ }
+ if (!ctx->object)
+ return len;
+ action_rss_data = ctx->object;
+ action_rss_data->conf.func = func;
+ return len;
+}
+
+/**
+ * Parse type field for RSS action.
+ *
+ * Valid tokens are type field names and the "end" token.
+ */
+static int
+parse_vc_action_rss_type(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ static const enum index next[] = NEXT_ENTRY(ACTION_RSS_TYPE);
+ struct action_rss_data *action_rss_data;
+ unsigned int i;
+
+ (void)token;
+ (void)buf;
+ (void)size;
+ if (ctx->curr != ACTION_RSS_TYPE)
+ return -1;
+ if (!(ctx->objdata >> 16) && ctx->object) {
+ action_rss_data = ctx->object;
+ action_rss_data->conf.types = 0;
+ }
+ if (!strcmp_partial("end", str, len)) {
+ ctx->objdata &= 0xffff;
+ return len;
+ }
+ for (i = 0; rss_type_table[i].str; ++i)
+ if (!strcmp_partial(rss_type_table[i].str, str, len))
+ break;
+ if (!rss_type_table[i].str)
+ return -1;
+ ctx->objdata = 1 << 16 | (ctx->objdata & 0xffff);
+ /* Repeat token. */
+ if (ctx->next_num == RTE_DIM(ctx->next))
+ return -1;
+ ctx->next[ctx->next_num++] = next;
+ if (!ctx->object)
+ return len;
+ action_rss_data = ctx->object;
+ action_rss_data->conf.types |= rss_type_table[i].rss_type;
+ return len;
+}
+
+/**
+ * Parse queue field for RSS action.
+ *
+ * Valid tokens are queue indices and the "end" token.
+ */
+static int
+parse_vc_action_rss_queue(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ static const enum index next[] = NEXT_ENTRY(ACTION_RSS_QUEUE);
+ struct action_rss_data *action_rss_data;
+ const struct arg *arg;
+ int ret;
+ int i;
+
+ (void)token;
+ (void)buf;
+ (void)size;
+ if (ctx->curr != ACTION_RSS_QUEUE)
+ return -1;
+ i = ctx->objdata >> 16;
+ if (!strcmp_partial("end", str, len)) {
+ ctx->objdata &= 0xffff;
+ goto end;
+ }
+ if (i >= ACTION_RSS_QUEUE_NUM)
+ return -1;
+ arg = ARGS_ENTRY_ARB(offsetof(struct action_rss_data, queue) +
+ i * sizeof(action_rss_data->queue[i]),
+ sizeof(action_rss_data->queue[i]));
+ if (push_args(ctx, arg))
+ return -1;
+ ret = parse_int(ctx, token, str, len, NULL, 0);
+ if (ret < 0) {
+ pop_args(ctx);
+ return -1;
+ }
+ ++i;
+ ctx->objdata = i << 16 | (ctx->objdata & 0xffff);
+ /* Repeat token. */
+ if (ctx->next_num == RTE_DIM(ctx->next))
+ return -1;
+ ctx->next[ctx->next_num++] = next;
+end:
+ if (!ctx->object)
+ return len;
+ action_rss_data = ctx->object;
+ action_rss_data->conf.queue_num = i;
+ action_rss_data->conf.queue = i ? action_rss_data->queue : NULL;
+ return len;
+}
+
+/** Parse VXLAN encap action. */
+static int
+parse_vc_action_vxlan_encap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_vxlan_encap_data *action_vxlan_encap_data;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Set up default configuration. */
+ action_vxlan_encap_data = ctx->object;
+ *action_vxlan_encap_data = (struct action_vxlan_encap_data){
+ .conf = (struct rte_flow_action_vxlan_encap){
+ .definition = action_vxlan_encap_data->items,
+ },
+ .items = {
+ {
+ .type = RTE_FLOW_ITEM_TYPE_ETH,
+ .spec = &action_vxlan_encap_data->item_eth,
+ .mask = &rte_flow_item_eth_mask,
+ },
+ {
+ .type = RTE_FLOW_ITEM_TYPE_VLAN,
+ .spec = &action_vxlan_encap_data->item_vlan,
+ .mask = &rte_flow_item_vlan_mask,
+ },
+ {
+ .type = RTE_FLOW_ITEM_TYPE_IPV4,
+ .spec = &action_vxlan_encap_data->item_ipv4,
+ .mask = &rte_flow_item_ipv4_mask,
+ },
+ {
+ .type = RTE_FLOW_ITEM_TYPE_UDP,
+ .spec = &action_vxlan_encap_data->item_udp,
+ .mask = &rte_flow_item_udp_mask,
+ },
+ {
+ .type = RTE_FLOW_ITEM_TYPE_VXLAN,
+ .spec = &action_vxlan_encap_data->item_vxlan,
+ .mask = &rte_flow_item_vxlan_mask,
+ },
+ {
+ .type = RTE_FLOW_ITEM_TYPE_END,
+ },
+ },
+ .item_eth.type = 0,
+ .item_vlan = {
+ .tci = vxlan_encap_conf.vlan_tci,
+ .inner_type = 0,
+ },
+ .item_ipv4.hdr = {
+ .src_addr = vxlan_encap_conf.ipv4_src,
+ .dst_addr = vxlan_encap_conf.ipv4_dst,
+ },
+ .item_udp.hdr = {
+ .src_port = vxlan_encap_conf.udp_src,
+ .dst_port = vxlan_encap_conf.udp_dst,
+ },
+ .item_vxlan.flags = 0,
+ };
+ memcpy(action_vxlan_encap_data->item_eth.dst.addr_bytes,
+ vxlan_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
+ memcpy(action_vxlan_encap_data->item_eth.src.addr_bytes,
+ vxlan_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
+ if (!vxlan_encap_conf.select_ipv4) {
+ memcpy(&action_vxlan_encap_data->item_ipv6.hdr.src_addr,
+ &vxlan_encap_conf.ipv6_src,
+ sizeof(vxlan_encap_conf.ipv6_src));
+ memcpy(&action_vxlan_encap_data->item_ipv6.hdr.dst_addr,
+ &vxlan_encap_conf.ipv6_dst,
+ sizeof(vxlan_encap_conf.ipv6_dst));
+ action_vxlan_encap_data->items[2] = (struct rte_flow_item){
+ .type = RTE_FLOW_ITEM_TYPE_IPV6,
+ .spec = &action_vxlan_encap_data->item_ipv6,
+ .mask = &rte_flow_item_ipv6_mask,
+ };
+ }
+ if (!vxlan_encap_conf.select_vlan)
+ action_vxlan_encap_data->items[1].type =
+ RTE_FLOW_ITEM_TYPE_VOID;
+ if (vxlan_encap_conf.select_tos_ttl) {
+ if (vxlan_encap_conf.select_ipv4) {
+ static struct rte_flow_item_ipv4 ipv4_mask_tos;
+
+ memcpy(&ipv4_mask_tos, &rte_flow_item_ipv4_mask,
+ sizeof(ipv4_mask_tos));
+ ipv4_mask_tos.hdr.type_of_service = 0xff;
+ ipv4_mask_tos.hdr.time_to_live = 0xff;
+ action_vxlan_encap_data->item_ipv4.hdr.type_of_service =
+ vxlan_encap_conf.ip_tos;
+ action_vxlan_encap_data->item_ipv4.hdr.time_to_live =
+ vxlan_encap_conf.ip_ttl;
+ action_vxlan_encap_data->items[2].mask =
+ &ipv4_mask_tos;
+ } else {
+ static struct rte_flow_item_ipv6 ipv6_mask_tos;
+
+ memcpy(&ipv6_mask_tos, &rte_flow_item_ipv6_mask,
+ sizeof(ipv6_mask_tos));
+ ipv6_mask_tos.hdr.vtc_flow |=
+ RTE_BE32(0xfful << RTE_IPV6_HDR_TC_SHIFT);
+ ipv6_mask_tos.hdr.hop_limits = 0xff;
+ action_vxlan_encap_data->item_ipv6.hdr.vtc_flow |=
+ rte_cpu_to_be_32
+ ((uint32_t)vxlan_encap_conf.ip_tos <<
+ RTE_IPV6_HDR_TC_SHIFT);
+ action_vxlan_encap_data->item_ipv6.hdr.hop_limits =
+ vxlan_encap_conf.ip_ttl;
+ action_vxlan_encap_data->items[2].mask =
+ &ipv6_mask_tos;
+ }
+ }
+ memcpy(action_vxlan_encap_data->item_vxlan.vni, vxlan_encap_conf.vni,
+ RTE_DIM(vxlan_encap_conf.vni));
+ action->conf = &action_vxlan_encap_data->conf;
+ return ret;
+}
+
+/** Parse NVGRE encap action. */
+static int
+parse_vc_action_nvgre_encap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_nvgre_encap_data *action_nvgre_encap_data;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Set up default configuration. */
+ action_nvgre_encap_data = ctx->object;
+ *action_nvgre_encap_data = (struct action_nvgre_encap_data){
+ .conf = (struct rte_flow_action_nvgre_encap){
+ .definition = action_nvgre_encap_data->items,
+ },
+ .items = {
+ {
+ .type = RTE_FLOW_ITEM_TYPE_ETH,
+ .spec = &action_nvgre_encap_data->item_eth,
+ .mask = &rte_flow_item_eth_mask,
+ },
+ {
+ .type = RTE_FLOW_ITEM_TYPE_VLAN,
+ .spec = &action_nvgre_encap_data->item_vlan,
+ .mask = &rte_flow_item_vlan_mask,
+ },
+ {
+ .type = RTE_FLOW_ITEM_TYPE_IPV4,
+ .spec = &action_nvgre_encap_data->item_ipv4,
+ .mask = &rte_flow_item_ipv4_mask,
+ },
+ {
+ .type = RTE_FLOW_ITEM_TYPE_NVGRE,
+ .spec = &action_nvgre_encap_data->item_nvgre,
+ .mask = &rte_flow_item_nvgre_mask,
+ },
+ {
+ .type = RTE_FLOW_ITEM_TYPE_END,
+ },
+ },
+ .item_eth.type = 0,
+ .item_vlan = {
+ .tci = nvgre_encap_conf.vlan_tci,
+ .inner_type = 0,
+ },
+ .item_ipv4.hdr = {
+ .src_addr = nvgre_encap_conf.ipv4_src,
+ .dst_addr = nvgre_encap_conf.ipv4_dst,
+ },
+ .item_nvgre.flow_id = 0,
+ };
+ memcpy(action_nvgre_encap_data->item_eth.dst.addr_bytes,
+ nvgre_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
+ memcpy(action_nvgre_encap_data->item_eth.src.addr_bytes,
+ nvgre_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
+ if (!nvgre_encap_conf.select_ipv4) {
+ memcpy(&action_nvgre_encap_data->item_ipv6.hdr.src_addr,
+ &nvgre_encap_conf.ipv6_src,
+ sizeof(nvgre_encap_conf.ipv6_src));
+ memcpy(&action_nvgre_encap_data->item_ipv6.hdr.dst_addr,
+ &nvgre_encap_conf.ipv6_dst,
+ sizeof(nvgre_encap_conf.ipv6_dst));
+ action_nvgre_encap_data->items[2] = (struct rte_flow_item){
+ .type = RTE_FLOW_ITEM_TYPE_IPV6,
+ .spec = &action_nvgre_encap_data->item_ipv6,
+ .mask = &rte_flow_item_ipv6_mask,
+ };
+ }
+ if (!nvgre_encap_conf.select_vlan)
+ action_nvgre_encap_data->items[1].type =
+ RTE_FLOW_ITEM_TYPE_VOID;
+ memcpy(action_nvgre_encap_data->item_nvgre.tni, nvgre_encap_conf.tni,
+ RTE_DIM(nvgre_encap_conf.tni));
+ action->conf = &action_nvgre_encap_data->conf;
+ return ret;
+}
+
+/** Parse l2 encap action. */
+static int
+parse_vc_action_l2_encap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_raw_encap_data *action_encap_data;
+ struct rte_flow_item_eth eth = { .type = 0, };
+ struct rte_flow_item_vlan vlan = {
+ .tci = mplsoudp_encap_conf.vlan_tci,
+ .inner_type = 0,
+ };
+ uint8_t *header;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Copy the headers to the buffer. */
+ action_encap_data = ctx->object;
+ *action_encap_data = (struct action_raw_encap_data) {
+ .conf = (struct rte_flow_action_raw_encap){
+ .data = action_encap_data->data,
+ },
+ .data = {},
+ };
+ header = action_encap_data->data;
+ if (l2_encap_conf.select_vlan)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
+ else if (l2_encap_conf.select_ipv4)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(eth.dst.addr_bytes,
+ l2_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
+ memcpy(eth.src.addr_bytes,
+ l2_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
+ memcpy(header, &eth, sizeof(eth));
+ header += sizeof(eth);
+ if (l2_encap_conf.select_vlan) {
+ if (l2_encap_conf.select_ipv4)
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(header, &vlan, sizeof(vlan));
+ header += sizeof(vlan);
+ }
+ action_encap_data->conf.size = header -
+ action_encap_data->data;
+ action->conf = &action_encap_data->conf;
+ return ret;
+}
+
+/** Parse l2 decap action. */
+static int
+parse_vc_action_l2_decap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_raw_decap_data *action_decap_data;
+ struct rte_flow_item_eth eth = { .type = 0, };
+ struct rte_flow_item_vlan vlan = {
+ .tci = mplsoudp_encap_conf.vlan_tci,
+ .inner_type = 0,
+ };
+ uint8_t *header;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Copy the headers to the buffer. */
+ action_decap_data = ctx->object;
+ *action_decap_data = (struct action_raw_decap_data) {
+ .conf = (struct rte_flow_action_raw_decap){
+ .data = action_decap_data->data,
+ },
+ .data = {},
+ };
+ header = action_decap_data->data;
+ if (l2_decap_conf.select_vlan)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
+ memcpy(header, &eth, sizeof(eth));
+ header += sizeof(eth);
+ if (l2_decap_conf.select_vlan) {
+ memcpy(header, &vlan, sizeof(vlan));
+ header += sizeof(vlan);
+ }
+ action_decap_data->conf.size = header -
+ action_decap_data->data;
+ action->conf = &action_decap_data->conf;
+ return ret;
+}
+
+#define ETHER_TYPE_MPLS_UNICAST 0x8847
+
+/** Parse MPLSOGRE encap action. */
+static int
+parse_vc_action_mplsogre_encap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_raw_encap_data *action_encap_data;
+ struct rte_flow_item_eth eth = { .type = 0, };
+ struct rte_flow_item_vlan vlan = {
+ .tci = mplsogre_encap_conf.vlan_tci,
+ .inner_type = 0,
+ };
+ struct rte_flow_item_ipv4 ipv4 = {
+ .hdr = {
+ .src_addr = mplsogre_encap_conf.ipv4_src,
+ .dst_addr = mplsogre_encap_conf.ipv4_dst,
+ .next_proto_id = IPPROTO_GRE,
+ .version_ihl = RTE_IPV4_VHL_DEF,
+ .time_to_live = IPDEFTTL,
+ },
+ };
+ struct rte_flow_item_ipv6 ipv6 = {
+ .hdr = {
+ .proto = IPPROTO_GRE,
+ .hop_limits = IPDEFTTL,
+ },
+ };
+ struct rte_flow_item_gre gre = {
+ .protocol = rte_cpu_to_be_16(ETHER_TYPE_MPLS_UNICAST),
+ };
+ struct rte_flow_item_mpls mpls = {
+ .ttl = 0,
+ };
+ uint8_t *header;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Copy the headers to the buffer. */
+ action_encap_data = ctx->object;
+ *action_encap_data = (struct action_raw_encap_data) {
+ .conf = (struct rte_flow_action_raw_encap){
+ .data = action_encap_data->data,
+ },
+ .data = {},
+ .preserve = {},
+ };
+ header = action_encap_data->data;
+ if (mplsogre_encap_conf.select_vlan)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
+ else if (mplsogre_encap_conf.select_ipv4)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(eth.dst.addr_bytes,
+ mplsogre_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
+ memcpy(eth.src.addr_bytes,
+ mplsogre_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
+ memcpy(header, &eth, sizeof(eth));
+ header += sizeof(eth);
+ if (mplsogre_encap_conf.select_vlan) {
+ if (mplsogre_encap_conf.select_ipv4)
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(header, &vlan, sizeof(vlan));
+ header += sizeof(vlan);
+ }
+ if (mplsogre_encap_conf.select_ipv4) {
+ memcpy(header, &ipv4, sizeof(ipv4));
+ header += sizeof(ipv4);
+ } else {
+ memcpy(&ipv6.hdr.src_addr,
+ &mplsogre_encap_conf.ipv6_src,
+ sizeof(mplsogre_encap_conf.ipv6_src));
+ memcpy(&ipv6.hdr.dst_addr,
+ &mplsogre_encap_conf.ipv6_dst,
+ sizeof(mplsogre_encap_conf.ipv6_dst));
+ memcpy(header, &ipv6, sizeof(ipv6));
+ header += sizeof(ipv6);
+ }
+ memcpy(header, &gre, sizeof(gre));
+ header += sizeof(gre);
+ memcpy(mpls.label_tc_s, mplsogre_encap_conf.label,
+ RTE_DIM(mplsogre_encap_conf.label));
+ mpls.label_tc_s[2] |= 0x1;
+ memcpy(header, &mpls, sizeof(mpls));
+ header += sizeof(mpls);
+ action_encap_data->conf.size = header -
+ action_encap_data->data;
+ action->conf = &action_encap_data->conf;
+ return ret;
+}
+
+/** Parse MPLSOGRE decap action. */
+static int
+parse_vc_action_mplsogre_decap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_raw_decap_data *action_decap_data;
+ struct rte_flow_item_eth eth = { .type = 0, };
+ struct rte_flow_item_vlan vlan = {.tci = 0};
+ struct rte_flow_item_ipv4 ipv4 = {
+ .hdr = {
+ .next_proto_id = IPPROTO_GRE,
+ },
+ };
+ struct rte_flow_item_ipv6 ipv6 = {
+ .hdr = {
+ .proto = IPPROTO_GRE,
+ },
+ };
+ struct rte_flow_item_gre gre = {
+ .protocol = rte_cpu_to_be_16(ETHER_TYPE_MPLS_UNICAST),
+ };
+ struct rte_flow_item_mpls mpls;
+ uint8_t *header;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Copy the headers to the buffer. */
+ action_decap_data = ctx->object;
+ *action_decap_data = (struct action_raw_decap_data) {
+ .conf = (struct rte_flow_action_raw_decap){
+ .data = action_decap_data->data,
+ },
+ .data = {},
+ };
+ header = action_decap_data->data;
+ if (mplsogre_decap_conf.select_vlan)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
+ else if (mplsogre_encap_conf.select_ipv4)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(eth.dst.addr_bytes,
+ mplsogre_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
+ memcpy(eth.src.addr_bytes,
+ mplsogre_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
+ memcpy(header, &eth, sizeof(eth));
+ header += sizeof(eth);
+ if (mplsogre_encap_conf.select_vlan) {
+ if (mplsogre_encap_conf.select_ipv4)
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(header, &vlan, sizeof(vlan));
+ header += sizeof(vlan);
+ }
+ if (mplsogre_encap_conf.select_ipv4) {
+ memcpy(header, &ipv4, sizeof(ipv4));
+ header += sizeof(ipv4);
+ } else {
+ memcpy(header, &ipv6, sizeof(ipv6));
+ header += sizeof(ipv6);
+ }
+ memcpy(header, &gre, sizeof(gre));
+ header += sizeof(gre);
+ memset(&mpls, 0, sizeof(mpls));
+ memcpy(header, &mpls, sizeof(mpls));
+ header += sizeof(mpls);
+ action_decap_data->conf.size = header -
+ action_decap_data->data;
+ action->conf = &action_decap_data->conf;
+ return ret;
+}
+
+/** Parse MPLSOUDP encap action. */
+static int
+parse_vc_action_mplsoudp_encap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_raw_encap_data *action_encap_data;
+ struct rte_flow_item_eth eth = { .type = 0, };
+ struct rte_flow_item_vlan vlan = {
+ .tci = mplsoudp_encap_conf.vlan_tci,
+ .inner_type = 0,
+ };
+ struct rte_flow_item_ipv4 ipv4 = {
+ .hdr = {
+ .src_addr = mplsoudp_encap_conf.ipv4_src,
+ .dst_addr = mplsoudp_encap_conf.ipv4_dst,
+ .next_proto_id = IPPROTO_UDP,
+ .version_ihl = RTE_IPV4_VHL_DEF,
+ .time_to_live = IPDEFTTL,
+ },
+ };
+ struct rte_flow_item_ipv6 ipv6 = {
+ .hdr = {
+ .proto = IPPROTO_UDP,
+ .hop_limits = IPDEFTTL,
+ },
+ };
+ struct rte_flow_item_udp udp = {
+ .hdr = {
+ .src_port = mplsoudp_encap_conf.udp_src,
+ .dst_port = mplsoudp_encap_conf.udp_dst,
+ },
+ };
+ struct rte_flow_item_mpls mpls;
+ uint8_t *header;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Copy the headers to the buffer. */
+ action_encap_data = ctx->object;
+ *action_encap_data = (struct action_raw_encap_data) {
+ .conf = (struct rte_flow_action_raw_encap){
+ .data = action_encap_data->data,
+ },
+ .data = {},
+ .preserve = {},
+ };
+ header = action_encap_data->data;
+ if (mplsoudp_encap_conf.select_vlan)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
+ else if (mplsoudp_encap_conf.select_ipv4)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(eth.dst.addr_bytes,
+ mplsoudp_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
+ memcpy(eth.src.addr_bytes,
+ mplsoudp_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
+ memcpy(header, &eth, sizeof(eth));
+ header += sizeof(eth);
+ if (mplsoudp_encap_conf.select_vlan) {
+ if (mplsoudp_encap_conf.select_ipv4)
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(header, &vlan, sizeof(vlan));
+ header += sizeof(vlan);
+ }
+ if (mplsoudp_encap_conf.select_ipv4) {
+ memcpy(header, &ipv4, sizeof(ipv4));
+ header += sizeof(ipv4);
+ } else {
+ memcpy(&ipv6.hdr.src_addr,
+ &mplsoudp_encap_conf.ipv6_src,
+ sizeof(mplsoudp_encap_conf.ipv6_src));
+ memcpy(&ipv6.hdr.dst_addr,
+ &mplsoudp_encap_conf.ipv6_dst,
+ sizeof(mplsoudp_encap_conf.ipv6_dst));
+ memcpy(header, &ipv6, sizeof(ipv6));
+ header += sizeof(ipv6);
+ }
+ memcpy(header, &udp, sizeof(udp));
+ header += sizeof(udp);
+ memcpy(mpls.label_tc_s, mplsoudp_encap_conf.label,
+ RTE_DIM(mplsoudp_encap_conf.label));
+ mpls.label_tc_s[2] |= 0x1;
+ memcpy(header, &mpls, sizeof(mpls));
+ header += sizeof(mpls);
+ action_encap_data->conf.size = header -
+ action_encap_data->data;
+ action->conf = &action_encap_data->conf;
+ return ret;
+}
+
+/** Parse MPLSOUDP decap action. */
+static int
+parse_vc_action_mplsoudp_decap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_raw_decap_data *action_decap_data;
+ struct rte_flow_item_eth eth = { .type = 0, };
+ struct rte_flow_item_vlan vlan = {.tci = 0};
+ struct rte_flow_item_ipv4 ipv4 = {
+ .hdr = {
+ .next_proto_id = IPPROTO_UDP,
+ },
+ };
+ struct rte_flow_item_ipv6 ipv6 = {
+ .hdr = {
+ .proto = IPPROTO_UDP,
+ },
+ };
+ struct rte_flow_item_udp udp = {
+ .hdr = {
+ .dst_port = rte_cpu_to_be_16(6635),
+ },
+ };
+ struct rte_flow_item_mpls mpls;
+ uint8_t *header;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Copy the headers to the buffer. */
+ action_decap_data = ctx->object;
+ *action_decap_data = (struct action_raw_decap_data) {
+ .conf = (struct rte_flow_action_raw_decap){
+ .data = action_decap_data->data,
+ },
+ .data = {},
+ };
+ header = action_decap_data->data;
+ if (mplsoudp_decap_conf.select_vlan)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
+ else if (mplsoudp_encap_conf.select_ipv4)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(eth.dst.addr_bytes,
+ mplsoudp_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
+ memcpy(eth.src.addr_bytes,
+ mplsoudp_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
+ memcpy(header, &eth, sizeof(eth));
+ header += sizeof(eth);
+ if (mplsoudp_encap_conf.select_vlan) {
+ if (mplsoudp_encap_conf.select_ipv4)
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(header, &vlan, sizeof(vlan));
+ header += sizeof(vlan);
+ }
+ if (mplsoudp_encap_conf.select_ipv4) {
+ memcpy(header, &ipv4, sizeof(ipv4));
+ header += sizeof(ipv4);
+ } else {
+ memcpy(header, &ipv6, sizeof(ipv6));
+ header += sizeof(ipv6);
+ }
+ memcpy(header, &udp, sizeof(udp));
+ header += sizeof(udp);
+ memset(&mpls, 0, sizeof(mpls));
+ memcpy(header, &mpls, sizeof(mpls));
+ header += sizeof(mpls);
+ action_decap_data->conf.size = header -
+ action_decap_data->data;
+ action->conf = &action_decap_data->conf;
+ return ret;
+}
+
+static int
+parse_vc_action_raw_decap_index(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len, void *buf,
+ unsigned int size)
+{
+ struct action_raw_decap_data *action_raw_decap_data;
+ struct rte_flow_action *action;
+ const struct arg *arg;
+ struct buffer *out = buf;
+ int ret;
+ uint16_t idx;
+
+ RTE_SET_USED(token);
+ RTE_SET_USED(buf);
+ RTE_SET_USED(size);
+ arg = ARGS_ENTRY_ARB_BOUNDED
+ (offsetof(struct action_raw_decap_data, idx),
+ sizeof(((struct action_raw_decap_data *)0)->idx),
+ 0, RAW_ENCAP_CONFS_MAX_NUM - 1);
+ if (push_args(ctx, arg))
+ return -1;
+ ret = parse_int(ctx, token, str, len, NULL, 0);
+ if (ret < 0) {
+ pop_args(ctx);
+ return -1;
+ }
+ if (!ctx->object)
+ return len;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ action_raw_decap_data = ctx->object;
+ idx = action_raw_decap_data->idx;
+ action_raw_decap_data->conf.data = raw_decap_confs[idx].data;
+ action_raw_decap_data->conf.size = raw_decap_confs[idx].size;
+ action->conf = &action_raw_decap_data->conf;
+ return len;
+}
+
+
+static int
+parse_vc_action_raw_encap_index(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len, void *buf,
+ unsigned int size)
+{
+ struct action_raw_encap_data *action_raw_encap_data;
+ struct rte_flow_action *action;
+ const struct arg *arg;
+ struct buffer *out = buf;
+ int ret;
+ uint16_t idx;
+
+ RTE_SET_USED(token);
+ RTE_SET_USED(buf);
+ RTE_SET_USED(size);
+ if (ctx->curr != ACTION_RAW_ENCAP_INDEX_VALUE)
+ return -1;
+ arg = ARGS_ENTRY_ARB_BOUNDED
+ (offsetof(struct action_raw_encap_data, idx),
+ sizeof(((struct action_raw_encap_data *)0)->idx),
+ 0, RAW_ENCAP_CONFS_MAX_NUM - 1);
+ if (push_args(ctx, arg))
+ return -1;
+ ret = parse_int(ctx, token, str, len, NULL, 0);
+ if (ret < 0) {
+ pop_args(ctx);
+ return -1;
+ }
+ if (!ctx->object)
+ return len;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ action_raw_encap_data = ctx->object;
+ idx = action_raw_encap_data->idx;
+ action_raw_encap_data->conf.data = raw_encap_confs[idx].data;
+ action_raw_encap_data->conf.size = raw_encap_confs[idx].size;
+ action_raw_encap_data->conf.preserve = NULL;
+ action->conf = &action_raw_encap_data->conf;
+ return len;
+}
+
+static int
+parse_vc_action_raw_encap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len, void *buf,
+ unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_raw_encap_data *action_raw_encap_data = NULL;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Copy the headers to the buffer. */
+ action_raw_encap_data = ctx->object;
+ action_raw_encap_data->conf.data = raw_encap_confs[0].data;
+ action_raw_encap_data->conf.preserve = NULL;
+ action_raw_encap_data->conf.size = raw_encap_confs[0].size;
+ action->conf = &action_raw_encap_data->conf;
+ return ret;
+}
+
+static int
+parse_vc_action_raw_decap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len, void *buf,
+ unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_raw_decap_data *action_raw_decap_data = NULL;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Copy the headers to the buffer. */
+ action_raw_decap_data = ctx->object;
+ action_raw_decap_data->conf.data = raw_decap_confs[0].data;
+ action_raw_decap_data->conf.size = raw_decap_confs[0].size;
+ action->conf = &action_raw_decap_data->conf;
+ return ret;
+}
+
+static int
+parse_vc_action_set_meta(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len, void *buf,
+ unsigned int size)
+{
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ ret = rte_flow_dynf_metadata_register();
+ if (ret < 0)
+ return -1;
+ return len;
+}
+
+/** Parse tokens for destroy command. */
+static int
+parse_destroy(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->command) {
+ if (ctx->curr != DESTROY)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ out->args.destroy.rule =
+ (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+ sizeof(double));
+ return len;
+ }
+ if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) +
+ sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size)
+ return -1;
+ ctx->objdata = 0;
+ ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++;
+ ctx->objmask = NULL;
+ return len;
+}
+
+/** Parse tokens for flush command. */
+static int
+parse_flush(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->command) {
+ if (ctx->curr != FLUSH)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ }
+ return len;
+}
+
+/** Parse tokens for dump command. */
+static int
+parse_dump(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->command) {
+ if (ctx->curr != DUMP)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ }
+ return len;
+}
+
+/** Parse tokens for query command. */
+static int
+parse_query(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->command) {
+ if (ctx->curr != QUERY)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ }
+ return len;
+}
+
+/** Parse action names. */
+static int
+parse_action(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ const struct arg *arg = pop_args(ctx);
+ unsigned int i;
+
+ (void)size;
+ /* Argument is expected. */
+ if (!arg)
+ return -1;
+ /* Parse action name. */
+ for (i = 0; next_action[i]; ++i) {
+ const struct parse_action_priv *priv;
+
+ token = &token_list[next_action[i]];
+ if (strcmp_partial(token->name, str, len))
+ continue;
+ priv = token->priv;
+ if (!priv)
+ goto error;
+ if (out)
+ memcpy((uint8_t *)ctx->object + arg->offset,
+ &priv->type,
+ arg->size);
+ return len;
+ }
+error:
+ push_args(ctx, arg);
+ return -1;
+}
+
+/** Parse tokens for list command. */
+static int
+parse_list(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->command) {
+ if (ctx->curr != LIST)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ out->args.list.group =
+ (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+ sizeof(double));
+ return len;
+ }
+ if (((uint8_t *)(out->args.list.group + out->args.list.group_n) +
+ sizeof(*out->args.list.group)) > (uint8_t *)out + size)
+ return -1;
+ ctx->objdata = 0;
+ ctx->object = out->args.list.group + out->args.list.group_n++;
+ ctx->objmask = NULL;
+ return len;
+}
+
+/** Parse tokens for list all aged flows command. */
+static int
+parse_aged(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->command) {
+ if (ctx->curr != AGED)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ }
+ if (ctx->curr == AGED_DESTROY)
+ out->args.aged.destroy = 1;
+ return len;
+}
+
+/** Parse tokens for isolate command. */
+static int
+parse_isolate(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->command) {
+ if (ctx->curr != ISOLATE)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ }
+ return len;
+}
+
+/**
+ * Parse signed/unsigned integers 8 to 64-bit long.
+ *
+ * Last argument (ctx->args) is retrieved to determine integer type and
+ * storage location.
+ */
+static int
+parse_int(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ const struct arg *arg = pop_args(ctx);
+ uintmax_t u;
+ char *end;
+
+ (void)token;
+ /* Argument is expected. */
+ if (!arg)
+ return -1;
+ errno = 0;
+ u = arg->sign ?
+ (uintmax_t)strtoimax(str, &end, 0) :
+ strtoumax(str, &end, 0);
+ if (errno || (size_t)(end - str) != len)
+ goto error;
+ if (arg->bounded &&
+ ((arg->sign && ((intmax_t)u < (intmax_t)arg->min ||
+ (intmax_t)u > (intmax_t)arg->max)) ||
+ (!arg->sign && (u < arg->min || u > arg->max))))
+ goto error;
+ if (!ctx->object)
+ return len;
+ if (arg->mask) {
+ if (!arg_entry_bf_fill(ctx->object, u, arg) ||
+ !arg_entry_bf_fill(ctx->objmask, -1, arg))
+ goto error;
+ return len;
+ }
+ buf = (uint8_t *)ctx->object + arg->offset;
+ size = arg->size;
+ if (u > RTE_LEN2MASK(size * CHAR_BIT, uint64_t))
+ return -1;
+objmask:
+ switch (size) {
+ case sizeof(uint8_t):
+ *(uint8_t *)buf = u;
+ break;
+ case sizeof(uint16_t):
+ *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u;
+ break;
+ case sizeof(uint8_t [3]):
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+ if (!arg->hton) {
+ ((uint8_t *)buf)[0] = u;
+ ((uint8_t *)buf)[1] = u >> 8;
+ ((uint8_t *)buf)[2] = u >> 16;
+ break;
+ }
+#endif
+ ((uint8_t *)buf)[0] = u >> 16;
+ ((uint8_t *)buf)[1] = u >> 8;
+ ((uint8_t *)buf)[2] = u;
+ break;
+ case sizeof(uint32_t):
+ *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u;
+ break;
+ case sizeof(uint64_t):
+ *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u;
+ break;
+ default:
+ goto error;
+ }
+ if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) {
+ u = -1;
+ buf = (uint8_t *)ctx->objmask + arg->offset;
+ goto objmask;
+ }
+ return len;
+error:
+ push_args(ctx, arg);
+ return -1;
+}
+
+/**
+ * Parse a string.
+ *
+ * Three arguments (ctx->args) are retrieved from the stack to store data,
+ * its actual length and address (in that order).
+ */
+static int
+parse_string(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ const struct arg *arg_data = pop_args(ctx);
+ const struct arg *arg_len = pop_args(ctx);
+ const struct arg *arg_addr = pop_args(ctx);
+ char tmp[16]; /* Ought to be enough. */
+ int ret;
+
+ /* Arguments are expected. */
+ if (!arg_data)
+ return -1;
+ if (!arg_len) {
+ push_args(ctx, arg_data);
+ return -1;
+ }
+ if (!arg_addr) {
+ push_args(ctx, arg_len);
+ push_args(ctx, arg_data);
+ return -1;
+ }
+ size = arg_data->size;
+ /* Bit-mask fill is not supported. */
+ if (arg_data->mask || size < len)
+ goto error;
+ if (!ctx->object)
+ return len;
+ /* Let parse_int() fill length information first. */
+ ret = snprintf(tmp, sizeof(tmp), "%u", len);
+ if (ret < 0)
+ goto error;
+ push_args(ctx, arg_len);
+ ret = parse_int(ctx, token, tmp, ret, NULL, 0);
+ if (ret < 0) {
+ pop_args(ctx);
+ goto error;
+ }
+ buf = (uint8_t *)ctx->object + arg_data->offset;
+ /* Output buffer is not necessarily NUL-terminated. */
+ memcpy(buf, str, len);
+ memset((uint8_t *)buf + len, 0x00, size - len);
+ if (ctx->objmask)
+ memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len);
+ /* Save address if requested. */
+ if (arg_addr->size) {
+ memcpy((uint8_t *)ctx->object + arg_addr->offset,
+ (void *[]){
+ (uint8_t *)ctx->object + arg_data->offset
+ },
+ arg_addr->size);
+ if (ctx->objmask)
+ memcpy((uint8_t *)ctx->objmask + arg_addr->offset,
+ (void *[]){
+ (uint8_t *)ctx->objmask + arg_data->offset
+ },
+ arg_addr->size);
+ }
+ return len;
+error:
+ push_args(ctx, arg_addr);
+ push_args(ctx, arg_len);
+ push_args(ctx, arg_data);
+ return -1;
+}
+
+static int
+parse_hex_string(const char *src, uint8_t *dst, uint32_t *size)
+{
+ char *c = NULL;
+ uint32_t i, len;
+ char tmp[3];
+
+ /* Check input parameters */
+ if ((src == NULL) ||
+ (dst == NULL) ||
+ (size == NULL) ||
+ (*size == 0))
+ return -1;
+
+ /* Convert chars to bytes */
+ for (i = 0, len = 0; i < *size; i += 2) {
+ snprintf(tmp, 3, "%s", src + i);
+ dst[len++] = strtoul(tmp, &c, 16);
+ if (*c != 0) {
+ len--;
+ dst[len] = 0;
+ *size = len;
+ return -1;
+ }
+ }
+ dst[len] = 0;
+ *size = len;
+
+ return 0;
+}
+
+static int
+parse_hex(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ const struct arg *arg_data = pop_args(ctx);
+ const struct arg *arg_len = pop_args(ctx);
+ const struct arg *arg_addr = pop_args(ctx);
+ char tmp[16]; /* Ought to be enough. */
+ int ret;
+ unsigned int hexlen = len;
+ unsigned int length = 256;
+ uint8_t hex_tmp[length];
+
+ /* Arguments are expected. */
+ if (!arg_data)
+ return -1;
+ if (!arg_len) {
+ push_args(ctx, arg_data);
+ return -1;
+ }
+ if (!arg_addr) {
+ push_args(ctx, arg_len);
+ push_args(ctx, arg_data);
+ return -1;
+ }
+ size = arg_data->size;
+ /* Bit-mask fill is not supported. */
+ if (arg_data->mask)
+ goto error;
+ if (!ctx->object)
+ return len;
+
+ /* translate bytes string to array. */
+ if (str[0] == '0' && ((str[1] == 'x') ||
+ (str[1] == 'X'))) {
+ str += 2;
+ hexlen -= 2;
+ }
+ if (hexlen > length)
+ return -1;
+ ret = parse_hex_string(str, hex_tmp, &hexlen);
+ if (ret < 0)
+ goto error;
+ /* Let parse_int() fill length information first. */
+ ret = snprintf(tmp, sizeof(tmp), "%u", hexlen);
+ if (ret < 0)
+ goto error;
+ push_args(ctx, arg_len);
+ ret = parse_int(ctx, token, tmp, ret, NULL, 0);
+ if (ret < 0) {
+ pop_args(ctx);
+ goto error;
+ }
+ buf = (uint8_t *)ctx->object + arg_data->offset;
+ /* Output buffer is not necessarily NUL-terminated. */
+ memcpy(buf, hex_tmp, hexlen);
+ memset((uint8_t *)buf + hexlen, 0x00, size - hexlen);
+ if (ctx->objmask)
+ memset((uint8_t *)ctx->objmask + arg_data->offset,
+ 0xff, hexlen);
+ /* Save address if requested. */
+ if (arg_addr->size) {
+ memcpy((uint8_t *)ctx->object + arg_addr->offset,
+ (void *[]){
+ (uint8_t *)ctx->object + arg_data->offset
+ },
+ arg_addr->size);
+ if (ctx->objmask)
+ memcpy((uint8_t *)ctx->objmask + arg_addr->offset,
+ (void *[]){
+ (uint8_t *)ctx->objmask + arg_data->offset
+ },
+ arg_addr->size);
+ }
+ return len;
+error:
+ push_args(ctx, arg_addr);
+ push_args(ctx, arg_len);
+ push_args(ctx, arg_data);
+ return -1;
+
+}
+
+/**
+ * Parse a zero-ended string.
+ */
+static int
+parse_string0(struct context *ctx, const struct token *token __rte_unused,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ const struct arg *arg_data = pop_args(ctx);
+
+ /* Arguments are expected. */
+ if (!arg_data)
+ return -1;
+ size = arg_data->size;
+ /* Bit-mask fill is not supported. */
+ if (arg_data->mask || size < len + 1)
+ goto error;
+ if (!ctx->object)
+ return len;
+ buf = (uint8_t *)ctx->object + arg_data->offset;
+ strncpy(buf, str, len);
+ if (ctx->objmask)
+ memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len);
+ return len;
+error:
+ push_args(ctx, arg_data);
+ return -1;
+}
+
+/**
+ * Parse a MAC address.
+ *
+ * Last argument (ctx->args) is retrieved to determine storage size and
+ * location.
+ */
+static int
+parse_mac_addr(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ const struct arg *arg = pop_args(ctx);
+ struct rte_ether_addr tmp;
+ int ret;
+
+ (void)token;
+ /* Argument is expected. */
+ if (!arg)
+ return -1;
+ size = arg->size;
+ /* Bit-mask fill is not supported. */
+ if (arg->mask || size != sizeof(tmp))
+ goto error;
+ /* Only network endian is supported. */
+ if (!arg->hton)
+ goto error;
+ ret = cmdline_parse_etheraddr(NULL, str, &tmp, size);
+ if (ret < 0 || (unsigned int)ret != len)
+ goto error;
+ if (!ctx->object)
+ return len;
+ buf = (uint8_t *)ctx->object + arg->offset;
+ memcpy(buf, &tmp, size);
+ if (ctx->objmask)
+ memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
+ return len;
+error:
+ push_args(ctx, arg);
+ return -1;
+}
+
+/**
+ * Parse an IPv4 address.
+ *
+ * Last argument (ctx->args) is retrieved to determine storage size and
+ * location.
+ */
+static int
+parse_ipv4_addr(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ const struct arg *arg = pop_args(ctx);
+ char str2[len + 1];
+ struct in_addr tmp;
+ int ret;
+
+ /* Argument is expected. */
+ if (!arg)
+ return -1;
+ size = arg->size;
+ /* Bit-mask fill is not supported. */
+ if (arg->mask || size != sizeof(tmp))
+ goto error;
+ /* Only network endian is supported. */
+ if (!arg->hton)
+ goto error;
+ memcpy(str2, str, len);
+ str2[len] = '\0';
+ ret = inet_pton(AF_INET, str2, &tmp);
+ if (ret != 1) {
+ /* Attempt integer parsing. */
+ push_args(ctx, arg);
+ return parse_int(ctx, token, str, len, buf, size);
+ }
+ if (!ctx->object)
+ return len;
+ buf = (uint8_t *)ctx->object + arg->offset;
+ memcpy(buf, &tmp, size);
+ if (ctx->objmask)
+ memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
+ return len;
+error:
+ push_args(ctx, arg);
+ return -1;
+}
+
+/**
+ * Parse an IPv6 address.
+ *
+ * Last argument (ctx->args) is retrieved to determine storage size and
+ * location.
+ */
+static int
+parse_ipv6_addr(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ const struct arg *arg = pop_args(ctx);
+ char str2[len + 1];
+ struct in6_addr tmp;
+ int ret;
+
+ (void)token;
+ /* Argument is expected. */
+ if (!arg)
+ return -1;
+ size = arg->size;
+ /* Bit-mask fill is not supported. */
+ if (arg->mask || size != sizeof(tmp))
+ goto error;
+ /* Only network endian is supported. */
+ if (!arg->hton)
+ goto error;
+ memcpy(str2, str, len);
+ str2[len] = '\0';
+ ret = inet_pton(AF_INET6, str2, &tmp);
+ if (ret != 1)
+ goto error;
+ if (!ctx->object)
+ return len;
+ buf = (uint8_t *)ctx->object + arg->offset;
+ memcpy(buf, &tmp, size);
+ if (ctx->objmask)
+ memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
+ return len;
+error:
+ push_args(ctx, arg);
+ return -1;
+}
+
+/** Boolean values (even indices stand for false). */
+static const char *const boolean_name[] = {
+ "0", "1",
+ "false", "true",
+ "no", "yes",
+ "N", "Y",
+ "off", "on",
+ NULL,
+};
+
+/**
+ * Parse a boolean value.
+ *
+ * Last argument (ctx->args) is retrieved to determine storage size and
+ * location.
+ */
+static int
+parse_boolean(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ const struct arg *arg = pop_args(ctx);
+ unsigned int i;
+ int ret;
+
+ /* Argument is expected. */
+ if (!arg)
+ return -1;
+ for (i = 0; boolean_name[i]; ++i)
+ if (!strcmp_partial(boolean_name[i], str, len))
+ break;
+ /* Process token as integer. */
+ if (boolean_name[i])
+ str = i & 1 ? "1" : "0";
+ push_args(ctx, arg);
+ ret = parse_int(ctx, token, str, strlen(str), buf, size);
+ return ret > 0 ? (int)len : ret;
+}
+
+/** Parse port and update context. */
+static int
+parse_port(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = &(struct buffer){ .port = 0 };
+ int ret;
+
+ if (buf)
+ out = buf;
+ else {
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ size = sizeof(*out);
+ }
+ ret = parse_int(ctx, token, str, len, out, size);
+ if (ret >= 0)
+ ctx->port = out->port;
+ if (!buf)
+ ctx->object = NULL;
+ return ret;
+}
+
+/** Parse set command, initialize output buffer for subsequent tokens. */
+static int
+parse_set_raw_encap_decap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ /* Make sure buffer is large enough. */
+ if (size < sizeof(*out))
+ return -1;
+ ctx->objdata = 0;
+ ctx->objmask = NULL;
+ ctx->object = out;
+ if (!out->command)
+ return -1;
+ out->command = ctx->curr;
+ return len;
+}
+
+/**
+ * Parse set raw_encap/raw_decap command,
+ * initialize output buffer for subsequent tokens.
+ */
+static int
+parse_set_init(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ /* Make sure buffer is large enough. */
+ if (size < sizeof(*out))
+ return -1;
+ /* Initialize buffer. */
+ memset(out, 0x00, sizeof(*out));
+ memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ if (!out->command) {
+ if (ctx->curr != SET)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ out->args.vc.data = (uint8_t *)out + size;
+ /* All we need is pattern */
+ out->args.vc.pattern =
+ (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+ sizeof(double));
+ ctx->object = out->args.vc.pattern;
+ }
+ return len;
+}
+
+/** No completion. */
+static int
+comp_none(struct context *ctx, const struct token *token,
+ unsigned int ent, char *buf, unsigned int size)
+{
+ (void)ctx;
+ (void)token;
+ (void)ent;
+ (void)buf;
+ (void)size;
+ return 0;
+}
+
+/** Complete boolean values. */
+static int
+comp_boolean(struct context *ctx, const struct token *token,
+ unsigned int ent, char *buf, unsigned int size)
+{
+ unsigned int i;
+
+ (void)ctx;
+ (void)token;
+ for (i = 0; boolean_name[i]; ++i)
+ if (buf && i == ent)
+ return strlcpy(buf, boolean_name[i], size);
+ if (buf)
+ return -1;
+ return i;
+}
+
+/** Complete action names. */
+static int
+comp_action(struct context *ctx, const struct token *token,
+ unsigned int ent, char *buf, unsigned int size)
+{
+ unsigned int i;
+
+ (void)ctx;
+ (void)token;
+ for (i = 0; next_action[i]; ++i)
+ if (buf && i == ent)
+ return strlcpy(buf, token_list[next_action[i]].name,
+ size);
+ if (buf)
+ return -1;
+ return i;
+}
+
+/** Complete available ports. */
+static int
+comp_port(struct context *ctx, const struct token *token,
+ unsigned int ent, char *buf, unsigned int size)
+{
+ unsigned int i = 0;
+ portid_t p;
+
+ (void)ctx;
+ (void)token;
+ RTE_ETH_FOREACH_DEV(p) {
+ if (buf && i == ent)
+ return snprintf(buf, size, "%u", p);
+ ++i;
+ }
+ if (buf)
+ return -1;
+ return i;
+}
+
+/** Complete available rule IDs. */
+static int
+comp_rule_id(struct context *ctx, const struct token *token,
+ unsigned int ent, char *buf, unsigned int size)
+{
+ unsigned int i = 0;
+ struct rte_port *port;
+ struct port_flow *pf;
+
+ (void)token;
+ if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
+ ctx->port == (portid_t)RTE_PORT_ALL)
+ return -1;
+ port = &ports[ctx->port];
+ for (pf = port->flow_list; pf != NULL; pf = pf->next) {
+ if (buf && i == ent)
+ return snprintf(buf, size, "%u", pf->id);
+ ++i;
+ }
+ if (buf)
+ return -1;
+ return i;
+}
+
+/** Complete type field for RSS action. */
+static int
+comp_vc_action_rss_type(struct context *ctx, const struct token *token,
+ unsigned int ent, char *buf, unsigned int size)
+{
+ unsigned int i;
+
+ (void)ctx;
+ (void)token;
+ for (i = 0; rss_type_table[i].str; ++i)
+ ;
+ if (!buf)
+ return i + 1;
+ if (ent < i)
+ return strlcpy(buf, rss_type_table[ent].str, size);
+ if (ent == i)
+ return snprintf(buf, size, "end");
+ return -1;
+}
+
+/** Complete queue field for RSS action. */
+static int
+comp_vc_action_rss_queue(struct context *ctx, const struct token *token,
+ unsigned int ent, char *buf, unsigned int size)
+{
+ (void)ctx;
+ (void)token;
+ if (!buf)
+ return nb_rxq + 1;
+ if (ent < nb_rxq)
+ return snprintf(buf, size, "%u", ent);
+ if (ent == nb_rxq)
+ return snprintf(buf, size, "end");
+ return -1;
+}
+
+/** Complete index number for set raw_encap/raw_decap commands. */
+static int
+comp_set_raw_index(struct context *ctx, const struct token *token,
+ unsigned int ent, char *buf, unsigned int size)
+{
+ uint16_t idx = 0;
+ uint16_t nb = 0;
+
+ RTE_SET_USED(ctx);
+ RTE_SET_USED(token);
+ for (idx = 0; idx < RAW_ENCAP_CONFS_MAX_NUM; ++idx) {
+ if (buf && idx == ent)
+ return snprintf(buf, size, "%u", idx);
+ ++nb;
+ }
+ return nb;
+}
+
+/** Internal context. */
+static struct context cmd_flow_context;
+
+/** Global parser instance (cmdline API). */
+cmdline_parse_inst_t cmd_flow;
+cmdline_parse_inst_t cmd_set_raw;
+
+/** Initialize context. */
+static void
+cmd_flow_context_init(struct context *ctx)
+{
+ /* A full memset() is not necessary. */
+ ctx->curr = ZERO;
+ ctx->prev = ZERO;
+ ctx->next_num = 0;
+ ctx->args_num = 0;
+ ctx->eol = 0;
+ ctx->last = 0;
+ ctx->port = 0;
+ ctx->objdata = 0;
+ ctx->object = NULL;
+ ctx->objmask = NULL;
+}
+
+/** Parse a token (cmdline API). */
+static int
+cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,
+ unsigned int size)
+{
+ struct context *ctx = &cmd_flow_context;
+ const struct token *token;
+ const enum index *list;
+ int len;
+ int i;
+
+ (void)hdr;
+ token = &token_list[ctx->curr];
+ /* Check argument length. */
+ ctx->eol = 0;
+ ctx->last = 1;
+ for (len = 0; src[len]; ++len)
+ if (src[len] == '#' || isspace(src[len]))
+ break;
+ if (!len)
+ return -1;
+ /* Last argument and EOL detection. */
+ for (i = len; src[i]; ++i)
+ if (src[i] == '#' || src[i] == '\r' || src[i] == '\n')
+ break;
+ else if (!isspace(src[i])) {
+ ctx->last = 0;
+ break;
+ }
+ for (; src[i]; ++i)
+ if (src[i] == '\r' || src[i] == '\n') {
+ ctx->eol = 1;
+ break;
+ }
+ /* Initialize context if necessary. */
+ if (!ctx->next_num) {
+ if (!token->next)
+ return 0;
+ ctx->next[ctx->next_num++] = token->next[0];
+ }
+ /* Process argument through candidates. */
+ ctx->prev = ctx->curr;
+ list = ctx->next[ctx->next_num - 1];
+ for (i = 0; list[i]; ++i) {
+ const struct token *next = &token_list[list[i]];
+ int tmp;
+
+ ctx->curr = list[i];
+ if (next->call)
+ tmp = next->call(ctx, next, src, len, result, size);
+ else
+ tmp = parse_default(ctx, next, src, len, result, size);
+ if (tmp == -1 || tmp != len)
+ continue;
+ token = next;
+ break;
+ }
+ if (!list[i])
+ return -1;
+ --ctx->next_num;
+ /* Push subsequent tokens if any. */
+ if (token->next)
+ for (i = 0; token->next[i]; ++i) {
+ if (ctx->next_num == RTE_DIM(ctx->next))
+ return -1;
+ ctx->next[ctx->next_num++] = token->next[i];
+ }
+ /* Push arguments if any. */
+ if (token->args)
+ for (i = 0; token->args[i]; ++i) {
+ if (ctx->args_num == RTE_DIM(ctx->args))
+ return -1;
+ ctx->args[ctx->args_num++] = token->args[i];
+ }
+ return len;
+}
+
+/** Return number of completion entries (cmdline API). */
+static int
+cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)
+{
+ struct context *ctx = &cmd_flow_context;
+ const struct token *token = &token_list[ctx->curr];
+ const enum index *list;
+ int i;
+
+ (void)hdr;
+ /* Count number of tokens in current list. */
+ if (ctx->next_num)
+ list = ctx->next[ctx->next_num - 1];
+ else
+ list = token->next[0];
+ for (i = 0; list[i]; ++i)
+ ;
+ if (!i)
+ return 0;
+ /*
+ * If there is a single token, use its completion callback, otherwise
+ * return the number of entries.
+ */
+ token = &token_list[list[0]];
+ if (i == 1 && token->comp) {
+ /* Save index for cmd_flow_get_help(). */
+ ctx->prev = list[0];
+ return token->comp(ctx, token, 0, NULL, 0);
+ }
+ return i;
+}
+
+/** Return a completion entry (cmdline API). */
+static int
+cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,
+ char *dst, unsigned int size)
+{
+ struct context *ctx = &cmd_flow_context;
+ const struct token *token = &token_list[ctx->curr];
+ const enum index *list;
+ int i;
+
+ (void)hdr;
+ /* Count number of tokens in current list. */
+ if (ctx->next_num)
+ list = ctx->next[ctx->next_num - 1];
+ else
+ list = token->next[0];
+ for (i = 0; list[i]; ++i)
+ ;
+ if (!i)
+ return -1;
+ /* If there is a single token, use its completion callback. */
+ token = &token_list[list[0]];
+ if (i == 1 && token->comp) {
+ /* Save index for cmd_flow_get_help(). */
+ ctx->prev = list[0];
+ return token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0;
+ }
+ /* Otherwise make sure the index is valid and use defaults. */
+ if (index >= i)
+ return -1;
+ token = &token_list[list[index]];
+ strlcpy(dst, token->name, size);
+ /* Save index for cmd_flow_get_help(). */
+ ctx->prev = list[index];
+ return 0;
+}
+
+/** Populate help strings for current token (cmdline API). */
+static int
+cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)
+{
+ struct context *ctx = &cmd_flow_context;
+ const struct token *token = &token_list[ctx->prev];
+
+ (void)hdr;
+ if (!size)
+ return -1;
+ /* Set token type and update global help with details. */
+ strlcpy(dst, (token->type ? token->type : "TOKEN"), size);
+ if (token->help)
+ cmd_flow.help_str = token->help;
+ else
+ cmd_flow.help_str = token->name;
+ return 0;
+}
+
+/** Token definition template (cmdline API). */
+static struct cmdline_token_hdr cmd_flow_token_hdr = {
+ .ops = &(struct cmdline_token_ops){
+ .parse = cmd_flow_parse,
+ .complete_get_nb = cmd_flow_complete_get_nb,
+ .complete_get_elt = cmd_flow_complete_get_elt,
+ .get_help = cmd_flow_get_help,
+ },
+ .offset = 0,
+};
+
+/** Populate the next dynamic token. */
+static void
+cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
+ cmdline_parse_token_hdr_t **hdr_inst)
+{
+ struct context *ctx = &cmd_flow_context;
+
+ /* Always reinitialize context before requesting the first token. */
+ if (!(hdr_inst - cmd_flow.tokens))
+ cmd_flow_context_init(ctx);
+ /* Return NULL when no more tokens are expected. */
+ if (!ctx->next_num && ctx->curr) {
+ *hdr = NULL;
+ return;
+ }
+ /* Determine if command should end here. */
+ if (ctx->eol && ctx->last && ctx->next_num) {
+ const enum index *list = ctx->next[ctx->next_num - 1];
+ int i;
+
+ for (i = 0; list[i]; ++i) {
+ if (list[i] != END)
+ continue;
+ *hdr = NULL;
+ return;
+ }
+ }
+ *hdr = &cmd_flow_token_hdr;
+}
+
+/** Dispatch parsed buffer to function calls. */
+static void
+cmd_flow_parsed(const struct buffer *in)
+{
+ switch (in->command) {
+ case VALIDATE:
+ port_flow_validate(in->port, &in->args.vc.attr,
+ in->args.vc.pattern, in->args.vc.actions);
+ break;
+ case CREATE:
+ port_flow_create(in->port, &in->args.vc.attr,
+ in->args.vc.pattern, in->args.vc.actions);
+ break;
+ case DESTROY:
+ port_flow_destroy(in->port, in->args.destroy.rule_n,
+ in->args.destroy.rule);
+ break;
+ case FLUSH:
+ port_flow_flush(in->port);
+ break;
+ case DUMP:
+ port_flow_dump(in->port, in->args.dump.file);
+ break;
+ case QUERY:
+ port_flow_query(in->port, in->args.query.rule,
+ &in->args.query.action);
+ break;
+ case LIST:
+ port_flow_list(in->port, in->args.list.group_n,
+ in->args.list.group);
+ break;
+ case ISOLATE:
+ port_flow_isolate(in->port, in->args.isolate.set);
+ break;
+ case AGED:
+ port_flow_aged(in->port, in->args.aged.destroy);
+ break;
+ default:
+ break;
+ }
+}
+
+/** Token generator and output processing callback (cmdline API). */
+static void
+cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)
+{
+ if (cl == NULL)
+ cmd_flow_tok(arg0, arg2);
+ else
+ cmd_flow_parsed(arg0);
+}
+
+/** Global parser instance (cmdline API). */
+cmdline_parse_inst_t cmd_flow = {
+ .f = cmd_flow_cb,
+ .data = NULL, /**< Unused. */
+ .help_str = NULL, /**< Updated by cmd_flow_get_help(). */
+ .tokens = {
+ NULL,
+ }, /**< Tokens are returned by cmd_flow_tok(). */
+};
+
+/** set cmd facility. Reuse cmd flow's infrastructure as much as possible. */
+
+static void
+update_fields(uint8_t *buf, struct rte_flow_item *item, uint16_t next_proto)
+{
+ struct rte_flow_item_ipv4 *ipv4;
+ struct rte_flow_item_eth *eth;
+ struct rte_flow_item_ipv6 *ipv6;
+ struct rte_flow_item_vxlan *vxlan;
+ struct rte_flow_item_vxlan_gpe *gpe;
+ struct rte_flow_item_nvgre *nvgre;
+ uint32_t ipv6_vtc_flow;
+
+ switch (item->type) {
+ case RTE_FLOW_ITEM_TYPE_ETH:
+ eth = (struct rte_flow_item_eth *)buf;
+ if (next_proto)
+ eth->type = rte_cpu_to_be_16(next_proto);
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV4:
+ ipv4 = (struct rte_flow_item_ipv4 *)buf;
+ ipv4->hdr.version_ihl = 0x45;
+ if (next_proto && ipv4->hdr.next_proto_id == 0)
+ ipv4->hdr.next_proto_id = (uint8_t)next_proto;
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV6:
+ ipv6 = (struct rte_flow_item_ipv6 *)buf;
+ if (next_proto && ipv6->hdr.proto == 0)
+ ipv6->hdr.proto = (uint8_t)next_proto;
+ ipv6_vtc_flow = rte_be_to_cpu_32(ipv6->hdr.vtc_flow);
+ ipv6_vtc_flow &= 0x0FFFFFFF; /*< reset version bits. */
+ ipv6_vtc_flow |= 0x60000000; /*< set ipv6 version. */
+ ipv6->hdr.vtc_flow = rte_cpu_to_be_32(ipv6_vtc_flow);
+ break;
+ case RTE_FLOW_ITEM_TYPE_VXLAN:
+ vxlan = (struct rte_flow_item_vxlan *)buf;
+ vxlan->flags = 0x08;
+ break;
+ case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+ gpe = (struct rte_flow_item_vxlan_gpe *)buf;
+ gpe->flags = 0x0C;
+ break;
+ case RTE_FLOW_ITEM_TYPE_NVGRE:
+ nvgre = (struct rte_flow_item_nvgre *)buf;
+ nvgre->protocol = rte_cpu_to_be_16(0x6558);
+ nvgre->c_k_s_rsvd0_ver = rte_cpu_to_be_16(0x2000);
+ break;
+ default:
+ break;
+ }
+}
+
+/** Helper of get item's default mask. */
+static const void *
+flow_item_default_mask(const struct rte_flow_item *item)
+{
+ const void *mask = NULL;
+ static rte_be32_t gre_key_default_mask = RTE_BE32(UINT32_MAX);
+
+ switch (item->type) {
+ case RTE_FLOW_ITEM_TYPE_ANY:
+ mask = &rte_flow_item_any_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_VF:
+ mask = &rte_flow_item_vf_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_PORT_ID:
+ mask = &rte_flow_item_port_id_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_RAW:
+ mask = &rte_flow_item_raw_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_ETH:
+ mask = &rte_flow_item_eth_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_VLAN:
+ mask = &rte_flow_item_vlan_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV4:
+ mask = &rte_flow_item_ipv4_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV6:
+ mask = &rte_flow_item_ipv6_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_ICMP:
+ mask = &rte_flow_item_icmp_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_UDP:
+ mask = &rte_flow_item_udp_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_TCP:
+ mask = &rte_flow_item_tcp_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_SCTP:
+ mask = &rte_flow_item_sctp_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_VXLAN:
+ mask = &rte_flow_item_vxlan_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+ mask = &rte_flow_item_vxlan_gpe_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_E_TAG:
+ mask = &rte_flow_item_e_tag_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_NVGRE:
+ mask = &rte_flow_item_nvgre_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_MPLS:
+ mask = &rte_flow_item_mpls_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_GRE:
+ mask = &rte_flow_item_gre_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_GRE_KEY:
+ mask = &gre_key_default_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_META:
+ mask = &rte_flow_item_meta_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_FUZZY:
+ mask = &rte_flow_item_fuzzy_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_GTP:
+ mask = &rte_flow_item_gtp_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_GTP_PSC:
+ mask = &rte_flow_item_gtp_psc_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_GENEVE:
+ mask = &rte_flow_item_geneve_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_PPPOE_PROTO_ID:
+ mask = &rte_flow_item_pppoe_proto_id_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_L2TPV3OIP:
+ mask = &rte_flow_item_l2tpv3oip_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_ESP:
+ mask = &rte_flow_item_esp_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_AH:
+ mask = &rte_flow_item_ah_mask;
+ break;
+ case RTE_FLOW_ITEM_TYPE_PFCP:
+ mask = &rte_flow_item_pfcp_mask;
+ break;
+ default:
+ break;
+ }
+ return mask;
+}
+
+
+
+/** Dispatch parsed buffer to function calls. */
+static void
+cmd_set_raw_parsed(const struct buffer *in)
+{
+ uint32_t n = in->args.vc.pattern_n;
+ int i = 0;
+ struct rte_flow_item *item = NULL;
+ size_t size = 0;
+ uint8_t *data = NULL;
+ uint8_t *data_tail = NULL;
+ size_t *total_size = NULL;
+ uint16_t upper_layer = 0;
+ uint16_t proto = 0;
+ uint16_t idx = in->port; /* We borrow port field as index */
+
+ RTE_ASSERT(in->command == SET_RAW_ENCAP ||
+ in->command == SET_RAW_DECAP);
+ if (in->command == SET_RAW_ENCAP) {
+ total_size = &raw_encap_confs[idx].size;
+ data = (uint8_t *)&raw_encap_confs[idx].data;
+ } else {
+ total_size = &raw_decap_confs[idx].size;
+ data = (uint8_t *)&raw_decap_confs[idx].data;
+ }
+ *total_size = 0;
+ memset(data, 0x00, ACTION_RAW_ENCAP_MAX_DATA);
+ /* process hdr from upper layer to low layer (L3/L4 -> L2). */
+ data_tail = data + ACTION_RAW_ENCAP_MAX_DATA;
+ for (i = n - 1 ; i >= 0; --i) {
+ item = in->args.vc.pattern + i;
+ if (item->spec == NULL)
+ item->spec = flow_item_default_mask(item);
+ switch (item->type) {
+ case RTE_FLOW_ITEM_TYPE_ETH:
+ size = sizeof(struct rte_flow_item_eth);
+ break;
+ case RTE_FLOW_ITEM_TYPE_VLAN:
+ size = sizeof(struct rte_flow_item_vlan);
+ proto = RTE_ETHER_TYPE_VLAN;
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV4:
+ size = sizeof(struct rte_flow_item_ipv4);
+ proto = RTE_ETHER_TYPE_IPV4;
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV6:
+ size = sizeof(struct rte_flow_item_ipv6);
+ proto = RTE_ETHER_TYPE_IPV6;
+ break;
+ case RTE_FLOW_ITEM_TYPE_UDP:
+ size = sizeof(struct rte_flow_item_udp);
+ proto = 0x11;
+ break;
+ case RTE_FLOW_ITEM_TYPE_TCP:
+ size = sizeof(struct rte_flow_item_tcp);
+ proto = 0x06;
+ break;
+ case RTE_FLOW_ITEM_TYPE_VXLAN:
+ size = sizeof(struct rte_flow_item_vxlan);
+ break;
+ case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+ size = sizeof(struct rte_flow_item_vxlan_gpe);
+ break;
+ case RTE_FLOW_ITEM_TYPE_GRE:
+ size = sizeof(struct rte_flow_item_gre);
+ proto = 0x2F;
+ break;
+ case RTE_FLOW_ITEM_TYPE_GRE_KEY:
+ size = sizeof(rte_be32_t);
+ proto = 0x0;
+ break;
+ case RTE_FLOW_ITEM_TYPE_MPLS:
+ size = sizeof(struct rte_flow_item_mpls);
+ proto = 0x0;
+ break;
+ case RTE_FLOW_ITEM_TYPE_NVGRE:
+ size = sizeof(struct rte_flow_item_nvgre);
+ proto = 0x2F;
+ break;
+ case RTE_FLOW_ITEM_TYPE_GENEVE:
+ size = sizeof(struct rte_flow_item_geneve);
+ break;
+ case RTE_FLOW_ITEM_TYPE_L2TPV3OIP:
+ size = sizeof(struct rte_flow_item_l2tpv3oip);
+ proto = 0x73;
+ break;
+ case RTE_FLOW_ITEM_TYPE_ESP:
+ size = sizeof(struct rte_flow_item_esp);
+ proto = 0x32;
+ break;
+ case RTE_FLOW_ITEM_TYPE_AH:
+ size = sizeof(struct rte_flow_item_ah);
+ proto = 0x33;
+ break;
+ case RTE_FLOW_ITEM_TYPE_GTP:
+ size = sizeof(struct rte_flow_item_gtp);
+ break;
+ case RTE_FLOW_ITEM_TYPE_PFCP:
+ size = sizeof(struct rte_flow_item_pfcp);
+ break;
+ default:
+ printf("Error - Not supported item\n");
+ *total_size = 0;
+ memset(data, 0x00, ACTION_RAW_ENCAP_MAX_DATA);
+ return;
+ }
+ *total_size += size;
+ rte_memcpy(data_tail - (*total_size), item->spec, size);
+ /* update some fields which cannot be set by cmdline */
+ update_fields((data_tail - (*total_size)), item,
+ upper_layer);
+ upper_layer = proto;
+ }
+ if (verbose_level & 0x1)
+ printf("total data size is %zu\n", (*total_size));
+ RTE_ASSERT((*total_size) <= ACTION_RAW_ENCAP_MAX_DATA);
+ memmove(data, (data_tail - (*total_size)), *total_size);
+}
+
+/** Populate help strings for current token (cmdline API). */
+static int
+cmd_set_raw_get_help(cmdline_parse_token_hdr_t *hdr, char *dst,
+ unsigned int size)
+{
+ struct context *ctx = &cmd_flow_context;
+ const struct token *token = &token_list[ctx->prev];
+
+ (void)hdr;
+ if (!size)
+ return -1;
+ /* Set token type and update global help with details. */
+ snprintf(dst, size, "%s", (token->type ? token->type : "TOKEN"));
+ if (token->help)
+ cmd_set_raw.help_str = token->help;
+ else
+ cmd_set_raw.help_str = token->name;
+ return 0;
+}
+
+/** Token definition template (cmdline API). */
+static struct cmdline_token_hdr cmd_set_raw_token_hdr = {
+ .ops = &(struct cmdline_token_ops){
+ .parse = cmd_flow_parse,
+ .complete_get_nb = cmd_flow_complete_get_nb,
+ .complete_get_elt = cmd_flow_complete_get_elt,
+ .get_help = cmd_set_raw_get_help,
+ },
+ .offset = 0,
+};
+
+/** Populate the next dynamic token. */
+static void
+cmd_set_raw_tok(cmdline_parse_token_hdr_t **hdr,
+ cmdline_parse_token_hdr_t **hdr_inst)
+{
+ struct context *ctx = &cmd_flow_context;
+
+ /* Always reinitialize context before requesting the first token. */
+ if (!(hdr_inst - cmd_set_raw.tokens)) {
+ cmd_flow_context_init(ctx);
+ ctx->curr = START_SET;
+ }
+ /* Return NULL when no more tokens are expected. */
+ if (!ctx->next_num && (ctx->curr != START_SET)) {
+ *hdr = NULL;
+ return;
+ }
+ /* Determine if command should end here. */
+ if (ctx->eol && ctx->last && ctx->next_num) {
+ const enum index *list = ctx->next[ctx->next_num - 1];
+ int i;
+
+ for (i = 0; list[i]; ++i) {
+ if (list[i] != END)
+ continue;
+ *hdr = NULL;
+ return;
+ }
+ }
+ *hdr = &cmd_set_raw_token_hdr;
+}
+
+/** Token generator and output processing callback (cmdline API). */
+static void
+cmd_set_raw_cb(void *arg0, struct cmdline *cl, void *arg2)
+{
+ if (cl == NULL)
+ cmd_set_raw_tok(arg0, arg2);
+ else
+ cmd_set_raw_parsed(arg0);
+}
+
+/** Global parser instance (cmdline API). */
+cmdline_parse_inst_t cmd_set_raw = {
+ .f = cmd_set_raw_cb,
+ .data = NULL, /**< Unused. */
+ .help_str = NULL, /**< Updated by cmd_flow_get_help(). */
+ .tokens = {
+ NULL,
+ }, /**< Tokens are returned by cmd_flow_tok(). */
+};
+
+/* *** display raw_encap/raw_decap buf */
+struct cmd_show_set_raw_result {
+ cmdline_fixed_string_t cmd_show;
+ cmdline_fixed_string_t cmd_what;
+ cmdline_fixed_string_t cmd_all;
+ uint16_t cmd_index;
+};
+
+static void
+cmd_show_set_raw_parsed(void *parsed_result, struct cmdline *cl, void *data)
+{
+ struct cmd_show_set_raw_result *res = parsed_result;
+ uint16_t index = res->cmd_index;
+ uint8_t all = 0;
+ uint8_t *raw_data = NULL;
+ size_t raw_size = 0;
+ char title[16] = {0};
+
+ RTE_SET_USED(cl);
+ RTE_SET_USED(data);
+ if (!strcmp(res->cmd_all, "all")) {
+ all = 1;
+ index = 0;
+ } else if (index >= RAW_ENCAP_CONFS_MAX_NUM) {
+ printf("index should be 0-%u\n", RAW_ENCAP_CONFS_MAX_NUM - 1);
+ return;
+ }
+ do {
+ if (!strcmp(res->cmd_what, "raw_encap")) {
+ raw_data = (uint8_t *)&raw_encap_confs[index].data;
+ raw_size = raw_encap_confs[index].size;
+ snprintf(title, 16, "\nindex: %u", index);
+ rte_hexdump(stdout, title, raw_data, raw_size);
+ } else {
+ raw_data = (uint8_t *)&raw_decap_confs[index].data;
+ raw_size = raw_decap_confs[index].size;
+ snprintf(title, 16, "\nindex: %u", index);
+ rte_hexdump(stdout, title, raw_data, raw_size);
+ }
+ } while (all && ++index < RAW_ENCAP_CONFS_MAX_NUM);
+}
+
+cmdline_parse_token_string_t cmd_show_set_raw_cmd_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_set_raw_result,
+ cmd_show, "show");
+cmdline_parse_token_string_t cmd_show_set_raw_cmd_what =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_set_raw_result,
+ cmd_what, "raw_encap#raw_decap");
+cmdline_parse_token_num_t cmd_show_set_raw_cmd_index =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_set_raw_result,
+ cmd_index, UINT16);
+cmdline_parse_token_string_t cmd_show_set_raw_cmd_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_set_raw_result,
+ cmd_all, "all");
+cmdline_parse_inst_t cmd_show_set_raw = {
+ .f = cmd_show_set_raw_parsed,
+ .data = NULL,
+ .help_str = "show <raw_encap|raw_decap> <index>",
+ .tokens = {
+ (void *)&cmd_show_set_raw_cmd_show,
+ (void *)&cmd_show_set_raw_cmd_what,
+ (void *)&cmd_show_set_raw_cmd_index,
+ NULL,
+ },
+};
+cmdline_parse_inst_t cmd_show_set_raw_all = {
+ .f = cmd_show_set_raw_parsed,
+ .data = NULL,
+ .help_str = "show <raw_encap|raw_decap> all",
+ .tokens = {
+ (void *)&cmd_show_set_raw_cmd_show,
+ (void *)&cmd_show_set_raw_cmd_what,
+ (void *)&cmd_show_set_raw_cmd_all,
+ NULL,
+ },
+};
diff --git a/src/spdk/dpdk/app/test-pmd/cmdline_mtr.c b/src/spdk/dpdk/app/test-pmd/cmdline_mtr.c
new file mode 100644
index 000000000..caa7e9864
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/cmdline_mtr.c
@@ -0,0 +1,1467 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation
+ */
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_mtr.h>
+
+#include "testpmd.h"
+#include "cmdline_mtr.h"
+
+#define PARSE_DELIMITER " \f\n\r\t\v"
+#define MAX_DSCP_TABLE_ENTRIES 64
+
+/** Display Meter Error Message */
+static void
+print_err_msg(struct rte_mtr_error *error)
+{
+ static const char *const errstrlist[] = {
+ [RTE_MTR_ERROR_TYPE_NONE] = "no error",
+ [RTE_MTR_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+ [RTE_MTR_ERROR_TYPE_METER_PROFILE_ID] = "meter profile id",
+ [RTE_MTR_ERROR_TYPE_METER_PROFILE] = "meter profile null",
+ [RTE_MTR_ERROR_TYPE_MTR_ID] = "meter id",
+ [RTE_MTR_ERROR_TYPE_MTR_PARAMS] = "meter params null",
+ [RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN]
+ = "policer action(green)",
+ [RTE_MTR_ERROR_TYPE_POLICER_ACTION_YELLOW]
+ = "policer action(yellow)",
+ [RTE_MTR_ERROR_TYPE_POLICER_ACTION_RED]
+ = "policer action(red)",
+ [RTE_MTR_ERROR_TYPE_STATS_MASK] = "stats mask",
+ [RTE_MTR_ERROR_TYPE_STATS] = "stats",
+ [RTE_MTR_ERROR_TYPE_SHARED]
+ = "shared meter",
+ };
+
+ const char *errstr;
+ char buf[64];
+
+ if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+ !errstrlist[error->type])
+ errstr = "unknown type";
+ else
+ errstr = errstrlist[error->type];
+
+ if (error->cause)
+ snprintf(buf, sizeof(buf), "cause: %p, ", error->cause);
+
+ printf("%s: %s%s (error %d)\n", errstr, error->cause ? buf : "",
+ error->message ? error->message : "(no stated reason)",
+ error->type);
+}
+
+static int
+parse_uint(uint64_t *value, const char *str)
+{
+ char *next = NULL;
+ uint64_t n;
+
+ errno = 0;
+ /* Parse number string */
+ n = strtol(str, &next, 10);
+ if (errno != 0 || str == next || *next != '\0')
+ return -1;
+
+ *value = n;
+
+ return 0;
+}
+
+static int
+parse_dscp_table_entries(char *str, enum rte_color **dscp_table)
+{
+ char *token;
+ int i = 0;
+
+ token = strtok_r(str, PARSE_DELIMITER, &str);
+ if (token == NULL)
+ return 0;
+
+ /* Allocate memory for dscp table */
+ *dscp_table = (enum rte_color *)malloc(MAX_DSCP_TABLE_ENTRIES *
+ sizeof(enum rte_color));
+ if (*dscp_table == NULL)
+ return -1;
+
+ while (1) {
+ if (strcmp(token, "G") == 0 ||
+ strcmp(token, "g") == 0)
+ *dscp_table[i++] = RTE_COLOR_GREEN;
+ else if (strcmp(token, "Y") == 0 ||
+ strcmp(token, "y") == 0)
+ *dscp_table[i++] = RTE_COLOR_YELLOW;
+ else if (strcmp(token, "R") == 0 ||
+ strcmp(token, "r") == 0)
+ *dscp_table[i++] = RTE_COLOR_RED;
+ else {
+ free(*dscp_table);
+ return -1;
+ }
+ if (i == MAX_DSCP_TABLE_ENTRIES)
+ break;
+
+ token = strtok_r(str, PARSE_DELIMITER, &str);
+ if (token == NULL) {
+ free(*dscp_table);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+parse_meter_color_str(char *c_str, uint32_t *use_prev_meter_color,
+ enum rte_color **dscp_table)
+{
+ char *token;
+ uint64_t previous_mtr_color = 0;
+ int ret;
+
+ /* First token: use previous meter color */
+ token = strtok_r(c_str, PARSE_DELIMITER, &c_str);
+ if (token == NULL)
+ return -1;
+
+ ret = parse_uint(&previous_mtr_color, token);
+ if (ret != 0)
+ return -1;
+
+ /* Check if previous meter color to be used */
+ if (previous_mtr_color) {
+ *use_prev_meter_color = previous_mtr_color;
+ return 0;
+ }
+
+ /* Parse dscp table entries */
+ ret = parse_dscp_table_entries(c_str, dscp_table);
+ if (ret != 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+string_to_policer_action(char *s)
+{
+ if ((strcmp(s, "G") == 0) || (strcmp(s, "g") == 0))
+ return MTR_POLICER_ACTION_COLOR_GREEN;
+
+ if ((strcmp(s, "Y") == 0) || (strcmp(s, "y") == 0))
+ return MTR_POLICER_ACTION_COLOR_YELLOW;
+
+ if ((strcmp(s, "R") == 0) || (strcmp(s, "r") == 0))
+ return MTR_POLICER_ACTION_COLOR_RED;
+
+ if ((strcmp(s, "D") == 0) || (strcmp(s, "d") == 0))
+ return MTR_POLICER_ACTION_DROP;
+
+ return -1;
+}
+
+static int
+parse_policer_action_string(char *p_str, uint32_t action_mask,
+ enum rte_mtr_policer_action actions[])
+{
+ char *token;
+ int count = __builtin_popcount(action_mask);
+ int g_color = 0, y_color = 0, action, i;
+
+ for (i = 0; i < count; i++) {
+ token = strtok_r(p_str, PARSE_DELIMITER, &p_str);
+ if (token == NULL)
+ return -1;
+
+ action = string_to_policer_action(token);
+ if (action == -1)
+ return -1;
+
+ if (g_color == 0 && (action_mask & 0x1)) {
+ actions[RTE_COLOR_GREEN] = action;
+ g_color = 1;
+ } else if (y_color == 0 && (action_mask & 0x2)) {
+ actions[RTE_COLOR_YELLOW] = action;
+ y_color = 1;
+ } else
+ actions[RTE_COLOR_RED] = action;
+ }
+ return 0;
+}
+
+static int
+parse_multi_token_string(char *t_str, uint16_t *port_id,
+ uint32_t *mtr_id, enum rte_color **dscp_table)
+{
+ char *token;
+ uint64_t val;
+ int ret;
+
+ /* First token: port id */
+ token = strtok_r(t_str, PARSE_DELIMITER, &t_str);
+ if (token == NULL)
+ return -1;
+
+ ret = parse_uint(&val, token);
+ if (ret != 0 || val > UINT16_MAX)
+ return -1;
+
+ *port_id = val;
+
+ /* Second token: meter id */
+ token = strtok_r(t_str, PARSE_DELIMITER, &t_str);
+ if (token == NULL)
+ return 0;
+
+ ret = parse_uint(&val, token);
+ if (ret != 0 || val > UINT32_MAX)
+ return -1;
+
+ *mtr_id = val;
+
+ ret = parse_dscp_table_entries(t_str, dscp_table);
+ if (ret != 0)
+ return -1;
+
+ return 0;
+}
+
+/* *** Show Port Meter Capabilities *** */
+struct cmd_show_port_meter_cap_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t meter;
+ cmdline_fixed_string_t cap;
+ uint16_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_meter_cap_show =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_meter_cap_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_meter_cap_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_meter_cap_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_meter_cap_meter =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_meter_cap_result, meter, "meter");
+cmdline_parse_token_string_t cmd_show_port_meter_cap_cap =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_meter_cap_result, cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_meter_cap_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_show_port_meter_cap_result, port_id, UINT16);
+
+static void cmd_show_port_meter_cap_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_port_meter_cap_result *res = parsed_result;
+ struct rte_mtr_capabilities cap;
+ struct rte_mtr_error error;
+ uint16_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&cap, 0, sizeof(struct rte_mtr_capabilities));
+ ret = rte_mtr_capabilities_get(port_id, &cap, &error);
+ if (ret) {
+ print_err_msg(&error);
+ return;
+ }
+
+ printf("\n**** Port Meter Object Capabilities ****\n\n");
+ printf("cap.n_max %" PRIu32 "\n", cap.n_max);
+ printf("cap.n_shared_max %" PRIu32 "\n", cap.n_shared_max);
+ printf("cap.identical %" PRId32 "\n", cap.identical);
+ printf("cap.shared_identical %" PRId32 "\n",
+ cap.shared_identical);
+ printf("cap.shared_n_flows_per_mtr_max %" PRIu32 "\n",
+ cap.shared_n_flows_per_mtr_max);
+ printf("cap.chaining_n_mtrs_per_flow_max %" PRIu32 "\n",
+ cap.chaining_n_mtrs_per_flow_max);
+ printf("cap.chaining_use_prev_mtr_color_supported %" PRId32 "\n",
+ cap.chaining_use_prev_mtr_color_supported);
+ printf("cap.chaining_use_prev_mtr_color_enforced %" PRId32 "\n",
+ cap.chaining_use_prev_mtr_color_enforced);
+ printf("cap.meter_srtcm_rfc2697_n_max %" PRIu32 "\n",
+ cap.meter_srtcm_rfc2697_n_max);
+ printf("cap.meter_trtcm_rfc2698_n_max %" PRIu32 "\n",
+ cap.meter_trtcm_rfc2698_n_max);
+ printf("cap.meter_trtcm_rfc4115_n_max %" PRIu32 "\n",
+ cap.meter_trtcm_rfc4115_n_max);
+ printf("cap.meter_rate_max %" PRIu64 "\n", cap.meter_rate_max);
+ printf("cap.color_aware_srtcm_rfc2697_supported %" PRId32 "\n",
+ cap.color_aware_srtcm_rfc2697_supported);
+ printf("cap.color_aware_trtcm_rfc2698_supported %" PRId32 "\n",
+ cap.color_aware_trtcm_rfc2698_supported);
+ printf("cap.color_aware_trtcm_rfc4115_supported %" PRId32 "\n",
+ cap.color_aware_trtcm_rfc4115_supported);
+ printf("cap.policer_action_recolor_supported %" PRId32 "\n",
+ cap.policer_action_recolor_supported);
+ printf("cap.policer_action_drop_supported %" PRId32 "\n",
+ cap.policer_action_drop_supported);
+ printf("cap.stats_mask %" PRIx64 "\n", cap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_meter_cap = {
+ .f = cmd_show_port_meter_cap_parsed,
+ .data = NULL,
+ .help_str = "Show port meter cap",
+ .tokens = {
+ (void *)&cmd_show_port_meter_cap_show,
+ (void *)&cmd_show_port_meter_cap_port,
+ (void *)&cmd_show_port_meter_cap_meter,
+ (void *)&cmd_show_port_meter_cap_cap,
+ (void *)&cmd_show_port_meter_cap_port_id,
+ NULL,
+ },
+};
+
+/* *** Add Port Meter Profile srtcm_rfc2697 *** */
+struct cmd_add_port_meter_profile_srtcm_result {
+ cmdline_fixed_string_t add;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t meter;
+ cmdline_fixed_string_t profile;
+ cmdline_fixed_string_t srtcm_rfc2697;
+ uint16_t port_id;
+ uint32_t profile_id;
+ uint64_t cir;
+ uint64_t cbs;
+ uint64_t ebs;
+};
+
+cmdline_parse_token_string_t cmd_add_port_meter_profile_srtcm_add =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_srtcm_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_meter_profile_srtcm_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_srtcm_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_add_port_meter_profile_srtcm_meter =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_srtcm_result,
+ meter, "meter");
+cmdline_parse_token_string_t cmd_add_port_meter_profile_srtcm_profile =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_srtcm_result,
+ profile, "profile");
+cmdline_parse_token_string_t cmd_add_port_meter_profile_srtcm_srtcm_rfc2697 =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_srtcm_result,
+ srtcm_rfc2697, "srtcm_rfc2697");
+cmdline_parse_token_num_t cmd_add_port_meter_profile_srtcm_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_srtcm_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_meter_profile_srtcm_profile_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_srtcm_result,
+ profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_meter_profile_srtcm_cir =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_srtcm_result,
+ cir, UINT64);
+cmdline_parse_token_num_t cmd_add_port_meter_profile_srtcm_cbs =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_srtcm_result,
+ cbs, UINT64);
+cmdline_parse_token_num_t cmd_add_port_meter_profile_srtcm_ebs =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_srtcm_result,
+ ebs, UINT64);
+
+static void cmd_add_port_meter_profile_srtcm_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_add_port_meter_profile_srtcm_result *res = parsed_result;
+ struct rte_mtr_meter_profile mp;
+ struct rte_mtr_error error;
+ uint32_t profile_id = res->profile_id;
+ uint16_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ /* Private shaper profile params */
+ memset(&mp, 0, sizeof(struct rte_mtr_meter_profile));
+ mp.alg = RTE_MTR_SRTCM_RFC2697;
+ mp.srtcm_rfc2697.cir = res->cir;
+ mp.srtcm_rfc2697.cbs = res->cbs;
+ mp.srtcm_rfc2697.ebs = res->ebs;
+
+ ret = rte_mtr_meter_profile_add(port_id, profile_id, &mp, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_add_port_meter_profile_srtcm = {
+ .f = cmd_add_port_meter_profile_srtcm_parsed,
+ .data = NULL,
+ .help_str = "Add port meter profile srtcm (rfc2697)",
+ .tokens = {
+ (void *)&cmd_add_port_meter_profile_srtcm_add,
+ (void *)&cmd_add_port_meter_profile_srtcm_port,
+ (void *)&cmd_add_port_meter_profile_srtcm_meter,
+ (void *)&cmd_add_port_meter_profile_srtcm_profile,
+ (void *)&cmd_add_port_meter_profile_srtcm_srtcm_rfc2697,
+ (void *)&cmd_add_port_meter_profile_srtcm_port_id,
+ (void *)&cmd_add_port_meter_profile_srtcm_profile_id,
+ (void *)&cmd_add_port_meter_profile_srtcm_cir,
+ (void *)&cmd_add_port_meter_profile_srtcm_cbs,
+ (void *)&cmd_add_port_meter_profile_srtcm_ebs,
+ NULL,
+ },
+};
+
+/* *** Add Port Meter Profile trtcm_rfc2698 *** */
+struct cmd_add_port_meter_profile_trtcm_result {
+ cmdline_fixed_string_t add;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t meter;
+ cmdline_fixed_string_t profile;
+ cmdline_fixed_string_t trtcm_rfc2698;
+ uint16_t port_id;
+ uint32_t profile_id;
+ uint64_t cir;
+ uint64_t pir;
+ uint64_t cbs;
+ uint64_t pbs;
+};
+
+cmdline_parse_token_string_t cmd_add_port_meter_profile_trtcm_add =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_meter_profile_trtcm_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_add_port_meter_profile_trtcm_meter =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_result,
+ meter, "meter");
+cmdline_parse_token_string_t cmd_add_port_meter_profile_trtcm_profile =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_result,
+ profile, "profile");
+cmdline_parse_token_string_t cmd_add_port_meter_profile_trtcm_trtcm_rfc2698 =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_result,
+ trtcm_rfc2698, "trtcm_rfc2698");
+cmdline_parse_token_num_t cmd_add_port_meter_profile_trtcm_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_meter_profile_trtcm_profile_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_result,
+ profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_meter_profile_trtcm_cir =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_result,
+ cir, UINT64);
+cmdline_parse_token_num_t cmd_add_port_meter_profile_trtcm_pir =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_result,
+ pir, UINT64);
+cmdline_parse_token_num_t cmd_add_port_meter_profile_trtcm_cbs =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_result,
+ cbs, UINT64);
+cmdline_parse_token_num_t cmd_add_port_meter_profile_trtcm_pbs =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_result,
+ pbs, UINT64);
+
+static void cmd_add_port_meter_profile_trtcm_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_add_port_meter_profile_trtcm_result *res = parsed_result;
+ struct rte_mtr_meter_profile mp;
+ struct rte_mtr_error error;
+ uint32_t profile_id = res->profile_id;
+ uint16_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ /* Private shaper profile params */
+ memset(&mp, 0, sizeof(struct rte_mtr_meter_profile));
+ mp.alg = RTE_MTR_TRTCM_RFC2698;
+ mp.trtcm_rfc2698.cir = res->cir;
+ mp.trtcm_rfc2698.pir = res->pir;
+ mp.trtcm_rfc2698.cbs = res->cbs;
+ mp.trtcm_rfc2698.pbs = res->pbs;
+
+ ret = rte_mtr_meter_profile_add(port_id, profile_id, &mp, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_add_port_meter_profile_trtcm = {
+ .f = cmd_add_port_meter_profile_trtcm_parsed,
+ .data = NULL,
+ .help_str = "Add port meter profile trtcm (rfc2698)",
+ .tokens = {
+ (void *)&cmd_add_port_meter_profile_trtcm_add,
+ (void *)&cmd_add_port_meter_profile_trtcm_port,
+ (void *)&cmd_add_port_meter_profile_trtcm_meter,
+ (void *)&cmd_add_port_meter_profile_trtcm_profile,
+ (void *)&cmd_add_port_meter_profile_trtcm_trtcm_rfc2698,
+ (void *)&cmd_add_port_meter_profile_trtcm_port_id,
+ (void *)&cmd_add_port_meter_profile_trtcm_profile_id,
+ (void *)&cmd_add_port_meter_profile_trtcm_cir,
+ (void *)&cmd_add_port_meter_profile_trtcm_pir,
+ (void *)&cmd_add_port_meter_profile_trtcm_cbs,
+ (void *)&cmd_add_port_meter_profile_trtcm_pbs,
+ NULL,
+ },
+};
+
+/* *** Add Port Meter Profile trtcm_rfc4115 *** */
+struct cmd_add_port_meter_profile_trtcm_rfc4115_result {
+ cmdline_fixed_string_t add;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t meter;
+ cmdline_fixed_string_t profile;
+ cmdline_fixed_string_t trtcm_rfc4115;
+ uint16_t port_id;
+ uint32_t profile_id;
+ uint64_t cir;
+ uint64_t eir;
+ uint64_t cbs;
+ uint64_t ebs;
+};
+
+cmdline_parse_token_string_t cmd_add_port_meter_profile_trtcm_rfc4115_add =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_rfc4115_result, add,
+ "add");
+cmdline_parse_token_string_t cmd_add_port_meter_profile_trtcm_rfc4115_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_rfc4115_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_add_port_meter_profile_trtcm_rfc4115_meter =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_rfc4115_result,
+ meter, "meter");
+cmdline_parse_token_string_t cmd_add_port_meter_profile_trtcm_rfc4115_profile =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_rfc4115_result,
+ profile, "profile");
+cmdline_parse_token_string_t
+ cmd_add_port_meter_profile_trtcm_rfc4115_trtcm_rfc4115 =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_rfc4115_result,
+ trtcm_rfc4115, "trtcm_rfc4115");
+cmdline_parse_token_num_t cmd_add_port_meter_profile_trtcm_rfc4115_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_rfc4115_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_meter_profile_trtcm_rfc4115_profile_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_rfc4115_result,
+ profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_meter_profile_trtcm_rfc4115_cir =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_rfc4115_result,
+ cir, UINT64);
+cmdline_parse_token_num_t cmd_add_port_meter_profile_trtcm_rfc4115_eir =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_rfc4115_result,
+ eir, UINT64);
+cmdline_parse_token_num_t cmd_add_port_meter_profile_trtcm_rfc4115_cbs =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_rfc4115_result,
+ cbs, UINT64);
+cmdline_parse_token_num_t cmd_add_port_meter_profile_trtcm_rfc4115_ebs =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_meter_profile_trtcm_rfc4115_result,
+ ebs, UINT64);
+
+static void cmd_add_port_meter_profile_trtcm_rfc4115_parsed(
+ void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_add_port_meter_profile_trtcm_rfc4115_result *res =
+ parsed_result;
+ struct rte_mtr_meter_profile mp;
+ struct rte_mtr_error error;
+ uint32_t profile_id = res->profile_id;
+ uint16_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ /* Private shaper profile params */
+ memset(&mp, 0, sizeof(struct rte_mtr_meter_profile));
+ mp.alg = RTE_MTR_TRTCM_RFC4115;
+ mp.trtcm_rfc4115.cir = res->cir;
+ mp.trtcm_rfc4115.eir = res->eir;
+ mp.trtcm_rfc4115.cbs = res->cbs;
+ mp.trtcm_rfc4115.ebs = res->ebs;
+
+ ret = rte_mtr_meter_profile_add(port_id, profile_id, &mp, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_add_port_meter_profile_trtcm_rfc4115 = {
+ .f = cmd_add_port_meter_profile_trtcm_rfc4115_parsed,
+ .data = NULL,
+ .help_str = "Add port meter profile trtcm (rfc4115)",
+ .tokens = {
+ (void *)&cmd_add_port_meter_profile_trtcm_rfc4115_add,
+ (void *)&cmd_add_port_meter_profile_trtcm_rfc4115_port,
+ (void *)&cmd_add_port_meter_profile_trtcm_rfc4115_meter,
+ (void *)&cmd_add_port_meter_profile_trtcm_rfc4115_profile,
+ (void *)&cmd_add_port_meter_profile_trtcm_rfc4115_trtcm_rfc4115,
+ (void *)&cmd_add_port_meter_profile_trtcm_rfc4115_port_id,
+ (void *)&cmd_add_port_meter_profile_trtcm_rfc4115_profile_id,
+ (void *)&cmd_add_port_meter_profile_trtcm_rfc4115_cir,
+ (void *)&cmd_add_port_meter_profile_trtcm_rfc4115_eir,
+ (void *)&cmd_add_port_meter_profile_trtcm_rfc4115_cbs,
+ (void *)&cmd_add_port_meter_profile_trtcm_rfc4115_ebs,
+ NULL,
+ },
+};
+
+/* *** Delete Port Meter Profile *** */
+struct cmd_del_port_meter_profile_result {
+ cmdline_fixed_string_t del;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t meter;
+ cmdline_fixed_string_t profile;
+ uint16_t port_id;
+ uint32_t profile_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_meter_profile_del =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_meter_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_meter_profile_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_meter_profile_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_del_port_meter_profile_meter =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_meter_profile_result,
+ meter, "meter");
+cmdline_parse_token_string_t cmd_del_port_meter_profile_profile =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_meter_profile_result,
+ profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_meter_profile_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_del_port_meter_profile_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_meter_profile_profile_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_del_port_meter_profile_result,
+ profile_id, UINT32);
+
+static void cmd_del_port_meter_profile_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_del_port_meter_profile_result *res = parsed_result;
+ struct rte_mtr_error error;
+ uint32_t profile_id = res->profile_id;
+ uint16_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ /* Delete meter profile */
+ ret = rte_mtr_meter_profile_delete(port_id, profile_id, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_del_port_meter_profile = {
+ .f = cmd_del_port_meter_profile_parsed,
+ .data = NULL,
+ .help_str = "Delete port meter profile",
+ .tokens = {
+ (void *)&cmd_del_port_meter_profile_del,
+ (void *)&cmd_del_port_meter_profile_port,
+ (void *)&cmd_del_port_meter_profile_meter,
+ (void *)&cmd_del_port_meter_profile_profile,
+ (void *)&cmd_del_port_meter_profile_port_id,
+ (void *)&cmd_del_port_meter_profile_profile_id,
+ NULL,
+ },
+};
+
+/* *** Create Port Meter Object *** */
+struct cmd_create_port_meter_result {
+ cmdline_fixed_string_t create;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t meter;
+ uint16_t port_id;
+ uint32_t mtr_id;
+ uint32_t profile_id;
+ cmdline_fixed_string_t meter_enable;
+ cmdline_fixed_string_t g_action;
+ cmdline_fixed_string_t y_action;
+ cmdline_fixed_string_t r_action;
+ uint64_t statistics_mask;
+ uint32_t shared;
+ cmdline_multi_string_t meter_input_color;
+};
+
+cmdline_parse_token_string_t cmd_create_port_meter_create =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_create_port_meter_result, create, "create");
+cmdline_parse_token_string_t cmd_create_port_meter_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_create_port_meter_result, port, "port");
+cmdline_parse_token_string_t cmd_create_port_meter_meter =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_create_port_meter_result, meter, "meter");
+cmdline_parse_token_num_t cmd_create_port_meter_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_create_port_meter_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_create_port_meter_mtr_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_create_port_meter_result, mtr_id, UINT32);
+cmdline_parse_token_num_t cmd_create_port_meter_profile_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_create_port_meter_result, profile_id, UINT32);
+cmdline_parse_token_string_t cmd_create_port_meter_meter_enable =
+ TOKEN_STRING_INITIALIZER(struct cmd_create_port_meter_result,
+ meter_enable, "yes#no");
+cmdline_parse_token_string_t cmd_create_port_meter_g_action =
+ TOKEN_STRING_INITIALIZER(struct cmd_create_port_meter_result,
+ g_action, "R#Y#G#D#r#y#g#d");
+cmdline_parse_token_string_t cmd_create_port_meter_y_action =
+ TOKEN_STRING_INITIALIZER(struct cmd_create_port_meter_result,
+ y_action, "R#Y#G#D#r#y#g#d");
+cmdline_parse_token_string_t cmd_create_port_meter_r_action =
+ TOKEN_STRING_INITIALIZER(struct cmd_create_port_meter_result,
+ r_action, "R#Y#G#D#r#y#g#d");
+cmdline_parse_token_num_t cmd_create_port_meter_statistics_mask =
+ TOKEN_NUM_INITIALIZER(struct cmd_create_port_meter_result,
+ statistics_mask, UINT64);
+cmdline_parse_token_num_t cmd_create_port_meter_shared =
+ TOKEN_NUM_INITIALIZER(struct cmd_create_port_meter_result,
+ shared, UINT32);
+cmdline_parse_token_string_t cmd_create_port_meter_input_color =
+ TOKEN_STRING_INITIALIZER(struct cmd_create_port_meter_result,
+ meter_input_color, TOKEN_STRING_MULTI);
+
+static void cmd_create_port_meter_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_create_port_meter_result *res = parsed_result;
+ struct rte_mtr_error error;
+ struct rte_mtr_params params;
+ uint32_t mtr_id = res->mtr_id;
+ uint32_t shared = res->shared;
+ uint32_t use_prev_meter_color = 0;
+ uint16_t port_id = res->port_id;
+ enum rte_color *dscp_table = NULL;
+ char *c_str = res->meter_input_color;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ /* Meter params */
+ memset(&params, 0, sizeof(struct rte_mtr_params));
+ params.meter_profile_id = res->profile_id;
+
+ /* Parse meter input color string params */
+ ret = parse_meter_color_str(c_str, &use_prev_meter_color, &dscp_table);
+ if (ret) {
+ printf(" Meter input color params string parse error\n");
+ return;
+ }
+
+ params.use_prev_mtr_color = use_prev_meter_color;
+ params.dscp_table = dscp_table;
+
+ if (strcmp(res->meter_enable, "yes") == 0)
+ params.meter_enable = 1;
+ else
+ params.meter_enable = 0;
+
+ params.action[RTE_COLOR_GREEN] =
+ string_to_policer_action(res->g_action);
+ params.action[RTE_COLOR_YELLOW] =
+ string_to_policer_action(res->y_action);
+ params.action[RTE_COLOR_RED] =
+ string_to_policer_action(res->r_action);
+ params.stats_mask = res->statistics_mask;
+
+ ret = rte_mtr_create(port_id, mtr_id, &params, shared, &error);
+ if (ret != 0) {
+ free(dscp_table);
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_create_port_meter = {
+ .f = cmd_create_port_meter_parsed,
+ .data = NULL,
+ .help_str = "Create port meter",
+ .tokens = {
+ (void *)&cmd_create_port_meter_create,
+ (void *)&cmd_create_port_meter_port,
+ (void *)&cmd_create_port_meter_meter,
+ (void *)&cmd_create_port_meter_port_id,
+ (void *)&cmd_create_port_meter_mtr_id,
+ (void *)&cmd_create_port_meter_profile_id,
+ (void *)&cmd_create_port_meter_meter_enable,
+ (void *)&cmd_create_port_meter_g_action,
+ (void *)&cmd_create_port_meter_y_action,
+ (void *)&cmd_create_port_meter_r_action,
+ (void *)&cmd_create_port_meter_statistics_mask,
+ (void *)&cmd_create_port_meter_shared,
+ (void *)&cmd_create_port_meter_input_color,
+ NULL,
+ },
+};
+
+/* *** Enable Meter of MTR Object *** */
+struct cmd_enable_port_meter_result {
+ cmdline_fixed_string_t enable;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t meter;
+ uint16_t port_id;
+ uint32_t mtr_id;
+};
+
+cmdline_parse_token_string_t cmd_enable_port_meter_enable =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_enable_port_meter_result, enable, "enable");
+cmdline_parse_token_string_t cmd_enable_port_meter_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_enable_port_meter_result, port, "port");
+cmdline_parse_token_string_t cmd_enable_port_meter_meter =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_enable_port_meter_result, meter, "meter");
+cmdline_parse_token_num_t cmd_enable_port_meter_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_enable_port_meter_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_enable_port_meter_mtr_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_enable_port_meter_result, mtr_id, UINT32);
+
+static void cmd_enable_port_meter_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_enable_port_meter_result *res = parsed_result;
+ struct rte_mtr_error error;
+ uint32_t mtr_id = res->mtr_id;
+ uint16_t port_id = res->port_id;
+
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ /* Enable Meter */
+ ret = rte_mtr_meter_enable(port_id, mtr_id, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_enable_port_meter = {
+ .f = cmd_enable_port_meter_parsed,
+ .data = NULL,
+ .help_str = "Enable port meter",
+ .tokens = {
+ (void *)&cmd_enable_port_meter_enable,
+ (void *)&cmd_enable_port_meter_port,
+ (void *)&cmd_enable_port_meter_meter,
+ (void *)&cmd_enable_port_meter_port_id,
+ (void *)&cmd_enable_port_meter_mtr_id,
+ NULL,
+ },
+};
+
+/* *** Disable Meter of MTR Object *** */
+struct cmd_disable_port_meter_result {
+ cmdline_fixed_string_t disable;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t meter;
+ uint16_t port_id;
+ uint32_t mtr_id;
+};
+
+cmdline_parse_token_string_t cmd_disable_port_meter_disable =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_disable_port_meter_result, disable, "disable");
+cmdline_parse_token_string_t cmd_disable_port_meter_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_disable_port_meter_result, port, "port");
+cmdline_parse_token_string_t cmd_disable_port_meter_meter =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_disable_port_meter_result, meter, "meter");
+cmdline_parse_token_num_t cmd_disable_port_meter_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_disable_port_meter_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_disable_port_meter_mtr_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_disable_port_meter_result, mtr_id, UINT32);
+
+static void cmd_disable_port_meter_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_disable_port_meter_result *res = parsed_result;
+ struct rte_mtr_error error;
+ uint32_t mtr_id = res->mtr_id;
+ uint16_t port_id = res->port_id;
+
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ /* Disable Meter */
+ ret = rte_mtr_meter_disable(port_id, mtr_id, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_disable_port_meter = {
+ .f = cmd_disable_port_meter_parsed,
+ .data = NULL,
+ .help_str = "Disable port meter",
+ .tokens = {
+ (void *)&cmd_disable_port_meter_disable,
+ (void *)&cmd_disable_port_meter_port,
+ (void *)&cmd_disable_port_meter_meter,
+ (void *)&cmd_disable_port_meter_port_id,
+ (void *)&cmd_disable_port_meter_mtr_id,
+ NULL,
+ },
+};
+
+/* *** Delete Port Meter Object *** */
+struct cmd_del_port_meter_result {
+ cmdline_fixed_string_t del;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t meter;
+ uint16_t port_id;
+ uint32_t mtr_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_meter_del =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_meter_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_meter_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_meter_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_meter_meter =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_meter_result, meter, "meter");
+cmdline_parse_token_num_t cmd_del_port_meter_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_del_port_meter_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_meter_mtr_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_del_port_meter_result, mtr_id, UINT32);
+
+static void cmd_del_port_meter_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_del_port_meter_result *res = parsed_result;
+ struct rte_mtr_error error;
+ uint32_t mtr_id = res->mtr_id;
+ uint16_t port_id = res->port_id;
+
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ /* Destroy Meter */
+ ret = rte_mtr_destroy(port_id, mtr_id, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_del_port_meter = {
+ .f = cmd_del_port_meter_parsed,
+ .data = NULL,
+ .help_str = "Delete port meter",
+ .tokens = {
+ (void *)&cmd_del_port_meter_del,
+ (void *)&cmd_del_port_meter_port,
+ (void *)&cmd_del_port_meter_meter,
+ (void *)&cmd_del_port_meter_port_id,
+ (void *)&cmd_del_port_meter_mtr_id,
+ NULL,
+ },
+};
+
+/* *** Set Port Meter Profile *** */
+struct cmd_set_port_meter_profile_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t meter;
+ cmdline_fixed_string_t profile;
+ uint16_t port_id;
+ uint32_t mtr_id;
+ uint32_t profile_id;
+};
+
+cmdline_parse_token_string_t cmd_set_port_meter_profile_set =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_profile_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_meter_profile_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_meter_profile_meter =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_profile_result, meter, "meter");
+cmdline_parse_token_string_t cmd_set_port_meter_profile_profile =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_profile_result, profile, "profile");
+cmdline_parse_token_num_t cmd_set_port_meter_profile_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_set_port_meter_profile_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_port_meter_profile_mtr_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_set_port_meter_profile_result, mtr_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_meter_profile_profile_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_set_port_meter_profile_result, profile_id, UINT32);
+
+static void cmd_set_port_meter_profile_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_port_meter_profile_result *res = parsed_result;
+ struct rte_mtr_error error;
+ uint32_t mtr_id = res->mtr_id;
+ uint32_t profile_id = res->profile_id;
+ uint16_t port_id = res->port_id;
+
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ /* Set meter profile */
+ ret = rte_mtr_meter_profile_update(port_id, mtr_id,
+ profile_id, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_set_port_meter_profile = {
+ .f = cmd_set_port_meter_profile_parsed,
+ .data = NULL,
+ .help_str = "Set port meter profile",
+ .tokens = {
+ (void *)&cmd_set_port_meter_profile_set,
+ (void *)&cmd_set_port_meter_profile_port,
+ (void *)&cmd_set_port_meter_profile_meter,
+ (void *)&cmd_set_port_meter_profile_profile,
+ (void *)&cmd_set_port_meter_profile_port_id,
+ (void *)&cmd_set_port_meter_profile_mtr_id,
+ (void *)&cmd_set_port_meter_profile_profile_id,
+ NULL,
+ },
+};
+
+/* *** Set Port Meter DSCP Table *** */
+struct cmd_set_port_meter_dscp_table_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t meter;
+ cmdline_fixed_string_t dscp_table;
+ cmdline_multi_string_t token_string;
+};
+
+cmdline_parse_token_string_t cmd_set_port_meter_dscp_table_set =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_dscp_table_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_meter_dscp_table_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_dscp_table_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_meter_dscp_table_meter =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_dscp_table_result, meter, "meter");
+cmdline_parse_token_string_t cmd_set_port_meter_dscp_table_dscp_table =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_dscp_table_result,
+ dscp_table, "dscp table");
+cmdline_parse_token_string_t cmd_set_port_meter_dscp_table_token_string =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_port_meter_dscp_table_result,
+ token_string, TOKEN_STRING_MULTI);
+
+static void cmd_set_port_meter_dscp_table_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_port_meter_dscp_table_result *res = parsed_result;
+ struct rte_mtr_error error;
+ enum rte_color *dscp_table = NULL;
+ char *t_str = res->token_string;
+ uint32_t mtr_id = 0;
+ uint16_t port_id;
+ int ret;
+
+ /* Parse string */
+ ret = parse_multi_token_string(t_str, &port_id, &mtr_id, &dscp_table);
+ if (ret) {
+ printf(" Multi token string parse error\n");
+ return;
+ }
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ goto free_table;
+
+ /* Update Meter DSCP Table*/
+ ret = rte_mtr_meter_dscp_table_update(port_id, mtr_id,
+ dscp_table, &error);
+ if (ret != 0)
+ print_err_msg(&error);
+
+free_table:
+ free(dscp_table);
+}
+
+cmdline_parse_inst_t cmd_set_port_meter_dscp_table = {
+ .f = cmd_set_port_meter_dscp_table_parsed,
+ .data = NULL,
+ .help_str = "Update port meter dscp table",
+ .tokens = {
+ (void *)&cmd_set_port_meter_dscp_table_set,
+ (void *)&cmd_set_port_meter_dscp_table_port,
+ (void *)&cmd_set_port_meter_dscp_table_meter,
+ (void *)&cmd_set_port_meter_dscp_table_dscp_table,
+ (void *)&cmd_set_port_meter_dscp_table_token_string,
+ NULL,
+ },
+};
+
+/* *** Set Port Meter Policer Action *** */
+struct cmd_set_port_meter_policer_action_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t meter;
+ cmdline_fixed_string_t policer;
+ cmdline_fixed_string_t action;
+ uint16_t port_id;
+ uint32_t mtr_id;
+ uint32_t action_mask;
+ cmdline_multi_string_t policer_action;
+};
+
+cmdline_parse_token_string_t cmd_set_port_meter_policer_action_set =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_policer_action_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_meter_policer_action_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_policer_action_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_meter_policer_action_meter =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_policer_action_result, meter,
+ "meter");
+cmdline_parse_token_string_t cmd_set_port_meter_policer_action_policer =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_policer_action_result, policer,
+ "policer");
+cmdline_parse_token_string_t cmd_set_port_meter_policer_action_action =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_policer_action_result, action,
+ "action");
+cmdline_parse_token_num_t cmd_set_port_meter_policer_action_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_set_port_meter_policer_action_result, port_id,
+ UINT16);
+cmdline_parse_token_num_t cmd_set_port_meter_policer_action_mtr_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_set_port_meter_policer_action_result, mtr_id,
+ UINT32);
+cmdline_parse_token_num_t cmd_set_port_meter_policer_action_action_mask =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_set_port_meter_policer_action_result, action_mask,
+ UINT32);
+cmdline_parse_token_string_t cmd_set_port_meter_policer_action_policer_action =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_policer_action_result,
+ policer_action, TOKEN_STRING_MULTI);
+
+static void cmd_set_port_meter_policer_action_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_port_meter_policer_action_result *res = parsed_result;
+ enum rte_mtr_policer_action *actions;
+ struct rte_mtr_error error;
+ uint32_t mtr_id = res->mtr_id;
+ uint32_t action_mask = res->action_mask;
+ uint16_t port_id = res->port_id;
+ char *p_str = res->policer_action;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ /* Check: action mask */
+ if (action_mask == 0 || (action_mask & (~0x7UL))) {
+ printf(" Policer action mask not correct (error)\n");
+ return;
+ }
+
+ /* Allocate memory for policer actions */
+ actions = (enum rte_mtr_policer_action *)malloc(RTE_COLORS *
+ sizeof(enum rte_mtr_policer_action));
+ if (actions == NULL) {
+ printf("Memory for policer actions not allocated (error)\n");
+ return;
+ }
+ /* Parse policer action string */
+ ret = parse_policer_action_string(p_str, action_mask, actions);
+ if (ret) {
+ printf(" Policer action string parse error\n");
+ free(actions);
+ return;
+ }
+
+ ret = rte_mtr_policer_actions_update(port_id, mtr_id,
+ action_mask, actions, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+
+ free(actions);
+}
+
+cmdline_parse_inst_t cmd_set_port_meter_policer_action = {
+ .f = cmd_set_port_meter_policer_action_parsed,
+ .data = NULL,
+ .help_str = "Set port meter policer action",
+ .tokens = {
+ (void *)&cmd_set_port_meter_policer_action_set,
+ (void *)&cmd_set_port_meter_policer_action_port,
+ (void *)&cmd_set_port_meter_policer_action_meter,
+ (void *)&cmd_set_port_meter_policer_action_policer,
+ (void *)&cmd_set_port_meter_policer_action_action,
+ (void *)&cmd_set_port_meter_policer_action_port_id,
+ (void *)&cmd_set_port_meter_policer_action_mtr_id,
+ (void *)&cmd_set_port_meter_policer_action_action_mask,
+ (void *)&cmd_set_port_meter_policer_action_policer_action,
+ NULL,
+ },
+};
+
+/* *** Set Port Meter Stats Mask *** */
+struct cmd_set_port_meter_stats_mask_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t meter;
+ cmdline_fixed_string_t stats;
+ cmdline_fixed_string_t mask;
+ uint16_t port_id;
+ uint32_t mtr_id;
+ uint64_t stats_mask;
+};
+
+cmdline_parse_token_string_t cmd_set_port_meter_stats_mask_set =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_stats_mask_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_meter_stats_mask_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_stats_mask_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_meter_stats_mask_meter =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_stats_mask_result, meter, "meter");
+cmdline_parse_token_string_t cmd_set_port_meter_stats_mask_stats =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_stats_mask_result, stats, "stats");
+cmdline_parse_token_string_t cmd_set_port_meter_stats_mask_mask =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_meter_stats_mask_result, mask, "mask");
+cmdline_parse_token_num_t cmd_set_port_meter_stats_mask_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_set_port_meter_stats_mask_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_port_meter_stats_mask_mtr_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_set_port_meter_stats_mask_result, mtr_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_meter_stats_mask_stats_mask =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_set_port_meter_stats_mask_result, stats_mask,
+ UINT64);
+
+static void cmd_set_port_meter_stats_mask_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_port_meter_stats_mask_result *res = parsed_result;
+ struct rte_mtr_error error;
+ uint64_t stats_mask = res->stats_mask;
+ uint32_t mtr_id = res->mtr_id;
+ uint16_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ ret = rte_mtr_stats_update(port_id, mtr_id, stats_mask, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_set_port_meter_stats_mask = {
+ .f = cmd_set_port_meter_stats_mask_parsed,
+ .data = NULL,
+ .help_str = "Set port meter stats mask",
+ .tokens = {
+ (void *)&cmd_set_port_meter_stats_mask_set,
+ (void *)&cmd_set_port_meter_stats_mask_port,
+ (void *)&cmd_set_port_meter_stats_mask_meter,
+ (void *)&cmd_set_port_meter_stats_mask_stats,
+ (void *)&cmd_set_port_meter_stats_mask_mask,
+ (void *)&cmd_set_port_meter_stats_mask_port_id,
+ (void *)&cmd_set_port_meter_stats_mask_mtr_id,
+ (void *)&cmd_set_port_meter_stats_mask_stats_mask,
+ NULL,
+ },
+};
+
+/* *** Show Port Meter Stats *** */
+struct cmd_show_port_meter_stats_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t meter;
+ cmdline_fixed_string_t stats;
+ uint16_t port_id;
+ uint32_t mtr_id;
+ cmdline_fixed_string_t clear;
+};
+
+cmdline_parse_token_string_t cmd_show_port_meter_stats_show =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_meter_stats_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_meter_stats_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_meter_stats_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_meter_stats_meter =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_meter_stats_result, meter, "meter");
+cmdline_parse_token_string_t cmd_show_port_meter_stats_stats =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_meter_stats_result, stats, "stats");
+cmdline_parse_token_num_t cmd_show_port_meter_stats_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_show_port_meter_stats_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_meter_stats_mtr_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_show_port_meter_stats_result, mtr_id, UINT32);
+cmdline_parse_token_string_t cmd_show_port_meter_stats_clear =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_meter_stats_result, clear, "yes#no");
+
+static void cmd_show_port_meter_stats_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_port_meter_stats_result *res = parsed_result;
+ struct rte_mtr_stats stats;
+ uint64_t stats_mask = 0;
+ struct rte_mtr_error error;
+ uint32_t mtr_id = res->mtr_id;
+ uint32_t clear = 0;
+ uint16_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ if (strcmp(res->clear, "yes") == 0)
+ clear = 1;
+
+ memset(&stats, 0, sizeof(struct rte_mtr_stats));
+ ret = rte_mtr_stats_read(port_id, mtr_id, &stats,
+ &stats_mask, clear, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+
+ /* Display stats */
+ if (stats_mask & RTE_MTR_STATS_N_PKTS_GREEN)
+ printf("\tPkts G: %" PRIu64 "\n",
+ stats.n_pkts[RTE_COLOR_GREEN]);
+ if (stats_mask & RTE_MTR_STATS_N_BYTES_GREEN)
+ printf("\tBytes G: %" PRIu64 "\n",
+ stats.n_bytes[RTE_COLOR_GREEN]);
+ if (stats_mask & RTE_MTR_STATS_N_PKTS_YELLOW)
+ printf("\tPkts Y: %" PRIu64 "\n",
+ stats.n_pkts[RTE_COLOR_YELLOW]);
+ if (stats_mask & RTE_MTR_STATS_N_BYTES_YELLOW)
+ printf("\tBytes Y: %" PRIu64 "\n",
+ stats.n_bytes[RTE_COLOR_YELLOW]);
+ if (stats_mask & RTE_MTR_STATS_N_PKTS_RED)
+ printf("\tPkts R: %" PRIu64 "\n",
+ stats.n_pkts[RTE_COLOR_RED]);
+ if (stats_mask & RTE_MTR_STATS_N_BYTES_RED)
+ printf("\tBytes R: %" PRIu64 "\n",
+ stats.n_bytes[RTE_COLOR_RED]);
+ if (stats_mask & RTE_MTR_STATS_N_PKTS_DROPPED)
+ printf("\tPkts DROPPED: %" PRIu64 "\n",
+ stats.n_pkts_dropped);
+ if (stats_mask & RTE_MTR_STATS_N_BYTES_DROPPED)
+ printf("\tBytes DROPPED: %" PRIu64 "\n",
+ stats.n_bytes_dropped);
+}
+
+cmdline_parse_inst_t cmd_show_port_meter_stats = {
+ .f = cmd_show_port_meter_stats_parsed,
+ .data = NULL,
+ .help_str = "Show port meter stats",
+ .tokens = {
+ (void *)&cmd_show_port_meter_stats_show,
+ (void *)&cmd_show_port_meter_stats_port,
+ (void *)&cmd_show_port_meter_stats_meter,
+ (void *)&cmd_show_port_meter_stats_stats,
+ (void *)&cmd_show_port_meter_stats_port_id,
+ (void *)&cmd_show_port_meter_stats_mtr_id,
+ (void *)&cmd_show_port_meter_stats_clear,
+ NULL,
+ },
+};
diff --git a/src/spdk/dpdk/app/test-pmd/cmdline_mtr.h b/src/spdk/dpdk/app/test-pmd/cmdline_mtr.h
new file mode 100644
index 000000000..e69d6da02
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/cmdline_mtr.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation
+ */
+
+#ifndef _CMDLINE_MTR_H_
+#define _CMDLINE_MTR_H_
+
+/* Traffic Metering and Policing */
+extern cmdline_parse_inst_t cmd_show_port_meter_cap;
+extern cmdline_parse_inst_t cmd_add_port_meter_profile_srtcm;
+extern cmdline_parse_inst_t cmd_add_port_meter_profile_trtcm;
+extern cmdline_parse_inst_t cmd_add_port_meter_profile_trtcm_rfc4115;
+extern cmdline_parse_inst_t cmd_del_port_meter_profile;
+extern cmdline_parse_inst_t cmd_create_port_meter;
+extern cmdline_parse_inst_t cmd_enable_port_meter;
+extern cmdline_parse_inst_t cmd_disable_port_meter;
+extern cmdline_parse_inst_t cmd_del_port_meter;
+extern cmdline_parse_inst_t cmd_set_port_meter_profile;
+extern cmdline_parse_inst_t cmd_set_port_meter_dscp_table;
+extern cmdline_parse_inst_t cmd_set_port_meter_policer_action;
+extern cmdline_parse_inst_t cmd_set_port_meter_stats_mask;
+extern cmdline_parse_inst_t cmd_show_port_meter_stats;
+
+#endif /* _CMDLINE_MTR_H_ */
diff --git a/src/spdk/dpdk/app/test-pmd/cmdline_tm.c b/src/spdk/dpdk/app/test-pmd/cmdline_tm.c
new file mode 100644
index 000000000..6951beb58
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/cmdline_tm.c
@@ -0,0 +1,2463 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation
+ */
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+#include "cmdline_tm.h"
+
+#define PARSE_DELIMITER " \f\n\r\t\v"
+#define MAX_NUM_SHARED_SHAPERS 256
+
+#define skip_white_spaces(pos) \
+({ \
+ __typeof__(pos) _p = (pos); \
+ for ( ; isspace(*_p); _p++) \
+ ; \
+ _p; \
+})
+
+/** Display TM Error Message */
+static void
+print_err_msg(struct rte_tm_error *error)
+{
+ static const char *const errstrlist[] = {
+ [RTE_TM_ERROR_TYPE_NONE] = "no error",
+ [RTE_TM_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+ [RTE_TM_ERROR_TYPE_CAPABILITIES]
+ = "capability parameter null",
+ [RTE_TM_ERROR_TYPE_LEVEL_ID] = "level id",
+ [RTE_TM_ERROR_TYPE_WRED_PROFILE]
+ = "wred profile null",
+ [RTE_TM_ERROR_TYPE_WRED_PROFILE_GREEN] = "wred profile(green)",
+ [RTE_TM_ERROR_TYPE_WRED_PROFILE_YELLOW]
+ = "wred profile(yellow)",
+ [RTE_TM_ERROR_TYPE_WRED_PROFILE_RED] = "wred profile(red)",
+ [RTE_TM_ERROR_TYPE_WRED_PROFILE_ID] = "wred profile id",
+ [RTE_TM_ERROR_TYPE_SHARED_WRED_CONTEXT_ID]
+ = "shared wred context id",
+ [RTE_TM_ERROR_TYPE_SHAPER_PROFILE] = "shaper profile null",
+ [RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE]
+ = "committed rate field (shaper profile)",
+ [RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE]
+ = "committed size field (shaper profile)",
+ [RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE]
+ = "peak rate field (shaper profile)",
+ [RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE]
+ = "peak size field (shaper profile)",
+ [RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN]
+ = "packet adjust length field (shaper profile)",
+ [RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID] = "shaper profile id",
+ [RTE_TM_ERROR_TYPE_SHARED_SHAPER_ID] = "shared shaper id",
+ [RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID] = "parent node id",
+ [RTE_TM_ERROR_TYPE_NODE_PRIORITY] = "node priority",
+ [RTE_TM_ERROR_TYPE_NODE_WEIGHT] = "node weight",
+ [RTE_TM_ERROR_TYPE_NODE_PARAMS] = "node parameter null",
+ [RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID]
+ = "shaper profile id field (node params)",
+ [RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID]
+ = "shared shaper id field (node params)",
+ [RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS]
+ = "num shared shapers field (node params)",
+ [RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE]
+ = "wfq weght mode field (node params)",
+ [RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES]
+ = "num strict priorities field (node params)",
+ [RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN]
+ = "congestion management mode field (node params)",
+ [RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID] =
+ "wred profile id field (node params)",
+ [RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID]
+ = "shared wred context id field (node params)",
+ [RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS]
+ = "num shared wred contexts field (node params)",
+ [RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS]
+ = "stats field (node params)",
+ [RTE_TM_ERROR_TYPE_NODE_ID] = "node id",
+ };
+
+ const char *errstr;
+ char buf[64];
+
+ if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+ !errstrlist[error->type])
+ errstr = "unknown type";
+ else
+ errstr = errstrlist[error->type];
+
+ if (error->cause)
+ snprintf(buf, sizeof(buf), "cause: %p, ", error->cause);
+
+ printf("%s: %s%s (error %d)\n", errstr, error->cause ? buf : "",
+ error->message ? error->message : "(no stated reason)",
+ error->type);
+}
+
+static int
+read_uint64(uint64_t *value, const char *p)
+{
+ char *next;
+ uint64_t val;
+
+ p = skip_white_spaces(p);
+ if (!isdigit(*p))
+ return -EINVAL;
+
+ val = strtoul(p, &next, 10);
+ if (p == next)
+ return -EINVAL;
+
+ p = next;
+ switch (*p) {
+ case 'T':
+ val *= 1024ULL;
+ /* fall through */
+ case 'G':
+ val *= 1024ULL;
+ /* fall through */
+ case 'M':
+ val *= 1024ULL;
+ /* fall through */
+ case 'k':
+ case 'K':
+ val *= 1024ULL;
+ p++;
+ break;
+ }
+
+ p = skip_white_spaces(p);
+ if (*p != '\0')
+ return -EINVAL;
+
+ *value = val;
+ return 0;
+}
+
+static int
+read_uint32(uint32_t *value, const char *p)
+{
+ uint64_t val = 0;
+ int ret = read_uint64(&val, p);
+
+ if (ret < 0)
+ return ret;
+
+ if (val > UINT32_MAX)
+ return -ERANGE;
+
+ *value = val;
+ return 0;
+}
+
+static int
+parse_multi_ss_id_str(char *s_str, uint32_t *n_ssp, uint32_t shaper_id[])
+{
+ uint32_t n_shared_shapers = 0, i = 0;
+ char *token;
+
+ /* First token: num of shared shapers */
+ token = strtok_r(s_str, PARSE_DELIMITER, &s_str);
+ if (token == NULL)
+ return -1;
+
+ if (read_uint32(&n_shared_shapers, token))
+ return -1;
+
+ /* Check: num of shared shaper */
+ if (n_shared_shapers >= MAX_NUM_SHARED_SHAPERS) {
+ printf(" Number of shared shapers exceed the max (error)\n");
+ return -1;
+ }
+
+ /* Parse shared shaper ids */
+ while (1) {
+ token = strtok_r(s_str, PARSE_DELIMITER, &s_str);
+ if ((token != NULL && n_shared_shapers == 0) ||
+ (token == NULL && i < n_shared_shapers))
+ return -1;
+
+ if (token == NULL)
+ break;
+
+ if (read_uint32(&shaper_id[i], token))
+ return -1;
+ i++;
+ }
+ *n_ssp = n_shared_shapers;
+
+ return 0;
+}
+/* *** Port TM Capability *** */
+struct cmd_show_port_tm_cap_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t cap;
+ uint16_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_cap_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+ show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_tm =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+ tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_cap =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+ cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_cap_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_cap_result,
+ port_id, UINT16);
+
+static void cmd_show_port_tm_cap_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_port_tm_cap_result *res = parsed_result;
+ struct rte_tm_capabilities cap;
+ struct rte_tm_error error;
+ portid_t port_id = res->port_id;
+ uint32_t i;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&cap, 0, sizeof(struct rte_tm_capabilities));
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ ret = rte_tm_capabilities_get(port_id, &cap, &error);
+ if (ret) {
+ print_err_msg(&error);
+ return;
+ }
+
+ printf("\n**** Port TM Capabilities ****\n\n");
+ printf("cap.n_nodes_max %" PRIu32 "\n", cap.n_nodes_max);
+ printf("cap.n_levels_max %" PRIu32 "\n", cap.n_levels_max);
+ printf("cap.non_leaf_nodes_identical %" PRId32 "\n",
+ cap.non_leaf_nodes_identical);
+ printf("cap.leaf_nodes_identical %" PRId32 "\n",
+ cap.leaf_nodes_identical);
+ printf("cap.shaper_n_max %u\n", cap.shaper_n_max);
+ printf("cap.shaper_private_n_max %" PRIu32 "\n",
+ cap.shaper_private_n_max);
+ printf("cap.shaper_private_dual_rate_n_max %" PRId32 "\n",
+ cap.shaper_private_dual_rate_n_max);
+ printf("cap.shaper_private_rate_min %" PRIu64 "\n",
+ cap.shaper_private_rate_min);
+ printf("cap.shaper_private_rate_max %" PRIu64 "\n",
+ cap.shaper_private_rate_max);
+ printf("cap.shaper_shared_n_max %" PRIu32 "\n",
+ cap.shaper_shared_n_max);
+ printf("cap.shaper_shared_n_nodes_per_shaper_max %" PRIu32 "\n",
+ cap.shaper_shared_n_nodes_per_shaper_max);
+ printf("cap.shaper_shared_n_shapers_per_node_max %" PRIu32 "\n",
+ cap.shaper_shared_n_shapers_per_node_max);
+ printf("cap.shaper_shared_dual_rate_n_max %" PRIu32 "\n",
+ cap.shaper_shared_dual_rate_n_max);
+ printf("cap.shaper_shared_rate_min %" PRIu64 "\n",
+ cap.shaper_shared_rate_min);
+ printf("cap.shaper_shared_rate_max %" PRIu64 "\n",
+ cap.shaper_shared_rate_max);
+ printf("cap.shaper_pkt_length_adjust_min %" PRId32 "\n",
+ cap.shaper_pkt_length_adjust_min);
+ printf("cap.shaper_pkt_length_adjust_max %" PRId32 "\n",
+ cap.shaper_pkt_length_adjust_max);
+ printf("cap.sched_n_children_max %" PRIu32 "\n",
+ cap.sched_n_children_max);
+ printf("cap.sched_sp_n_priorities_max %" PRIu32 "\n",
+ cap.sched_sp_n_priorities_max);
+ printf("cap.sched_wfq_n_children_per_group_max %" PRIu32 "\n",
+ cap.sched_wfq_n_children_per_group_max);
+ printf("cap.sched_wfq_n_groups_max %" PRIu32 "\n",
+ cap.sched_wfq_n_groups_max);
+ printf("cap.sched_wfq_weight_max %" PRIu32 "\n",
+ cap.sched_wfq_weight_max);
+ printf("cap.cman_head_drop_supported %" PRId32 "\n",
+ cap.cman_head_drop_supported);
+ printf("cap.cman_wred_context_n_max %" PRIu32 "\n",
+ cap.cman_wred_context_n_max);
+ printf("cap.cman_wred_context_private_n_max %" PRIu32 "\n",
+ cap.cman_wred_context_private_n_max);
+ printf("cap.cman_wred_context_shared_n_max %" PRIu32 "\n",
+ cap.cman_wred_context_shared_n_max);
+ printf("cap.cman_wred_context_shared_n_nodes_per_context_max %" PRIu32
+ "\n", cap.cman_wred_context_shared_n_nodes_per_context_max);
+ printf("cap.cman_wred_context_shared_n_contexts_per_node_max %" PRIu32
+ "\n", cap.cman_wred_context_shared_n_contexts_per_node_max);
+
+ for (i = 0; i < RTE_COLORS; i++) {
+ printf("cap.mark_vlan_dei_supported %" PRId32 "\n",
+ cap.mark_vlan_dei_supported[i]);
+ printf("cap.mark_ip_ecn_tcp_supported %" PRId32 "\n",
+ cap.mark_ip_ecn_tcp_supported[i]);
+ printf("cap.mark_ip_ecn_sctp_supported %" PRId32 "\n",
+ cap.mark_ip_ecn_sctp_supported[i]);
+ printf("cap.mark_ip_dscp_supported %" PRId32 "\n",
+ cap.mark_ip_dscp_supported[i]);
+ }
+
+ printf("cap.dynamic_update_mask %" PRIx64 "\n",
+ cap.dynamic_update_mask);
+ printf("cap.stats_mask %" PRIx64 "\n", cap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_cap = {
+ .f = cmd_show_port_tm_cap_parsed,
+ .data = NULL,
+ .help_str = "Show Port TM Capabilities",
+ .tokens = {
+ (void *)&cmd_show_port_tm_cap_show,
+ (void *)&cmd_show_port_tm_cap_port,
+ (void *)&cmd_show_port_tm_cap_tm,
+ (void *)&cmd_show_port_tm_cap_cap,
+ (void *)&cmd_show_port_tm_cap_port_id,
+ NULL,
+ },
+};
+
+/* *** Port TM Hierarchical Level Capability *** */
+struct cmd_show_port_tm_level_cap_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t level;
+ cmdline_fixed_string_t cap;
+ uint16_t port_id;
+ uint32_t level_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+ show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_tm =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+ tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_level =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+ level, "level");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_cap =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+ cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_level_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+ level_id, UINT32);
+
+
+static void cmd_show_port_tm_level_cap_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_port_tm_level_cap_result *res = parsed_result;
+ struct rte_tm_level_capabilities lcap;
+ struct rte_tm_error error;
+ portid_t port_id = res->port_id;
+ uint32_t level_id = res->level_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&lcap, 0, sizeof(struct rte_tm_level_capabilities));
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ ret = rte_tm_level_capabilities_get(port_id, level_id, &lcap, &error);
+ if (ret) {
+ print_err_msg(&error);
+ return;
+ }
+ printf("\n** Port TM Hierarchy level %" PRIu32 " Capability **\n\n",
+ level_id);
+
+ printf("cap.n_nodes_max %" PRIu32 "\n", lcap.n_nodes_max);
+ printf("cap.n_nodes_nonleaf_max %" PRIu32 "\n",
+ lcap.n_nodes_nonleaf_max);
+ printf("cap.n_nodes_leaf_max %" PRIu32 "\n", lcap.n_nodes_leaf_max);
+ printf("cap.non_leaf_nodes_identical %" PRId32 "\n",
+ lcap.non_leaf_nodes_identical);
+ printf("cap.leaf_nodes_identical %" PRId32 "\n",
+ lcap.leaf_nodes_identical);
+ if (level_id <= 3) {
+ printf("cap.nonleaf.shaper_private_supported %" PRId32 "\n",
+ lcap.nonleaf.shaper_private_supported);
+ printf("cap.nonleaf.shaper_private_dual_rate_supported %" PRId32
+ "\n", lcap.nonleaf.shaper_private_dual_rate_supported);
+ printf("cap.nonleaf.shaper_private_rate_min %" PRIu64 "\n",
+ lcap.nonleaf.shaper_private_rate_min);
+ printf("cap.nonleaf.shaper_private_rate_max %" PRIu64 "\n",
+ lcap.nonleaf.shaper_private_rate_max);
+ printf("cap.nonleaf.shaper_shared_n_max %" PRIu32 "\n",
+ lcap.nonleaf.shaper_shared_n_max);
+ printf("cap.nonleaf.sched_n_children_max %" PRIu32 "\n",
+ lcap.nonleaf.sched_n_children_max);
+ printf("cap.nonleaf.sched_sp_n_priorities_max %" PRIu32 "\n",
+ lcap.nonleaf.sched_sp_n_priorities_max);
+ printf("cap.nonleaf.sched_wfq_n_children_per_group_max %" PRIu32
+ "\n", lcap.nonleaf.sched_wfq_n_children_per_group_max);
+ printf("cap.nonleaf.sched_wfq_n_groups_max %" PRIu32 "\n",
+ lcap.nonleaf.sched_wfq_n_groups_max);
+ printf("cap.nonleaf.sched_wfq_weight_max %" PRIu32 "\n",
+ lcap.nonleaf.sched_wfq_weight_max);
+ printf("cap.nonleaf.stats_mask %" PRIx64 "\n",
+ lcap.nonleaf.stats_mask);
+ } else {
+ printf("cap.leaf.shaper_private_supported %" PRId32 "\n",
+ lcap.leaf.shaper_private_supported);
+ printf("cap.leaf.shaper_private_dual_rate_supported %" PRId32
+ "\n", lcap.leaf.shaper_private_dual_rate_supported);
+ printf("cap.leaf.shaper_private_rate_min %" PRIu64 "\n",
+ lcap.leaf.shaper_private_rate_min);
+ printf("cap.leaf.shaper_private_rate_max %" PRIu64 "\n",
+ lcap.leaf.shaper_private_rate_max);
+ printf("cap.leaf.shaper_shared_n_max %" PRIu32 "\n",
+ lcap.leaf.shaper_shared_n_max);
+ printf("cap.leaf.cman_head_drop_supported %" PRId32 "\n",
+ lcap.leaf.cman_head_drop_supported);
+ printf("cap.leaf.cman_wred_context_private_supported %" PRId32
+ "\n", lcap.leaf.cman_wred_context_private_supported);
+ printf("cap.leaf.cman_wred_context_shared_n_max %" PRIu32 "\n",
+ lcap.leaf.cman_wred_context_shared_n_max);
+ printf("cap.leaf.stats_mask %" PRIx64 "\n",
+ lcap.leaf.stats_mask);
+ }
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_level_cap = {
+ .f = cmd_show_port_tm_level_cap_parsed,
+ .data = NULL,
+ .help_str = "Show Port TM Hierarhical level Capabilities",
+ .tokens = {
+ (void *)&cmd_show_port_tm_level_cap_show,
+ (void *)&cmd_show_port_tm_level_cap_port,
+ (void *)&cmd_show_port_tm_level_cap_tm,
+ (void *)&cmd_show_port_tm_level_cap_level,
+ (void *)&cmd_show_port_tm_level_cap_cap,
+ (void *)&cmd_show_port_tm_level_cap_port_id,
+ (void *)&cmd_show_port_tm_level_cap_level_id,
+ NULL,
+ },
+};
+
+/* *** Port TM Hierarchy Node Capability *** */
+struct cmd_show_port_tm_node_cap_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t node;
+ cmdline_fixed_string_t cap;
+ uint16_t port_id;
+ uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+ show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_tm =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+ tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_node =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+ node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_cap =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+ cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_node_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+ node_id, UINT32);
+
+static void cmd_show_port_tm_node_cap_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_port_tm_node_cap_result *res = parsed_result;
+ struct rte_tm_node_capabilities ncap;
+ struct rte_tm_error error;
+ uint32_t node_id = res->node_id;
+ portid_t port_id = res->port_id;
+ int ret, is_leaf = 0;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ /* Node id must be valid */
+ ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+
+ memset(&ncap, 0, sizeof(struct rte_tm_node_capabilities));
+ ret = rte_tm_node_capabilities_get(port_id, node_id, &ncap, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+ printf("\n** Port TM Hierarchy node %" PRIu32 " Capability **\n\n",
+ node_id);
+ printf("cap.shaper_private_supported %" PRId32 "\n",
+ ncap.shaper_private_supported);
+ printf("cap.shaper_private_dual_rate_supported %" PRId32 "\n",
+ ncap.shaper_private_dual_rate_supported);
+ printf("cap.shaper_private_rate_min %" PRIu64 "\n",
+ ncap.shaper_private_rate_min);
+ printf("cap.shaper_private_rate_max %" PRIu64 "\n",
+ ncap.shaper_private_rate_max);
+ printf("cap.shaper_shared_n_max %" PRIu32 "\n",
+ ncap.shaper_shared_n_max);
+ if (!is_leaf) {
+ printf("cap.nonleaf.sched_n_children_max %" PRIu32 "\n",
+ ncap.nonleaf.sched_n_children_max);
+ printf("cap.nonleaf.sched_sp_n_priorities_max %" PRIu32 "\n",
+ ncap.nonleaf.sched_sp_n_priorities_max);
+ printf("cap.nonleaf.sched_wfq_n_children_per_group_max %" PRIu32
+ "\n", ncap.nonleaf.sched_wfq_n_children_per_group_max);
+ printf("cap.nonleaf.sched_wfq_n_groups_max %" PRIu32 "\n",
+ ncap.nonleaf.sched_wfq_n_groups_max);
+ printf("cap.nonleaf.sched_wfq_weight_max %" PRIu32 "\n",
+ ncap.nonleaf.sched_wfq_weight_max);
+ } else {
+ printf("cap.leaf.cman_head_drop_supported %" PRId32 "\n",
+ ncap.leaf.cman_head_drop_supported);
+ printf("cap.leaf.cman_wred_context_private_supported %" PRId32
+ "\n", ncap.leaf.cman_wred_context_private_supported);
+ printf("cap.leaf.cman_wred_context_shared_n_max %" PRIu32 "\n",
+ ncap.leaf.cman_wred_context_shared_n_max);
+ }
+ printf("cap.stats_mask %" PRIx64 "\n", ncap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_cap = {
+ .f = cmd_show_port_tm_node_cap_parsed,
+ .data = NULL,
+ .help_str = "Show Port TM Hierarchy node capabilities",
+ .tokens = {
+ (void *)&cmd_show_port_tm_node_cap_show,
+ (void *)&cmd_show_port_tm_node_cap_port,
+ (void *)&cmd_show_port_tm_node_cap_tm,
+ (void *)&cmd_show_port_tm_node_cap_node,
+ (void *)&cmd_show_port_tm_node_cap_cap,
+ (void *)&cmd_show_port_tm_node_cap_port_id,
+ (void *)&cmd_show_port_tm_node_cap_node_id,
+ NULL,
+ },
+};
+
+/* *** Show Port TM Node Statistics *** */
+struct cmd_show_port_tm_node_stats_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t node;
+ cmdline_fixed_string_t stats;
+ uint16_t port_id;
+ uint32_t node_id;
+ uint32_t clear;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_show =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_tm_node_stats_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_tm_node_stats_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_tm_node_stats_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_tm_node_stats_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_stats =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_tm_node_stats_result, stats, "stats");
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_stats_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_node_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_show_port_tm_node_stats_result,
+ node_id, UINT32);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_clear =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_show_port_tm_node_stats_result, clear, UINT32);
+
+static void cmd_show_port_tm_node_stats_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_port_tm_node_stats_result *res = parsed_result;
+ struct rte_tm_node_stats stats;
+ struct rte_tm_error error;
+ uint64_t stats_mask = 0;
+ uint32_t node_id = res->node_id;
+ uint32_t clear = res->clear;
+ portid_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ /* Port status */
+ if (!port_is_started(port_id)) {
+ printf(" Port %u not started (error)\n", port_id);
+ return;
+ }
+
+ memset(&stats, 0, sizeof(struct rte_tm_node_stats));
+ ret = rte_tm_node_stats_read(port_id, node_id, &stats,
+ &stats_mask, clear, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+
+ /* Display stats */
+ if (stats_mask & RTE_TM_STATS_N_PKTS)
+ printf("\tPkts scheduled from node: %" PRIu64 "\n",
+ stats.n_pkts);
+ if (stats_mask & RTE_TM_STATS_N_BYTES)
+ printf("\tBytes scheduled from node: %" PRIu64 "\n",
+ stats.n_bytes);
+ if (stats_mask & RTE_TM_STATS_N_PKTS_GREEN_DROPPED)
+ printf("\tPkts dropped (green): %" PRIu64 "\n",
+ stats.leaf.n_pkts_dropped[RTE_COLOR_GREEN]);
+ if (stats_mask & RTE_TM_STATS_N_PKTS_YELLOW_DROPPED)
+ printf("\tPkts dropped (yellow): %" PRIu64 "\n",
+ stats.leaf.n_pkts_dropped[RTE_COLOR_YELLOW]);
+ if (stats_mask & RTE_TM_STATS_N_PKTS_RED_DROPPED)
+ printf("\tPkts dropped (red): %" PRIu64 "\n",
+ stats.leaf.n_pkts_dropped[RTE_COLOR_RED]);
+ if (stats_mask & RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
+ printf("\tBytes dropped (green): %" PRIu64 "\n",
+ stats.leaf.n_bytes_dropped[RTE_COLOR_GREEN]);
+ if (stats_mask & RTE_TM_STATS_N_BYTES_YELLOW_DROPPED)
+ printf("\tBytes dropped (yellow): %" PRIu64 "\n",
+ stats.leaf.n_bytes_dropped[RTE_COLOR_YELLOW]);
+ if (stats_mask & RTE_TM_STATS_N_BYTES_RED_DROPPED)
+ printf("\tBytes dropped (red): %" PRIu64 "\n",
+ stats.leaf.n_bytes_dropped[RTE_COLOR_RED]);
+ if (stats_mask & RTE_TM_STATS_N_PKTS_QUEUED)
+ printf("\tPkts queued: %" PRIu64 "\n",
+ stats.leaf.n_pkts_queued);
+ if (stats_mask & RTE_TM_STATS_N_BYTES_QUEUED)
+ printf("\tBytes queued: %" PRIu64 "\n",
+ stats.leaf.n_bytes_queued);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_stats = {
+ .f = cmd_show_port_tm_node_stats_parsed,
+ .data = NULL,
+ .help_str = "Show port tm node stats",
+ .tokens = {
+ (void *)&cmd_show_port_tm_node_stats_show,
+ (void *)&cmd_show_port_tm_node_stats_port,
+ (void *)&cmd_show_port_tm_node_stats_tm,
+ (void *)&cmd_show_port_tm_node_stats_node,
+ (void *)&cmd_show_port_tm_node_stats_stats,
+ (void *)&cmd_show_port_tm_node_stats_port_id,
+ (void *)&cmd_show_port_tm_node_stats_node_id,
+ (void *)&cmd_show_port_tm_node_stats_clear,
+ NULL,
+ },
+};
+
+/* *** Show Port TM Node Type *** */
+struct cmd_show_port_tm_node_type_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t node;
+ cmdline_fixed_string_t type;
+ uint16_t port_id;
+ uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_show =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_tm_node_type_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_tm_node_type_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_tm_node_type_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_tm_node_type_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_type =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_show_port_tm_node_type_result, type, "type");
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_show_port_tm_node_type_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_node_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_show_port_tm_node_type_result,
+ node_id, UINT32);
+
+static void cmd_show_port_tm_node_type_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_port_tm_node_type_result *res = parsed_result;
+ struct rte_tm_error error;
+ uint32_t node_id = res->node_id;
+ portid_t port_id = res->port_id;
+ int ret, is_leaf = 0;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+
+ if (is_leaf == 1)
+ printf("leaf node\n");
+ else
+ printf("nonleaf node\n");
+
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_type = {
+ .f = cmd_show_port_tm_node_type_parsed,
+ .data = NULL,
+ .help_str = "Show port tm node type",
+ .tokens = {
+ (void *)&cmd_show_port_tm_node_type_show,
+ (void *)&cmd_show_port_tm_node_type_port,
+ (void *)&cmd_show_port_tm_node_type_tm,
+ (void *)&cmd_show_port_tm_node_type_node,
+ (void *)&cmd_show_port_tm_node_type_type,
+ (void *)&cmd_show_port_tm_node_type_port_id,
+ (void *)&cmd_show_port_tm_node_type_node_id,
+ NULL,
+ },
+};
+
+/* *** Add Port TM Private Shaper Profile *** */
+struct cmd_add_port_tm_node_shaper_profile_result {
+ cmdline_fixed_string_t add;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t node;
+ cmdline_fixed_string_t shaper;
+ cmdline_fixed_string_t profile;
+ uint16_t port_id;
+ uint32_t shaper_id;
+ uint64_t cmit_tb_rate;
+ uint64_t cmit_tb_size;
+ uint64_t peak_tb_rate;
+ uint64_t peak_tb_size;
+ uint32_t pktlen_adjust;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_add =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_shaper_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_shaper_profile_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_shaper_profile_result,
+ tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_shaper_profile_result,
+ node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_shaper =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_shaper_profile_result,
+ shaper, "shaper");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_profile =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_shaper_profile_result,
+ profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_shaper_profile_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_shaper_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_shaper_profile_result,
+ shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_cmit_tb_rate =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_shaper_profile_result,
+ cmit_tb_rate, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_cmit_tb_size =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_shaper_profile_result,
+ cmit_tb_size, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_peak_tb_rate =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_shaper_profile_result,
+ peak_tb_rate, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_peak_tb_size =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_shaper_profile_result,
+ peak_tb_size, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_pktlen_adjust =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_shaper_profile_result,
+ pktlen_adjust, UINT32);
+
+static void cmd_add_port_tm_node_shaper_profile_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_add_port_tm_node_shaper_profile_result *res = parsed_result;
+ struct rte_tm_shaper_params sp;
+ struct rte_tm_error error;
+ uint32_t shaper_id = res->shaper_id;
+ uint32_t pkt_len_adjust = res->pktlen_adjust;
+ portid_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ /* Private shaper profile params */
+ memset(&sp, 0, sizeof(struct rte_tm_shaper_params));
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ sp.committed.rate = res->cmit_tb_rate;
+ sp.committed.size = res->cmit_tb_size;
+ sp.peak.rate = res->peak_tb_rate;
+ sp.peak.size = res->peak_tb_size;
+ sp.pkt_length_adjust = pkt_len_adjust;
+
+ ret = rte_tm_shaper_profile_add(port_id, shaper_id, &sp, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile = {
+ .f = cmd_add_port_tm_node_shaper_profile_parsed,
+ .data = NULL,
+ .help_str = "Add port tm node private shaper profile",
+ .tokens = {
+ (void *)&cmd_add_port_tm_node_shaper_profile_add,
+ (void *)&cmd_add_port_tm_node_shaper_profile_port,
+ (void *)&cmd_add_port_tm_node_shaper_profile_tm,
+ (void *)&cmd_add_port_tm_node_shaper_profile_node,
+ (void *)&cmd_add_port_tm_node_shaper_profile_shaper,
+ (void *)&cmd_add_port_tm_node_shaper_profile_profile,
+ (void *)&cmd_add_port_tm_node_shaper_profile_port_id,
+ (void *)&cmd_add_port_tm_node_shaper_profile_shaper_id,
+ (void *)&cmd_add_port_tm_node_shaper_profile_cmit_tb_rate,
+ (void *)&cmd_add_port_tm_node_shaper_profile_cmit_tb_size,
+ (void *)&cmd_add_port_tm_node_shaper_profile_peak_tb_rate,
+ (void *)&cmd_add_port_tm_node_shaper_profile_peak_tb_size,
+ (void *)&cmd_add_port_tm_node_shaper_profile_pktlen_adjust,
+ NULL,
+ },
+};
+
+/* *** Delete Port TM Private Shaper Profile *** */
+struct cmd_del_port_tm_node_shaper_profile_result {
+ cmdline_fixed_string_t del;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t node;
+ cmdline_fixed_string_t shaper;
+ cmdline_fixed_string_t profile;
+ uint16_t port_id;
+ uint32_t shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_del =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_shaper_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_shaper_profile_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_shaper_profile_result,
+ node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_shaper =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_shaper_profile_result,
+ shaper, "shaper");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_profile =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_shaper_profile_result,
+ profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_del_port_tm_node_shaper_profile_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_shaper_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_del_port_tm_node_shaper_profile_result,
+ shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shaper_profile_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_del_port_tm_node_shaper_profile_result *res = parsed_result;
+ struct rte_tm_error error;
+ uint32_t shaper_id = res->shaper_id;
+ portid_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ ret = rte_tm_shaper_profile_delete(port_id, shaper_id, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile = {
+ .f = cmd_del_port_tm_node_shaper_profile_parsed,
+ .data = NULL,
+ .help_str = "Delete port tm node private shaper profile",
+ .tokens = {
+ (void *)&cmd_del_port_tm_node_shaper_profile_del,
+ (void *)&cmd_del_port_tm_node_shaper_profile_port,
+ (void *)&cmd_del_port_tm_node_shaper_profile_tm,
+ (void *)&cmd_del_port_tm_node_shaper_profile_node,
+ (void *)&cmd_del_port_tm_node_shaper_profile_shaper,
+ (void *)&cmd_del_port_tm_node_shaper_profile_profile,
+ (void *)&cmd_del_port_tm_node_shaper_profile_port_id,
+ (void *)&cmd_del_port_tm_node_shaper_profile_shaper_id,
+ NULL,
+ },
+};
+
+/* *** Add/Update Port TM shared Shaper *** */
+struct cmd_add_port_tm_node_shared_shaper_result {
+ cmdline_fixed_string_t cmd_type;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t node;
+ cmdline_fixed_string_t shared;
+ cmdline_fixed_string_t shaper;
+ uint16_t port_id;
+ uint32_t shared_shaper_id;
+ uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_cmd_type =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_shared_shaper_result,
+ cmd_type, "add#set");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shared =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_shared_shaper_result,
+ shared, "shared");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shaper =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_shared_shaper_result,
+ shaper, "shaper");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_shared_shaper_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shared_shaper_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_shared_shaper_result,
+ shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shaper_profile_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_shared_shaper_result,
+ shaper_profile_id, UINT32);
+
+static void cmd_add_port_tm_node_shared_shaper_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_add_port_tm_node_shared_shaper_result *res = parsed_result;
+ struct rte_tm_error error;
+ uint32_t shared_shaper_id = res->shared_shaper_id;
+ uint32_t shaper_profile_id = res->shaper_profile_id;
+ portid_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ /* Command type: add */
+ if ((strcmp(res->cmd_type, "add") == 0) &&
+ (port_is_started(port_id))) {
+ printf(" Port %u not stopped (error)\n", port_id);
+ return;
+ }
+
+ /* Command type: set (update) */
+ if ((strcmp(res->cmd_type, "set") == 0) &&
+ (!port_is_started(port_id))) {
+ printf(" Port %u not started (error)\n", port_id);
+ return;
+ }
+
+ ret = rte_tm_shared_shaper_add_update(port_id, shared_shaper_id,
+ shaper_profile_id, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper = {
+ .f = cmd_add_port_tm_node_shared_shaper_parsed,
+ .data = NULL,
+ .help_str = "add/update port tm node shared shaper",
+ .tokens = {
+ (void *)&cmd_add_port_tm_node_shared_shaper_cmd_type,
+ (void *)&cmd_add_port_tm_node_shared_shaper_port,
+ (void *)&cmd_add_port_tm_node_shared_shaper_tm,
+ (void *)&cmd_add_port_tm_node_shared_shaper_node,
+ (void *)&cmd_add_port_tm_node_shared_shaper_shared,
+ (void *)&cmd_add_port_tm_node_shared_shaper_shaper,
+ (void *)&cmd_add_port_tm_node_shared_shaper_port_id,
+ (void *)&cmd_add_port_tm_node_shared_shaper_shared_shaper_id,
+ (void *)&cmd_add_port_tm_node_shared_shaper_shaper_profile_id,
+ NULL,
+ },
+};
+
+/* *** Delete Port TM shared Shaper *** */
+struct cmd_del_port_tm_node_shared_shaper_result {
+ cmdline_fixed_string_t del;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t node;
+ cmdline_fixed_string_t shared;
+ cmdline_fixed_string_t shaper;
+ uint16_t port_id;
+ uint32_t shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_del =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_shared_shaper_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shared =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_shared_shaper_result,
+ shared, "shared");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shaper =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_shared_shaper_result,
+ shaper, "shaper");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_del_port_tm_node_shared_shaper_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_shared_shaper_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_del_port_tm_node_shared_shaper_result,
+ shared_shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shared_shaper_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_del_port_tm_node_shared_shaper_result *res = parsed_result;
+ struct rte_tm_error error;
+ uint32_t shared_shaper_id = res->shared_shaper_id;
+ portid_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ ret = rte_tm_shared_shaper_delete(port_id, shared_shaper_id, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper = {
+ .f = cmd_del_port_tm_node_shared_shaper_parsed,
+ .data = NULL,
+ .help_str = "delete port tm node shared shaper",
+ .tokens = {
+ (void *)&cmd_del_port_tm_node_shared_shaper_del,
+ (void *)&cmd_del_port_tm_node_shared_shaper_port,
+ (void *)&cmd_del_port_tm_node_shared_shaper_tm,
+ (void *)&cmd_del_port_tm_node_shared_shaper_node,
+ (void *)&cmd_del_port_tm_node_shared_shaper_shared,
+ (void *)&cmd_del_port_tm_node_shared_shaper_shaper,
+ (void *)&cmd_del_port_tm_node_shared_shaper_port_id,
+ (void *)&cmd_del_port_tm_node_shared_shaper_shared_shaper_id,
+ NULL,
+ },
+};
+
+/* *** Add Port TM Node WRED Profile *** */
+struct cmd_add_port_tm_node_wred_profile_result {
+ cmdline_fixed_string_t add;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t node;
+ cmdline_fixed_string_t wred;
+ cmdline_fixed_string_t profile;
+ uint16_t port_id;
+ uint32_t wred_profile_id;
+ cmdline_fixed_string_t color_g;
+ uint64_t min_th_g;
+ uint64_t max_th_g;
+ uint16_t maxp_inv_g;
+ uint16_t wq_log2_g;
+ cmdline_fixed_string_t color_y;
+ uint64_t min_th_y;
+ uint64_t max_th_y;
+ uint16_t maxp_inv_y;
+ uint16_t wq_log2_y;
+ cmdline_fixed_string_t color_r;
+ uint64_t min_th_r;
+ uint64_t max_th_r;
+ uint16_t maxp_inv_r;
+ uint16_t wq_log2_r;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_add =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_wred =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_profile =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wred_profile_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ wred_profile_id, UINT32);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_g =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ color_g, "G#g");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_g =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ min_th_g, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_g =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ max_th_g, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_g =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ maxp_inv_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_g =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ wq_log2_g, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_y =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ color_y, "Y#y");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_y =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ min_th_y, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_y =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ max_th_y, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_y =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ maxp_inv_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_y =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ wq_log2_y, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_r =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ color_r, "R#r");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_r =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ min_th_r, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_r =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ max_th_r, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_r =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ maxp_inv_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_r =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_node_wred_profile_result,
+ wq_log2_r, UINT16);
+
+
+static void cmd_add_port_tm_node_wred_profile_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_add_port_tm_node_wred_profile_result *res = parsed_result;
+ struct rte_tm_wred_params wp;
+ enum rte_color color;
+ struct rte_tm_error error;
+ uint32_t wred_profile_id = res->wred_profile_id;
+ portid_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&wp, 0, sizeof(struct rte_tm_wred_params));
+ memset(&error, 0, sizeof(struct rte_tm_error));
+
+ /* WRED Params (Green Color)*/
+ color = RTE_COLOR_GREEN;
+ wp.red_params[color].min_th = res->min_th_g;
+ wp.red_params[color].max_th = res->max_th_g;
+ wp.red_params[color].maxp_inv = res->maxp_inv_g;
+ wp.red_params[color].wq_log2 = res->wq_log2_g;
+
+
+ /* WRED Params (Yellow Color)*/
+ color = RTE_COLOR_YELLOW;
+ wp.red_params[color].min_th = res->min_th_y;
+ wp.red_params[color].max_th = res->max_th_y;
+ wp.red_params[color].maxp_inv = res->maxp_inv_y;
+ wp.red_params[color].wq_log2 = res->wq_log2_y;
+
+ /* WRED Params (Red Color)*/
+ color = RTE_COLOR_RED;
+ wp.red_params[color].min_th = res->min_th_r;
+ wp.red_params[color].max_th = res->max_th_r;
+ wp.red_params[color].maxp_inv = res->maxp_inv_r;
+ wp.red_params[color].wq_log2 = res->wq_log2_r;
+
+ ret = rte_tm_wred_profile_add(port_id, wred_profile_id, &wp, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile = {
+ .f = cmd_add_port_tm_node_wred_profile_parsed,
+ .data = NULL,
+ .help_str = "Add port tm node wred profile",
+ .tokens = {
+ (void *)&cmd_add_port_tm_node_wred_profile_add,
+ (void *)&cmd_add_port_tm_node_wred_profile_port,
+ (void *)&cmd_add_port_tm_node_wred_profile_tm,
+ (void *)&cmd_add_port_tm_node_wred_profile_node,
+ (void *)&cmd_add_port_tm_node_wred_profile_wred,
+ (void *)&cmd_add_port_tm_node_wred_profile_profile,
+ (void *)&cmd_add_port_tm_node_wred_profile_port_id,
+ (void *)&cmd_add_port_tm_node_wred_profile_wred_profile_id,
+ (void *)&cmd_add_port_tm_node_wred_profile_color_g,
+ (void *)&cmd_add_port_tm_node_wred_profile_min_th_g,
+ (void *)&cmd_add_port_tm_node_wred_profile_max_th_g,
+ (void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_g,
+ (void *)&cmd_add_port_tm_node_wred_profile_wq_log2_g,
+ (void *)&cmd_add_port_tm_node_wred_profile_color_y,
+ (void *)&cmd_add_port_tm_node_wred_profile_min_th_y,
+ (void *)&cmd_add_port_tm_node_wred_profile_max_th_y,
+ (void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_y,
+ (void *)&cmd_add_port_tm_node_wred_profile_wq_log2_y,
+ (void *)&cmd_add_port_tm_node_wred_profile_color_r,
+ (void *)&cmd_add_port_tm_node_wred_profile_min_th_r,
+ (void *)&cmd_add_port_tm_node_wred_profile_max_th_r,
+ (void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_r,
+ (void *)&cmd_add_port_tm_node_wred_profile_wq_log2_r,
+ NULL,
+ },
+};
+
+/* *** Delete Port TM node WRED Profile *** */
+struct cmd_del_port_tm_node_wred_profile_result {
+ cmdline_fixed_string_t del;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t node;
+ cmdline_fixed_string_t wred;
+ cmdline_fixed_string_t profile;
+ uint16_t port_id;
+ uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_del =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_wred_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_wred =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_profile =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_wred_profile_result,
+ profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_del_port_tm_node_wred_profile_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_wred_profile_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_del_port_tm_node_wred_profile_result,
+ wred_profile_id, UINT32);
+
+static void cmd_del_port_tm_node_wred_profile_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_del_port_tm_node_wred_profile_result *res = parsed_result;
+ struct rte_tm_error error;
+ uint32_t wred_profile_id = res->wred_profile_id;
+ portid_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ ret = rte_tm_wred_profile_delete(port_id, wred_profile_id, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile = {
+ .f = cmd_del_port_tm_node_wred_profile_parsed,
+ .data = NULL,
+ .help_str = "Delete port tm node wred profile",
+ .tokens = {
+ (void *)&cmd_del_port_tm_node_wred_profile_del,
+ (void *)&cmd_del_port_tm_node_wred_profile_port,
+ (void *)&cmd_del_port_tm_node_wred_profile_tm,
+ (void *)&cmd_del_port_tm_node_wred_profile_node,
+ (void *)&cmd_del_port_tm_node_wred_profile_wred,
+ (void *)&cmd_del_port_tm_node_wred_profile_profile,
+ (void *)&cmd_del_port_tm_node_wred_profile_port_id,
+ (void *)&cmd_del_port_tm_node_wred_profile_wred_profile_id,
+ NULL,
+ },
+};
+
+/* *** Update Port TM Node Shaper profile *** */
+struct cmd_set_port_tm_node_shaper_profile_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t node;
+ cmdline_fixed_string_t shaper;
+ cmdline_fixed_string_t profile;
+ uint16_t port_id;
+ uint32_t node_id;
+ uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_set =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_node_shaper_profile_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_node_shaper_profile_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_node_shaper_profile_result,
+ node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_shaper =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_node_shaper_profile_result,
+ shaper, "shaper");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_profile =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_node_shaper_profile_result,
+ profile, "profile");
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_set_port_tm_node_shaper_profile_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_node_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_shaper_profile_result,
+ node_id, UINT32);
+cmdline_parse_token_num_t
+ cmd_set_port_tm_node_shaper_shaper_profile_profile_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_set_port_tm_node_shaper_profile_result,
+ shaper_profile_id, UINT32);
+
+static void cmd_set_port_tm_node_shaper_profile_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_port_tm_node_shaper_profile_result *res = parsed_result;
+ struct rte_tm_error error;
+ uint32_t node_id = res->node_id;
+ uint32_t shaper_profile_id = res->shaper_profile_id;
+ portid_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ /* Port status */
+ if (!port_is_started(port_id)) {
+ printf(" Port %u not started (error)\n", port_id);
+ return;
+ }
+
+ ret = rte_tm_node_shaper_update(port_id, node_id,
+ shaper_profile_id, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
+ .f = cmd_set_port_tm_node_shaper_profile_parsed,
+ .data = NULL,
+ .help_str = "Set port tm node shaper profile",
+ .tokens = {
+ (void *)&cmd_set_port_tm_node_shaper_profile_set,
+ (void *)&cmd_set_port_tm_node_shaper_profile_port,
+ (void *)&cmd_set_port_tm_node_shaper_profile_tm,
+ (void *)&cmd_set_port_tm_node_shaper_profile_node,
+ (void *)&cmd_set_port_tm_node_shaper_profile_shaper,
+ (void *)&cmd_set_port_tm_node_shaper_profile_profile,
+ (void *)&cmd_set_port_tm_node_shaper_profile_port_id,
+ (void *)&cmd_set_port_tm_node_shaper_profile_node_id,
+ (void *)&cmd_set_port_tm_node_shaper_shaper_profile_profile_id,
+ NULL,
+ },
+};
+
+/* *** Add Port TM nonleaf node *** */
+struct cmd_add_port_tm_nonleaf_node_result {
+ cmdline_fixed_string_t add;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t nonleaf;
+ cmdline_fixed_string_t node;
+ uint16_t port_id;
+ uint32_t node_id;
+ int32_t parent_node_id;
+ uint32_t priority;
+ uint32_t weight;
+ uint32_t level_id;
+ int32_t shaper_profile_id;
+ uint32_t n_sp_priorities;
+ uint64_t stats_mask;
+ cmdline_multi_string_t multi_shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_add =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_nonleaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_nonleaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_nonleaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_nonleaf =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_nonleaf_node_result, nonleaf, "nonleaf");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_nonleaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_add_port_tm_nonleaf_node_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_node_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+ node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_parent_node_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+ parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_priority =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+ priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_weight =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+ weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_level_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+ level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shaper_profile_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+ shaper_profile_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_sp_priorities =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+ n_sp_priorities, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_stats_mask =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+ stats_mask, UINT64);
+cmdline_parse_token_string_t
+ cmd_add_port_tm_nonleaf_node_multi_shared_shaper_id =
+ TOKEN_STRING_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+ multi_shared_shaper_id, TOKEN_STRING_MULTI);
+
+static void cmd_add_port_tm_nonleaf_node_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_add_port_tm_nonleaf_node_result *res = parsed_result;
+ struct rte_tm_error error;
+ struct rte_tm_node_params np;
+ uint32_t *shared_shaper_id;
+ uint32_t parent_node_id, n_shared_shapers = 0;
+ char *s_str = res->multi_shared_shaper_id;
+ portid_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&np, 0, sizeof(struct rte_tm_node_params));
+ memset(&error, 0, sizeof(struct rte_tm_error));
+
+ /* Node parameters */
+ if (res->parent_node_id < 0)
+ parent_node_id = UINT32_MAX;
+ else
+ parent_node_id = res->parent_node_id;
+
+ shared_shaper_id = (uint32_t *)malloc(MAX_NUM_SHARED_SHAPERS *
+ sizeof(uint32_t));
+ if (shared_shaper_id == NULL) {
+ printf(" Memory not allocated for shared shapers (error)\n");
+ return;
+ }
+
+ /* Parse multi shared shaper id string */
+ ret = parse_multi_ss_id_str(s_str, &n_shared_shapers, shared_shaper_id);
+ if (ret) {
+ printf(" Shared shapers params string parse error\n");
+ free(shared_shaper_id);
+ return;
+ }
+
+ if (res->shaper_profile_id < 0)
+ np.shaper_profile_id = UINT32_MAX;
+ else
+ np.shaper_profile_id = res->shaper_profile_id;
+
+ np.n_shared_shapers = n_shared_shapers;
+ if (np.n_shared_shapers) {
+ np.shared_shaper_id = &shared_shaper_id[0];
+ } else {
+ free(shared_shaper_id);
+ shared_shaper_id = NULL;
+ }
+
+ np.nonleaf.n_sp_priorities = res->n_sp_priorities;
+ np.stats_mask = res->stats_mask;
+ np.nonleaf.wfq_weight_mode = NULL;
+
+ ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+ res->priority, res->weight, res->level_id,
+ &np, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ free(shared_shaper_id);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node = {
+ .f = cmd_add_port_tm_nonleaf_node_parsed,
+ .data = NULL,
+ .help_str = "Add port tm nonleaf node",
+ .tokens = {
+ (void *)&cmd_add_port_tm_nonleaf_node_add,
+ (void *)&cmd_add_port_tm_nonleaf_node_port,
+ (void *)&cmd_add_port_tm_nonleaf_node_tm,
+ (void *)&cmd_add_port_tm_nonleaf_node_nonleaf,
+ (void *)&cmd_add_port_tm_nonleaf_node_node,
+ (void *)&cmd_add_port_tm_nonleaf_node_port_id,
+ (void *)&cmd_add_port_tm_nonleaf_node_node_id,
+ (void *)&cmd_add_port_tm_nonleaf_node_parent_node_id,
+ (void *)&cmd_add_port_tm_nonleaf_node_priority,
+ (void *)&cmd_add_port_tm_nonleaf_node_weight,
+ (void *)&cmd_add_port_tm_nonleaf_node_level_id,
+ (void *)&cmd_add_port_tm_nonleaf_node_shaper_profile_id,
+ (void *)&cmd_add_port_tm_nonleaf_node_n_sp_priorities,
+ (void *)&cmd_add_port_tm_nonleaf_node_stats_mask,
+ (void *)&cmd_add_port_tm_nonleaf_node_multi_shared_shaper_id,
+ NULL,
+ },
+};
+
+/* *** Add Port TM leaf node *** */
+struct cmd_add_port_tm_leaf_node_result {
+ cmdline_fixed_string_t add;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t leaf;
+ cmdline_fixed_string_t node;
+ uint16_t port_id;
+ uint32_t node_id;
+ int32_t parent_node_id;
+ uint32_t priority;
+ uint32_t weight;
+ uint32_t level_id;
+ int32_t shaper_profile_id;
+ uint32_t cman_mode;
+ uint32_t wred_profile_id;
+ uint64_t stats_mask;
+ cmdline_multi_string_t multi_shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_add =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_leaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_leaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_leaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_nonleaf =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_leaf_node_result, leaf, "leaf");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_add_port_tm_leaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_node_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+ node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_parent_node_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+ parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_priority =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+ priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_weight =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+ weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_level_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+ level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_shaper_profile_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+ shaper_profile_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_cman_mode =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+ cman_mode, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_wred_profile_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+ wred_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_stats_mask =
+ TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+ stats_mask, UINT64);
+cmdline_parse_token_string_t
+ cmd_add_port_tm_leaf_node_multi_shared_shaper_id =
+ TOKEN_STRING_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+ multi_shared_shaper_id, TOKEN_STRING_MULTI);
+
+static void cmd_add_port_tm_leaf_node_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_add_port_tm_leaf_node_result *res = parsed_result;
+ struct rte_tm_error error;
+ struct rte_tm_node_params np;
+ uint32_t *shared_shaper_id;
+ uint32_t parent_node_id, n_shared_shapers = 0;
+ portid_t port_id = res->port_id;
+ char *s_str = res->multi_shared_shaper_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&np, 0, sizeof(struct rte_tm_node_params));
+ memset(&error, 0, sizeof(struct rte_tm_error));
+
+ /* Node parameters */
+ if (res->parent_node_id < 0)
+ parent_node_id = UINT32_MAX;
+ else
+ parent_node_id = res->parent_node_id;
+
+ shared_shaper_id = (uint32_t *)malloc(MAX_NUM_SHARED_SHAPERS *
+ sizeof(uint32_t));
+ if (shared_shaper_id == NULL) {
+ printf(" Memory not allocated for shared shapers (error)\n");
+ return;
+ }
+
+ /* Parse multi shared shaper id string */
+ ret = parse_multi_ss_id_str(s_str, &n_shared_shapers, shared_shaper_id);
+ if (ret) {
+ printf(" Shared shapers params string parse error\n");
+ free(shared_shaper_id);
+ return;
+ }
+
+ if (res->shaper_profile_id < 0)
+ np.shaper_profile_id = UINT32_MAX;
+ else
+ np.shaper_profile_id = res->shaper_profile_id;
+
+ np.n_shared_shapers = n_shared_shapers;
+
+ if (np.n_shared_shapers) {
+ np.shared_shaper_id = &shared_shaper_id[0];
+ } else {
+ free(shared_shaper_id);
+ shared_shaper_id = NULL;
+ }
+
+ np.leaf.cman = res->cman_mode;
+ np.leaf.wred.wred_profile_id = res->wred_profile_id;
+ np.stats_mask = res->stats_mask;
+
+ ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+ res->priority, res->weight, res->level_id,
+ &np, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ free(shared_shaper_id);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_leaf_node = {
+ .f = cmd_add_port_tm_leaf_node_parsed,
+ .data = NULL,
+ .help_str = "Add port tm leaf node",
+ .tokens = {
+ (void *)&cmd_add_port_tm_leaf_node_add,
+ (void *)&cmd_add_port_tm_leaf_node_port,
+ (void *)&cmd_add_port_tm_leaf_node_tm,
+ (void *)&cmd_add_port_tm_leaf_node_nonleaf,
+ (void *)&cmd_add_port_tm_leaf_node_node,
+ (void *)&cmd_add_port_tm_leaf_node_port_id,
+ (void *)&cmd_add_port_tm_leaf_node_node_id,
+ (void *)&cmd_add_port_tm_leaf_node_parent_node_id,
+ (void *)&cmd_add_port_tm_leaf_node_priority,
+ (void *)&cmd_add_port_tm_leaf_node_weight,
+ (void *)&cmd_add_port_tm_leaf_node_level_id,
+ (void *)&cmd_add_port_tm_leaf_node_shaper_profile_id,
+ (void *)&cmd_add_port_tm_leaf_node_cman_mode,
+ (void *)&cmd_add_port_tm_leaf_node_wred_profile_id,
+ (void *)&cmd_add_port_tm_leaf_node_stats_mask,
+ (void *)&cmd_add_port_tm_leaf_node_multi_shared_shaper_id,
+ NULL,
+ },
+};
+
+/* *** Delete Port TM Node *** */
+struct cmd_del_port_tm_node_result {
+ cmdline_fixed_string_t del;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t node;
+ uint16_t port_id;
+ uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_del =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_del_port_tm_node_result, node, "node");
+cmdline_parse_token_num_t cmd_del_port_tm_node_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+ port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_node_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+ node_id, UINT32);
+
+static void cmd_del_port_tm_node_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_del_port_tm_node_result *res = parsed_result;
+ struct rte_tm_error error;
+ uint32_t node_id = res->node_id;
+ portid_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ /* Port status */
+ if (port_is_started(port_id)) {
+ printf(" Port %u not stopped (error)\n", port_id);
+ return;
+ }
+
+ ret = rte_tm_node_delete(port_id, node_id, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node = {
+ .f = cmd_del_port_tm_node_parsed,
+ .data = NULL,
+ .help_str = "Delete port tm node",
+ .tokens = {
+ (void *)&cmd_del_port_tm_node_del,
+ (void *)&cmd_del_port_tm_node_port,
+ (void *)&cmd_del_port_tm_node_tm,
+ (void *)&cmd_del_port_tm_node_node,
+ (void *)&cmd_del_port_tm_node_port_id,
+ (void *)&cmd_del_port_tm_node_node_id,
+ NULL,
+ },
+};
+
+/* *** Update Port TM Node Parent *** */
+struct cmd_set_port_tm_node_parent_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t node;
+ cmdline_fixed_string_t parent;
+ uint16_t port_id;
+ uint32_t node_id;
+ uint32_t parent_id;
+ uint32_t priority;
+ uint32_t weight;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_set =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_node_parent_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_node_parent_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_node_parent_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_node_parent_result, node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_parent =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_set_port_tm_node_parent_result, parent, "parent");
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_set_port_tm_node_parent_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_node_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_set_port_tm_node_parent_result, node_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_parent_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+ parent_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_priority =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+ priority, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_weight =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+ weight, UINT32);
+
+static void cmd_set_port_tm_node_parent_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_set_port_tm_node_parent_result *res = parsed_result;
+ struct rte_tm_error error;
+ uint32_t node_id = res->node_id;
+ uint32_t parent_id = res->parent_id;
+ uint32_t priority = res->priority;
+ uint32_t weight = res->weight;
+ portid_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ /* Port status */
+ if (!port_is_started(port_id)) {
+ printf(" Port %u not started (error)\n", port_id);
+ return;
+ }
+
+ ret = rte_tm_node_parent_update(port_id, node_id,
+ parent_id, priority, weight, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_parent = {
+ .f = cmd_set_port_tm_node_parent_parsed,
+ .data = NULL,
+ .help_str = "Set port tm node parent",
+ .tokens = {
+ (void *)&cmd_set_port_tm_node_parent_set,
+ (void *)&cmd_set_port_tm_node_parent_port,
+ (void *)&cmd_set_port_tm_node_parent_tm,
+ (void *)&cmd_set_port_tm_node_parent_node,
+ (void *)&cmd_set_port_tm_node_parent_parent,
+ (void *)&cmd_set_port_tm_node_parent_port_id,
+ (void *)&cmd_set_port_tm_node_parent_node_id,
+ (void *)&cmd_set_port_tm_node_parent_parent_id,
+ (void *)&cmd_set_port_tm_node_parent_priority,
+ (void *)&cmd_set_port_tm_node_parent_weight,
+ NULL,
+ },
+};
+
+/* *** Suspend Port TM Node *** */
+struct cmd_suspend_port_tm_node_result {
+ cmdline_fixed_string_t suspend;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t node;
+ uint16_t port_id;
+ uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_suspend_port_tm_node_suspend =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_suspend_port_tm_node_result, suspend, "suspend");
+cmdline_parse_token_string_t cmd_suspend_port_tm_node_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_suspend_port_tm_node_result, port, "port");
+cmdline_parse_token_string_t cmd_suspend_port_tm_node_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_suspend_port_tm_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_suspend_port_tm_node_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_suspend_port_tm_node_result, node, "node");
+cmdline_parse_token_num_t cmd_suspend_port_tm_node_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_suspend_port_tm_node_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_suspend_port_tm_node_node_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_suspend_port_tm_node_result, node_id, UINT32);
+
+static void cmd_suspend_port_tm_node_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_suspend_port_tm_node_result *res = parsed_result;
+ struct rte_tm_error error;
+ uint32_t node_id = res->node_id;
+ portid_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ ret = rte_tm_node_suspend(port_id, node_id, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_suspend_port_tm_node = {
+ .f = cmd_suspend_port_tm_node_parsed,
+ .data = NULL,
+ .help_str = "Suspend port tm node",
+ .tokens = {
+ (void *)&cmd_suspend_port_tm_node_suspend,
+ (void *)&cmd_suspend_port_tm_node_port,
+ (void *)&cmd_suspend_port_tm_node_tm,
+ (void *)&cmd_suspend_port_tm_node_node,
+ (void *)&cmd_suspend_port_tm_node_port_id,
+ (void *)&cmd_suspend_port_tm_node_node_id,
+ NULL,
+ },
+};
+
+/* *** Resume Port TM Node *** */
+struct cmd_resume_port_tm_node_result {
+ cmdline_fixed_string_t resume;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t node;
+ uint16_t port_id;
+ uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_resume_port_tm_node_resume =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_resume_port_tm_node_result, resume, "resume");
+cmdline_parse_token_string_t cmd_resume_port_tm_node_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_resume_port_tm_node_result, port, "port");
+cmdline_parse_token_string_t cmd_resume_port_tm_node_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_resume_port_tm_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_resume_port_tm_node_node =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_resume_port_tm_node_result, node, "node");
+cmdline_parse_token_num_t cmd_resume_port_tm_node_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_resume_port_tm_node_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_resume_port_tm_node_node_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_resume_port_tm_node_result, node_id, UINT32);
+
+static void cmd_resume_port_tm_node_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_resume_port_tm_node_result *res = parsed_result;
+ struct rte_tm_error error;
+ uint32_t node_id = res->node_id;
+ portid_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ ret = rte_tm_node_resume(port_id, node_id, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_resume_port_tm_node = {
+ .f = cmd_resume_port_tm_node_parsed,
+ .data = NULL,
+ .help_str = "Resume port tm node",
+ .tokens = {
+ (void *)&cmd_resume_port_tm_node_resume,
+ (void *)&cmd_resume_port_tm_node_port,
+ (void *)&cmd_resume_port_tm_node_tm,
+ (void *)&cmd_resume_port_tm_node_node,
+ (void *)&cmd_resume_port_tm_node_port_id,
+ (void *)&cmd_resume_port_tm_node_node_id,
+ NULL,
+ },
+};
+
+/* *** Port TM Hierarchy Commit *** */
+struct cmd_port_tm_hierarchy_commit_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t hierarchy;
+ cmdline_fixed_string_t commit;
+ uint16_t port_id;
+ cmdline_fixed_string_t clean_on_fail;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_port =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_port_tm_hierarchy_commit_result, port, "port");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_tm =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_port_tm_hierarchy_commit_result, tm, "tm");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_hierarchy =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_port_tm_hierarchy_commit_result,
+ hierarchy, "hierarchy");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_commit =
+ TOKEN_STRING_INITIALIZER(
+ struct cmd_port_tm_hierarchy_commit_result, commit, "commit");
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_port_id =
+ TOKEN_NUM_INITIALIZER(
+ struct cmd_port_tm_hierarchy_commit_result,
+ port_id, UINT16);
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_clean_on_fail =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_hierarchy_commit_result,
+ clean_on_fail, "yes#no");
+
+static void cmd_port_tm_hierarchy_commit_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_port_tm_hierarchy_commit_result *res = parsed_result;
+ struct rte_tm_error error;
+ uint32_t clean_on_fail;
+ portid_t port_id = res->port_id;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ if (strcmp(res->clean_on_fail, "yes") == 0)
+ clean_on_fail = 1;
+ else
+ clean_on_fail = 0;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ ret = rte_tm_hierarchy_commit(port_id, clean_on_fail, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_port_tm_hierarchy_commit = {
+ .f = cmd_port_tm_hierarchy_commit_parsed,
+ .data = NULL,
+ .help_str = "Commit port tm hierarchy",
+ .tokens = {
+ (void *)&cmd_port_tm_hierarchy_commit_port,
+ (void *)&cmd_port_tm_hierarchy_commit_tm,
+ (void *)&cmd_port_tm_hierarchy_commit_hierarchy,
+ (void *)&cmd_port_tm_hierarchy_commit_commit,
+ (void *)&cmd_port_tm_hierarchy_commit_port_id,
+ (void *)&cmd_port_tm_hierarchy_commit_clean_on_fail,
+ NULL,
+ },
+};
+
+/* *** Port TM Mark IP ECN *** */
+struct cmd_port_tm_mark_ip_ecn_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t mark;
+ cmdline_fixed_string_t ip_ecn;
+ uint16_t port_id;
+ uint16_t green;
+ uint16_t yellow;
+ uint16_t red;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_mark_ip_ecn_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_ip_ecn_result,
+ set, "set");
+
+cmdline_parse_token_string_t cmd_port_tm_mark_ip_ecn_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_ip_ecn_result,
+ port, "port");
+
+cmdline_parse_token_string_t cmd_port_tm_mark_ip_ecn_tm =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_ip_ecn_result, tm,
+ "tm");
+
+cmdline_parse_token_string_t cmd_port_tm_mark_ip_ecn_mark =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_ip_ecn_result,
+ mark, "mark");
+
+cmdline_parse_token_string_t cmd_port_tm_mark_ip_ecn_ip_ecn =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_ip_ecn_result,
+ ip_ecn, "ip_ecn");
+cmdline_parse_token_num_t cmd_port_tm_mark_ip_ecn_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_port_tm_mark_ip_ecn_result,
+ port_id, UINT16);
+
+cmdline_parse_token_num_t cmd_port_tm_mark_ip_ecn_green =
+ TOKEN_NUM_INITIALIZER(struct cmd_port_tm_mark_ip_ecn_result,
+ green, UINT16);
+cmdline_parse_token_num_t cmd_port_tm_mark_ip_ecn_yellow =
+ TOKEN_NUM_INITIALIZER(struct cmd_port_tm_mark_ip_ecn_result,
+ yellow, UINT16);
+cmdline_parse_token_num_t cmd_port_tm_mark_ip_ecn_red =
+ TOKEN_NUM_INITIALIZER(struct cmd_port_tm_mark_ip_ecn_result,
+ red, UINT16);
+
+static void cmd_port_tm_mark_ip_ecn_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_port_tm_mark_ip_ecn_result *res = parsed_result;
+ struct rte_tm_error error;
+ portid_t port_id = res->port_id;
+ int green = res->green;
+ int yellow = res->yellow;
+ int red = res->red;
+ int ret;
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ ret = rte_tm_mark_ip_ecn(port_id, green, yellow, red, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_port_tm_mark_ip_ecn = {
+ .f = cmd_port_tm_mark_ip_ecn_parsed,
+ .data = NULL,
+ .help_str = "set port tm mark ip_ecn <port> <green> <yellow> <red>",
+ .tokens = {
+ (void *)&cmd_port_tm_mark_ip_ecn_set,
+ (void *)&cmd_port_tm_mark_ip_ecn_port,
+ (void *)&cmd_port_tm_mark_ip_ecn_tm,
+ (void *)&cmd_port_tm_mark_ip_ecn_mark,
+ (void *)&cmd_port_tm_mark_ip_ecn_ip_ecn,
+ (void *)&cmd_port_tm_mark_ip_ecn_port_id,
+ (void *)&cmd_port_tm_mark_ip_ecn_green,
+ (void *)&cmd_port_tm_mark_ip_ecn_yellow,
+ (void *)&cmd_port_tm_mark_ip_ecn_red,
+ NULL,
+ },
+};
+
+
+/* *** Port TM Mark IP DSCP *** */
+struct cmd_port_tm_mark_ip_dscp_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t mark;
+ cmdline_fixed_string_t ip_dscp;
+ uint16_t port_id;
+ uint16_t green;
+ uint16_t yellow;
+ uint16_t red;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_mark_ip_dscp_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_ip_dscp_result,
+ set, "set");
+
+cmdline_parse_token_string_t cmd_port_tm_mark_ip_dscp_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_ip_dscp_result,
+ port, "port");
+
+cmdline_parse_token_string_t cmd_port_tm_mark_ip_dscp_tm =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_ip_dscp_result, tm,
+ "tm");
+
+cmdline_parse_token_string_t cmd_port_tm_mark_ip_dscp_mark =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_ip_dscp_result,
+ mark, "mark");
+
+cmdline_parse_token_string_t cmd_port_tm_mark_ip_dscp_ip_dscp =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_ip_dscp_result,
+ ip_dscp, "ip_dscp");
+cmdline_parse_token_num_t cmd_port_tm_mark_ip_dscp_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_port_tm_mark_ip_dscp_result,
+ port_id, UINT16);
+
+cmdline_parse_token_num_t cmd_port_tm_mark_ip_dscp_green =
+ TOKEN_NUM_INITIALIZER(struct cmd_port_tm_mark_ip_dscp_result,
+ green, UINT16);
+cmdline_parse_token_num_t cmd_port_tm_mark_ip_dscp_yellow =
+ TOKEN_NUM_INITIALIZER(struct cmd_port_tm_mark_ip_dscp_result,
+ yellow, UINT16);
+cmdline_parse_token_num_t cmd_port_tm_mark_ip_dscp_red =
+ TOKEN_NUM_INITIALIZER(struct cmd_port_tm_mark_ip_dscp_result,
+ red, UINT16);
+
+static void cmd_port_tm_mark_ip_dscp_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_port_tm_mark_ip_dscp_result *res = parsed_result;
+ struct rte_tm_error error;
+ portid_t port_id = res->port_id;
+ int green = res->green;
+ int yellow = res->yellow;
+ int red = res->red;
+ int ret;
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ ret = rte_tm_mark_ip_dscp(port_id, green, yellow, red, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_port_tm_mark_ip_dscp = {
+ .f = cmd_port_tm_mark_ip_dscp_parsed,
+ .data = NULL,
+ .help_str = "set port tm mark ip_dscp <port> <green> <yellow> <red>",
+ .tokens = {
+ (void *)&cmd_port_tm_mark_ip_dscp_set,
+ (void *)&cmd_port_tm_mark_ip_dscp_port,
+ (void *)&cmd_port_tm_mark_ip_dscp_tm,
+ (void *)&cmd_port_tm_mark_ip_dscp_mark,
+ (void *)&cmd_port_tm_mark_ip_dscp_ip_dscp,
+ (void *)&cmd_port_tm_mark_ip_dscp_port_id,
+ (void *)&cmd_port_tm_mark_ip_dscp_green,
+ (void *)&cmd_port_tm_mark_ip_dscp_yellow,
+ (void *)&cmd_port_tm_mark_ip_dscp_red,
+ NULL,
+ },
+};
+
+
+/* *** Port TM Mark VLAN_DEI *** */
+struct cmd_port_tm_mark_vlan_dei_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t tm;
+ cmdline_fixed_string_t mark;
+ cmdline_fixed_string_t vlan_dei;
+ uint16_t port_id;
+ uint16_t green;
+ uint16_t yellow;
+ uint16_t red;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_mark_vlan_dei_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_vlan_dei_result,
+ set, "set");
+
+cmdline_parse_token_string_t cmd_port_tm_mark_vlan_dei_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_vlan_dei_result,
+ port, "port");
+
+cmdline_parse_token_string_t cmd_port_tm_mark_vlan_dei_tm =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_vlan_dei_result, tm,
+ "tm");
+
+cmdline_parse_token_string_t cmd_port_tm_mark_vlan_dei_mark =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_vlan_dei_result,
+ mark, "mark");
+
+cmdline_parse_token_string_t cmd_port_tm_mark_vlan_dei_vlan_dei =
+ TOKEN_STRING_INITIALIZER(struct cmd_port_tm_mark_vlan_dei_result,
+ vlan_dei, "vlan_dei");
+cmdline_parse_token_num_t cmd_port_tm_mark_vlan_dei_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_port_tm_mark_vlan_dei_result,
+ port_id, UINT16);
+
+cmdline_parse_token_num_t cmd_port_tm_mark_vlan_dei_green =
+ TOKEN_NUM_INITIALIZER(struct cmd_port_tm_mark_vlan_dei_result,
+ green, UINT16);
+cmdline_parse_token_num_t cmd_port_tm_mark_vlan_dei_yellow =
+ TOKEN_NUM_INITIALIZER(struct cmd_port_tm_mark_vlan_dei_result,
+ yellow, UINT16);
+cmdline_parse_token_num_t cmd_port_tm_mark_vlan_dei_red =
+ TOKEN_NUM_INITIALIZER(struct cmd_port_tm_mark_vlan_dei_result,
+ red, UINT16);
+
+static void cmd_port_tm_mark_vlan_dei_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_port_tm_mark_vlan_dei_result *res = parsed_result;
+ struct rte_tm_error error;
+ portid_t port_id = res->port_id;
+ int green = res->green;
+ int yellow = res->yellow;
+ int red = res->red;
+ int ret;
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ memset(&error, 0, sizeof(struct rte_tm_error));
+ ret = rte_tm_mark_vlan_dei(port_id, green, yellow, red, &error);
+ if (ret != 0) {
+ print_err_msg(&error);
+ return;
+ }
+}
+
+cmdline_parse_inst_t cmd_port_tm_mark_vlan_dei = {
+ .f = cmd_port_tm_mark_vlan_dei_parsed,
+ .data = NULL,
+ .help_str = "set port tm mark vlan_dei <port> <green> <yellow> <red>",
+ .tokens = {
+ (void *)&cmd_port_tm_mark_vlan_dei_set,
+ (void *)&cmd_port_tm_mark_vlan_dei_port,
+ (void *)&cmd_port_tm_mark_vlan_dei_tm,
+ (void *)&cmd_port_tm_mark_vlan_dei_mark,
+ (void *)&cmd_port_tm_mark_vlan_dei_vlan_dei,
+ (void *)&cmd_port_tm_mark_vlan_dei_port_id,
+ (void *)&cmd_port_tm_mark_vlan_dei_green,
+ (void *)&cmd_port_tm_mark_vlan_dei_yellow,
+ (void *)&cmd_port_tm_mark_vlan_dei_red,
+ NULL,
+ },
+};
diff --git a/src/spdk/dpdk/app/test-pmd/cmdline_tm.h b/src/spdk/dpdk/app/test-pmd/cmdline_tm.h
new file mode 100644
index 000000000..950cb7538
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/cmdline_tm.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation
+ */
+
+#ifndef _CMDLINE_TM_H_
+#define _CMDLINE_TM_H_
+
+ /* Traffic Management CLI */
+extern cmdline_parse_inst_t cmd_show_port_tm_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node;
+extern cmdline_parse_inst_t cmd_add_port_tm_leaf_node;
+extern cmdline_parse_inst_t cmd_del_port_tm_node;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_parent;
+extern cmdline_parse_inst_t cmd_suspend_port_tm_node;
+extern cmdline_parse_inst_t cmd_resume_port_tm_node;
+extern cmdline_parse_inst_t cmd_port_tm_hierarchy_commit;
+extern cmdline_parse_inst_t cmd_port_tm_mark_vlan_dei;
+extern cmdline_parse_inst_t cmd_port_tm_mark_ip_ecn;
+extern cmdline_parse_inst_t cmd_port_tm_mark_ip_dscp;
+
+#endif /* _CMDLINE_TM_H_ */
diff --git a/src/spdk/dpdk/app/test-pmd/config.c b/src/spdk/dpdk/app/test-pmd/config.c
new file mode 100644
index 000000000..5381207cc
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/config.c
@@ -0,0 +1,4318 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation.
+ * Copyright 2013-2014 6WIND S.A.
+ */
+
+#include <stdarg.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_debug.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_string_fns.h>
+#include <rte_cycles.h>
+#include <rte_flow.h>
+#include <rte_errno.h>
+#ifdef RTE_LIBRTE_IXGBE_PMD
+#include <rte_pmd_ixgbe.h>
+#endif
+#ifdef RTE_LIBRTE_I40E_PMD
+#include <rte_pmd_i40e.h>
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+#include <rte_pmd_bnxt.h>
+#endif
+#include <rte_gro.h>
+
+#include "testpmd.h"
+
+#define ETHDEV_FWVERS_LEN 32
+
+static char *flowtype_to_str(uint16_t flow_type);
+
+static const struct {
+ enum tx_pkt_split split;
+ const char *name;
+} tx_split_name[] = {
+ {
+ .split = TX_PKT_SPLIT_OFF,
+ .name = "off",
+ },
+ {
+ .split = TX_PKT_SPLIT_ON,
+ .name = "on",
+ },
+ {
+ .split = TX_PKT_SPLIT_RND,
+ .name = "rand",
+ },
+};
+
+const struct rss_type_info rss_type_table[] = {
+ { "all", ETH_RSS_ETH | ETH_RSS_VLAN | ETH_RSS_IP | ETH_RSS_TCP |
+ ETH_RSS_UDP | ETH_RSS_SCTP | ETH_RSS_L2_PAYLOAD |
+ ETH_RSS_L2TPV3 | ETH_RSS_ESP | ETH_RSS_AH | ETH_RSS_PFCP},
+ { "none", 0 },
+ { "eth", ETH_RSS_ETH },
+ { "l2-src-only", ETH_RSS_L2_SRC_ONLY },
+ { "l2-dst-only", ETH_RSS_L2_DST_ONLY },
+ { "vlan", ETH_RSS_VLAN },
+ { "s-vlan", ETH_RSS_S_VLAN },
+ { "c-vlan", ETH_RSS_C_VLAN },
+ { "ipv4", ETH_RSS_IPV4 },
+ { "ipv4-frag", ETH_RSS_FRAG_IPV4 },
+ { "ipv4-tcp", ETH_RSS_NONFRAG_IPV4_TCP },
+ { "ipv4-udp", ETH_RSS_NONFRAG_IPV4_UDP },
+ { "ipv4-sctp", ETH_RSS_NONFRAG_IPV4_SCTP },
+ { "ipv4-other", ETH_RSS_NONFRAG_IPV4_OTHER },
+ { "ipv6", ETH_RSS_IPV6 },
+ { "ipv6-frag", ETH_RSS_FRAG_IPV6 },
+ { "ipv6-tcp", ETH_RSS_NONFRAG_IPV6_TCP },
+ { "ipv6-udp", ETH_RSS_NONFRAG_IPV6_UDP },
+ { "ipv6-sctp", ETH_RSS_NONFRAG_IPV6_SCTP },
+ { "ipv6-other", ETH_RSS_NONFRAG_IPV6_OTHER },
+ { "l2-payload", ETH_RSS_L2_PAYLOAD },
+ { "ipv6-ex", ETH_RSS_IPV6_EX },
+ { "ipv6-tcp-ex", ETH_RSS_IPV6_TCP_EX },
+ { "ipv6-udp-ex", ETH_RSS_IPV6_UDP_EX },
+ { "port", ETH_RSS_PORT },
+ { "vxlan", ETH_RSS_VXLAN },
+ { "geneve", ETH_RSS_GENEVE },
+ { "nvgre", ETH_RSS_NVGRE },
+ { "ip", ETH_RSS_IP },
+ { "udp", ETH_RSS_UDP },
+ { "tcp", ETH_RSS_TCP },
+ { "sctp", ETH_RSS_SCTP },
+ { "tunnel", ETH_RSS_TUNNEL },
+ { "l3-src-only", ETH_RSS_L3_SRC_ONLY },
+ { "l3-dst-only", ETH_RSS_L3_DST_ONLY },
+ { "l4-src-only", ETH_RSS_L4_SRC_ONLY },
+ { "l4-dst-only", ETH_RSS_L4_DST_ONLY },
+ { "esp", ETH_RSS_ESP },
+ { "ah", ETH_RSS_AH },
+ { "l2tpv3", ETH_RSS_L2TPV3 },
+ { "pfcp", ETH_RSS_PFCP },
+ { NULL, 0 },
+};
+
+static void
+print_ethaddr(const char *name, 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);
+}
+
+void
+nic_stats_display(portid_t port_id)
+{
+ static uint64_t prev_pkts_rx[RTE_MAX_ETHPORTS];
+ static uint64_t prev_pkts_tx[RTE_MAX_ETHPORTS];
+ static uint64_t prev_bytes_rx[RTE_MAX_ETHPORTS];
+ static uint64_t prev_bytes_tx[RTE_MAX_ETHPORTS];
+ static uint64_t prev_cycles[RTE_MAX_ETHPORTS];
+ uint64_t diff_pkts_rx, diff_pkts_tx, diff_bytes_rx, diff_bytes_tx,
+ diff_cycles;
+ uint64_t mpps_rx, mpps_tx, mbps_rx, mbps_tx;
+ struct rte_eth_stats stats;
+ struct rte_port *port = &ports[port_id];
+ uint8_t i;
+
+ static const char *nic_stats_border = "########################";
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+ print_valid_ports();
+ return;
+ }
+ rte_eth_stats_get(port_id, &stats);
+ printf("\n %s NIC statistics for port %-2d %s\n",
+ nic_stats_border, port_id, nic_stats_border);
+
+ if ((!port->rx_queue_stats_mapping_enabled) && (!port->tx_queue_stats_mapping_enabled)) {
+ printf(" RX-packets: %-10"PRIu64" RX-missed: %-10"PRIu64" RX-bytes: "
+ "%-"PRIu64"\n",
+ stats.ipackets, stats.imissed, stats.ibytes);
+ printf(" RX-errors: %-"PRIu64"\n", stats.ierrors);
+ printf(" RX-nombuf: %-10"PRIu64"\n",
+ stats.rx_nombuf);
+ printf(" TX-packets: %-10"PRIu64" TX-errors: %-10"PRIu64" TX-bytes: "
+ "%-"PRIu64"\n",
+ stats.opackets, stats.oerrors, stats.obytes);
+ }
+ else {
+ printf(" RX-packets: %10"PRIu64" RX-errors: %10"PRIu64
+ " RX-bytes: %10"PRIu64"\n",
+ stats.ipackets, stats.ierrors, stats.ibytes);
+ printf(" RX-errors: %10"PRIu64"\n", stats.ierrors);
+ printf(" RX-nombuf: %10"PRIu64"\n",
+ stats.rx_nombuf);
+ printf(" TX-packets: %10"PRIu64" TX-errors: %10"PRIu64
+ " TX-bytes: %10"PRIu64"\n",
+ stats.opackets, stats.oerrors, stats.obytes);
+ }
+
+ if (port->rx_queue_stats_mapping_enabled) {
+ printf("\n");
+ for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) {
+ printf(" Stats reg %2d RX-packets: %10"PRIu64
+ " RX-errors: %10"PRIu64
+ " RX-bytes: %10"PRIu64"\n",
+ i, stats.q_ipackets[i], stats.q_errors[i], stats.q_ibytes[i]);
+ }
+ }
+ if (port->tx_queue_stats_mapping_enabled) {
+ printf("\n");
+ for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) {
+ printf(" Stats reg %2d TX-packets: %10"PRIu64
+ " TX-bytes: %10"PRIu64"\n",
+ i, stats.q_opackets[i], stats.q_obytes[i]);
+ }
+ }
+
+ diff_cycles = prev_cycles[port_id];
+ prev_cycles[port_id] = rte_rdtsc();
+ if (diff_cycles > 0)
+ diff_cycles = prev_cycles[port_id] - diff_cycles;
+
+ diff_pkts_rx = (stats.ipackets > prev_pkts_rx[port_id]) ?
+ (stats.ipackets - prev_pkts_rx[port_id]) : 0;
+ diff_pkts_tx = (stats.opackets > prev_pkts_tx[port_id]) ?
+ (stats.opackets - prev_pkts_tx[port_id]) : 0;
+ prev_pkts_rx[port_id] = stats.ipackets;
+ prev_pkts_tx[port_id] = stats.opackets;
+ mpps_rx = diff_cycles > 0 ?
+ diff_pkts_rx * rte_get_tsc_hz() / diff_cycles : 0;
+ mpps_tx = diff_cycles > 0 ?
+ diff_pkts_tx * rte_get_tsc_hz() / diff_cycles : 0;
+
+ diff_bytes_rx = (stats.ibytes > prev_bytes_rx[port_id]) ?
+ (stats.ibytes - prev_bytes_rx[port_id]) : 0;
+ diff_bytes_tx = (stats.obytes > prev_bytes_tx[port_id]) ?
+ (stats.obytes - prev_bytes_tx[port_id]) : 0;
+ prev_bytes_rx[port_id] = stats.ibytes;
+ prev_bytes_tx[port_id] = stats.obytes;
+ mbps_rx = diff_cycles > 0 ?
+ diff_bytes_rx * rte_get_tsc_hz() / diff_cycles : 0;
+ mbps_tx = diff_cycles > 0 ?
+ diff_bytes_tx * rte_get_tsc_hz() / diff_cycles : 0;
+
+ printf("\n Throughput (since last show)\n");
+ printf(" Rx-pps: %12"PRIu64" Rx-bps: %12"PRIu64"\n Tx-pps: %12"
+ PRIu64" Tx-bps: %12"PRIu64"\n", mpps_rx, mbps_rx * 8,
+ mpps_tx, mbps_tx * 8);
+
+ printf(" %s############################%s\n",
+ nic_stats_border, nic_stats_border);
+}
+
+void
+nic_stats_clear(portid_t port_id)
+{
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+ print_valid_ports();
+ return;
+ }
+
+ ret = rte_eth_stats_reset(port_id);
+ if (ret != 0) {
+ printf("%s: Error: failed to reset stats (port %u): %s",
+ __func__, port_id, strerror(ret));
+ return;
+ }
+
+ ret = rte_eth_stats_get(port_id, &ports[port_id].stats);
+ if (ret != 0) {
+ printf("%s: Error: failed to get stats (port %u): %s",
+ __func__, port_id, strerror(ret));
+ return;
+ }
+ printf("\n NIC statistics for port %d cleared\n", port_id);
+}
+
+void
+nic_xstats_display(portid_t port_id)
+{
+ struct rte_eth_xstat *xstats;
+ int cnt_xstats, idx_xstat;
+ struct rte_eth_xstat_name *xstats_names;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+ print_valid_ports();
+ return;
+ }
+ printf("###### NIC extended statistics for port %-2d\n", port_id);
+ if (!rte_eth_dev_is_valid_port(port_id)) {
+ printf("Error: Invalid port number %i\n", port_id);
+ return;
+ }
+
+ /* Get count */
+ cnt_xstats = rte_eth_xstats_get_names(port_id, NULL, 0);
+ if (cnt_xstats < 0) {
+ printf("Error: Cannot get count of xstats\n");
+ return;
+ }
+
+ /* Get id-name lookup table */
+ xstats_names = malloc(sizeof(struct rte_eth_xstat_name) * cnt_xstats);
+ if (xstats_names == NULL) {
+ printf("Cannot allocate memory for xstats lookup\n");
+ return;
+ }
+ if (cnt_xstats != rte_eth_xstats_get_names(
+ port_id, xstats_names, cnt_xstats)) {
+ printf("Error: Cannot get xstats lookup\n");
+ free(xstats_names);
+ return;
+ }
+
+ /* Get stats themselves */
+ xstats = malloc(sizeof(struct rte_eth_xstat) * cnt_xstats);
+ if (xstats == NULL) {
+ printf("Cannot allocate memory for xstats\n");
+ free(xstats_names);
+ return;
+ }
+ if (cnt_xstats != rte_eth_xstats_get(port_id, xstats, cnt_xstats)) {
+ printf("Error: Unable to get xstats\n");
+ free(xstats_names);
+ free(xstats);
+ return;
+ }
+
+ /* Display xstats */
+ for (idx_xstat = 0; idx_xstat < cnt_xstats; idx_xstat++) {
+ if (xstats_hide_zero && !xstats[idx_xstat].value)
+ continue;
+ printf("%s: %"PRIu64"\n",
+ xstats_names[idx_xstat].name,
+ xstats[idx_xstat].value);
+ }
+ free(xstats_names);
+ free(xstats);
+}
+
+void
+nic_xstats_clear(portid_t port_id)
+{
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+ print_valid_ports();
+ return;
+ }
+
+ ret = rte_eth_xstats_reset(port_id);
+ if (ret != 0) {
+ printf("%s: Error: failed to reset xstats (port %u): %s",
+ __func__, port_id, strerror(ret));
+ return;
+ }
+
+ ret = rte_eth_stats_get(port_id, &ports[port_id].stats);
+ if (ret != 0) {
+ printf("%s: Error: failed to get stats (port %u): %s",
+ __func__, port_id, strerror(ret));
+ return;
+ }
+}
+
+void
+nic_stats_mapping_display(portid_t port_id)
+{
+ struct rte_port *port = &ports[port_id];
+ uint16_t i;
+
+ static const char *nic_stats_mapping_border = "########################";
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+ print_valid_ports();
+ return;
+ }
+
+ if ((!port->rx_queue_stats_mapping_enabled) && (!port->tx_queue_stats_mapping_enabled)) {
+ printf("Port id %d - either does not support queue statistic mapping or"
+ " no queue statistic mapping set\n", port_id);
+ return;
+ }
+
+ printf("\n %s NIC statistics mapping for port %-2d %s\n",
+ nic_stats_mapping_border, port_id, nic_stats_mapping_border);
+
+ if (port->rx_queue_stats_mapping_enabled) {
+ for (i = 0; i < nb_rx_queue_stats_mappings; i++) {
+ if (rx_queue_stats_mappings[i].port_id == port_id) {
+ printf(" RX-queue %2d mapped to Stats Reg %2d\n",
+ rx_queue_stats_mappings[i].queue_id,
+ rx_queue_stats_mappings[i].stats_counter_id);
+ }
+ }
+ printf("\n");
+ }
+
+
+ if (port->tx_queue_stats_mapping_enabled) {
+ for (i = 0; i < nb_tx_queue_stats_mappings; i++) {
+ if (tx_queue_stats_mappings[i].port_id == port_id) {
+ printf(" TX-queue %2d mapped to Stats Reg %2d\n",
+ tx_queue_stats_mappings[i].queue_id,
+ tx_queue_stats_mappings[i].stats_counter_id);
+ }
+ }
+ }
+
+ printf(" %s####################################%s\n",
+ nic_stats_mapping_border, nic_stats_mapping_border);
+}
+
+void
+rx_queue_infos_display(portid_t port_id, uint16_t queue_id)
+{
+ struct rte_eth_burst_mode mode;
+ struct rte_eth_rxq_info qinfo;
+ int32_t rc;
+ static const char *info_border = "*********************";
+
+ rc = rte_eth_rx_queue_info_get(port_id, queue_id, &qinfo);
+ if (rc != 0) {
+ printf("Failed to retrieve information for port: %u, "
+ "RX queue: %hu\nerror desc: %s(%d)\n",
+ port_id, queue_id, strerror(-rc), rc);
+ return;
+ }
+
+ printf("\n%s Infos for port %-2u, RX queue %-2u %s",
+ info_border, port_id, queue_id, info_border);
+
+ printf("\nMempool: %s", (qinfo.mp == NULL) ? "NULL" : qinfo.mp->name);
+ printf("\nRX prefetch threshold: %hhu", qinfo.conf.rx_thresh.pthresh);
+ printf("\nRX host threshold: %hhu", qinfo.conf.rx_thresh.hthresh);
+ printf("\nRX writeback threshold: %hhu", qinfo.conf.rx_thresh.wthresh);
+ printf("\nRX free threshold: %hu", qinfo.conf.rx_free_thresh);
+ printf("\nRX drop packets: %s",
+ (qinfo.conf.rx_drop_en != 0) ? "on" : "off");
+ printf("\nRX deferred start: %s",
+ (qinfo.conf.rx_deferred_start != 0) ? "on" : "off");
+ printf("\nRX scattered packets: %s",
+ (qinfo.scattered_rx != 0) ? "on" : "off");
+ printf("\nNumber of RXDs: %hu", qinfo.nb_desc);
+
+ if (rte_eth_rx_burst_mode_get(port_id, queue_id, &mode) == 0)
+ printf("\nBurst mode: %s%s",
+ mode.info,
+ mode.flags & RTE_ETH_BURST_FLAG_PER_QUEUE ?
+ " (per queue)" : "");
+
+ printf("\n");
+}
+
+void
+tx_queue_infos_display(portid_t port_id, uint16_t queue_id)
+{
+ struct rte_eth_burst_mode mode;
+ struct rte_eth_txq_info qinfo;
+ int32_t rc;
+ static const char *info_border = "*********************";
+
+ rc = rte_eth_tx_queue_info_get(port_id, queue_id, &qinfo);
+ if (rc != 0) {
+ printf("Failed to retrieve information for port: %u, "
+ "TX queue: %hu\nerror desc: %s(%d)\n",
+ port_id, queue_id, strerror(-rc), rc);
+ return;
+ }
+
+ printf("\n%s Infos for port %-2u, TX queue %-2u %s",
+ info_border, port_id, queue_id, info_border);
+
+ printf("\nTX prefetch threshold: %hhu", qinfo.conf.tx_thresh.pthresh);
+ printf("\nTX host threshold: %hhu", qinfo.conf.tx_thresh.hthresh);
+ printf("\nTX writeback threshold: %hhu", qinfo.conf.tx_thresh.wthresh);
+ printf("\nTX RS threshold: %hu", qinfo.conf.tx_rs_thresh);
+ printf("\nTX free threshold: %hu", qinfo.conf.tx_free_thresh);
+ printf("\nTX deferred start: %s",
+ (qinfo.conf.tx_deferred_start != 0) ? "on" : "off");
+ printf("\nNumber of TXDs: %hu", qinfo.nb_desc);
+
+ if (rte_eth_tx_burst_mode_get(port_id, queue_id, &mode) == 0)
+ printf("\nBurst mode: %s%s",
+ mode.info,
+ mode.flags & RTE_ETH_BURST_FLAG_PER_QUEUE ?
+ " (per queue)" : "");
+
+ printf("\n");
+}
+
+static int bus_match_all(const struct rte_bus *bus, const void *data)
+{
+ RTE_SET_USED(bus);
+ RTE_SET_USED(data);
+ return 0;
+}
+
+void
+device_infos_display(const char *identifier)
+{
+ static const char *info_border = "*********************";
+ struct rte_bus *start = NULL, *next;
+ struct rte_dev_iterator dev_iter;
+ char name[RTE_ETH_NAME_MAX_LEN];
+ struct rte_ether_addr mac_addr;
+ struct rte_device *dev;
+ struct rte_devargs da;
+ portid_t port_id;
+ char devstr[128];
+
+ memset(&da, 0, sizeof(da));
+ if (!identifier)
+ goto skip_parse;
+
+ if (rte_devargs_parsef(&da, "%s", identifier)) {
+ printf("cannot parse identifier\n");
+ if (da.args)
+ free(da.args);
+ return;
+ }
+
+skip_parse:
+ while ((next = rte_bus_find(start, bus_match_all, NULL)) != NULL) {
+
+ start = next;
+ if (identifier && da.bus != next)
+ continue;
+
+ /* Skip buses that don't have iterate method */
+ if (!next->dev_iterate)
+ continue;
+
+ snprintf(devstr, sizeof(devstr), "bus=%s", next->name);
+ RTE_DEV_FOREACH(dev, devstr, &dev_iter) {
+
+ if (!dev->driver)
+ continue;
+ /* Check for matching device if identifier is present */
+ if (identifier &&
+ strncmp(da.name, dev->name, strlen(dev->name)))
+ continue;
+ printf("\n%s Infos for device %s %s\n",
+ info_border, dev->name, info_border);
+ printf("Bus name: %s", dev->bus->name);
+ printf("\nDriver name: %s", dev->driver->name);
+ printf("\nDevargs: %s",
+ dev->devargs ? dev->devargs->args : "");
+ printf("\nConnect to socket: %d", dev->numa_node);
+ printf("\n");
+
+ /* List ports with matching device name */
+ RTE_ETH_FOREACH_DEV_OF(port_id, dev) {
+ printf("\n\tPort id: %-2d", port_id);
+ if (eth_macaddr_get_print_err(port_id,
+ &mac_addr) == 0)
+ print_ethaddr("\n\tMAC address: ",
+ &mac_addr);
+ rte_eth_dev_get_name_by_port(port_id, name);
+ printf("\n\tDevice name: %s", name);
+ printf("\n");
+ }
+ }
+ };
+}
+
+void
+port_infos_display(portid_t port_id)
+{
+ struct rte_port *port;
+ struct rte_ether_addr mac_addr;
+ struct rte_eth_link link;
+ struct rte_eth_dev_info dev_info;
+ int vlan_offload;
+ struct rte_mempool * mp;
+ static const char *info_border = "*********************";
+ uint16_t mtu;
+ char name[RTE_ETH_NAME_MAX_LEN];
+ int ret;
+ char fw_version[ETHDEV_FWVERS_LEN];
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+ print_valid_ports();
+ return;
+ }
+ port = &ports[port_id];
+ ret = eth_link_get_nowait_print_err(port_id, &link);
+ if (ret < 0)
+ return;
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ printf("\n%s Infos for port %-2d %s\n",
+ info_border, port_id, info_border);
+ if (eth_macaddr_get_print_err(port_id, &mac_addr) == 0)
+ print_ethaddr("MAC address: ", &mac_addr);
+ rte_eth_dev_get_name_by_port(port_id, name);
+ printf("\nDevice name: %s", name);
+ printf("\nDriver name: %s", dev_info.driver_name);
+
+ if (rte_eth_dev_fw_version_get(port_id, fw_version,
+ ETHDEV_FWVERS_LEN) == 0)
+ printf("\nFirmware-version: %s", fw_version);
+ else
+ printf("\nFirmware-version: %s", "not available");
+
+ if (dev_info.device->devargs && dev_info.device->devargs->args)
+ printf("\nDevargs: %s", dev_info.device->devargs->args);
+ printf("\nConnect to socket: %u", port->socket_id);
+
+ if (port_numa[port_id] != NUMA_NO_CONFIG) {
+ mp = mbuf_pool_find(port_numa[port_id]);
+ if (mp)
+ printf("\nmemory allocation on the socket: %d",
+ port_numa[port_id]);
+ } else
+ printf("\nmemory allocation on the socket: %u",port->socket_id);
+
+ printf("\nLink status: %s\n", (link.link_status) ? ("up") : ("down"));
+ printf("Link speed: %u Mbps\n", (unsigned) link.link_speed);
+ printf("Link duplex: %s\n", (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+ ("full-duplex") : ("half-duplex"));
+
+ if (!rte_eth_dev_get_mtu(port_id, &mtu))
+ printf("MTU: %u\n", mtu);
+
+ printf("Promiscuous mode: %s\n",
+ rte_eth_promiscuous_get(port_id) ? "enabled" : "disabled");
+ printf("Allmulticast mode: %s\n",
+ rte_eth_allmulticast_get(port_id) ? "enabled" : "disabled");
+ printf("Maximum number of MAC addresses: %u\n",
+ (unsigned int)(port->dev_info.max_mac_addrs));
+ printf("Maximum number of MAC addresses of hash filtering: %u\n",
+ (unsigned int)(port->dev_info.max_hash_mac_addrs));
+
+ vlan_offload = rte_eth_dev_get_vlan_offload(port_id);
+ if (vlan_offload >= 0){
+ printf("VLAN offload: \n");
+ if (vlan_offload & ETH_VLAN_STRIP_OFFLOAD)
+ printf(" strip on, ");
+ else
+ printf(" strip off, ");
+
+ if (vlan_offload & ETH_VLAN_FILTER_OFFLOAD)
+ printf("filter on, ");
+ else
+ printf("filter off, ");
+
+ if (vlan_offload & ETH_VLAN_EXTEND_OFFLOAD)
+ printf("extend on, ");
+ else
+ printf("extend off, ");
+
+ if (vlan_offload & ETH_QINQ_STRIP_OFFLOAD)
+ printf("qinq strip on\n");
+ else
+ printf("qinq strip off\n");
+ }
+
+ if (dev_info.hash_key_size > 0)
+ printf("Hash key size in bytes: %u\n", dev_info.hash_key_size);
+ if (dev_info.reta_size > 0)
+ printf("Redirection table size: %u\n", dev_info.reta_size);
+ if (!dev_info.flow_type_rss_offloads)
+ printf("No RSS offload flow type is supported.\n");
+ else {
+ uint16_t i;
+ char *p;
+
+ printf("Supported RSS offload flow types:\n");
+ for (i = RTE_ETH_FLOW_UNKNOWN + 1;
+ i < sizeof(dev_info.flow_type_rss_offloads) * CHAR_BIT; i++) {
+ if (!(dev_info.flow_type_rss_offloads & (1ULL << i)))
+ continue;
+ p = flowtype_to_str(i);
+ if (p)
+ printf(" %s\n", p);
+ else
+ printf(" user defined %d\n", i);
+ }
+ }
+
+ printf("Minimum size of RX buffer: %u\n", dev_info.min_rx_bufsize);
+ printf("Maximum configurable length of RX packet: %u\n",
+ dev_info.max_rx_pktlen);
+ printf("Maximum configurable size of LRO aggregated packet: %u\n",
+ dev_info.max_lro_pkt_size);
+ if (dev_info.max_vfs)
+ printf("Maximum number of VFs: %u\n", dev_info.max_vfs);
+ if (dev_info.max_vmdq_pools)
+ printf("Maximum number of VMDq pools: %u\n",
+ dev_info.max_vmdq_pools);
+
+ printf("Current number of RX queues: %u\n", dev_info.nb_rx_queues);
+ printf("Max possible RX queues: %u\n", dev_info.max_rx_queues);
+ printf("Max possible number of RXDs per queue: %hu\n",
+ dev_info.rx_desc_lim.nb_max);
+ printf("Min possible number of RXDs per queue: %hu\n",
+ dev_info.rx_desc_lim.nb_min);
+ printf("RXDs number alignment: %hu\n", dev_info.rx_desc_lim.nb_align);
+
+ printf("Current number of TX queues: %u\n", dev_info.nb_tx_queues);
+ printf("Max possible TX queues: %u\n", dev_info.max_tx_queues);
+ printf("Max possible number of TXDs per queue: %hu\n",
+ dev_info.tx_desc_lim.nb_max);
+ printf("Min possible number of TXDs per queue: %hu\n",
+ dev_info.tx_desc_lim.nb_min);
+ printf("TXDs number alignment: %hu\n", dev_info.tx_desc_lim.nb_align);
+ printf("Max segment number per packet: %hu\n",
+ dev_info.tx_desc_lim.nb_seg_max);
+ printf("Max segment number per MTU/TSO: %hu\n",
+ dev_info.tx_desc_lim.nb_mtu_seg_max);
+
+ /* Show switch info only if valid switch domain and port id is set */
+ if (dev_info.switch_info.domain_id !=
+ RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID) {
+ if (dev_info.switch_info.name)
+ printf("Switch name: %s\n", dev_info.switch_info.name);
+
+ printf("Switch domain Id: %u\n",
+ dev_info.switch_info.domain_id);
+ printf("Switch Port Id: %u\n",
+ dev_info.switch_info.port_id);
+ }
+}
+
+void
+port_summary_header_display(void)
+{
+ uint16_t port_number;
+
+ port_number = rte_eth_dev_count_avail();
+ printf("Number of available ports: %i\n", port_number);
+ printf("%-4s %-17s %-12s %-14s %-8s %s\n", "Port", "MAC Address", "Name",
+ "Driver", "Status", "Link");
+}
+
+void
+port_summary_display(portid_t port_id)
+{
+ struct rte_ether_addr mac_addr;
+ struct rte_eth_link link;
+ struct rte_eth_dev_info dev_info;
+ char name[RTE_ETH_NAME_MAX_LEN];
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+ print_valid_ports();
+ return;
+ }
+
+ ret = eth_link_get_nowait_print_err(port_id, &link);
+ if (ret < 0)
+ return;
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ rte_eth_dev_get_name_by_port(port_id, name);
+ ret = eth_macaddr_get_print_err(port_id, &mac_addr);
+ if (ret != 0)
+ return;
+
+ printf("%-4d %02X:%02X:%02X:%02X:%02X:%02X %-12s %-14s %-8s %uMbps\n",
+ port_id, mac_addr.addr_bytes[0], mac_addr.addr_bytes[1],
+ mac_addr.addr_bytes[2], mac_addr.addr_bytes[3],
+ mac_addr.addr_bytes[4], mac_addr.addr_bytes[5], name,
+ dev_info.driver_name, (link.link_status) ? ("up") : ("down"),
+ (unsigned int) link.link_speed);
+}
+
+void
+port_offload_cap_display(portid_t port_id)
+{
+ struct rte_eth_dev_info dev_info;
+ static const char *info_border = "************";
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ printf("\n%s Port %d supported offload features: %s\n",
+ info_border, port_id, info_border);
+
+ if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_VLAN_STRIP) {
+ printf("VLAN stripped: ");
+ if (ports[port_id].dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_VLAN_STRIP)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_QINQ_STRIP) {
+ printf("Double VLANs stripped: ");
+ if (ports[port_id].dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_QINQ_STRIP)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_IPV4_CKSUM) {
+ printf("RX IPv4 checksum: ");
+ if (ports[port_id].dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_IPV4_CKSUM)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_UDP_CKSUM) {
+ printf("RX UDP checksum: ");
+ if (ports[port_id].dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_UDP_CKSUM)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_TCP_CKSUM) {
+ printf("RX TCP checksum: ");
+ if (ports[port_id].dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_TCP_CKSUM)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_SCTP_CKSUM) {
+ printf("RX SCTP checksum: ");
+ if (ports[port_id].dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_SCTP_CKSUM)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM) {
+ printf("RX Outer IPv4 checksum: ");
+ if (ports[port_id].dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_OUTER_UDP_CKSUM) {
+ printf("RX Outer UDP checksum: ");
+ if (ports[port_id].dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_OUTER_UDP_CKSUM)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_TCP_LRO) {
+ printf("Large receive offload: ");
+ if (ports[port_id].dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_TCP_LRO)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_TIMESTAMP) {
+ printf("HW timestamp: ");
+ if (ports[port_id].dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_TIMESTAMP)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_KEEP_CRC) {
+ printf("Rx Keep CRC: ");
+ if (ports[port_id].dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_KEEP_CRC)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_SECURITY) {
+ printf("RX offload security: ");
+ if (ports[port_id].dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_SECURITY)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_VLAN_INSERT) {
+ printf("VLAN insert: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_VLAN_INSERT)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_QINQ_INSERT) {
+ printf("Double VLANs insert: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_QINQ_INSERT)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_IPV4_CKSUM) {
+ printf("TX IPv4 checksum: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_IPV4_CKSUM)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_UDP_CKSUM) {
+ printf("TX UDP checksum: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_UDP_CKSUM)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_TCP_CKSUM) {
+ printf("TX TCP checksum: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_TCP_CKSUM)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_SCTP_CKSUM) {
+ printf("TX SCTP checksum: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_SCTP_CKSUM)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM) {
+ printf("TX Outer IPv4 checksum: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_TCP_TSO) {
+ printf("TX TCP segmentation: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_TCP_TSO)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_UDP_TSO) {
+ printf("TX UDP segmentation: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_UDP_TSO)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_VXLAN_TNL_TSO) {
+ printf("TSO for VXLAN tunnel packet: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_VXLAN_TNL_TSO)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_GRE_TNL_TSO) {
+ printf("TSO for GRE tunnel packet: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_GRE_TNL_TSO)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_IPIP_TNL_TSO) {
+ printf("TSO for IPIP tunnel packet: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_IPIP_TNL_TSO)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_GENEVE_TNL_TSO) {
+ printf("TSO for GENEVE tunnel packet: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_GENEVE_TNL_TSO)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_IP_TNL_TSO) {
+ printf("IP tunnel TSO: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_IP_TNL_TSO)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_UDP_TNL_TSO) {
+ printf("UDP tunnel TSO: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_UDP_TNL_TSO)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_OUTER_UDP_CKSUM) {
+ printf("TX Outer UDP checksum: ");
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_OUTER_UDP_CKSUM)
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+
+}
+
+int
+port_id_is_invalid(portid_t port_id, enum print_warning warning)
+{
+ uint16_t pid;
+
+ if (port_id == (portid_t)RTE_PORT_ALL)
+ return 0;
+
+ RTE_ETH_FOREACH_DEV(pid)
+ if (port_id == pid)
+ return 0;
+
+ if (warning == ENABLED_WARN)
+ printf("Invalid port %d\n", port_id);
+
+ return 1;
+}
+
+void print_valid_ports(void)
+{
+ portid_t pid;
+
+ printf("The valid ports array is [");
+ RTE_ETH_FOREACH_DEV(pid) {
+ printf(" %d", pid);
+ }
+ printf(" ]\n");
+}
+
+static int
+vlan_id_is_invalid(uint16_t vlan_id)
+{
+ if (vlan_id < 4096)
+ return 0;
+ printf("Invalid vlan_id %d (must be < 4096)\n", vlan_id);
+ return 1;
+}
+
+static int
+port_reg_off_is_invalid(portid_t port_id, uint32_t reg_off)
+{
+ const struct rte_pci_device *pci_dev;
+ const struct rte_bus *bus;
+ uint64_t pci_len;
+
+ if (reg_off & 0x3) {
+ printf("Port register offset 0x%X not aligned on a 4-byte "
+ "boundary\n",
+ (unsigned)reg_off);
+ return 1;
+ }
+
+ if (!ports[port_id].dev_info.device) {
+ printf("Invalid device\n");
+ return 0;
+ }
+
+ bus = rte_bus_find_by_device(ports[port_id].dev_info.device);
+ if (bus && !strcmp(bus->name, "pci")) {
+ pci_dev = RTE_DEV_TO_PCI(ports[port_id].dev_info.device);
+ } else {
+ printf("Not a PCI device\n");
+ return 1;
+ }
+
+ pci_len = pci_dev->mem_resource[0].len;
+ if (reg_off >= pci_len) {
+ printf("Port %d: register offset %u (0x%X) out of port PCI "
+ "resource (length=%"PRIu64")\n",
+ port_id, (unsigned)reg_off, (unsigned)reg_off, pci_len);
+ return 1;
+ }
+ return 0;
+}
+
+static int
+reg_bit_pos_is_invalid(uint8_t bit_pos)
+{
+ if (bit_pos <= 31)
+ return 0;
+ printf("Invalid bit position %d (must be <= 31)\n", bit_pos);
+ return 1;
+}
+
+#define display_port_and_reg_off(port_id, reg_off) \
+ printf("port %d PCI register at offset 0x%X: ", (port_id), (reg_off))
+
+static inline void
+display_port_reg_value(portid_t port_id, uint32_t reg_off, uint32_t reg_v)
+{
+ display_port_and_reg_off(port_id, (unsigned)reg_off);
+ printf("0x%08X (%u)\n", (unsigned)reg_v, (unsigned)reg_v);
+}
+
+void
+port_reg_bit_display(portid_t port_id, uint32_t reg_off, uint8_t bit_x)
+{
+ uint32_t reg_v;
+
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ if (port_reg_off_is_invalid(port_id, reg_off))
+ return;
+ if (reg_bit_pos_is_invalid(bit_x))
+ return;
+ reg_v = port_id_pci_reg_read(port_id, reg_off);
+ display_port_and_reg_off(port_id, (unsigned)reg_off);
+ printf("bit %d=%d\n", bit_x, (int) ((reg_v & (1 << bit_x)) >> bit_x));
+}
+
+void
+port_reg_bit_field_display(portid_t port_id, uint32_t reg_off,
+ uint8_t bit1_pos, uint8_t bit2_pos)
+{
+ uint32_t reg_v;
+ uint8_t l_bit;
+ uint8_t h_bit;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ if (port_reg_off_is_invalid(port_id, reg_off))
+ return;
+ if (reg_bit_pos_is_invalid(bit1_pos))
+ return;
+ if (reg_bit_pos_is_invalid(bit2_pos))
+ return;
+ if (bit1_pos > bit2_pos)
+ l_bit = bit2_pos, h_bit = bit1_pos;
+ else
+ l_bit = bit1_pos, h_bit = bit2_pos;
+
+ reg_v = port_id_pci_reg_read(port_id, reg_off);
+ reg_v >>= l_bit;
+ if (h_bit < 31)
+ reg_v &= ((1 << (h_bit - l_bit + 1)) - 1);
+ display_port_and_reg_off(port_id, (unsigned)reg_off);
+ printf("bits[%d, %d]=0x%0*X (%u)\n", l_bit, h_bit,
+ ((h_bit - l_bit) / 4) + 1, (unsigned)reg_v, (unsigned)reg_v);
+}
+
+void
+port_reg_display(portid_t port_id, uint32_t reg_off)
+{
+ uint32_t reg_v;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ if (port_reg_off_is_invalid(port_id, reg_off))
+ return;
+ reg_v = port_id_pci_reg_read(port_id, reg_off);
+ display_port_reg_value(port_id, reg_off, reg_v);
+}
+
+void
+port_reg_bit_set(portid_t port_id, uint32_t reg_off, uint8_t bit_pos,
+ uint8_t bit_v)
+{
+ uint32_t reg_v;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ if (port_reg_off_is_invalid(port_id, reg_off))
+ return;
+ if (reg_bit_pos_is_invalid(bit_pos))
+ return;
+ if (bit_v > 1) {
+ printf("Invalid bit value %d (must be 0 or 1)\n", (int) bit_v);
+ return;
+ }
+ reg_v = port_id_pci_reg_read(port_id, reg_off);
+ if (bit_v == 0)
+ reg_v &= ~(1 << bit_pos);
+ else
+ reg_v |= (1 << bit_pos);
+ port_id_pci_reg_write(port_id, reg_off, reg_v);
+ display_port_reg_value(port_id, reg_off, reg_v);
+}
+
+void
+port_reg_bit_field_set(portid_t port_id, uint32_t reg_off,
+ uint8_t bit1_pos, uint8_t bit2_pos, uint32_t value)
+{
+ uint32_t max_v;
+ uint32_t reg_v;
+ uint8_t l_bit;
+ uint8_t h_bit;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ if (port_reg_off_is_invalid(port_id, reg_off))
+ return;
+ if (reg_bit_pos_is_invalid(bit1_pos))
+ return;
+ if (reg_bit_pos_is_invalid(bit2_pos))
+ return;
+ if (bit1_pos > bit2_pos)
+ l_bit = bit2_pos, h_bit = bit1_pos;
+ else
+ l_bit = bit1_pos, h_bit = bit2_pos;
+
+ if ((h_bit - l_bit) < 31)
+ max_v = (1 << (h_bit - l_bit + 1)) - 1;
+ else
+ max_v = 0xFFFFFFFF;
+
+ if (value > max_v) {
+ printf("Invalid value %u (0x%x) must be < %u (0x%x)\n",
+ (unsigned)value, (unsigned)value,
+ (unsigned)max_v, (unsigned)max_v);
+ return;
+ }
+ reg_v = port_id_pci_reg_read(port_id, reg_off);
+ reg_v &= ~(max_v << l_bit); /* Keep unchanged bits */
+ reg_v |= (value << l_bit); /* Set changed bits */
+ port_id_pci_reg_write(port_id, reg_off, reg_v);
+ display_port_reg_value(port_id, reg_off, reg_v);
+}
+
+void
+port_reg_set(portid_t port_id, uint32_t reg_off, uint32_t reg_v)
+{
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ if (port_reg_off_is_invalid(port_id, reg_off))
+ return;
+ port_id_pci_reg_write(port_id, reg_off, reg_v);
+ display_port_reg_value(port_id, reg_off, reg_v);
+}
+
+void
+port_mtu_set(portid_t port_id, uint16_t mtu)
+{
+ int diag;
+ struct rte_port *rte_port = &ports[port_id];
+ struct rte_eth_dev_info dev_info;
+ uint16_t eth_overhead;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if (mtu > dev_info.max_mtu || mtu < dev_info.min_mtu) {
+ printf("Set MTU failed. MTU:%u is not in valid range, min:%u - max:%u\n",
+ mtu, dev_info.min_mtu, dev_info.max_mtu);
+ return;
+ }
+ diag = rte_eth_dev_set_mtu(port_id, mtu);
+ if (diag == 0 &&
+ dev_info.rx_offload_capa & DEV_RX_OFFLOAD_JUMBO_FRAME) {
+ /*
+ * Ether overhead in driver is equal to the difference of
+ * max_rx_pktlen and max_mtu in rte_eth_dev_info when the
+ * device supports jumbo frame.
+ */
+ eth_overhead = dev_info.max_rx_pktlen - dev_info.max_mtu;
+ if (mtu > RTE_ETHER_MAX_LEN - eth_overhead) {
+ rte_port->dev_conf.rxmode.offloads |=
+ DEV_RX_OFFLOAD_JUMBO_FRAME;
+ rte_port->dev_conf.rxmode.max_rx_pkt_len =
+ mtu + eth_overhead;
+ } else
+ rte_port->dev_conf.rxmode.offloads &=
+ ~DEV_RX_OFFLOAD_JUMBO_FRAME;
+
+ return;
+ }
+ printf("Set MTU failed. diag=%d\n", diag);
+}
+
+/* Generic flow management functions. */
+
+/** Generate a port_flow entry from attributes/pattern/actions. */
+static struct port_flow *
+port_flow_new(const struct rte_flow_attr *attr,
+ const struct rte_flow_item *pattern,
+ const struct rte_flow_action *actions,
+ struct rte_flow_error *error)
+{
+ const struct rte_flow_conv_rule rule = {
+ .attr_ro = attr,
+ .pattern_ro = pattern,
+ .actions_ro = actions,
+ };
+ struct port_flow *pf;
+ int ret;
+
+ ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, NULL, 0, &rule, error);
+ if (ret < 0)
+ return NULL;
+ pf = calloc(1, offsetof(struct port_flow, rule) + ret);
+ if (!pf) {
+ rte_flow_error_set
+ (error, errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "calloc() failed");
+ return NULL;
+ }
+ if (rte_flow_conv(RTE_FLOW_CONV_OP_RULE, &pf->rule, ret, &rule,
+ error) >= 0)
+ return pf;
+ free(pf);
+ return NULL;
+}
+
+/** Print a message out of a flow error. */
+static int
+port_flow_complain(struct rte_flow_error *error)
+{
+ static const char *const errstrlist[] = {
+ [RTE_FLOW_ERROR_TYPE_NONE] = "no error",
+ [RTE_FLOW_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+ [RTE_FLOW_ERROR_TYPE_HANDLE] = "flow rule (handle)",
+ [RTE_FLOW_ERROR_TYPE_ATTR_GROUP] = "group field",
+ [RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY] = "priority field",
+ [RTE_FLOW_ERROR_TYPE_ATTR_INGRESS] = "ingress field",
+ [RTE_FLOW_ERROR_TYPE_ATTR_EGRESS] = "egress field",
+ [RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER] = "transfer field",
+ [RTE_FLOW_ERROR_TYPE_ATTR] = "attributes structure",
+ [RTE_FLOW_ERROR_TYPE_ITEM_NUM] = "pattern length",
+ [RTE_FLOW_ERROR_TYPE_ITEM_SPEC] = "item specification",
+ [RTE_FLOW_ERROR_TYPE_ITEM_LAST] = "item specification range",
+ [RTE_FLOW_ERROR_TYPE_ITEM_MASK] = "item specification mask",
+ [RTE_FLOW_ERROR_TYPE_ITEM] = "specific pattern item",
+ [RTE_FLOW_ERROR_TYPE_ACTION_NUM] = "number of actions",
+ [RTE_FLOW_ERROR_TYPE_ACTION_CONF] = "action configuration",
+ [RTE_FLOW_ERROR_TYPE_ACTION] = "specific action",
+ };
+ const char *errstr;
+ char buf[32];
+ int err = rte_errno;
+
+ if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+ !errstrlist[error->type])
+ errstr = "unknown type";
+ else
+ errstr = errstrlist[error->type];
+ printf("%s(): Caught PMD error type %d (%s): %s%s: %s\n", __func__,
+ error->type, errstr,
+ error->cause ? (snprintf(buf, sizeof(buf), "cause: %p, ",
+ error->cause), buf) : "",
+ error->message ? error->message : "(no stated reason)",
+ rte_strerror(err));
+ return -err;
+}
+
+/** Validate flow rule. */
+int
+port_flow_validate(portid_t port_id,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item *pattern,
+ const struct rte_flow_action *actions)
+{
+ struct rte_flow_error error;
+
+ /* Poisoning to make sure PMDs update it in case of error. */
+ memset(&error, 0x11, sizeof(error));
+ if (rte_flow_validate(port_id, attr, pattern, actions, &error))
+ return port_flow_complain(&error);
+ printf("Flow rule validated\n");
+ return 0;
+}
+
+/** Update age action context by port_flow pointer. */
+void
+update_age_action_context(const struct rte_flow_action *actions,
+ struct port_flow *pf)
+{
+ struct rte_flow_action_age *age = NULL;
+
+ for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+ switch (actions->type) {
+ case RTE_FLOW_ACTION_TYPE_AGE:
+ age = (struct rte_flow_action_age *)
+ (uintptr_t)actions->conf;
+ age->context = pf;
+ return;
+ default:
+ break;
+ }
+ }
+}
+
+/** Create flow rule. */
+int
+port_flow_create(portid_t port_id,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item *pattern,
+ const struct rte_flow_action *actions)
+{
+ struct rte_flow *flow;
+ struct rte_port *port;
+ struct port_flow *pf;
+ uint32_t id = 0;
+ struct rte_flow_error error;
+
+ port = &ports[port_id];
+ if (port->flow_list) {
+ if (port->flow_list->id == UINT32_MAX) {
+ printf("Highest rule ID is already assigned, delete"
+ " it first");
+ return -ENOMEM;
+ }
+ id = port->flow_list->id + 1;
+ }
+ pf = port_flow_new(attr, pattern, actions, &error);
+ if (!pf)
+ return port_flow_complain(&error);
+ update_age_action_context(actions, pf);
+ /* Poisoning to make sure PMDs update it in case of error. */
+ memset(&error, 0x22, sizeof(error));
+ flow = rte_flow_create(port_id, attr, pattern, actions, &error);
+ if (!flow) {
+ free(pf);
+ return port_flow_complain(&error);
+ }
+ pf->next = port->flow_list;
+ pf->id = id;
+ pf->flow = flow;
+ port->flow_list = pf;
+ printf("Flow rule #%u created\n", pf->id);
+ return 0;
+}
+
+/** Destroy a number of flow rules. */
+int
+port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule)
+{
+ struct rte_port *port;
+ struct port_flow **tmp;
+ uint32_t c = 0;
+ int ret = 0;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL)
+ return -EINVAL;
+ port = &ports[port_id];
+ tmp = &port->flow_list;
+ while (*tmp) {
+ uint32_t i;
+
+ for (i = 0; i != n; ++i) {
+ struct rte_flow_error error;
+ struct port_flow *pf = *tmp;
+
+ if (rule[i] != pf->id)
+ continue;
+ /*
+ * Poisoning to make sure PMDs update it in case
+ * of error.
+ */
+ memset(&error, 0x33, sizeof(error));
+ if (rte_flow_destroy(port_id, pf->flow, &error)) {
+ ret = port_flow_complain(&error);
+ continue;
+ }
+ printf("Flow rule #%u destroyed\n", pf->id);
+ *tmp = pf->next;
+ free(pf);
+ break;
+ }
+ if (i == n)
+ tmp = &(*tmp)->next;
+ ++c;
+ }
+ return ret;
+}
+
+/** Remove all flow rules. */
+int
+port_flow_flush(portid_t port_id)
+{
+ struct rte_flow_error error;
+ struct rte_port *port;
+ int ret = 0;
+
+ /* Poisoning to make sure PMDs update it in case of error. */
+ memset(&error, 0x44, sizeof(error));
+ if (rte_flow_flush(port_id, &error)) {
+ ret = port_flow_complain(&error);
+ if (port_id_is_invalid(port_id, DISABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL)
+ return ret;
+ }
+ port = &ports[port_id];
+ while (port->flow_list) {
+ struct port_flow *pf = port->flow_list->next;
+
+ free(port->flow_list);
+ port->flow_list = pf;
+ }
+ return ret;
+}
+
+/** Dump all flow rules. */
+int
+port_flow_dump(portid_t port_id, const char *file_name)
+{
+ int ret = 0;
+ FILE *file = stdout;
+ struct rte_flow_error error;
+
+ if (file_name && strlen(file_name)) {
+ file = fopen(file_name, "w");
+ if (!file) {
+ printf("Failed to create file %s: %s\n", file_name,
+ strerror(errno));
+ return -errno;
+ }
+ }
+ ret = rte_flow_dev_dump(port_id, file, &error);
+ if (ret) {
+ port_flow_complain(&error);
+ printf("Failed to dump flow: %s\n", strerror(-ret));
+ } else
+ printf("Flow dump finished\n");
+ if (file_name && strlen(file_name))
+ fclose(file);
+ return ret;
+}
+
+/** Query a flow rule. */
+int
+port_flow_query(portid_t port_id, uint32_t rule,
+ const struct rte_flow_action *action)
+{
+ struct rte_flow_error error;
+ struct rte_port *port;
+ struct port_flow *pf;
+ const char *name;
+ union {
+ struct rte_flow_query_count count;
+ } query;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL)
+ return -EINVAL;
+ port = &ports[port_id];
+ for (pf = port->flow_list; pf; pf = pf->next)
+ if (pf->id == rule)
+ break;
+ if (!pf) {
+ printf("Flow rule #%u not found\n", rule);
+ return -ENOENT;
+ }
+ ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR,
+ &name, sizeof(name),
+ (void *)(uintptr_t)action->type, &error);
+ if (ret < 0)
+ return port_flow_complain(&error);
+ switch (action->type) {
+ case RTE_FLOW_ACTION_TYPE_COUNT:
+ break;
+ default:
+ printf("Cannot query action type %d (%s)\n",
+ action->type, name);
+ return -ENOTSUP;
+ }
+ /* Poisoning to make sure PMDs update it in case of error. */
+ memset(&error, 0x55, sizeof(error));
+ memset(&query, 0, sizeof(query));
+ if (rte_flow_query(port_id, pf->flow, action, &query, &error))
+ return port_flow_complain(&error);
+ switch (action->type) {
+ case RTE_FLOW_ACTION_TYPE_COUNT:
+ printf("%s:\n"
+ " hits_set: %u\n"
+ " bytes_set: %u\n"
+ " hits: %" PRIu64 "\n"
+ " bytes: %" PRIu64 "\n",
+ name,
+ query.count.hits_set,
+ query.count.bytes_set,
+ query.count.hits,
+ query.count.bytes);
+ break;
+ default:
+ printf("Cannot display result for action type %d (%s)\n",
+ action->type, name);
+ break;
+ }
+ return 0;
+}
+
+/** List simply and destroy all aged flows. */
+void
+port_flow_aged(portid_t port_id, uint8_t destroy)
+{
+ void **contexts;
+ int nb_context, total = 0, idx;
+ struct rte_flow_error error;
+ struct port_flow *pf;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL)
+ return;
+ total = rte_flow_get_aged_flows(port_id, NULL, 0, &error);
+ printf("Port %u total aged flows: %d\n", port_id, total);
+ if (total < 0) {
+ port_flow_complain(&error);
+ return;
+ }
+ if (total == 0)
+ return;
+ contexts = malloc(sizeof(void *) * total);
+ if (contexts == NULL) {
+ printf("Cannot allocate contexts for aged flow\n");
+ return;
+ }
+ printf("ID\tGroup\tPrio\tAttr\n");
+ nb_context = rte_flow_get_aged_flows(port_id, contexts, total, &error);
+ if (nb_context != total) {
+ printf("Port:%d get aged flows count(%d) != total(%d)\n",
+ port_id, nb_context, total);
+ free(contexts);
+ return;
+ }
+ for (idx = 0; idx < nb_context; idx++) {
+ pf = (struct port_flow *)contexts[idx];
+ if (!pf) {
+ printf("Error: get Null context in port %u\n", port_id);
+ continue;
+ }
+ printf("%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 "\t%c%c%c\t\n",
+ pf->id,
+ pf->rule.attr->group,
+ pf->rule.attr->priority,
+ pf->rule.attr->ingress ? 'i' : '-',
+ pf->rule.attr->egress ? 'e' : '-',
+ pf->rule.attr->transfer ? 't' : '-');
+ }
+ if (destroy) {
+ int ret;
+ uint32_t flow_id;
+
+ total = 0;
+ printf("\n");
+ for (idx = 0; idx < nb_context; idx++) {
+ pf = (struct port_flow *)contexts[idx];
+ if (!pf)
+ continue;
+ flow_id = pf->id;
+ ret = port_flow_destroy(port_id, 1, &flow_id);
+ if (!ret)
+ total++;
+ }
+ printf("%d flows be destroyed\n", total);
+ }
+ free(contexts);
+}
+
+/** List flow rules. */
+void
+port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])
+{
+ struct rte_port *port;
+ struct port_flow *pf;
+ struct port_flow *list = NULL;
+ uint32_t i;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL)
+ return;
+ port = &ports[port_id];
+ if (!port->flow_list)
+ return;
+ /* Sort flows by group, priority and ID. */
+ for (pf = port->flow_list; pf != NULL; pf = pf->next) {
+ struct port_flow **tmp;
+ const struct rte_flow_attr *curr = pf->rule.attr;
+
+ if (n) {
+ /* Filter out unwanted groups. */
+ for (i = 0; i != n; ++i)
+ if (curr->group == group[i])
+ break;
+ if (i == n)
+ continue;
+ }
+ for (tmp = &list; *tmp; tmp = &(*tmp)->tmp) {
+ const struct rte_flow_attr *comp = (*tmp)->rule.attr;
+
+ if (curr->group > comp->group ||
+ (curr->group == comp->group &&
+ curr->priority > comp->priority) ||
+ (curr->group == comp->group &&
+ curr->priority == comp->priority &&
+ pf->id > (*tmp)->id))
+ continue;
+ break;
+ }
+ pf->tmp = *tmp;
+ *tmp = pf;
+ }
+ printf("ID\tGroup\tPrio\tAttr\tRule\n");
+ for (pf = list; pf != NULL; pf = pf->tmp) {
+ const struct rte_flow_item *item = pf->rule.pattern;
+ const struct rte_flow_action *action = pf->rule.actions;
+ const char *name;
+
+ printf("%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 "\t%c%c%c\t",
+ pf->id,
+ pf->rule.attr->group,
+ pf->rule.attr->priority,
+ pf->rule.attr->ingress ? 'i' : '-',
+ pf->rule.attr->egress ? 'e' : '-',
+ pf->rule.attr->transfer ? 't' : '-');
+ while (item->type != RTE_FLOW_ITEM_TYPE_END) {
+ if (rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_NAME_PTR,
+ &name, sizeof(name),
+ (void *)(uintptr_t)item->type,
+ NULL) <= 0)
+ name = "[UNKNOWN]";
+ if (item->type != RTE_FLOW_ITEM_TYPE_VOID)
+ printf("%s ", name);
+ ++item;
+ }
+ printf("=>");
+ while (action->type != RTE_FLOW_ACTION_TYPE_END) {
+ if (rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR,
+ &name, sizeof(name),
+ (void *)(uintptr_t)action->type,
+ NULL) <= 0)
+ name = "[UNKNOWN]";
+ if (action->type != RTE_FLOW_ACTION_TYPE_VOID)
+ printf(" %s", name);
+ ++action;
+ }
+ printf("\n");
+ }
+}
+
+/** Restrict ingress traffic to the defined flow rules. */
+int
+port_flow_isolate(portid_t port_id, int set)
+{
+ struct rte_flow_error error;
+
+ /* Poisoning to make sure PMDs update it in case of error. */
+ memset(&error, 0x66, sizeof(error));
+ if (rte_flow_isolate(port_id, set, &error))
+ return port_flow_complain(&error);
+ printf("Ingress traffic on port %u is %s to the defined flow rules\n",
+ port_id,
+ set ? "now restricted" : "not restricted anymore");
+ return 0;
+}
+
+/*
+ * RX/TX ring descriptors display functions.
+ */
+int
+rx_queue_id_is_invalid(queueid_t rxq_id)
+{
+ if (rxq_id < nb_rxq)
+ return 0;
+ printf("Invalid RX queue %d (must be < nb_rxq=%d)\n", rxq_id, nb_rxq);
+ return 1;
+}
+
+int
+tx_queue_id_is_invalid(queueid_t txq_id)
+{
+ if (txq_id < nb_txq)
+ return 0;
+ printf("Invalid TX queue %d (must be < nb_rxq=%d)\n", txq_id, nb_txq);
+ return 1;
+}
+
+static int
+rx_desc_id_is_invalid(uint16_t rxdesc_id)
+{
+ if (rxdesc_id < nb_rxd)
+ return 0;
+ printf("Invalid RX descriptor %d (must be < nb_rxd=%d)\n",
+ rxdesc_id, nb_rxd);
+ return 1;
+}
+
+static int
+tx_desc_id_is_invalid(uint16_t txdesc_id)
+{
+ if (txdesc_id < nb_txd)
+ return 0;
+ printf("Invalid TX descriptor %d (must be < nb_txd=%d)\n",
+ txdesc_id, nb_txd);
+ return 1;
+}
+
+static const struct rte_memzone *
+ring_dma_zone_lookup(const char *ring_name, portid_t port_id, uint16_t q_id)
+{
+ char mz_name[RTE_MEMZONE_NAMESIZE];
+ const struct rte_memzone *mz;
+
+ snprintf(mz_name, sizeof(mz_name), "eth_p%d_q%d_%s",
+ port_id, q_id, ring_name);
+ mz = rte_memzone_lookup(mz_name);
+ if (mz == NULL)
+ printf("%s ring memory zoneof (port %d, queue %d) not"
+ "found (zone name = %s\n",
+ ring_name, port_id, q_id, mz_name);
+ return mz;
+}
+
+union igb_ring_dword {
+ uint64_t dword;
+ struct {
+#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+ uint32_t lo;
+ uint32_t hi;
+#else
+ uint32_t hi;
+ uint32_t lo;
+#endif
+ } words;
+};
+
+struct igb_ring_desc_32_bytes {
+ union igb_ring_dword lo_dword;
+ union igb_ring_dword hi_dword;
+ union igb_ring_dword resv1;
+ union igb_ring_dword resv2;
+};
+
+struct igb_ring_desc_16_bytes {
+ union igb_ring_dword lo_dword;
+ union igb_ring_dword hi_dword;
+};
+
+static void
+ring_rxd_display_dword(union igb_ring_dword dword)
+{
+ printf(" 0x%08X - 0x%08X\n", (unsigned)dword.words.lo,
+ (unsigned)dword.words.hi);
+}
+
+static void
+ring_rx_descriptor_display(const struct rte_memzone *ring_mz,
+#ifndef RTE_LIBRTE_I40E_16BYTE_RX_DESC
+ portid_t port_id,
+#else
+ __rte_unused portid_t port_id,
+#endif
+ uint16_t desc_id)
+{
+ struct igb_ring_desc_16_bytes *ring =
+ (struct igb_ring_desc_16_bytes *)ring_mz->addr;
+#ifndef RTE_LIBRTE_I40E_16BYTE_RX_DESC
+ int ret;
+ struct rte_eth_dev_info dev_info;
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if (strstr(dev_info.driver_name, "i40e") != NULL) {
+ /* 32 bytes RX descriptor, i40e only */
+ struct igb_ring_desc_32_bytes *ring =
+ (struct igb_ring_desc_32_bytes *)ring_mz->addr;
+ ring[desc_id].lo_dword.dword =
+ rte_le_to_cpu_64(ring[desc_id].lo_dword.dword);
+ ring_rxd_display_dword(ring[desc_id].lo_dword);
+ ring[desc_id].hi_dword.dword =
+ rte_le_to_cpu_64(ring[desc_id].hi_dword.dword);
+ ring_rxd_display_dword(ring[desc_id].hi_dword);
+ ring[desc_id].resv1.dword =
+ rte_le_to_cpu_64(ring[desc_id].resv1.dword);
+ ring_rxd_display_dword(ring[desc_id].resv1);
+ ring[desc_id].resv2.dword =
+ rte_le_to_cpu_64(ring[desc_id].resv2.dword);
+ ring_rxd_display_dword(ring[desc_id].resv2);
+
+ return;
+ }
+#endif
+ /* 16 bytes RX descriptor */
+ ring[desc_id].lo_dword.dword =
+ rte_le_to_cpu_64(ring[desc_id].lo_dword.dword);
+ ring_rxd_display_dword(ring[desc_id].lo_dword);
+ ring[desc_id].hi_dword.dword =
+ rte_le_to_cpu_64(ring[desc_id].hi_dword.dword);
+ ring_rxd_display_dword(ring[desc_id].hi_dword);
+}
+
+static void
+ring_tx_descriptor_display(const struct rte_memzone *ring_mz, uint16_t desc_id)
+{
+ struct igb_ring_desc_16_bytes *ring;
+ struct igb_ring_desc_16_bytes txd;
+
+ ring = (struct igb_ring_desc_16_bytes *)ring_mz->addr;
+ txd.lo_dword.dword = rte_le_to_cpu_64(ring[desc_id].lo_dword.dword);
+ txd.hi_dword.dword = rte_le_to_cpu_64(ring[desc_id].hi_dword.dword);
+ printf(" 0x%08X - 0x%08X / 0x%08X - 0x%08X\n",
+ (unsigned)txd.lo_dword.words.lo,
+ (unsigned)txd.lo_dword.words.hi,
+ (unsigned)txd.hi_dword.words.lo,
+ (unsigned)txd.hi_dword.words.hi);
+}
+
+void
+rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id)
+{
+ const struct rte_memzone *rx_mz;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ if (rx_queue_id_is_invalid(rxq_id))
+ return;
+ if (rx_desc_id_is_invalid(rxd_id))
+ return;
+ rx_mz = ring_dma_zone_lookup("rx_ring", port_id, rxq_id);
+ if (rx_mz == NULL)
+ return;
+ ring_rx_descriptor_display(rx_mz, port_id, rxd_id);
+}
+
+void
+tx_ring_desc_display(portid_t port_id, queueid_t txq_id, uint16_t txd_id)
+{
+ const struct rte_memzone *tx_mz;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ if (tx_queue_id_is_invalid(txq_id))
+ return;
+ if (tx_desc_id_is_invalid(txd_id))
+ return;
+ tx_mz = ring_dma_zone_lookup("tx_ring", port_id, txq_id);
+ if (tx_mz == NULL)
+ return;
+ ring_tx_descriptor_display(tx_mz, txd_id);
+}
+
+void
+fwd_lcores_config_display(void)
+{
+ lcoreid_t lc_id;
+
+ printf("List of forwarding lcores:");
+ for (lc_id = 0; lc_id < nb_cfg_lcores; lc_id++)
+ printf(" %2u", fwd_lcores_cpuids[lc_id]);
+ printf("\n");
+}
+void
+rxtx_config_display(void)
+{
+ portid_t pid;
+ queueid_t qid;
+
+ printf(" %s packet forwarding%s packets/burst=%d\n",
+ cur_fwd_eng->fwd_mode_name,
+ retry_enabled == 0 ? "" : " with retry",
+ nb_pkt_per_burst);
+
+ if (cur_fwd_eng == &tx_only_engine || cur_fwd_eng == &flow_gen_engine)
+ printf(" packet len=%u - nb packet segments=%d\n",
+ (unsigned)tx_pkt_length, (int) tx_pkt_nb_segs);
+
+ printf(" nb forwarding cores=%d - nb forwarding ports=%d\n",
+ nb_fwd_lcores, nb_fwd_ports);
+
+ RTE_ETH_FOREACH_DEV(pid) {
+ struct rte_eth_rxconf *rx_conf = &ports[pid].rx_conf[0];
+ struct rte_eth_txconf *tx_conf = &ports[pid].tx_conf[0];
+ uint16_t *nb_rx_desc = &ports[pid].nb_rx_desc[0];
+ uint16_t *nb_tx_desc = &ports[pid].nb_tx_desc[0];
+ uint16_t nb_rx_desc_tmp;
+ uint16_t nb_tx_desc_tmp;
+ struct rte_eth_rxq_info rx_qinfo;
+ struct rte_eth_txq_info tx_qinfo;
+ int32_t rc;
+
+ /* per port config */
+ printf(" port %d: RX queue number: %d Tx queue number: %d\n",
+ (unsigned int)pid, nb_rxq, nb_txq);
+
+ printf(" Rx offloads=0x%"PRIx64" Tx offloads=0x%"PRIx64"\n",
+ ports[pid].dev_conf.rxmode.offloads,
+ ports[pid].dev_conf.txmode.offloads);
+
+ /* per rx queue config only for first queue to be less verbose */
+ for (qid = 0; qid < 1; qid++) {
+ rc = rte_eth_rx_queue_info_get(pid, qid, &rx_qinfo);
+ if (rc)
+ nb_rx_desc_tmp = nb_rx_desc[qid];
+ else
+ nb_rx_desc_tmp = rx_qinfo.nb_desc;
+
+ printf(" RX queue: %d\n", qid);
+ printf(" RX desc=%d - RX free threshold=%d\n",
+ nb_rx_desc_tmp, rx_conf[qid].rx_free_thresh);
+ printf(" RX threshold registers: pthresh=%d hthresh=%d "
+ " wthresh=%d\n",
+ rx_conf[qid].rx_thresh.pthresh,
+ rx_conf[qid].rx_thresh.hthresh,
+ rx_conf[qid].rx_thresh.wthresh);
+ printf(" RX Offloads=0x%"PRIx64"\n",
+ rx_conf[qid].offloads);
+ }
+
+ /* per tx queue config only for first queue to be less verbose */
+ for (qid = 0; qid < 1; qid++) {
+ rc = rte_eth_tx_queue_info_get(pid, qid, &tx_qinfo);
+ if (rc)
+ nb_tx_desc_tmp = nb_tx_desc[qid];
+ else
+ nb_tx_desc_tmp = tx_qinfo.nb_desc;
+
+ printf(" TX queue: %d\n", qid);
+ printf(" TX desc=%d - TX free threshold=%d\n",
+ nb_tx_desc_tmp, tx_conf[qid].tx_free_thresh);
+ printf(" TX threshold registers: pthresh=%d hthresh=%d "
+ " wthresh=%d\n",
+ tx_conf[qid].tx_thresh.pthresh,
+ tx_conf[qid].tx_thresh.hthresh,
+ tx_conf[qid].tx_thresh.wthresh);
+ printf(" TX offloads=0x%"PRIx64" - TX RS bit threshold=%d\n",
+ tx_conf[qid].offloads, tx_conf->tx_rs_thresh);
+ }
+ }
+}
+
+void
+port_rss_reta_info(portid_t port_id,
+ struct rte_eth_rss_reta_entry64 *reta_conf,
+ uint16_t nb_entries)
+{
+ uint16_t i, idx, shift;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ ret = rte_eth_dev_rss_reta_query(port_id, reta_conf, nb_entries);
+ if (ret != 0) {
+ printf("Failed to get RSS RETA info, return code = %d\n", ret);
+ return;
+ }
+
+ for (i = 0; i < nb_entries; i++) {
+ idx = i / RTE_RETA_GROUP_SIZE;
+ shift = i % RTE_RETA_GROUP_SIZE;
+ if (!(reta_conf[idx].mask & (1ULL << shift)))
+ continue;
+ printf("RSS RETA configuration: hash index=%u, queue=%u\n",
+ i, reta_conf[idx].reta[shift]);
+ }
+}
+
+/*
+ * Displays the RSS hash functions of a port, and, optionaly, the RSS hash
+ * key of the port.
+ */
+void
+port_rss_hash_conf_show(portid_t port_id, int show_rss_key)
+{
+ struct rte_eth_rss_conf rss_conf = {0};
+ uint8_t rss_key[RSS_HASH_KEY_LENGTH];
+ uint64_t rss_hf;
+ uint8_t i;
+ int diag;
+ struct rte_eth_dev_info dev_info;
+ uint8_t hash_key_size;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if (dev_info.hash_key_size > 0 &&
+ dev_info.hash_key_size <= sizeof(rss_key))
+ hash_key_size = dev_info.hash_key_size;
+ else {
+ printf("dev_info did not provide a valid hash key size\n");
+ return;
+ }
+
+ /* Get RSS hash key if asked to display it */
+ rss_conf.rss_key = (show_rss_key) ? rss_key : NULL;
+ rss_conf.rss_key_len = hash_key_size;
+ diag = rte_eth_dev_rss_hash_conf_get(port_id, &rss_conf);
+ if (diag != 0) {
+ switch (diag) {
+ case -ENODEV:
+ printf("port index %d invalid\n", port_id);
+ break;
+ case -ENOTSUP:
+ printf("operation not supported by device\n");
+ break;
+ default:
+ printf("operation failed - diag=%d\n", diag);
+ break;
+ }
+ return;
+ }
+ rss_hf = rss_conf.rss_hf;
+ if (rss_hf == 0) {
+ printf("RSS disabled\n");
+ return;
+ }
+ printf("RSS functions:\n ");
+ for (i = 0; rss_type_table[i].str; i++) {
+ if (rss_hf & rss_type_table[i].rss_type)
+ printf("%s ", rss_type_table[i].str);
+ }
+ printf("\n");
+ if (!show_rss_key)
+ return;
+ printf("RSS key:\n");
+ for (i = 0; i < hash_key_size; i++)
+ printf("%02X", rss_key[i]);
+ printf("\n");
+}
+
+void
+port_rss_hash_key_update(portid_t port_id, char rss_type[], uint8_t *hash_key,
+ uint hash_key_len)
+{
+ struct rte_eth_rss_conf rss_conf;
+ int diag;
+ unsigned int i;
+
+ rss_conf.rss_key = NULL;
+ rss_conf.rss_key_len = hash_key_len;
+ rss_conf.rss_hf = 0;
+ for (i = 0; rss_type_table[i].str; i++) {
+ if (!strcmp(rss_type_table[i].str, rss_type))
+ rss_conf.rss_hf = rss_type_table[i].rss_type;
+ }
+ diag = rte_eth_dev_rss_hash_conf_get(port_id, &rss_conf);
+ if (diag == 0) {
+ rss_conf.rss_key = hash_key;
+ diag = rte_eth_dev_rss_hash_update(port_id, &rss_conf);
+ }
+ if (diag == 0)
+ return;
+
+ switch (diag) {
+ case -ENODEV:
+ printf("port index %d invalid\n", port_id);
+ break;
+ case -ENOTSUP:
+ printf("operation not supported by device\n");
+ break;
+ default:
+ printf("operation failed - diag=%d\n", diag);
+ break;
+ }
+}
+
+/*
+ * Setup forwarding configuration for each logical core.
+ */
+static void
+setup_fwd_config_of_each_lcore(struct fwd_config *cfg)
+{
+ streamid_t nb_fs_per_lcore;
+ streamid_t nb_fs;
+ streamid_t sm_id;
+ lcoreid_t nb_extra;
+ lcoreid_t nb_fc;
+ lcoreid_t nb_lc;
+ lcoreid_t lc_id;
+
+ nb_fs = cfg->nb_fwd_streams;
+ nb_fc = cfg->nb_fwd_lcores;
+ if (nb_fs <= nb_fc) {
+ nb_fs_per_lcore = 1;
+ nb_extra = 0;
+ } else {
+ nb_fs_per_lcore = (streamid_t) (nb_fs / nb_fc);
+ nb_extra = (lcoreid_t) (nb_fs % nb_fc);
+ }
+
+ nb_lc = (lcoreid_t) (nb_fc - nb_extra);
+ sm_id = 0;
+ for (lc_id = 0; lc_id < nb_lc; lc_id++) {
+ fwd_lcores[lc_id]->stream_idx = sm_id;
+ fwd_lcores[lc_id]->stream_nb = nb_fs_per_lcore;
+ sm_id = (streamid_t) (sm_id + nb_fs_per_lcore);
+ }
+
+ /*
+ * Assign extra remaining streams, if any.
+ */
+ nb_fs_per_lcore = (streamid_t) (nb_fs_per_lcore + 1);
+ for (lc_id = 0; lc_id < nb_extra; lc_id++) {
+ fwd_lcores[nb_lc + lc_id]->stream_idx = sm_id;
+ fwd_lcores[nb_lc + lc_id]->stream_nb = nb_fs_per_lcore;
+ sm_id = (streamid_t) (sm_id + nb_fs_per_lcore);
+ }
+}
+
+static portid_t
+fwd_topology_tx_port_get(portid_t rxp)
+{
+ static int warning_once = 1;
+
+ RTE_ASSERT(rxp < cur_fwd_config.nb_fwd_ports);
+
+ switch (port_topology) {
+ default:
+ case PORT_TOPOLOGY_PAIRED:
+ if ((rxp & 0x1) == 0) {
+ if (rxp + 1 < cur_fwd_config.nb_fwd_ports)
+ return rxp + 1;
+ if (warning_once) {
+ printf("\nWarning! port-topology=paired"
+ " and odd forward ports number,"
+ " the last port will pair with"
+ " itself.\n\n");
+ warning_once = 0;
+ }
+ return rxp;
+ }
+ return rxp - 1;
+ case PORT_TOPOLOGY_CHAINED:
+ return (rxp + 1) % cur_fwd_config.nb_fwd_ports;
+ case PORT_TOPOLOGY_LOOP:
+ return rxp;
+ }
+}
+
+static void
+simple_fwd_config_setup(void)
+{
+ portid_t i;
+
+ cur_fwd_config.nb_fwd_ports = (portid_t) nb_fwd_ports;
+ cur_fwd_config.nb_fwd_streams =
+ (streamid_t) cur_fwd_config.nb_fwd_ports;
+
+ /* reinitialize forwarding streams */
+ init_fwd_streams();
+
+ /*
+ * In the simple forwarding test, the number of forwarding cores
+ * must be lower or equal to the number of forwarding ports.
+ */
+ cur_fwd_config.nb_fwd_lcores = (lcoreid_t) nb_fwd_lcores;
+ if (cur_fwd_config.nb_fwd_lcores > cur_fwd_config.nb_fwd_ports)
+ cur_fwd_config.nb_fwd_lcores =
+ (lcoreid_t) cur_fwd_config.nb_fwd_ports;
+ setup_fwd_config_of_each_lcore(&cur_fwd_config);
+
+ for (i = 0; i < cur_fwd_config.nb_fwd_ports; i++) {
+ fwd_streams[i]->rx_port = fwd_ports_ids[i];
+ fwd_streams[i]->rx_queue = 0;
+ fwd_streams[i]->tx_port =
+ fwd_ports_ids[fwd_topology_tx_port_get(i)];
+ fwd_streams[i]->tx_queue = 0;
+ fwd_streams[i]->peer_addr = fwd_streams[i]->tx_port;
+ fwd_streams[i]->retry_enabled = retry_enabled;
+ }
+}
+
+/**
+ * For the RSS forwarding test all streams distributed over lcores. Each stream
+ * being composed of a RX queue to poll on a RX port for input messages,
+ * associated with a TX queue of a TX port where to send forwarded packets.
+ */
+static void
+rss_fwd_config_setup(void)
+{
+ portid_t rxp;
+ portid_t txp;
+ queueid_t rxq;
+ queueid_t nb_q;
+ streamid_t sm_id;
+
+ nb_q = nb_rxq;
+ if (nb_q > nb_txq)
+ nb_q = nb_txq;
+ cur_fwd_config.nb_fwd_lcores = (lcoreid_t) nb_fwd_lcores;
+ cur_fwd_config.nb_fwd_ports = nb_fwd_ports;
+ cur_fwd_config.nb_fwd_streams =
+ (streamid_t) (nb_q * cur_fwd_config.nb_fwd_ports);
+
+ if (cur_fwd_config.nb_fwd_streams < cur_fwd_config.nb_fwd_lcores)
+ cur_fwd_config.nb_fwd_lcores =
+ (lcoreid_t)cur_fwd_config.nb_fwd_streams;
+
+ /* reinitialize forwarding streams */
+ init_fwd_streams();
+
+ setup_fwd_config_of_each_lcore(&cur_fwd_config);
+ rxp = 0; rxq = 0;
+ for (sm_id = 0; sm_id < cur_fwd_config.nb_fwd_streams; sm_id++) {
+ struct fwd_stream *fs;
+
+ fs = fwd_streams[sm_id];
+ txp = fwd_topology_tx_port_get(rxp);
+ fs->rx_port = fwd_ports_ids[rxp];
+ fs->rx_queue = rxq;
+ fs->tx_port = fwd_ports_ids[txp];
+ fs->tx_queue = rxq;
+ fs->peer_addr = fs->tx_port;
+ fs->retry_enabled = retry_enabled;
+ rxp++;
+ if (rxp < nb_fwd_ports)
+ continue;
+ rxp = 0;
+ rxq++;
+ }
+}
+
+/**
+ * For the DCB forwarding test, each core is assigned on each traffic class.
+ *
+ * Each core is assigned a multi-stream, each stream being composed of
+ * a RX queue to poll on a RX port for input messages, associated with
+ * a TX queue of a TX port where to send forwarded packets. All RX and
+ * TX queues are mapping to the same traffic class.
+ * If VMDQ and DCB co-exist, each traffic class on different POOLs share
+ * the same core
+ */
+static void
+dcb_fwd_config_setup(void)
+{
+ struct rte_eth_dcb_info rxp_dcb_info, txp_dcb_info;
+ portid_t txp, rxp = 0;
+ queueid_t txq, rxq = 0;
+ lcoreid_t lc_id;
+ uint16_t nb_rx_queue, nb_tx_queue;
+ uint16_t i, j, k, sm_id = 0;
+ uint8_t tc = 0;
+
+ cur_fwd_config.nb_fwd_lcores = (lcoreid_t) nb_fwd_lcores;
+ cur_fwd_config.nb_fwd_ports = nb_fwd_ports;
+ cur_fwd_config.nb_fwd_streams =
+ (streamid_t) (nb_rxq * cur_fwd_config.nb_fwd_ports);
+
+ /* reinitialize forwarding streams */
+ init_fwd_streams();
+ sm_id = 0;
+ txp = 1;
+ /* get the dcb info on the first RX and TX ports */
+ (void)rte_eth_dev_get_dcb_info(fwd_ports_ids[rxp], &rxp_dcb_info);
+ (void)rte_eth_dev_get_dcb_info(fwd_ports_ids[txp], &txp_dcb_info);
+
+ for (lc_id = 0; lc_id < cur_fwd_config.nb_fwd_lcores; lc_id++) {
+ fwd_lcores[lc_id]->stream_nb = 0;
+ fwd_lcores[lc_id]->stream_idx = sm_id;
+ for (i = 0; i < ETH_MAX_VMDQ_POOL; i++) {
+ /* if the nb_queue is zero, means this tc is
+ * not enabled on the POOL
+ */
+ if (rxp_dcb_info.tc_queue.tc_rxq[i][tc].nb_queue == 0)
+ break;
+ k = fwd_lcores[lc_id]->stream_nb +
+ fwd_lcores[lc_id]->stream_idx;
+ rxq = rxp_dcb_info.tc_queue.tc_rxq[i][tc].base;
+ txq = txp_dcb_info.tc_queue.tc_txq[i][tc].base;
+ nb_rx_queue = txp_dcb_info.tc_queue.tc_rxq[i][tc].nb_queue;
+ nb_tx_queue = txp_dcb_info.tc_queue.tc_txq[i][tc].nb_queue;
+ for (j = 0; j < nb_rx_queue; j++) {
+ struct fwd_stream *fs;
+
+ fs = fwd_streams[k + j];
+ fs->rx_port = fwd_ports_ids[rxp];
+ fs->rx_queue = rxq + j;
+ fs->tx_port = fwd_ports_ids[txp];
+ fs->tx_queue = txq + j % nb_tx_queue;
+ fs->peer_addr = fs->tx_port;
+ fs->retry_enabled = retry_enabled;
+ }
+ fwd_lcores[lc_id]->stream_nb +=
+ rxp_dcb_info.tc_queue.tc_rxq[i][tc].nb_queue;
+ }
+ sm_id = (streamid_t) (sm_id + fwd_lcores[lc_id]->stream_nb);
+
+ tc++;
+ if (tc < rxp_dcb_info.nb_tcs)
+ continue;
+ /* Restart from TC 0 on next RX port */
+ tc = 0;
+ if (numa_support && (nb_fwd_ports <= (nb_ports >> 1)))
+ rxp = (portid_t)
+ (rxp + ((nb_ports >> 1) / nb_fwd_ports));
+ else
+ rxp++;
+ if (rxp >= nb_fwd_ports)
+ return;
+ /* get the dcb information on next RX and TX ports */
+ if ((rxp & 0x1) == 0)
+ txp = (portid_t) (rxp + 1);
+ else
+ txp = (portid_t) (rxp - 1);
+ rte_eth_dev_get_dcb_info(fwd_ports_ids[rxp], &rxp_dcb_info);
+ rte_eth_dev_get_dcb_info(fwd_ports_ids[txp], &txp_dcb_info);
+ }
+}
+
+static void
+icmp_echo_config_setup(void)
+{
+ portid_t rxp;
+ queueid_t rxq;
+ lcoreid_t lc_id;
+ uint16_t sm_id;
+
+ if ((nb_txq * nb_fwd_ports) < nb_fwd_lcores)
+ cur_fwd_config.nb_fwd_lcores = (lcoreid_t)
+ (nb_txq * nb_fwd_ports);
+ else
+ cur_fwd_config.nb_fwd_lcores = (lcoreid_t) nb_fwd_lcores;
+ cur_fwd_config.nb_fwd_ports = nb_fwd_ports;
+ cur_fwd_config.nb_fwd_streams =
+ (streamid_t) (nb_rxq * cur_fwd_config.nb_fwd_ports);
+ if (cur_fwd_config.nb_fwd_streams < cur_fwd_config.nb_fwd_lcores)
+ cur_fwd_config.nb_fwd_lcores =
+ (lcoreid_t)cur_fwd_config.nb_fwd_streams;
+ if (verbose_level > 0) {
+ printf("%s fwd_cores=%d fwd_ports=%d fwd_streams=%d\n",
+ __FUNCTION__,
+ cur_fwd_config.nb_fwd_lcores,
+ cur_fwd_config.nb_fwd_ports,
+ cur_fwd_config.nb_fwd_streams);
+ }
+
+ /* reinitialize forwarding streams */
+ init_fwd_streams();
+ setup_fwd_config_of_each_lcore(&cur_fwd_config);
+ rxp = 0; rxq = 0;
+ for (lc_id = 0; lc_id < cur_fwd_config.nb_fwd_lcores; lc_id++) {
+ if (verbose_level > 0)
+ printf(" core=%d: \n", lc_id);
+ for (sm_id = 0; sm_id < fwd_lcores[lc_id]->stream_nb; sm_id++) {
+ struct fwd_stream *fs;
+ fs = fwd_streams[fwd_lcores[lc_id]->stream_idx + sm_id];
+ fs->rx_port = fwd_ports_ids[rxp];
+ fs->rx_queue = rxq;
+ fs->tx_port = fs->rx_port;
+ fs->tx_queue = rxq;
+ fs->peer_addr = fs->tx_port;
+ fs->retry_enabled = retry_enabled;
+ if (verbose_level > 0)
+ printf(" stream=%d port=%d rxq=%d txq=%d\n",
+ sm_id, fs->rx_port, fs->rx_queue,
+ fs->tx_queue);
+ rxq = (queueid_t) (rxq + 1);
+ if (rxq == nb_rxq) {
+ rxq = 0;
+ rxp = (portid_t) (rxp + 1);
+ }
+ }
+ }
+}
+
+#if defined RTE_LIBRTE_PMD_SOFTNIC
+static void
+softnic_fwd_config_setup(void)
+{
+ struct rte_port *port;
+ portid_t pid, softnic_portid;
+ queueid_t i;
+ uint8_t softnic_enable = 0;
+
+ RTE_ETH_FOREACH_DEV(pid) {
+ port = &ports[pid];
+ const char *driver = port->dev_info.driver_name;
+
+ if (strcmp(driver, "net_softnic") == 0) {
+ softnic_portid = pid;
+ softnic_enable = 1;
+ break;
+ }
+ }
+
+ if (softnic_enable == 0) {
+ printf("Softnic mode not configured(%s)!\n", __func__);
+ return;
+ }
+
+ cur_fwd_config.nb_fwd_ports = 1;
+ cur_fwd_config.nb_fwd_streams = (streamid_t) nb_rxq;
+
+ /* Re-initialize forwarding streams */
+ init_fwd_streams();
+
+ /*
+ * In the softnic forwarding test, the number of forwarding cores
+ * is set to one and remaining are used for softnic packet processing.
+ */
+ cur_fwd_config.nb_fwd_lcores = 1;
+ setup_fwd_config_of_each_lcore(&cur_fwd_config);
+
+ for (i = 0; i < cur_fwd_config.nb_fwd_streams; i++) {
+ fwd_streams[i]->rx_port = softnic_portid;
+ fwd_streams[i]->rx_queue = i;
+ fwd_streams[i]->tx_port = softnic_portid;
+ fwd_streams[i]->tx_queue = i;
+ fwd_streams[i]->peer_addr = fwd_streams[i]->tx_port;
+ fwd_streams[i]->retry_enabled = retry_enabled;
+ }
+}
+#endif
+
+void
+fwd_config_setup(void)
+{
+ cur_fwd_config.fwd_eng = cur_fwd_eng;
+ if (strcmp(cur_fwd_eng->fwd_mode_name, "icmpecho") == 0) {
+ icmp_echo_config_setup();
+ return;
+ }
+
+#if defined RTE_LIBRTE_PMD_SOFTNIC
+ if (strcmp(cur_fwd_eng->fwd_mode_name, "softnic") == 0) {
+ softnic_fwd_config_setup();
+ return;
+ }
+#endif
+
+ if ((nb_rxq > 1) && (nb_txq > 1)){
+ if (dcb_config)
+ dcb_fwd_config_setup();
+ else
+ rss_fwd_config_setup();
+ }
+ else
+ simple_fwd_config_setup();
+}
+
+static const char *
+mp_alloc_to_str(uint8_t mode)
+{
+ switch (mode) {
+ case MP_ALLOC_NATIVE:
+ return "native";
+ case MP_ALLOC_ANON:
+ return "anon";
+ case MP_ALLOC_XMEM:
+ return "xmem";
+ case MP_ALLOC_XMEM_HUGE:
+ return "xmemhuge";
+ case MP_ALLOC_XBUF:
+ return "xbuf";
+ default:
+ return "invalid";
+ }
+}
+
+void
+pkt_fwd_config_display(struct fwd_config *cfg)
+{
+ struct fwd_stream *fs;
+ lcoreid_t lc_id;
+ streamid_t sm_id;
+
+ printf("%s packet forwarding%s - ports=%d - cores=%d - streams=%d - "
+ "NUMA support %s, MP allocation mode: %s\n",
+ cfg->fwd_eng->fwd_mode_name,
+ retry_enabled == 0 ? "" : " with retry",
+ cfg->nb_fwd_ports, cfg->nb_fwd_lcores, cfg->nb_fwd_streams,
+ numa_support == 1 ? "enabled" : "disabled",
+ mp_alloc_to_str(mp_alloc_type));
+
+ if (retry_enabled)
+ printf("TX retry num: %u, delay between TX retries: %uus\n",
+ burst_tx_retry_num, burst_tx_delay_time);
+ for (lc_id = 0; lc_id < cfg->nb_fwd_lcores; lc_id++) {
+ printf("Logical Core %u (socket %u) forwards packets on "
+ "%d streams:",
+ fwd_lcores_cpuids[lc_id],
+ rte_lcore_to_socket_id(fwd_lcores_cpuids[lc_id]),
+ fwd_lcores[lc_id]->stream_nb);
+ for (sm_id = 0; sm_id < fwd_lcores[lc_id]->stream_nb; sm_id++) {
+ fs = fwd_streams[fwd_lcores[lc_id]->stream_idx + sm_id];
+ printf("\n RX P=%d/Q=%d (socket %u) -> TX "
+ "P=%d/Q=%d (socket %u) ",
+ fs->rx_port, fs->rx_queue,
+ ports[fs->rx_port].socket_id,
+ fs->tx_port, fs->tx_queue,
+ ports[fs->tx_port].socket_id);
+ print_ethaddr("peer=",
+ &peer_eth_addrs[fs->peer_addr]);
+ }
+ printf("\n");
+ }
+ printf("\n");
+}
+
+void
+set_fwd_eth_peer(portid_t port_id, char *peer_addr)
+{
+ struct rte_ether_addr new_peer_addr;
+ if (!rte_eth_dev_is_valid_port(port_id)) {
+ printf("Error: Invalid port number %i\n", port_id);
+ return;
+ }
+ if (rte_ether_unformat_addr(peer_addr, &new_peer_addr) < 0) {
+ printf("Error: Invalid ethernet address: %s\n", peer_addr);
+ return;
+ }
+ peer_eth_addrs[port_id] = new_peer_addr;
+}
+
+int
+set_fwd_lcores_list(unsigned int *lcorelist, unsigned int nb_lc)
+{
+ unsigned int i;
+ unsigned int lcore_cpuid;
+ int record_now;
+
+ record_now = 0;
+ again:
+ for (i = 0; i < nb_lc; i++) {
+ lcore_cpuid = lcorelist[i];
+ if (! rte_lcore_is_enabled(lcore_cpuid)) {
+ printf("lcore %u not enabled\n", lcore_cpuid);
+ return -1;
+ }
+ if (lcore_cpuid == rte_get_master_lcore()) {
+ printf("lcore %u cannot be masked on for running "
+ "packet forwarding, which is the master lcore "
+ "and reserved for command line parsing only\n",
+ lcore_cpuid);
+ return -1;
+ }
+ if (record_now)
+ fwd_lcores_cpuids[i] = lcore_cpuid;
+ }
+ if (record_now == 0) {
+ record_now = 1;
+ goto again;
+ }
+ nb_cfg_lcores = (lcoreid_t) nb_lc;
+ if (nb_fwd_lcores != (lcoreid_t) nb_lc) {
+ printf("previous number of forwarding cores %u - changed to "
+ "number of configured cores %u\n",
+ (unsigned int) nb_fwd_lcores, nb_lc);
+ nb_fwd_lcores = (lcoreid_t) nb_lc;
+ }
+
+ return 0;
+}
+
+int
+set_fwd_lcores_mask(uint64_t lcoremask)
+{
+ unsigned int lcorelist[64];
+ unsigned int nb_lc;
+ unsigned int i;
+
+ if (lcoremask == 0) {
+ printf("Invalid NULL mask of cores\n");
+ return -1;
+ }
+ nb_lc = 0;
+ for (i = 0; i < 64; i++) {
+ if (! ((uint64_t)(1ULL << i) & lcoremask))
+ continue;
+ lcorelist[nb_lc++] = i;
+ }
+ return set_fwd_lcores_list(lcorelist, nb_lc);
+}
+
+void
+set_fwd_lcores_number(uint16_t nb_lc)
+{
+ if (nb_lc > nb_cfg_lcores) {
+ printf("nb fwd cores %u > %u (max. number of configured "
+ "lcores) - ignored\n",
+ (unsigned int) nb_lc, (unsigned int) nb_cfg_lcores);
+ return;
+ }
+ nb_fwd_lcores = (lcoreid_t) nb_lc;
+ printf("Number of forwarding cores set to %u\n",
+ (unsigned int) nb_fwd_lcores);
+}
+
+void
+set_fwd_ports_list(unsigned int *portlist, unsigned int nb_pt)
+{
+ unsigned int i;
+ portid_t port_id;
+ int record_now;
+
+ record_now = 0;
+ again:
+ for (i = 0; i < nb_pt; i++) {
+ port_id = (portid_t) portlist[i];
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ if (record_now)
+ fwd_ports_ids[i] = port_id;
+ }
+ if (record_now == 0) {
+ record_now = 1;
+ goto again;
+ }
+ nb_cfg_ports = (portid_t) nb_pt;
+ if (nb_fwd_ports != (portid_t) nb_pt) {
+ printf("previous number of forwarding ports %u - changed to "
+ "number of configured ports %u\n",
+ (unsigned int) nb_fwd_ports, nb_pt);
+ nb_fwd_ports = (portid_t) nb_pt;
+ }
+}
+
+/**
+ * Parse the user input and obtain the list of forwarding ports
+ *
+ * @param[in] list
+ * String containing the user input. User can specify
+ * in these formats 1,3,5 or 1-3 or 1-2,5 or 3,5-6.
+ * For example, if the user wants to use all the available
+ * 4 ports in his system, then the input can be 0-3 or 0,1,2,3.
+ * If the user wants to use only the ports 1,2 then the input
+ * is 1,2.
+ * valid characters are '-' and ','
+ * @param[out] values
+ * This array will be filled with a list of port IDs
+ * based on the user input
+ * Note that duplicate entries are discarded and only the first
+ * count entries in this array are port IDs and all the rest
+ * will contain default values
+ * @param[in] maxsize
+ * This parameter denotes 2 things
+ * 1) Number of elements in the values array
+ * 2) Maximum value of each element in the values array
+ * @return
+ * On success, returns total count of parsed port IDs
+ * On failure, returns 0
+ */
+static unsigned int
+parse_port_list(const char *list, unsigned int *values, unsigned int maxsize)
+{
+ unsigned int count = 0;
+ char *end = NULL;
+ int min, max;
+ int value, i;
+ unsigned int marked[maxsize];
+
+ if (list == NULL || values == NULL)
+ return 0;
+
+ for (i = 0; i < (int)maxsize; i++)
+ marked[i] = 0;
+
+ min = INT_MAX;
+
+ do {
+ /*Remove the blank spaces if any*/
+ while (isblank(*list))
+ list++;
+ if (*list == '\0')
+ break;
+ errno = 0;
+ value = strtol(list, &end, 10);
+ if (errno || end == NULL)
+ return 0;
+ if (value < 0 || value >= (int)maxsize)
+ return 0;
+ while (isblank(*end))
+ end++;
+ if (*end == '-' && min == INT_MAX) {
+ min = value;
+ } else if ((*end == ',') || (*end == '\0')) {
+ max = value;
+ if (min == INT_MAX)
+ min = value;
+ for (i = min; i <= max; i++) {
+ if (count < maxsize) {
+ if (marked[i])
+ continue;
+ values[count] = i;
+ marked[i] = 1;
+ count++;
+ }
+ }
+ min = INT_MAX;
+ } else
+ return 0;
+ list = end + 1;
+ } while (*end != '\0');
+
+ return count;
+}
+
+void
+parse_fwd_portlist(const char *portlist)
+{
+ unsigned int portcount;
+ unsigned int portindex[RTE_MAX_ETHPORTS];
+ unsigned int i, valid_port_count = 0;
+
+ portcount = parse_port_list(portlist, portindex, RTE_MAX_ETHPORTS);
+ if (!portcount)
+ rte_exit(EXIT_FAILURE, "Invalid fwd port list\n");
+
+ /*
+ * Here we verify the validity of the ports
+ * and thereby calculate the total number of
+ * valid ports
+ */
+ for (i = 0; i < portcount && i < RTE_DIM(portindex); i++) {
+ if (rte_eth_dev_is_valid_port(portindex[i])) {
+ portindex[valid_port_count] = portindex[i];
+ valid_port_count++;
+ }
+ }
+
+ set_fwd_ports_list(portindex, valid_port_count);
+}
+
+void
+set_fwd_ports_mask(uint64_t portmask)
+{
+ unsigned int portlist[64];
+ unsigned int nb_pt;
+ unsigned int i;
+
+ if (portmask == 0) {
+ printf("Invalid NULL mask of ports\n");
+ return;
+ }
+ nb_pt = 0;
+ RTE_ETH_FOREACH_DEV(i) {
+ if (! ((uint64_t)(1ULL << i) & portmask))
+ continue;
+ portlist[nb_pt++] = i;
+ }
+ set_fwd_ports_list(portlist, nb_pt);
+}
+
+void
+set_fwd_ports_number(uint16_t nb_pt)
+{
+ if (nb_pt > nb_cfg_ports) {
+ printf("nb fwd ports %u > %u (number of configured "
+ "ports) - ignored\n",
+ (unsigned int) nb_pt, (unsigned int) nb_cfg_ports);
+ return;
+ }
+ nb_fwd_ports = (portid_t) nb_pt;
+ printf("Number of forwarding ports set to %u\n",
+ (unsigned int) nb_fwd_ports);
+}
+
+int
+port_is_forwarding(portid_t port_id)
+{
+ unsigned int i;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return -1;
+
+ for (i = 0; i < nb_fwd_ports; i++) {
+ if (fwd_ports_ids[i] == port_id)
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+set_nb_pkt_per_burst(uint16_t nb)
+{
+ if (nb > MAX_PKT_BURST) {
+ printf("nb pkt per burst: %u > %u (maximum packet per burst) "
+ " ignored\n",
+ (unsigned int) nb, (unsigned int) MAX_PKT_BURST);
+ return;
+ }
+ nb_pkt_per_burst = nb;
+ printf("Number of packets per burst set to %u\n",
+ (unsigned int) nb_pkt_per_burst);
+}
+
+static const char *
+tx_split_get_name(enum tx_pkt_split split)
+{
+ uint32_t i;
+
+ for (i = 0; i != RTE_DIM(tx_split_name); i++) {
+ if (tx_split_name[i].split == split)
+ return tx_split_name[i].name;
+ }
+ return NULL;
+}
+
+void
+set_tx_pkt_split(const char *name)
+{
+ uint32_t i;
+
+ for (i = 0; i != RTE_DIM(tx_split_name); i++) {
+ if (strcmp(tx_split_name[i].name, name) == 0) {
+ tx_pkt_split = tx_split_name[i].split;
+ return;
+ }
+ }
+ printf("unknown value: \"%s\"\n", name);
+}
+
+void
+show_tx_pkt_segments(void)
+{
+ uint32_t i, n;
+ const char *split;
+
+ n = tx_pkt_nb_segs;
+ split = tx_split_get_name(tx_pkt_split);
+
+ printf("Number of segments: %u\n", n);
+ printf("Segment sizes: ");
+ for (i = 0; i != n - 1; i++)
+ printf("%hu,", tx_pkt_seg_lengths[i]);
+ printf("%hu\n", tx_pkt_seg_lengths[i]);
+ printf("Split packet: %s\n", split);
+}
+
+void
+set_tx_pkt_segments(unsigned *seg_lengths, unsigned nb_segs)
+{
+ uint16_t tx_pkt_len;
+ unsigned i;
+
+ if (nb_segs >= (unsigned) nb_txd) {
+ printf("nb segments per TX packets=%u >= nb_txd=%u - ignored\n",
+ nb_segs, (unsigned int) nb_txd);
+ return;
+ }
+
+ /*
+ * Check that each segment length is greater or equal than
+ * the mbuf data sise.
+ * Check also that the total packet length is greater or equal than the
+ * size of an empty UDP/IP packet (sizeof(struct rte_ether_hdr) +
+ * 20 + 8).
+ */
+ tx_pkt_len = 0;
+ for (i = 0; i < nb_segs; i++) {
+ if (seg_lengths[i] > (unsigned) mbuf_data_size) {
+ printf("length[%u]=%u > mbuf_data_size=%u - give up\n",
+ i, seg_lengths[i], (unsigned) mbuf_data_size);
+ return;
+ }
+ tx_pkt_len = (uint16_t)(tx_pkt_len + seg_lengths[i]);
+ }
+ if (tx_pkt_len < (sizeof(struct rte_ether_hdr) + 20 + 8)) {
+ printf("total packet length=%u < %d - give up\n",
+ (unsigned) tx_pkt_len,
+ (int)(sizeof(struct rte_ether_hdr) + 20 + 8));
+ return;
+ }
+
+ for (i = 0; i < nb_segs; i++)
+ tx_pkt_seg_lengths[i] = (uint16_t) seg_lengths[i];
+
+ tx_pkt_length = tx_pkt_len;
+ tx_pkt_nb_segs = (uint8_t) nb_segs;
+}
+
+void
+setup_gro(const char *onoff, portid_t port_id)
+{
+ if (!rte_eth_dev_is_valid_port(port_id)) {
+ printf("invalid port id %u\n", port_id);
+ return;
+ }
+ if (test_done == 0) {
+ printf("Before enable/disable GRO,"
+ " please stop forwarding first\n");
+ return;
+ }
+ if (strcmp(onoff, "on") == 0) {
+ if (gro_ports[port_id].enable != 0) {
+ printf("Port %u has enabled GRO. Please"
+ " disable GRO first\n", port_id);
+ return;
+ }
+ if (gro_flush_cycles == GRO_DEFAULT_FLUSH_CYCLES) {
+ gro_ports[port_id].param.gro_types = RTE_GRO_TCP_IPV4;
+ gro_ports[port_id].param.max_flow_num =
+ GRO_DEFAULT_FLOW_NUM;
+ gro_ports[port_id].param.max_item_per_flow =
+ GRO_DEFAULT_ITEM_NUM_PER_FLOW;
+ }
+ gro_ports[port_id].enable = 1;
+ } else {
+ if (gro_ports[port_id].enable == 0) {
+ printf("Port %u has disabled GRO\n", port_id);
+ return;
+ }
+ gro_ports[port_id].enable = 0;
+ }
+}
+
+void
+setup_gro_flush_cycles(uint8_t cycles)
+{
+ if (test_done == 0) {
+ printf("Before change flush interval for GRO,"
+ " please stop forwarding first.\n");
+ return;
+ }
+
+ if (cycles > GRO_MAX_FLUSH_CYCLES || cycles <
+ GRO_DEFAULT_FLUSH_CYCLES) {
+ printf("The flushing cycle be in the range"
+ " of 1 to %u. Revert to the default"
+ " value %u.\n",
+ GRO_MAX_FLUSH_CYCLES,
+ GRO_DEFAULT_FLUSH_CYCLES);
+ cycles = GRO_DEFAULT_FLUSH_CYCLES;
+ }
+
+ gro_flush_cycles = cycles;
+}
+
+void
+show_gro(portid_t port_id)
+{
+ struct rte_gro_param *param;
+ uint32_t max_pkts_num;
+
+ param = &gro_ports[port_id].param;
+
+ if (!rte_eth_dev_is_valid_port(port_id)) {
+ printf("Invalid port id %u.\n", port_id);
+ return;
+ }
+ if (gro_ports[port_id].enable) {
+ printf("GRO type: TCP/IPv4\n");
+ if (gro_flush_cycles == GRO_DEFAULT_FLUSH_CYCLES) {
+ max_pkts_num = param->max_flow_num *
+ param->max_item_per_flow;
+ } else
+ max_pkts_num = MAX_PKT_BURST * GRO_MAX_FLUSH_CYCLES;
+ printf("Max number of packets to perform GRO: %u\n",
+ max_pkts_num);
+ printf("Flushing cycles: %u\n", gro_flush_cycles);
+ } else
+ printf("Port %u doesn't enable GRO.\n", port_id);
+}
+
+void
+setup_gso(const char *mode, portid_t port_id)
+{
+ if (!rte_eth_dev_is_valid_port(port_id)) {
+ printf("invalid port id %u\n", port_id);
+ return;
+ }
+ if (strcmp(mode, "on") == 0) {
+ if (test_done == 0) {
+ printf("before enabling GSO,"
+ " please stop forwarding first\n");
+ return;
+ }
+ gso_ports[port_id].enable = 1;
+ } else if (strcmp(mode, "off") == 0) {
+ if (test_done == 0) {
+ printf("before disabling GSO,"
+ " please stop forwarding first\n");
+ return;
+ }
+ gso_ports[port_id].enable = 0;
+ }
+}
+
+char*
+list_pkt_forwarding_modes(void)
+{
+ static char fwd_modes[128] = "";
+ const char *separator = "|";
+ struct fwd_engine *fwd_eng;
+ unsigned i = 0;
+
+ if (strlen (fwd_modes) == 0) {
+ while ((fwd_eng = fwd_engines[i++]) != NULL) {
+ strncat(fwd_modes, fwd_eng->fwd_mode_name,
+ sizeof(fwd_modes) - strlen(fwd_modes) - 1);
+ strncat(fwd_modes, separator,
+ sizeof(fwd_modes) - strlen(fwd_modes) - 1);
+ }
+ fwd_modes[strlen(fwd_modes) - strlen(separator)] = '\0';
+ }
+
+ return fwd_modes;
+}
+
+char*
+list_pkt_forwarding_retry_modes(void)
+{
+ static char fwd_modes[128] = "";
+ const char *separator = "|";
+ struct fwd_engine *fwd_eng;
+ unsigned i = 0;
+
+ if (strlen(fwd_modes) == 0) {
+ while ((fwd_eng = fwd_engines[i++]) != NULL) {
+ if (fwd_eng == &rx_only_engine)
+ continue;
+ strncat(fwd_modes, fwd_eng->fwd_mode_name,
+ sizeof(fwd_modes) -
+ strlen(fwd_modes) - 1);
+ strncat(fwd_modes, separator,
+ sizeof(fwd_modes) -
+ strlen(fwd_modes) - 1);
+ }
+ fwd_modes[strlen(fwd_modes) - strlen(separator)] = '\0';
+ }
+
+ return fwd_modes;
+}
+
+void
+set_pkt_forwarding_mode(const char *fwd_mode_name)
+{
+ struct fwd_engine *fwd_eng;
+ unsigned i;
+
+ i = 0;
+ while ((fwd_eng = fwd_engines[i]) != NULL) {
+ if (! strcmp(fwd_eng->fwd_mode_name, fwd_mode_name)) {
+ printf("Set %s packet forwarding mode%s\n",
+ fwd_mode_name,
+ retry_enabled == 0 ? "" : " with retry");
+ cur_fwd_eng = fwd_eng;
+ return;
+ }
+ i++;
+ }
+ printf("Invalid %s packet forwarding mode\n", fwd_mode_name);
+}
+
+void
+add_rx_dump_callbacks(portid_t portid)
+{
+ struct rte_eth_dev_info dev_info;
+ uint16_t queue;
+ int ret;
+
+ if (port_id_is_invalid(portid, ENABLED_WARN))
+ return;
+
+ ret = eth_dev_info_get_print_err(portid, &dev_info);
+ if (ret != 0)
+ return;
+
+ for (queue = 0; queue < dev_info.nb_rx_queues; queue++)
+ if (!ports[portid].rx_dump_cb[queue])
+ ports[portid].rx_dump_cb[queue] =
+ rte_eth_add_rx_callback(portid, queue,
+ dump_rx_pkts, NULL);
+}
+
+void
+add_tx_dump_callbacks(portid_t portid)
+{
+ struct rte_eth_dev_info dev_info;
+ uint16_t queue;
+ int ret;
+
+ if (port_id_is_invalid(portid, ENABLED_WARN))
+ return;
+
+ ret = eth_dev_info_get_print_err(portid, &dev_info);
+ if (ret != 0)
+ return;
+
+ for (queue = 0; queue < dev_info.nb_tx_queues; queue++)
+ if (!ports[portid].tx_dump_cb[queue])
+ ports[portid].tx_dump_cb[queue] =
+ rte_eth_add_tx_callback(portid, queue,
+ dump_tx_pkts, NULL);
+}
+
+void
+remove_rx_dump_callbacks(portid_t portid)
+{
+ struct rte_eth_dev_info dev_info;
+ uint16_t queue;
+ int ret;
+
+ if (port_id_is_invalid(portid, ENABLED_WARN))
+ return;
+
+ ret = eth_dev_info_get_print_err(portid, &dev_info);
+ if (ret != 0)
+ return;
+
+ for (queue = 0; queue < dev_info.nb_rx_queues; queue++)
+ if (ports[portid].rx_dump_cb[queue]) {
+ rte_eth_remove_rx_callback(portid, queue,
+ ports[portid].rx_dump_cb[queue]);
+ ports[portid].rx_dump_cb[queue] = NULL;
+ }
+}
+
+void
+remove_tx_dump_callbacks(portid_t portid)
+{
+ struct rte_eth_dev_info dev_info;
+ uint16_t queue;
+ int ret;
+
+ if (port_id_is_invalid(portid, ENABLED_WARN))
+ return;
+
+ ret = eth_dev_info_get_print_err(portid, &dev_info);
+ if (ret != 0)
+ return;
+
+ for (queue = 0; queue < dev_info.nb_tx_queues; queue++)
+ if (ports[portid].tx_dump_cb[queue]) {
+ rte_eth_remove_tx_callback(portid, queue,
+ ports[portid].tx_dump_cb[queue]);
+ ports[portid].tx_dump_cb[queue] = NULL;
+ }
+}
+
+void
+configure_rxtx_dump_callbacks(uint16_t verbose)
+{
+ portid_t portid;
+
+#ifndef RTE_ETHDEV_RXTX_CALLBACKS
+ TESTPMD_LOG(ERR, "setting rxtx callbacks is not enabled\n");
+ return;
+#endif
+
+ RTE_ETH_FOREACH_DEV(portid)
+ {
+ if (verbose == 1 || verbose > 2)
+ add_rx_dump_callbacks(portid);
+ else
+ remove_rx_dump_callbacks(portid);
+ if (verbose >= 2)
+ add_tx_dump_callbacks(portid);
+ else
+ remove_tx_dump_callbacks(portid);
+ }
+}
+
+void
+set_verbose_level(uint16_t vb_level)
+{
+ printf("Change verbose level from %u to %u\n",
+ (unsigned int) verbose_level, (unsigned int) vb_level);
+ verbose_level = vb_level;
+ configure_rxtx_dump_callbacks(verbose_level);
+}
+
+void
+vlan_extend_set(portid_t port_id, int on)
+{
+ int diag;
+ int vlan_offload;
+ uint64_t port_rx_offloads = ports[port_id].dev_conf.rxmode.offloads;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ vlan_offload = rte_eth_dev_get_vlan_offload(port_id);
+
+ if (on) {
+ vlan_offload |= ETH_VLAN_EXTEND_OFFLOAD;
+ port_rx_offloads |= DEV_RX_OFFLOAD_VLAN_EXTEND;
+ } else {
+ vlan_offload &= ~ETH_VLAN_EXTEND_OFFLOAD;
+ port_rx_offloads &= ~DEV_RX_OFFLOAD_VLAN_EXTEND;
+ }
+
+ diag = rte_eth_dev_set_vlan_offload(port_id, vlan_offload);
+ if (diag < 0)
+ printf("rx_vlan_extend_set(port_pi=%d, on=%d) failed "
+ "diag=%d\n", port_id, on, diag);
+ ports[port_id].dev_conf.rxmode.offloads = port_rx_offloads;
+}
+
+void
+rx_vlan_strip_set(portid_t port_id, int on)
+{
+ int diag;
+ int vlan_offload;
+ uint64_t port_rx_offloads = ports[port_id].dev_conf.rxmode.offloads;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ vlan_offload = rte_eth_dev_get_vlan_offload(port_id);
+
+ if (on) {
+ vlan_offload |= ETH_VLAN_STRIP_OFFLOAD;
+ port_rx_offloads |= DEV_RX_OFFLOAD_VLAN_STRIP;
+ } else {
+ vlan_offload &= ~ETH_VLAN_STRIP_OFFLOAD;
+ port_rx_offloads &= ~DEV_RX_OFFLOAD_VLAN_STRIP;
+ }
+
+ diag = rte_eth_dev_set_vlan_offload(port_id, vlan_offload);
+ if (diag < 0)
+ printf("rx_vlan_strip_set(port_pi=%d, on=%d) failed "
+ "diag=%d\n", port_id, on, diag);
+ ports[port_id].dev_conf.rxmode.offloads = port_rx_offloads;
+}
+
+void
+rx_vlan_strip_set_on_queue(portid_t port_id, uint16_t queue_id, int on)
+{
+ int diag;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ diag = rte_eth_dev_set_vlan_strip_on_queue(port_id, queue_id, on);
+ if (diag < 0)
+ printf("rx_vlan_strip_set_on_queue(port_pi=%d, queue_id=%d, on=%d) failed "
+ "diag=%d\n", port_id, queue_id, on, diag);
+}
+
+void
+rx_vlan_filter_set(portid_t port_id, int on)
+{
+ int diag;
+ int vlan_offload;
+ uint64_t port_rx_offloads = ports[port_id].dev_conf.rxmode.offloads;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ vlan_offload = rte_eth_dev_get_vlan_offload(port_id);
+
+ if (on) {
+ vlan_offload |= ETH_VLAN_FILTER_OFFLOAD;
+ port_rx_offloads |= DEV_RX_OFFLOAD_VLAN_FILTER;
+ } else {
+ vlan_offload &= ~ETH_VLAN_FILTER_OFFLOAD;
+ port_rx_offloads &= ~DEV_RX_OFFLOAD_VLAN_FILTER;
+ }
+
+ diag = rte_eth_dev_set_vlan_offload(port_id, vlan_offload);
+ if (diag < 0)
+ printf("rx_vlan_filter_set(port_pi=%d, on=%d) failed "
+ "diag=%d\n", port_id, on, diag);
+ ports[port_id].dev_conf.rxmode.offloads = port_rx_offloads;
+}
+
+void
+rx_vlan_qinq_strip_set(portid_t port_id, int on)
+{
+ int diag;
+ int vlan_offload;
+ uint64_t port_rx_offloads = ports[port_id].dev_conf.rxmode.offloads;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ vlan_offload = rte_eth_dev_get_vlan_offload(port_id);
+
+ if (on) {
+ vlan_offload |= ETH_QINQ_STRIP_OFFLOAD;
+ port_rx_offloads |= DEV_RX_OFFLOAD_QINQ_STRIP;
+ } else {
+ vlan_offload &= ~ETH_QINQ_STRIP_OFFLOAD;
+ port_rx_offloads &= ~DEV_RX_OFFLOAD_QINQ_STRIP;
+ }
+
+ diag = rte_eth_dev_set_vlan_offload(port_id, vlan_offload);
+ if (diag < 0)
+ printf("%s(port_pi=%d, on=%d) failed "
+ "diag=%d\n", __func__, port_id, on, diag);
+ ports[port_id].dev_conf.rxmode.offloads = port_rx_offloads;
+}
+
+int
+rx_vft_set(portid_t port_id, uint16_t vlan_id, int on)
+{
+ int diag;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return 1;
+ if (vlan_id_is_invalid(vlan_id))
+ return 1;
+ diag = rte_eth_dev_vlan_filter(port_id, vlan_id, on);
+ if (diag == 0)
+ return 0;
+ printf("rte_eth_dev_vlan_filter(port_pi=%d, vlan_id=%d, on=%d) failed "
+ "diag=%d\n",
+ port_id, vlan_id, on, diag);
+ return -1;
+}
+
+void
+rx_vlan_all_filter_set(portid_t port_id, int on)
+{
+ uint16_t vlan_id;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ for (vlan_id = 0; vlan_id < 4096; vlan_id++) {
+ if (rx_vft_set(port_id, vlan_id, on))
+ break;
+ }
+}
+
+void
+vlan_tpid_set(portid_t port_id, enum rte_vlan_type vlan_type, uint16_t tp_id)
+{
+ int diag;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ diag = rte_eth_dev_set_vlan_ether_type(port_id, vlan_type, tp_id);
+ if (diag == 0)
+ return;
+
+ printf("tx_vlan_tpid_set(port_pi=%d, vlan_type=%d, tpid=%d) failed "
+ "diag=%d\n",
+ port_id, vlan_type, tp_id, diag);
+}
+
+void
+tx_vlan_set(portid_t port_id, uint16_t vlan_id)
+{
+ struct rte_eth_dev_info dev_info;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ if (vlan_id_is_invalid(vlan_id))
+ return;
+
+ if (ports[port_id].dev_conf.txmode.offloads &
+ DEV_TX_OFFLOAD_QINQ_INSERT) {
+ printf("Error, as QinQ has been enabled.\n");
+ return;
+ }
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if ((dev_info.tx_offload_capa & DEV_TX_OFFLOAD_VLAN_INSERT) == 0) {
+ printf("Error: vlan insert is not supported by port %d\n",
+ port_id);
+ return;
+ }
+
+ tx_vlan_reset(port_id);
+ ports[port_id].dev_conf.txmode.offloads |= DEV_TX_OFFLOAD_VLAN_INSERT;
+ ports[port_id].tx_vlan_id = vlan_id;
+}
+
+void
+tx_qinq_set(portid_t port_id, uint16_t vlan_id, uint16_t vlan_id_outer)
+{
+ struct rte_eth_dev_info dev_info;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ if (vlan_id_is_invalid(vlan_id))
+ return;
+ if (vlan_id_is_invalid(vlan_id_outer))
+ return;
+
+ ret = eth_dev_info_get_print_err(port_id, &dev_info);
+ if (ret != 0)
+ return;
+
+ if ((dev_info.tx_offload_capa & DEV_TX_OFFLOAD_QINQ_INSERT) == 0) {
+ printf("Error: qinq insert not supported by port %d\n",
+ port_id);
+ return;
+ }
+
+ tx_vlan_reset(port_id);
+ ports[port_id].dev_conf.txmode.offloads |= (DEV_TX_OFFLOAD_VLAN_INSERT |
+ DEV_TX_OFFLOAD_QINQ_INSERT);
+ ports[port_id].tx_vlan_id = vlan_id;
+ ports[port_id].tx_vlan_id_outer = vlan_id_outer;
+}
+
+void
+tx_vlan_reset(portid_t port_id)
+{
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ ports[port_id].dev_conf.txmode.offloads &=
+ ~(DEV_TX_OFFLOAD_VLAN_INSERT |
+ DEV_TX_OFFLOAD_QINQ_INSERT);
+ ports[port_id].tx_vlan_id = 0;
+ ports[port_id].tx_vlan_id_outer = 0;
+}
+
+void
+tx_vlan_pvid_set(portid_t port_id, uint16_t vlan_id, int on)
+{
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ rte_eth_dev_set_vlan_pvid(port_id, vlan_id, on);
+}
+
+void
+set_qmap(portid_t port_id, uint8_t is_rx, uint16_t queue_id, uint8_t map_value)
+{
+ uint16_t i;
+ uint8_t existing_mapping_found = 0;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ if (is_rx ? (rx_queue_id_is_invalid(queue_id)) : (tx_queue_id_is_invalid(queue_id)))
+ return;
+
+ if (map_value >= RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+ printf("map_value not in required range 0..%d\n",
+ RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
+ return;
+ }
+
+ if (!is_rx) { /*then tx*/
+ for (i = 0; i < nb_tx_queue_stats_mappings; i++) {
+ if ((tx_queue_stats_mappings[i].port_id == port_id) &&
+ (tx_queue_stats_mappings[i].queue_id == queue_id)) {
+ tx_queue_stats_mappings[i].stats_counter_id = map_value;
+ existing_mapping_found = 1;
+ break;
+ }
+ }
+ if (!existing_mapping_found) { /* A new additional mapping... */
+ tx_queue_stats_mappings[nb_tx_queue_stats_mappings].port_id = port_id;
+ tx_queue_stats_mappings[nb_tx_queue_stats_mappings].queue_id = queue_id;
+ tx_queue_stats_mappings[nb_tx_queue_stats_mappings].stats_counter_id = map_value;
+ nb_tx_queue_stats_mappings++;
+ }
+ }
+ else { /*rx*/
+ for (i = 0; i < nb_rx_queue_stats_mappings; i++) {
+ if ((rx_queue_stats_mappings[i].port_id == port_id) &&
+ (rx_queue_stats_mappings[i].queue_id == queue_id)) {
+ rx_queue_stats_mappings[i].stats_counter_id = map_value;
+ existing_mapping_found = 1;
+ break;
+ }
+ }
+ if (!existing_mapping_found) { /* A new additional mapping... */
+ rx_queue_stats_mappings[nb_rx_queue_stats_mappings].port_id = port_id;
+ rx_queue_stats_mappings[nb_rx_queue_stats_mappings].queue_id = queue_id;
+ rx_queue_stats_mappings[nb_rx_queue_stats_mappings].stats_counter_id = map_value;
+ nb_rx_queue_stats_mappings++;
+ }
+ }
+}
+
+void
+set_xstats_hide_zero(uint8_t on_off)
+{
+ xstats_hide_zero = on_off;
+}
+
+static inline void
+print_fdir_mask(struct rte_eth_fdir_masks *mask)
+{
+ printf("\n vlan_tci: 0x%04x", rte_be_to_cpu_16(mask->vlan_tci_mask));
+
+ if (fdir_conf.mode == RTE_FDIR_MODE_PERFECT_TUNNEL)
+ printf(", mac_addr: 0x%02x, tunnel_type: 0x%01x,"
+ " tunnel_id: 0x%08x",
+ mask->mac_addr_byte_mask, mask->tunnel_type_mask,
+ rte_be_to_cpu_32(mask->tunnel_id_mask));
+ else if (fdir_conf.mode != RTE_FDIR_MODE_PERFECT_MAC_VLAN) {
+ printf(", src_ipv4: 0x%08x, dst_ipv4: 0x%08x",
+ rte_be_to_cpu_32(mask->ipv4_mask.src_ip),
+ rte_be_to_cpu_32(mask->ipv4_mask.dst_ip));
+
+ printf("\n src_port: 0x%04x, dst_port: 0x%04x",
+ rte_be_to_cpu_16(mask->src_port_mask),
+ rte_be_to_cpu_16(mask->dst_port_mask));
+
+ printf("\n src_ipv6: 0x%08x,0x%08x,0x%08x,0x%08x",
+ rte_be_to_cpu_32(mask->ipv6_mask.src_ip[0]),
+ rte_be_to_cpu_32(mask->ipv6_mask.src_ip[1]),
+ rte_be_to_cpu_32(mask->ipv6_mask.src_ip[2]),
+ rte_be_to_cpu_32(mask->ipv6_mask.src_ip[3]));
+
+ printf("\n dst_ipv6: 0x%08x,0x%08x,0x%08x,0x%08x",
+ rte_be_to_cpu_32(mask->ipv6_mask.dst_ip[0]),
+ rte_be_to_cpu_32(mask->ipv6_mask.dst_ip[1]),
+ rte_be_to_cpu_32(mask->ipv6_mask.dst_ip[2]),
+ rte_be_to_cpu_32(mask->ipv6_mask.dst_ip[3]));
+ }
+
+ printf("\n");
+}
+
+static inline void
+print_fdir_flex_payload(struct rte_eth_fdir_flex_conf *flex_conf, uint32_t num)
+{
+ struct rte_eth_flex_payload_cfg *cfg;
+ uint32_t i, j;
+
+ for (i = 0; i < flex_conf->nb_payloads; i++) {
+ cfg = &flex_conf->flex_set[i];
+ if (cfg->type == RTE_ETH_RAW_PAYLOAD)
+ printf("\n RAW: ");
+ else if (cfg->type == RTE_ETH_L2_PAYLOAD)
+ printf("\n L2_PAYLOAD: ");
+ else if (cfg->type == RTE_ETH_L3_PAYLOAD)
+ printf("\n L3_PAYLOAD: ");
+ else if (cfg->type == RTE_ETH_L4_PAYLOAD)
+ printf("\n L4_PAYLOAD: ");
+ else
+ printf("\n UNKNOWN PAYLOAD(%u): ", cfg->type);
+ for (j = 0; j < num; j++)
+ printf(" %-5u", cfg->src_offset[j]);
+ }
+ printf("\n");
+}
+
+static char *
+flowtype_to_str(uint16_t flow_type)
+{
+ struct flow_type_info {
+ char str[32];
+ uint16_t ftype;
+ };
+
+ uint8_t i;
+ static struct flow_type_info flowtype_str_table[] = {
+ {"raw", RTE_ETH_FLOW_RAW},
+ {"ipv4", RTE_ETH_FLOW_IPV4},
+ {"ipv4-frag", RTE_ETH_FLOW_FRAG_IPV4},
+ {"ipv4-tcp", RTE_ETH_FLOW_NONFRAG_IPV4_TCP},
+ {"ipv4-udp", RTE_ETH_FLOW_NONFRAG_IPV4_UDP},
+ {"ipv4-sctp", RTE_ETH_FLOW_NONFRAG_IPV4_SCTP},
+ {"ipv4-other", RTE_ETH_FLOW_NONFRAG_IPV4_OTHER},
+ {"ipv6", RTE_ETH_FLOW_IPV6},
+ {"ipv6-frag", RTE_ETH_FLOW_FRAG_IPV6},
+ {"ipv6-tcp", RTE_ETH_FLOW_NONFRAG_IPV6_TCP},
+ {"ipv6-udp", RTE_ETH_FLOW_NONFRAG_IPV6_UDP},
+ {"ipv6-sctp", RTE_ETH_FLOW_NONFRAG_IPV6_SCTP},
+ {"ipv6-other", RTE_ETH_FLOW_NONFRAG_IPV6_OTHER},
+ {"l2_payload", RTE_ETH_FLOW_L2_PAYLOAD},
+ {"port", RTE_ETH_FLOW_PORT},
+ {"vxlan", RTE_ETH_FLOW_VXLAN},
+ {"geneve", RTE_ETH_FLOW_GENEVE},
+ {"nvgre", RTE_ETH_FLOW_NVGRE},
+ {"vxlan-gpe", RTE_ETH_FLOW_VXLAN_GPE},
+ };
+
+ for (i = 0; i < RTE_DIM(flowtype_str_table); i++) {
+ if (flowtype_str_table[i].ftype == flow_type)
+ return flowtype_str_table[i].str;
+ }
+
+ return NULL;
+}
+
+static inline void
+print_fdir_flex_mask(struct rte_eth_fdir_flex_conf *flex_conf, uint32_t num)
+{
+ struct rte_eth_fdir_flex_mask *mask;
+ uint32_t i, j;
+ char *p;
+
+ for (i = 0; i < flex_conf->nb_flexmasks; i++) {
+ mask = &flex_conf->flex_mask[i];
+ p = flowtype_to_str(mask->flow_type);
+ printf("\n %s:\t", p ? p : "unknown");
+ for (j = 0; j < num; j++)
+ printf(" %02x", mask->mask[j]);
+ }
+ printf("\n");
+}
+
+static inline void
+print_fdir_flow_type(uint32_t flow_types_mask)
+{
+ int i;
+ char *p;
+
+ for (i = RTE_ETH_FLOW_UNKNOWN; i < RTE_ETH_FLOW_MAX; i++) {
+ if (!(flow_types_mask & (1 << i)))
+ continue;
+ p = flowtype_to_str(i);
+ if (p)
+ printf(" %s", p);
+ else
+ printf(" unknown");
+ }
+ printf("\n");
+}
+
+void
+fdir_get_infos(portid_t port_id)
+{
+ struct rte_eth_fdir_stats fdir_stat;
+ struct rte_eth_fdir_info fdir_info;
+ int ret;
+
+ static const char *fdir_stats_border = "########################";
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ ret = rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR);
+ if (ret < 0) {
+ printf("\n FDIR is not supported on port %-2d\n",
+ port_id);
+ return;
+ }
+
+ memset(&fdir_info, 0, sizeof(fdir_info));
+ rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR,
+ RTE_ETH_FILTER_INFO, &fdir_info);
+ memset(&fdir_stat, 0, sizeof(fdir_stat));
+ rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR,
+ RTE_ETH_FILTER_STATS, &fdir_stat);
+ printf("\n %s FDIR infos for port %-2d %s\n",
+ fdir_stats_border, port_id, fdir_stats_border);
+ printf(" MODE: ");
+ if (fdir_info.mode == RTE_FDIR_MODE_PERFECT)
+ printf(" PERFECT\n");
+ else if (fdir_info.mode == RTE_FDIR_MODE_PERFECT_MAC_VLAN)
+ printf(" PERFECT-MAC-VLAN\n");
+ else if (fdir_info.mode == RTE_FDIR_MODE_PERFECT_TUNNEL)
+ printf(" PERFECT-TUNNEL\n");
+ else if (fdir_info.mode == RTE_FDIR_MODE_SIGNATURE)
+ printf(" SIGNATURE\n");
+ else
+ printf(" DISABLE\n");
+ if (fdir_info.mode != RTE_FDIR_MODE_PERFECT_MAC_VLAN
+ && fdir_info.mode != RTE_FDIR_MODE_PERFECT_TUNNEL) {
+ printf(" SUPPORTED FLOW TYPE: ");
+ print_fdir_flow_type(fdir_info.flow_types_mask[0]);
+ }
+ printf(" FLEX PAYLOAD INFO:\n");
+ printf(" max_len: %-10"PRIu32" payload_limit: %-10"PRIu32"\n"
+ " payload_unit: %-10"PRIu32" payload_seg: %-10"PRIu32"\n"
+ " bitmask_unit: %-10"PRIu32" bitmask_num: %-10"PRIu32"\n",
+ fdir_info.max_flexpayload, fdir_info.flex_payload_limit,
+ fdir_info.flex_payload_unit,
+ fdir_info.max_flex_payload_segment_num,
+ fdir_info.flex_bitmask_unit, fdir_info.max_flex_bitmask_num);
+ printf(" MASK: ");
+ print_fdir_mask(&fdir_info.mask);
+ if (fdir_info.flex_conf.nb_payloads > 0) {
+ printf(" FLEX PAYLOAD SRC OFFSET:");
+ print_fdir_flex_payload(&fdir_info.flex_conf, fdir_info.max_flexpayload);
+ }
+ if (fdir_info.flex_conf.nb_flexmasks > 0) {
+ printf(" FLEX MASK CFG:");
+ print_fdir_flex_mask(&fdir_info.flex_conf, fdir_info.max_flexpayload);
+ }
+ printf(" guarant_count: %-10"PRIu32" best_count: %"PRIu32"\n",
+ fdir_stat.guarant_cnt, fdir_stat.best_cnt);
+ printf(" guarant_space: %-10"PRIu32" best_space: %"PRIu32"\n",
+ fdir_info.guarant_spc, fdir_info.best_spc);
+ printf(" collision: %-10"PRIu32" free: %"PRIu32"\n"
+ " maxhash: %-10"PRIu32" maxlen: %"PRIu32"\n"
+ " add: %-10"PRIu64" remove: %"PRIu64"\n"
+ " f_add: %-10"PRIu64" f_remove: %"PRIu64"\n",
+ fdir_stat.collision, fdir_stat.free,
+ fdir_stat.maxhash, fdir_stat.maxlen,
+ fdir_stat.add, fdir_stat.remove,
+ fdir_stat.f_add, fdir_stat.f_remove);
+ printf(" %s############################%s\n",
+ fdir_stats_border, fdir_stats_border);
+}
+
+void
+fdir_set_flex_mask(portid_t port_id, struct rte_eth_fdir_flex_mask *cfg)
+{
+ struct rte_port *port;
+ struct rte_eth_fdir_flex_conf *flex_conf;
+ int i, idx = 0;
+
+ port = &ports[port_id];
+ flex_conf = &port->dev_conf.fdir_conf.flex_conf;
+ for (i = 0; i < RTE_ETH_FLOW_MAX; i++) {
+ if (cfg->flow_type == flex_conf->flex_mask[i].flow_type) {
+ idx = i;
+ break;
+ }
+ }
+ if (i >= RTE_ETH_FLOW_MAX) {
+ if (flex_conf->nb_flexmasks < RTE_DIM(flex_conf->flex_mask)) {
+ idx = flex_conf->nb_flexmasks;
+ flex_conf->nb_flexmasks++;
+ } else {
+ printf("The flex mask table is full. Can not set flex"
+ " mask for flow_type(%u).", cfg->flow_type);
+ return;
+ }
+ }
+ rte_memcpy(&flex_conf->flex_mask[idx],
+ cfg,
+ sizeof(struct rte_eth_fdir_flex_mask));
+}
+
+void
+fdir_set_flex_payload(portid_t port_id, struct rte_eth_flex_payload_cfg *cfg)
+{
+ struct rte_port *port;
+ struct rte_eth_fdir_flex_conf *flex_conf;
+ int i, idx = 0;
+
+ port = &ports[port_id];
+ flex_conf = &port->dev_conf.fdir_conf.flex_conf;
+ for (i = 0; i < RTE_ETH_PAYLOAD_MAX; i++) {
+ if (cfg->type == flex_conf->flex_set[i].type) {
+ idx = i;
+ break;
+ }
+ }
+ if (i >= RTE_ETH_PAYLOAD_MAX) {
+ if (flex_conf->nb_payloads < RTE_DIM(flex_conf->flex_set)) {
+ idx = flex_conf->nb_payloads;
+ flex_conf->nb_payloads++;
+ } else {
+ printf("The flex payload table is full. Can not set"
+ " flex payload for type(%u).", cfg->type);
+ return;
+ }
+ }
+ rte_memcpy(&flex_conf->flex_set[idx],
+ cfg,
+ sizeof(struct rte_eth_flex_payload_cfg));
+
+}
+
+void
+set_vf_traffic(portid_t port_id, uint8_t is_rx, uint16_t vf, uint8_t on)
+{
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ int diag;
+
+ if (is_rx)
+ diag = rte_pmd_ixgbe_set_vf_rx(port_id, vf, on);
+ else
+ diag = rte_pmd_ixgbe_set_vf_tx(port_id, vf, on);
+
+ if (diag == 0)
+ return;
+ printf("rte_pmd_ixgbe_set_vf_%s for port_id=%d failed diag=%d\n",
+ is_rx ? "rx" : "tx", port_id, diag);
+ return;
+#endif
+ printf("VF %s setting not supported for port %d\n",
+ is_rx ? "Rx" : "Tx", port_id);
+ RTE_SET_USED(vf);
+ RTE_SET_USED(on);
+}
+
+int
+set_queue_rate_limit(portid_t port_id, uint16_t queue_idx, uint16_t rate)
+{
+ int diag;
+ struct rte_eth_link link;
+ int ret;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return 1;
+ ret = eth_link_get_nowait_print_err(port_id, &link);
+ if (ret < 0)
+ return 1;
+ if (rate > link.link_speed) {
+ printf("Invalid rate value:%u bigger than link speed: %u\n",
+ rate, link.link_speed);
+ return 1;
+ }
+ diag = rte_eth_set_queue_rate_limit(port_id, queue_idx, rate);
+ if (diag == 0)
+ return diag;
+ printf("rte_eth_set_queue_rate_limit for port_id=%d failed diag=%d\n",
+ port_id, diag);
+ return diag;
+}
+
+int
+set_vf_rate_limit(portid_t port_id, uint16_t vf, uint16_t rate, uint64_t q_msk)
+{
+ int diag = -ENOTSUP;
+
+ RTE_SET_USED(vf);
+ RTE_SET_USED(rate);
+ RTE_SET_USED(q_msk);
+
+#ifdef RTE_LIBRTE_IXGBE_PMD
+ if (diag == -ENOTSUP)
+ diag = rte_pmd_ixgbe_set_vf_rate_limit(port_id, vf, rate,
+ q_msk);
+#endif
+#ifdef RTE_LIBRTE_BNXT_PMD
+ if (diag == -ENOTSUP)
+ diag = rte_pmd_bnxt_set_vf_rate_limit(port_id, vf, rate, q_msk);
+#endif
+ if (diag == 0)
+ return diag;
+
+ printf("set_vf_rate_limit for port_id=%d failed diag=%d\n",
+ port_id, diag);
+ return diag;
+}
+
+/*
+ * Functions to manage the set of filtered Multicast MAC addresses.
+ *
+ * A pool of filtered multicast MAC addresses is associated with each port.
+ * The pool is allocated in chunks of MCAST_POOL_INC multicast addresses.
+ * The address of the pool and the number of valid multicast MAC addresses
+ * recorded in the pool are stored in the fields "mc_addr_pool" and
+ * "mc_addr_nb" of the "rte_port" data structure.
+ *
+ * The function "rte_eth_dev_set_mc_addr_list" of the PMDs API imposes
+ * to be supplied a contiguous array of multicast MAC addresses.
+ * To comply with this constraint, the set of multicast addresses recorded
+ * into the pool are systematically compacted at the beginning of the pool.
+ * Hence, when a multicast address is removed from the pool, all following
+ * addresses, if any, are copied back to keep the set contiguous.
+ */
+#define MCAST_POOL_INC 32
+
+static int
+mcast_addr_pool_extend(struct rte_port *port)
+{
+ struct rte_ether_addr *mc_pool;
+ size_t mc_pool_size;
+
+ /*
+ * If a free entry is available at the end of the pool, just
+ * increment the number of recorded multicast addresses.
+ */
+ if ((port->mc_addr_nb % MCAST_POOL_INC) != 0) {
+ port->mc_addr_nb++;
+ return 0;
+ }
+
+ /*
+ * [re]allocate a pool with MCAST_POOL_INC more entries.
+ * The previous test guarantees that port->mc_addr_nb is a multiple
+ * of MCAST_POOL_INC.
+ */
+ mc_pool_size = sizeof(struct rte_ether_addr) * (port->mc_addr_nb +
+ MCAST_POOL_INC);
+ mc_pool = (struct rte_ether_addr *) realloc(port->mc_addr_pool,
+ mc_pool_size);
+ if (mc_pool == NULL) {
+ printf("allocation of pool of %u multicast addresses failed\n",
+ port->mc_addr_nb + MCAST_POOL_INC);
+ return -ENOMEM;
+ }
+
+ port->mc_addr_pool = mc_pool;
+ port->mc_addr_nb++;
+ return 0;
+
+}
+
+static void
+mcast_addr_pool_append(struct rte_port *port, struct rte_ether_addr *mc_addr)
+{
+ if (mcast_addr_pool_extend(port) != 0)
+ return;
+ rte_ether_addr_copy(mc_addr, &port->mc_addr_pool[port->mc_addr_nb - 1]);
+}
+
+static void
+mcast_addr_pool_remove(struct rte_port *port, uint32_t addr_idx)
+{
+ port->mc_addr_nb--;
+ if (addr_idx == port->mc_addr_nb) {
+ /* No need to recompact the set of multicast addressses. */
+ if (port->mc_addr_nb == 0) {
+ /* free the pool of multicast addresses. */
+ free(port->mc_addr_pool);
+ port->mc_addr_pool = NULL;
+ }
+ return;
+ }
+ memmove(&port->mc_addr_pool[addr_idx],
+ &port->mc_addr_pool[addr_idx + 1],
+ sizeof(struct rte_ether_addr) * (port->mc_addr_nb - addr_idx));
+}
+
+static int
+eth_port_multicast_addr_list_set(portid_t port_id)
+{
+ struct rte_port *port;
+ int diag;
+
+ port = &ports[port_id];
+ diag = rte_eth_dev_set_mc_addr_list(port_id, port->mc_addr_pool,
+ port->mc_addr_nb);
+ if (diag < 0)
+ printf("rte_eth_dev_set_mc_addr_list(port=%d, nb=%u) failed. diag=%d\n",
+ port_id, port->mc_addr_nb, diag);
+
+ return diag;
+}
+
+void
+mcast_addr_add(portid_t port_id, struct rte_ether_addr *mc_addr)
+{
+ struct rte_port *port;
+ uint32_t i;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ port = &ports[port_id];
+
+ /*
+ * Check that the added multicast MAC address is not already recorded
+ * in the pool of multicast addresses.
+ */
+ for (i = 0; i < port->mc_addr_nb; i++) {
+ if (rte_is_same_ether_addr(mc_addr, &port->mc_addr_pool[i])) {
+ printf("multicast address already filtered by port\n");
+ return;
+ }
+ }
+
+ mcast_addr_pool_append(port, mc_addr);
+ if (eth_port_multicast_addr_list_set(port_id) < 0)
+ /* Rollback on failure, remove the address from the pool */
+ mcast_addr_pool_remove(port, i);
+}
+
+void
+mcast_addr_remove(portid_t port_id, struct rte_ether_addr *mc_addr)
+{
+ struct rte_port *port;
+ uint32_t i;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ port = &ports[port_id];
+
+ /*
+ * Search the pool of multicast MAC addresses for the removed address.
+ */
+ for (i = 0; i < port->mc_addr_nb; i++) {
+ if (rte_is_same_ether_addr(mc_addr, &port->mc_addr_pool[i]))
+ break;
+ }
+ if (i == port->mc_addr_nb) {
+ printf("multicast address not filtered by port %d\n", port_id);
+ return;
+ }
+
+ mcast_addr_pool_remove(port, i);
+ if (eth_port_multicast_addr_list_set(port_id) < 0)
+ /* Rollback on failure, add the address back into the pool */
+ mcast_addr_pool_append(port, mc_addr);
+}
+
+void
+port_dcb_info_display(portid_t port_id)
+{
+ struct rte_eth_dcb_info dcb_info;
+ uint16_t i;
+ int ret;
+ static const char *border = "================";
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ ret = rte_eth_dev_get_dcb_info(port_id, &dcb_info);
+ if (ret) {
+ printf("\n Failed to get dcb infos on port %-2d\n",
+ port_id);
+ return;
+ }
+ printf("\n %s DCB infos for port %-2d %s\n", border, port_id, border);
+ printf(" TC NUMBER: %d\n", dcb_info.nb_tcs);
+ printf("\n TC : ");
+ for (i = 0; i < dcb_info.nb_tcs; i++)
+ printf("\t%4d", i);
+ printf("\n Priority : ");
+ for (i = 0; i < dcb_info.nb_tcs; i++)
+ printf("\t%4d", dcb_info.prio_tc[i]);
+ printf("\n BW percent :");
+ for (i = 0; i < dcb_info.nb_tcs; i++)
+ printf("\t%4d%%", dcb_info.tc_bws[i]);
+ printf("\n RXQ base : ");
+ for (i = 0; i < dcb_info.nb_tcs; i++)
+ printf("\t%4d", dcb_info.tc_queue.tc_rxq[0][i].base);
+ printf("\n RXQ number :");
+ for (i = 0; i < dcb_info.nb_tcs; i++)
+ printf("\t%4d", dcb_info.tc_queue.tc_rxq[0][i].nb_queue);
+ printf("\n TXQ base : ");
+ for (i = 0; i < dcb_info.nb_tcs; i++)
+ printf("\t%4d", dcb_info.tc_queue.tc_txq[0][i].base);
+ printf("\n TXQ number :");
+ for (i = 0; i < dcb_info.nb_tcs; i++)
+ printf("\t%4d", dcb_info.tc_queue.tc_txq[0][i].nb_queue);
+ printf("\n");
+}
+
+uint8_t *
+open_file(const char *file_path, uint32_t *size)
+{
+ int fd = open(file_path, O_RDONLY);
+ off_t pkg_size;
+ uint8_t *buf = NULL;
+ int ret = 0;
+ struct stat st_buf;
+
+ if (size)
+ *size = 0;
+
+ if (fd == -1) {
+ printf("%s: Failed to open %s\n", __func__, file_path);
+ return buf;
+ }
+
+ if ((fstat(fd, &st_buf) != 0) || (!S_ISREG(st_buf.st_mode))) {
+ close(fd);
+ printf("%s: File operations failed\n", __func__);
+ return buf;
+ }
+
+ pkg_size = st_buf.st_size;
+ if (pkg_size < 0) {
+ close(fd);
+ printf("%s: File operations failed\n", __func__);
+ return buf;
+ }
+
+ buf = (uint8_t *)malloc(pkg_size);
+ if (!buf) {
+ close(fd);
+ printf("%s: Failed to malloc memory\n", __func__);
+ return buf;
+ }
+
+ ret = read(fd, buf, pkg_size);
+ if (ret < 0) {
+ close(fd);
+ printf("%s: File read operation failed\n", __func__);
+ close_file(buf);
+ return NULL;
+ }
+
+ if (size)
+ *size = pkg_size;
+
+ close(fd);
+
+ return buf;
+}
+
+int
+save_file(const char *file_path, uint8_t *buf, uint32_t size)
+{
+ FILE *fh = fopen(file_path, "wb");
+
+ if (fh == NULL) {
+ printf("%s: Failed to open %s\n", __func__, file_path);
+ return -1;
+ }
+
+ if (fwrite(buf, 1, size, fh) != size) {
+ fclose(fh);
+ printf("%s: File write operation failed\n", __func__);
+ return -1;
+ }
+
+ fclose(fh);
+
+ return 0;
+}
+
+int
+close_file(uint8_t *buf)
+{
+ if (buf) {
+ free((void *)buf);
+ return 0;
+ }
+
+ return -1;
+}
+
+void
+port_queue_region_info_display(portid_t port_id, void *buf)
+{
+#ifdef RTE_LIBRTE_I40E_PMD
+ uint16_t i, j;
+ struct rte_pmd_i40e_queue_regions *info =
+ (struct rte_pmd_i40e_queue_regions *)buf;
+ static const char *queue_region_info_stats_border = "-------";
+
+ if (!info->queue_region_number)
+ printf("there is no region has been set before");
+
+ printf("\n %s All queue region info for port=%2d %s",
+ queue_region_info_stats_border, port_id,
+ queue_region_info_stats_border);
+ printf("\n queue_region_number: %-14u \n",
+ info->queue_region_number);
+
+ for (i = 0; i < info->queue_region_number; i++) {
+ printf("\n region_id: %-14u queue_number: %-14u "
+ "queue_start_index: %-14u \n",
+ info->region[i].region_id,
+ info->region[i].queue_num,
+ info->region[i].queue_start_index);
+
+ printf(" user_priority_num is %-14u :",
+ info->region[i].user_priority_num);
+ for (j = 0; j < info->region[i].user_priority_num; j++)
+ printf(" %-14u ", info->region[i].user_priority[j]);
+
+ printf("\n flowtype_num is %-14u :",
+ info->region[i].flowtype_num);
+ for (j = 0; j < info->region[i].flowtype_num; j++)
+ printf(" %-14u ", info->region[i].hw_flowtype[j]);
+ }
+#else
+ RTE_SET_USED(port_id);
+ RTE_SET_USED(buf);
+#endif
+
+ printf("\n\n");
+}
+
+void
+show_macs(portid_t port_id)
+{
+ char buf[RTE_ETHER_ADDR_FMT_SIZE];
+ struct rte_eth_dev_info dev_info;
+ struct rte_ether_addr *addr;
+ uint32_t i, num_macs = 0;
+ struct rte_eth_dev *dev;
+
+ dev = &rte_eth_devices[port_id];
+
+ rte_eth_dev_info_get(port_id, &dev_info);
+
+ for (i = 0; i < dev_info.max_mac_addrs; i++) {
+ addr = &dev->data->mac_addrs[i];
+
+ /* skip zero address */
+ if (rte_is_zero_ether_addr(addr))
+ continue;
+
+ num_macs++;
+ }
+
+ printf("Number of MAC address added: %d\n", num_macs);
+
+ for (i = 0; i < dev_info.max_mac_addrs; i++) {
+ addr = &dev->data->mac_addrs[i];
+
+ /* skip zero address */
+ if (rte_is_zero_ether_addr(addr))
+ continue;
+
+ rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, addr);
+ printf(" %s\n", buf);
+ }
+}
+
+void
+show_mcast_macs(portid_t port_id)
+{
+ char buf[RTE_ETHER_ADDR_FMT_SIZE];
+ struct rte_ether_addr *addr;
+ struct rte_port *port;
+ uint32_t i;
+
+ port = &ports[port_id];
+
+ printf("Number of Multicast MAC address added: %d\n", port->mc_addr_nb);
+
+ for (i = 0; i < port->mc_addr_nb; i++) {
+ addr = &port->mc_addr_pool[i];
+
+ rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, addr);
+ printf(" %s\n", buf);
+ }
+}
diff --git a/src/spdk/dpdk/app/test-pmd/csumonly.c b/src/spdk/dpdk/app/test-pmd/csumonly.c
new file mode 100644
index 000000000..862622379
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/csumonly.c
@@ -0,0 +1,1112 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation.
+ * Copyright 2014 6WIND S.A.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
+#include <rte_vxlan.h>
+#include <rte_sctp.h>
+#include <rte_gtp.h>
+#include <rte_prefetch.h>
+#include <rte_string_fns.h>
+#include <rte_flow.h>
+#include <rte_gro.h>
+#include <rte_gso.h>
+
+#include "testpmd.h"
+
+#define IP_DEFTTL 64 /* from RFC 1340. */
+
+#define GRE_CHECKSUM_PRESENT 0x8000
+#define GRE_KEY_PRESENT 0x2000
+#define GRE_SEQUENCE_PRESENT 0x1000
+#define GRE_EXT_LEN 4
+#define GRE_SUPPORTED_FIELDS (GRE_CHECKSUM_PRESENT | GRE_KEY_PRESENT |\
+ GRE_SEQUENCE_PRESENT)
+
+/* We cannot use rte_cpu_to_be_16() on a constant in a switch/case */
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+#define _htons(x) ((uint16_t)((((x) & 0x00ffU) << 8) | (((x) & 0xff00U) >> 8)))
+#else
+#define _htons(x) (x)
+#endif
+
+uint16_t vxlan_gpe_udp_port = 4790;
+
+/* structure that caches offload info for the current packet */
+struct testpmd_offload_info {
+ uint16_t ethertype;
+ uint8_t gso_enable;
+ uint16_t l2_len;
+ uint16_t l3_len;
+ uint16_t l4_len;
+ uint8_t l4_proto;
+ uint8_t is_tunnel;
+ uint16_t outer_ethertype;
+ uint16_t outer_l2_len;
+ uint16_t outer_l3_len;
+ uint8_t outer_l4_proto;
+ uint16_t tso_segsz;
+ uint16_t tunnel_tso_segsz;
+ uint32_t pkt_len;
+};
+
+/* simplified GRE header */
+struct simple_gre_hdr {
+ uint16_t flags;
+ uint16_t proto;
+} __rte_packed;
+
+static uint16_t
+get_udptcp_checksum(void *l3_hdr, void *l4_hdr, uint16_t ethertype)
+{
+ if (ethertype == _htons(RTE_ETHER_TYPE_IPV4))
+ return rte_ipv4_udptcp_cksum(l3_hdr, l4_hdr);
+ else /* assume ethertype == RTE_ETHER_TYPE_IPV6 */
+ return rte_ipv6_udptcp_cksum(l3_hdr, l4_hdr);
+}
+
+/* Parse an IPv4 header to fill l3_len, l4_len, and l4_proto */
+static void
+parse_ipv4(struct rte_ipv4_hdr *ipv4_hdr, struct testpmd_offload_info *info)
+{
+ struct rte_tcp_hdr *tcp_hdr;
+
+ info->l3_len = (ipv4_hdr->version_ihl & 0x0f) * 4;
+ info->l4_proto = ipv4_hdr->next_proto_id;
+
+ /* only fill l4_len for TCP, it's useful for TSO */
+ if (info->l4_proto == IPPROTO_TCP) {
+ tcp_hdr = (struct rte_tcp_hdr *)
+ ((char *)ipv4_hdr + info->l3_len);
+ info->l4_len = (tcp_hdr->data_off & 0xf0) >> 2;
+ } else if (info->l4_proto == IPPROTO_UDP)
+ info->l4_len = sizeof(struct rte_udp_hdr);
+ else
+ info->l4_len = 0;
+}
+
+/* Parse an IPv6 header to fill l3_len, l4_len, and l4_proto */
+static void
+parse_ipv6(struct rte_ipv6_hdr *ipv6_hdr, struct testpmd_offload_info *info)
+{
+ struct rte_tcp_hdr *tcp_hdr;
+
+ info->l3_len = sizeof(struct rte_ipv6_hdr);
+ info->l4_proto = ipv6_hdr->proto;
+
+ /* only fill l4_len for TCP, it's useful for TSO */
+ if (info->l4_proto == IPPROTO_TCP) {
+ tcp_hdr = (struct rte_tcp_hdr *)
+ ((char *)ipv6_hdr + info->l3_len);
+ info->l4_len = (tcp_hdr->data_off & 0xf0) >> 2;
+ } else if (info->l4_proto == IPPROTO_UDP)
+ info->l4_len = sizeof(struct rte_udp_hdr);
+ else
+ info->l4_len = 0;
+}
+
+/*
+ * Parse an ethernet header to fill the ethertype, l2_len, l3_len and
+ * ipproto. This function is able to recognize IPv4/IPv6 with optional VLAN
+ * headers. The l4_len argument is only set in case of TCP (useful for TSO).
+ */
+static void
+parse_ethernet(struct rte_ether_hdr *eth_hdr, struct testpmd_offload_info *info)
+{
+ struct rte_ipv4_hdr *ipv4_hdr;
+ struct rte_ipv6_hdr *ipv6_hdr;
+ struct rte_vlan_hdr *vlan_hdr;
+
+ info->l2_len = sizeof(struct rte_ether_hdr);
+ info->ethertype = eth_hdr->ether_type;
+
+ while (info->ethertype == _htons(RTE_ETHER_TYPE_VLAN) ||
+ info->ethertype == _htons(RTE_ETHER_TYPE_QINQ)) {
+ vlan_hdr = (struct rte_vlan_hdr *)
+ ((char *)eth_hdr + info->l2_len);
+ info->l2_len += sizeof(struct rte_vlan_hdr);
+ info->ethertype = vlan_hdr->eth_proto;
+ }
+
+ switch (info->ethertype) {
+ case _htons(RTE_ETHER_TYPE_IPV4):
+ ipv4_hdr = (struct rte_ipv4_hdr *)
+ ((char *)eth_hdr + info->l2_len);
+ parse_ipv4(ipv4_hdr, info);
+ break;
+ case _htons(RTE_ETHER_TYPE_IPV6):
+ ipv6_hdr = (struct rte_ipv6_hdr *)
+ ((char *)eth_hdr + info->l2_len);
+ parse_ipv6(ipv6_hdr, info);
+ break;
+ default:
+ info->l4_len = 0;
+ info->l3_len = 0;
+ info->l4_proto = 0;
+ break;
+ }
+}
+
+/*
+ * Parse a GTP protocol header.
+ * No optional fields and next extension header type.
+ */
+static void
+parse_gtp(struct rte_udp_hdr *udp_hdr,
+ struct testpmd_offload_info *info)
+{
+ struct rte_ipv4_hdr *ipv4_hdr;
+ struct rte_ipv6_hdr *ipv6_hdr;
+ struct rte_gtp_hdr *gtp_hdr;
+ uint8_t gtp_len = sizeof(*gtp_hdr);
+ uint8_t ip_ver;
+
+ /* Check udp destination port. */
+ if (udp_hdr->dst_port != _htons(RTE_GTPC_UDP_PORT) &&
+ udp_hdr->src_port != _htons(RTE_GTPC_UDP_PORT) &&
+ udp_hdr->dst_port != _htons(RTE_GTPU_UDP_PORT))
+ return;
+
+ info->is_tunnel = 1;
+ info->outer_ethertype = info->ethertype;
+ info->outer_l2_len = info->l2_len;
+ info->outer_l3_len = info->l3_len;
+ info->outer_l4_proto = info->l4_proto;
+ info->l2_len = 0;
+
+ gtp_hdr = (struct rte_gtp_hdr *)((char *)udp_hdr +
+ sizeof(struct rte_udp_hdr));
+
+ /*
+ * Check message type. If message type is 0xff, it is
+ * a GTP data packet. If not, it is a GTP control packet
+ */
+ if (gtp_hdr->msg_type == 0xff) {
+ ip_ver = *(uint8_t *)((char *)udp_hdr +
+ sizeof(struct rte_udp_hdr) +
+ sizeof(struct rte_gtp_hdr));
+ ip_ver = (ip_ver) & 0xf0;
+
+ if (ip_ver == RTE_GTP_TYPE_IPV4) {
+ ipv4_hdr = (struct rte_ipv4_hdr *)((char *)gtp_hdr +
+ gtp_len);
+ info->ethertype = _htons(RTE_ETHER_TYPE_IPV4);
+ parse_ipv4(ipv4_hdr, info);
+ } else if (ip_ver == RTE_GTP_TYPE_IPV6) {
+ ipv6_hdr = (struct rte_ipv6_hdr *)((char *)gtp_hdr +
+ gtp_len);
+ info->ethertype = _htons(RTE_ETHER_TYPE_IPV6);
+ parse_ipv6(ipv6_hdr, info);
+ }
+ } else {
+ info->ethertype = 0;
+ info->l4_len = 0;
+ info->l3_len = 0;
+ info->l4_proto = 0;
+ }
+
+ info->l2_len += RTE_ETHER_GTP_HLEN;
+}
+
+/* Parse a vxlan header */
+static void
+parse_vxlan(struct rte_udp_hdr *udp_hdr,
+ struct testpmd_offload_info *info,
+ uint32_t pkt_type)
+{
+ struct rte_ether_hdr *eth_hdr;
+
+ /* check udp destination port, 4789 is the default vxlan port
+ * (rfc7348) or that the rx offload flag is set (i40e only
+ * currently) */
+ if (udp_hdr->dst_port != _htons(4789) &&
+ RTE_ETH_IS_TUNNEL_PKT(pkt_type) == 0)
+ return;
+
+ info->is_tunnel = 1;
+ info->outer_ethertype = info->ethertype;
+ info->outer_l2_len = info->l2_len;
+ info->outer_l3_len = info->l3_len;
+ info->outer_l4_proto = info->l4_proto;
+
+ eth_hdr = (struct rte_ether_hdr *)((char *)udp_hdr +
+ sizeof(struct rte_udp_hdr) +
+ sizeof(struct rte_vxlan_hdr));
+
+ parse_ethernet(eth_hdr, info);
+ info->l2_len += RTE_ETHER_VXLAN_HLEN; /* add udp + vxlan */
+}
+
+/* Parse a vxlan-gpe header */
+static void
+parse_vxlan_gpe(struct rte_udp_hdr *udp_hdr,
+ struct testpmd_offload_info *info)
+{
+ struct rte_ether_hdr *eth_hdr;
+ struct rte_ipv4_hdr *ipv4_hdr;
+ struct rte_ipv6_hdr *ipv6_hdr;
+ struct rte_vxlan_gpe_hdr *vxlan_gpe_hdr;
+ uint8_t vxlan_gpe_len = sizeof(*vxlan_gpe_hdr);
+
+ /* Check udp destination port. */
+ if (udp_hdr->dst_port != _htons(vxlan_gpe_udp_port))
+ return;
+
+ vxlan_gpe_hdr = (struct rte_vxlan_gpe_hdr *)((char *)udp_hdr +
+ sizeof(struct rte_udp_hdr));
+
+ if (!vxlan_gpe_hdr->proto || vxlan_gpe_hdr->proto ==
+ RTE_VXLAN_GPE_TYPE_IPV4) {
+ info->is_tunnel = 1;
+ info->outer_ethertype = info->ethertype;
+ info->outer_l2_len = info->l2_len;
+ info->outer_l3_len = info->l3_len;
+ info->outer_l4_proto = info->l4_proto;
+
+ ipv4_hdr = (struct rte_ipv4_hdr *)((char *)vxlan_gpe_hdr +
+ vxlan_gpe_len);
+
+ parse_ipv4(ipv4_hdr, info);
+ info->ethertype = _htons(RTE_ETHER_TYPE_IPV4);
+ info->l2_len = 0;
+
+ } else if (vxlan_gpe_hdr->proto == RTE_VXLAN_GPE_TYPE_IPV6) {
+ info->is_tunnel = 1;
+ info->outer_ethertype = info->ethertype;
+ info->outer_l2_len = info->l2_len;
+ info->outer_l3_len = info->l3_len;
+ info->outer_l4_proto = info->l4_proto;
+
+ ipv6_hdr = (struct rte_ipv6_hdr *)((char *)vxlan_gpe_hdr +
+ vxlan_gpe_len);
+
+ info->ethertype = _htons(RTE_ETHER_TYPE_IPV6);
+ parse_ipv6(ipv6_hdr, info);
+ info->l2_len = 0;
+
+ } else if (vxlan_gpe_hdr->proto == RTE_VXLAN_GPE_TYPE_ETH) {
+ info->is_tunnel = 1;
+ info->outer_ethertype = info->ethertype;
+ info->outer_l2_len = info->l2_len;
+ info->outer_l3_len = info->l3_len;
+ info->outer_l4_proto = info->l4_proto;
+
+ eth_hdr = (struct rte_ether_hdr *)((char *)vxlan_gpe_hdr +
+ vxlan_gpe_len);
+
+ parse_ethernet(eth_hdr, info);
+ } else
+ return;
+
+ info->l2_len += RTE_ETHER_VXLAN_GPE_HLEN;
+}
+
+/* Parse a gre header */
+static void
+parse_gre(struct simple_gre_hdr *gre_hdr, struct testpmd_offload_info *info)
+{
+ struct rte_ether_hdr *eth_hdr;
+ struct rte_ipv4_hdr *ipv4_hdr;
+ struct rte_ipv6_hdr *ipv6_hdr;
+ uint8_t gre_len = 0;
+
+ gre_len += sizeof(struct simple_gre_hdr);
+
+ if (gre_hdr->flags & _htons(GRE_KEY_PRESENT))
+ gre_len += GRE_EXT_LEN;
+ if (gre_hdr->flags & _htons(GRE_SEQUENCE_PRESENT))
+ gre_len += GRE_EXT_LEN;
+ if (gre_hdr->flags & _htons(GRE_CHECKSUM_PRESENT))
+ gre_len += GRE_EXT_LEN;
+
+ if (gre_hdr->proto == _htons(RTE_ETHER_TYPE_IPV4)) {
+ info->is_tunnel = 1;
+ info->outer_ethertype = info->ethertype;
+ info->outer_l2_len = info->l2_len;
+ info->outer_l3_len = info->l3_len;
+ info->outer_l4_proto = info->l4_proto;
+
+ ipv4_hdr = (struct rte_ipv4_hdr *)((char *)gre_hdr + gre_len);
+
+ parse_ipv4(ipv4_hdr, info);
+ info->ethertype = _htons(RTE_ETHER_TYPE_IPV4);
+ info->l2_len = 0;
+
+ } else if (gre_hdr->proto == _htons(RTE_ETHER_TYPE_IPV6)) {
+ info->is_tunnel = 1;
+ info->outer_ethertype = info->ethertype;
+ info->outer_l2_len = info->l2_len;
+ info->outer_l3_len = info->l3_len;
+ info->outer_l4_proto = info->l4_proto;
+
+ ipv6_hdr = (struct rte_ipv6_hdr *)((char *)gre_hdr + gre_len);
+
+ info->ethertype = _htons(RTE_ETHER_TYPE_IPV6);
+ parse_ipv6(ipv6_hdr, info);
+ info->l2_len = 0;
+
+ } else if (gre_hdr->proto == _htons(RTE_ETHER_TYPE_TEB)) {
+ info->is_tunnel = 1;
+ info->outer_ethertype = info->ethertype;
+ info->outer_l2_len = info->l2_len;
+ info->outer_l3_len = info->l3_len;
+ info->outer_l4_proto = info->l4_proto;
+
+ eth_hdr = (struct rte_ether_hdr *)((char *)gre_hdr + gre_len);
+
+ parse_ethernet(eth_hdr, info);
+ } else
+ return;
+
+ info->l2_len += gre_len;
+}
+
+
+/* Parse an encapsulated ip or ipv6 header */
+static void
+parse_encap_ip(void *encap_ip, struct testpmd_offload_info *info)
+{
+ struct rte_ipv4_hdr *ipv4_hdr = encap_ip;
+ struct rte_ipv6_hdr *ipv6_hdr = encap_ip;
+ uint8_t ip_version;
+
+ ip_version = (ipv4_hdr->version_ihl & 0xf0) >> 4;
+
+ if (ip_version != 4 && ip_version != 6)
+ return;
+
+ info->is_tunnel = 1;
+ info->outer_ethertype = info->ethertype;
+ info->outer_l2_len = info->l2_len;
+ info->outer_l3_len = info->l3_len;
+
+ if (ip_version == 4) {
+ parse_ipv4(ipv4_hdr, info);
+ info->ethertype = _htons(RTE_ETHER_TYPE_IPV4);
+ } else {
+ parse_ipv6(ipv6_hdr, info);
+ info->ethertype = _htons(RTE_ETHER_TYPE_IPV6);
+ }
+ info->l2_len = 0;
+}
+
+/* if possible, calculate the checksum of a packet in hw or sw,
+ * depending on the testpmd command line configuration */
+static uint64_t
+process_inner_cksums(void *l3_hdr, const struct testpmd_offload_info *info,
+ uint64_t tx_offloads)
+{
+ struct rte_ipv4_hdr *ipv4_hdr = l3_hdr;
+ struct rte_udp_hdr *udp_hdr;
+ struct rte_tcp_hdr *tcp_hdr;
+ struct rte_sctp_hdr *sctp_hdr;
+ uint64_t ol_flags = 0;
+ uint32_t max_pkt_len, tso_segsz = 0;
+
+ /* ensure packet is large enough to require tso */
+ if (!info->is_tunnel) {
+ max_pkt_len = info->l2_len + info->l3_len + info->l4_len +
+ info->tso_segsz;
+ if (info->tso_segsz != 0 && info->pkt_len > max_pkt_len)
+ tso_segsz = info->tso_segsz;
+ } else {
+ max_pkt_len = info->outer_l2_len + info->outer_l3_len +
+ info->l2_len + info->l3_len + info->l4_len +
+ info->tunnel_tso_segsz;
+ if (info->tunnel_tso_segsz != 0 && info->pkt_len > max_pkt_len)
+ tso_segsz = info->tunnel_tso_segsz;
+ }
+
+ if (info->ethertype == _htons(RTE_ETHER_TYPE_IPV4)) {
+ ipv4_hdr = l3_hdr;
+ ipv4_hdr->hdr_checksum = 0;
+
+ ol_flags |= PKT_TX_IPV4;
+ if (info->l4_proto == IPPROTO_TCP && tso_segsz) {
+ ol_flags |= PKT_TX_IP_CKSUM;
+ } else {
+ if (tx_offloads & DEV_TX_OFFLOAD_IPV4_CKSUM)
+ ol_flags |= PKT_TX_IP_CKSUM;
+ else
+ ipv4_hdr->hdr_checksum =
+ rte_ipv4_cksum(ipv4_hdr);
+ }
+ } else if (info->ethertype == _htons(RTE_ETHER_TYPE_IPV6))
+ ol_flags |= PKT_TX_IPV6;
+ else
+ return 0; /* packet type not supported, nothing to do */
+
+ if (info->l4_proto == IPPROTO_UDP) {
+ udp_hdr = (struct rte_udp_hdr *)((char *)l3_hdr + info->l3_len);
+ /* do not recalculate udp cksum if it was 0 */
+ if (udp_hdr->dgram_cksum != 0) {
+ udp_hdr->dgram_cksum = 0;
+ if (tx_offloads & DEV_TX_OFFLOAD_UDP_CKSUM)
+ ol_flags |= PKT_TX_UDP_CKSUM;
+ else {
+ udp_hdr->dgram_cksum =
+ get_udptcp_checksum(l3_hdr, udp_hdr,
+ info->ethertype);
+ }
+ }
+ if (info->gso_enable)
+ ol_flags |= PKT_TX_UDP_SEG;
+ } else if (info->l4_proto == IPPROTO_TCP) {
+ tcp_hdr = (struct rte_tcp_hdr *)((char *)l3_hdr + info->l3_len);
+ tcp_hdr->cksum = 0;
+ if (tso_segsz)
+ ol_flags |= PKT_TX_TCP_SEG;
+ else if (tx_offloads & DEV_TX_OFFLOAD_TCP_CKSUM)
+ ol_flags |= PKT_TX_TCP_CKSUM;
+ else {
+ tcp_hdr->cksum =
+ get_udptcp_checksum(l3_hdr, tcp_hdr,
+ info->ethertype);
+ }
+ if (info->gso_enable)
+ ol_flags |= PKT_TX_TCP_SEG;
+ } else if (info->l4_proto == IPPROTO_SCTP) {
+ sctp_hdr = (struct rte_sctp_hdr *)
+ ((char *)l3_hdr + info->l3_len);
+ sctp_hdr->cksum = 0;
+ /* sctp payload must be a multiple of 4 to be
+ * offloaded */
+ if ((tx_offloads & DEV_TX_OFFLOAD_SCTP_CKSUM) &&
+ ((ipv4_hdr->total_length & 0x3) == 0)) {
+ ol_flags |= PKT_TX_SCTP_CKSUM;
+ } else {
+ /* XXX implement CRC32c, example available in
+ * RFC3309 */
+ }
+ }
+
+ return ol_flags;
+}
+
+/* Calculate the checksum of outer header */
+static uint64_t
+process_outer_cksums(void *outer_l3_hdr, struct testpmd_offload_info *info,
+ uint64_t tx_offloads, int tso_enabled)
+{
+ struct rte_ipv4_hdr *ipv4_hdr = outer_l3_hdr;
+ struct rte_ipv6_hdr *ipv6_hdr = outer_l3_hdr;
+ struct rte_udp_hdr *udp_hdr;
+ uint64_t ol_flags = 0;
+
+ if (info->outer_ethertype == _htons(RTE_ETHER_TYPE_IPV4)) {
+ ipv4_hdr->hdr_checksum = 0;
+ ol_flags |= PKT_TX_OUTER_IPV4;
+
+ if (tx_offloads & DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM)
+ ol_flags |= PKT_TX_OUTER_IP_CKSUM;
+ else
+ ipv4_hdr->hdr_checksum = rte_ipv4_cksum(ipv4_hdr);
+ } else
+ ol_flags |= PKT_TX_OUTER_IPV6;
+
+ if (info->outer_l4_proto != IPPROTO_UDP)
+ return ol_flags;
+
+ udp_hdr = (struct rte_udp_hdr *)
+ ((char *)outer_l3_hdr + info->outer_l3_len);
+
+ if (tso_enabled)
+ ol_flags |= PKT_TX_TCP_SEG;
+
+ /* Skip SW outer UDP checksum generation if HW supports it */
+ if (tx_offloads & DEV_TX_OFFLOAD_OUTER_UDP_CKSUM) {
+ if (info->outer_ethertype == _htons(RTE_ETHER_TYPE_IPV4))
+ udp_hdr->dgram_cksum
+ = rte_ipv4_phdr_cksum(ipv4_hdr, ol_flags);
+ else
+ udp_hdr->dgram_cksum
+ = rte_ipv6_phdr_cksum(ipv6_hdr, ol_flags);
+
+ ol_flags |= PKT_TX_OUTER_UDP_CKSUM;
+ return ol_flags;
+ }
+
+ /* outer UDP checksum is done in software. In the other side, for
+ * UDP tunneling, like VXLAN or Geneve, outer UDP checksum can be
+ * set to zero.
+ *
+ * If a packet will be TSOed into small packets by NIC, we cannot
+ * set/calculate a non-zero checksum, because it will be a wrong
+ * value after the packet be split into several small packets.
+ */
+ if (tso_enabled)
+ udp_hdr->dgram_cksum = 0;
+
+ /* do not recalculate udp cksum if it was 0 */
+ if (udp_hdr->dgram_cksum != 0) {
+ udp_hdr->dgram_cksum = 0;
+ if (info->outer_ethertype == _htons(RTE_ETHER_TYPE_IPV4))
+ udp_hdr->dgram_cksum =
+ rte_ipv4_udptcp_cksum(ipv4_hdr, udp_hdr);
+ else
+ udp_hdr->dgram_cksum =
+ rte_ipv6_udptcp_cksum(ipv6_hdr, udp_hdr);
+ }
+
+ return ol_flags;
+}
+
+/*
+ * Helper function.
+ * Performs actual copying.
+ * Returns number of segments in the destination mbuf on success,
+ * or negative error code on failure.
+ */
+static int
+mbuf_copy_split(const struct rte_mbuf *ms, struct rte_mbuf *md[],
+ uint16_t seglen[], uint8_t nb_seg)
+{
+ uint32_t dlen, slen, tlen;
+ uint32_t i, len;
+ const struct rte_mbuf *m;
+ const uint8_t *src;
+ uint8_t *dst;
+
+ dlen = 0;
+ slen = 0;
+ tlen = 0;
+
+ dst = NULL;
+ src = NULL;
+
+ m = ms;
+ i = 0;
+ while (ms != NULL && i != nb_seg) {
+
+ if (slen == 0) {
+ slen = rte_pktmbuf_data_len(ms);
+ src = rte_pktmbuf_mtod(ms, const uint8_t *);
+ }
+
+ if (dlen == 0) {
+ dlen = RTE_MIN(seglen[i], slen);
+ md[i]->data_len = dlen;
+ md[i]->next = (i + 1 == nb_seg) ? NULL : md[i + 1];
+ dst = rte_pktmbuf_mtod(md[i], uint8_t *);
+ }
+
+ len = RTE_MIN(slen, dlen);
+ memcpy(dst, src, len);
+ tlen += len;
+ slen -= len;
+ dlen -= len;
+ src += len;
+ dst += len;
+
+ if (slen == 0)
+ ms = ms->next;
+ if (dlen == 0)
+ i++;
+ }
+
+ if (ms != NULL)
+ return -ENOBUFS;
+ else if (tlen != m->pkt_len)
+ return -EINVAL;
+
+ md[0]->nb_segs = nb_seg;
+ md[0]->pkt_len = tlen;
+ md[0]->vlan_tci = m->vlan_tci;
+ md[0]->vlan_tci_outer = m->vlan_tci_outer;
+ md[0]->ol_flags = m->ol_flags;
+ md[0]->tx_offload = m->tx_offload;
+
+ return nb_seg;
+}
+
+/*
+ * Allocate a new mbuf with up to tx_pkt_nb_segs segments.
+ * Copy packet contents and offload information into the new segmented mbuf.
+ */
+static struct rte_mbuf *
+pkt_copy_split(const struct rte_mbuf *pkt)
+{
+ int32_t n, rc;
+ uint32_t i, len, nb_seg;
+ struct rte_mempool *mp;
+ uint16_t seglen[RTE_MAX_SEGS_PER_PKT];
+ struct rte_mbuf *p, *md[RTE_MAX_SEGS_PER_PKT];
+
+ mp = current_fwd_lcore()->mbp;
+
+ if (tx_pkt_split == TX_PKT_SPLIT_RND)
+ nb_seg = random() % tx_pkt_nb_segs + 1;
+ else
+ nb_seg = tx_pkt_nb_segs;
+
+ memcpy(seglen, tx_pkt_seg_lengths, nb_seg * sizeof(seglen[0]));
+
+ /* calculate number of segments to use and their length. */
+ len = 0;
+ for (i = 0; i != nb_seg && len < pkt->pkt_len; i++) {
+ len += seglen[i];
+ md[i] = NULL;
+ }
+
+ n = pkt->pkt_len - len;
+
+ /* update size of the last segment to fit rest of the packet */
+ if (n >= 0) {
+ seglen[i - 1] += n;
+ len += n;
+ }
+
+ nb_seg = i;
+ while (i != 0) {
+ p = rte_pktmbuf_alloc(mp);
+ if (p == NULL) {
+ TESTPMD_LOG(ERR,
+ "failed to allocate %u-th of %u mbuf "
+ "from mempool: %s\n",
+ nb_seg - i, nb_seg, mp->name);
+ break;
+ }
+
+ md[--i] = p;
+ if (rte_pktmbuf_tailroom(md[i]) < seglen[i]) {
+ TESTPMD_LOG(ERR, "mempool %s, %u-th segment: "
+ "expected seglen: %u, "
+ "actual mbuf tailroom: %u\n",
+ mp->name, i, seglen[i],
+ rte_pktmbuf_tailroom(md[i]));
+ break;
+ }
+ }
+
+ /* all mbufs successfully allocated, do copy */
+ if (i == 0) {
+ rc = mbuf_copy_split(pkt, md, seglen, nb_seg);
+ if (rc < 0)
+ TESTPMD_LOG(ERR,
+ "mbuf_copy_split for %p(len=%u, nb_seg=%u) "
+ "into %u segments failed with error code: %d\n",
+ pkt, pkt->pkt_len, pkt->nb_segs, nb_seg, rc);
+
+ /* figure out how many mbufs to free. */
+ i = RTE_MAX(rc, 0);
+ }
+
+ /* free unused mbufs */
+ for (; i != nb_seg; i++) {
+ rte_pktmbuf_free_seg(md[i]);
+ md[i] = NULL;
+ }
+
+ return md[0];
+}
+
+/*
+ * Receive a burst of packets, and for each packet:
+ * - parse packet, and try to recognize a supported packet type (1)
+ * - if it's not a supported packet type, don't touch the packet, else:
+ * - reprocess the checksum of all supported layers. This is done in SW
+ * or HW, depending on testpmd command line configuration
+ * - if TSO is enabled in testpmd command line, also flag the mbuf for TCP
+ * segmentation offload (this implies HW TCP checksum)
+ * Then transmit packets on the output port.
+ *
+ * (1) Supported packets are:
+ * Ether / (vlan) / IP|IP6 / UDP|TCP|SCTP .
+ * Ether / (vlan) / outer IP|IP6 / outer UDP / VxLAN / Ether / IP|IP6 /
+ * UDP|TCP|SCTP
+ * Ether / (vlan) / outer IP|IP6 / outer UDP / VXLAN-GPE / Ether / IP|IP6 /
+ * UDP|TCP|SCTP
+ * Ether / (vlan) / outer IP|IP6 / outer UDP / VXLAN-GPE / IP|IP6 /
+ * UDP|TCP|SCTP
+ * Ether / (vlan) / outer IP / outer UDP / GTP / IP|IP6 / UDP|TCP|SCTP
+ * Ether / (vlan) / outer IP|IP6 / GRE / Ether / IP|IP6 / UDP|TCP|SCTP
+ * Ether / (vlan) / outer IP|IP6 / GRE / IP|IP6 / UDP|TCP|SCTP
+ * Ether / (vlan) / outer IP|IP6 / IP|IP6 / UDP|TCP|SCTP
+ *
+ * The testpmd command line for this forward engine sets the flags
+ * TESTPMD_TX_OFFLOAD_* in ports[tx_port].tx_ol_flags. They control
+ * wether a checksum must be calculated in software or in hardware. The
+ * IP, UDP, TCP and SCTP flags always concern the inner layer. The
+ * OUTER_IP is only useful for tunnel packets.
+ */
+static void
+pkt_burst_checksum_forward(struct fwd_stream *fs)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_mbuf *gso_segments[GSO_MAX_PKT_BURST];
+ struct rte_gso_ctx *gso_ctx;
+ struct rte_mbuf **tx_pkts_burst;
+ struct rte_port *txp;
+ struct rte_mbuf *m, *p;
+ struct rte_ether_hdr *eth_hdr;
+ void *l3_hdr = NULL, *outer_l3_hdr = NULL; /* can be IPv4 or IPv6 */
+ void **gro_ctx;
+ uint16_t gro_pkts_num;
+ uint8_t gro_enable;
+ uint16_t nb_rx;
+ uint16_t nb_tx;
+ uint16_t nb_prep;
+ uint16_t i;
+ uint64_t rx_ol_flags, tx_ol_flags;
+ uint64_t tx_offloads;
+ uint32_t retry;
+ uint32_t rx_bad_ip_csum;
+ uint32_t rx_bad_l4_csum;
+ uint32_t rx_bad_outer_l4_csum;
+ struct testpmd_offload_info info;
+ uint16_t nb_segments = 0;
+ int ret;
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ uint64_t start_tsc;
+ uint64_t end_tsc;
+ uint64_t core_cycles;
+#endif
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ start_tsc = rte_rdtsc();
+#endif
+
+ /* receive a burst of packet */
+ nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
+ nb_pkt_per_burst);
+ if (unlikely(nb_rx == 0))
+ return;
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
+#endif
+ fs->rx_packets += nb_rx;
+ rx_bad_ip_csum = 0;
+ rx_bad_l4_csum = 0;
+ rx_bad_outer_l4_csum = 0;
+ gro_enable = gro_ports[fs->rx_port].enable;
+
+ txp = &ports[fs->tx_port];
+ tx_offloads = txp->dev_conf.txmode.offloads;
+ memset(&info, 0, sizeof(info));
+ info.tso_segsz = txp->tso_segsz;
+ info.tunnel_tso_segsz = txp->tunnel_tso_segsz;
+ if (gso_ports[fs->tx_port].enable)
+ info.gso_enable = 1;
+
+ for (i = 0; i < nb_rx; i++) {
+ if (likely(i < nb_rx - 1))
+ rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
+ void *));
+
+ m = pkts_burst[i];
+ info.is_tunnel = 0;
+ info.pkt_len = rte_pktmbuf_pkt_len(m);
+ tx_ol_flags = m->ol_flags &
+ (IND_ATTACHED_MBUF | EXT_ATTACHED_MBUF);
+ rx_ol_flags = m->ol_flags;
+
+ /* Update the L3/L4 checksum error packet statistics */
+ if ((rx_ol_flags & PKT_RX_IP_CKSUM_MASK) == PKT_RX_IP_CKSUM_BAD)
+ rx_bad_ip_csum += 1;
+ if ((rx_ol_flags & PKT_RX_L4_CKSUM_MASK) == PKT_RX_L4_CKSUM_BAD)
+ rx_bad_l4_csum += 1;
+ if (rx_ol_flags & PKT_RX_OUTER_L4_CKSUM_BAD)
+ rx_bad_outer_l4_csum += 1;
+
+ /* step 1: dissect packet, parsing optional vlan, ip4/ip6, vxlan
+ * and inner headers */
+
+ eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
+ rte_ether_addr_copy(&peer_eth_addrs[fs->peer_addr],
+ &eth_hdr->d_addr);
+ rte_ether_addr_copy(&ports[fs->tx_port].eth_addr,
+ &eth_hdr->s_addr);
+ parse_ethernet(eth_hdr, &info);
+ l3_hdr = (char *)eth_hdr + info.l2_len;
+
+ /* check if it's a supported tunnel */
+ if (txp->parse_tunnel) {
+ if (info.l4_proto == IPPROTO_UDP) {
+ struct rte_udp_hdr *udp_hdr;
+
+ udp_hdr = (struct rte_udp_hdr *)
+ ((char *)l3_hdr + info.l3_len);
+ parse_gtp(udp_hdr, &info);
+ if (info.is_tunnel) {
+ tx_ol_flags |= PKT_TX_TUNNEL_GTP;
+ goto tunnel_update;
+ }
+ parse_vxlan_gpe(udp_hdr, &info);
+ if (info.is_tunnel) {
+ tx_ol_flags |=
+ PKT_TX_TUNNEL_VXLAN_GPE;
+ goto tunnel_update;
+ }
+ parse_vxlan(udp_hdr, &info,
+ m->packet_type);
+ if (info.is_tunnel)
+ tx_ol_flags |=
+ PKT_TX_TUNNEL_VXLAN;
+ } else if (info.l4_proto == IPPROTO_GRE) {
+ struct simple_gre_hdr *gre_hdr;
+
+ gre_hdr = (struct simple_gre_hdr *)
+ ((char *)l3_hdr + info.l3_len);
+ parse_gre(gre_hdr, &info);
+ if (info.is_tunnel)
+ tx_ol_flags |= PKT_TX_TUNNEL_GRE;
+ } else if (info.l4_proto == IPPROTO_IPIP) {
+ void *encap_ip_hdr;
+
+ encap_ip_hdr = (char *)l3_hdr + info.l3_len;
+ parse_encap_ip(encap_ip_hdr, &info);
+ if (info.is_tunnel)
+ tx_ol_flags |= PKT_TX_TUNNEL_IPIP;
+ }
+ }
+
+tunnel_update:
+ /* update l3_hdr and outer_l3_hdr if a tunnel was parsed */
+ if (info.is_tunnel) {
+ outer_l3_hdr = l3_hdr;
+ l3_hdr = (char *)l3_hdr + info.outer_l3_len + info.l2_len;
+ }
+
+ /* step 2: depending on user command line configuration,
+ * recompute checksum either in software or flag the
+ * mbuf to offload the calculation to the NIC. If TSO
+ * is configured, prepare the mbuf for TCP segmentation. */
+
+ /* process checksums of inner headers first */
+ tx_ol_flags |= process_inner_cksums(l3_hdr, &info,
+ tx_offloads);
+
+ /* Then process outer headers if any. Note that the software
+ * checksum will be wrong if one of the inner checksums is
+ * processed in hardware. */
+ if (info.is_tunnel == 1) {
+ tx_ol_flags |= process_outer_cksums(outer_l3_hdr, &info,
+ tx_offloads,
+ !!(tx_ol_flags & PKT_TX_TCP_SEG));
+ }
+
+ /* step 3: fill the mbuf meta data (flags and header lengths) */
+
+ m->tx_offload = 0;
+ if (info.is_tunnel == 1) {
+ if (info.tunnel_tso_segsz ||
+ (tx_offloads &
+ DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM) ||
+ (tx_offloads &
+ DEV_TX_OFFLOAD_OUTER_UDP_CKSUM) ||
+ (tx_ol_flags & PKT_TX_OUTER_IPV6)) {
+ m->outer_l2_len = info.outer_l2_len;
+ m->outer_l3_len = info.outer_l3_len;
+ m->l2_len = info.l2_len;
+ m->l3_len = info.l3_len;
+ m->l4_len = info.l4_len;
+ m->tso_segsz = info.tunnel_tso_segsz;
+ }
+ else {
+ /* if there is a outer UDP cksum
+ processed in sw and the inner in hw,
+ the outer checksum will be wrong as
+ the payload will be modified by the
+ hardware */
+ m->l2_len = info.outer_l2_len +
+ info.outer_l3_len + info.l2_len;
+ m->l3_len = info.l3_len;
+ m->l4_len = info.l4_len;
+ }
+ } else {
+ /* this is only useful if an offload flag is
+ * set, but it does not hurt to fill it in any
+ * case */
+ m->l2_len = info.l2_len;
+ m->l3_len = info.l3_len;
+ m->l4_len = info.l4_len;
+ m->tso_segsz = info.tso_segsz;
+ }
+ m->ol_flags = tx_ol_flags;
+
+ /* Do split & copy for the packet. */
+ if (tx_pkt_split != TX_PKT_SPLIT_OFF) {
+ p = pkt_copy_split(m);
+ if (p != NULL) {
+ rte_pktmbuf_free(m);
+ m = p;
+ pkts_burst[i] = m;
+ }
+ }
+
+ /* if verbose mode is enabled, dump debug info */
+ if (verbose_level > 0) {
+ char buf[256];
+
+ printf("-----------------\n");
+ printf("port=%u, mbuf=%p, pkt_len=%u, nb_segs=%u:\n",
+ fs->rx_port, m, m->pkt_len, m->nb_segs);
+ /* dump rx parsed packet info */
+ rte_get_rx_ol_flag_list(rx_ol_flags, buf, sizeof(buf));
+ printf("rx: l2_len=%d ethertype=%x l3_len=%d "
+ "l4_proto=%d l4_len=%d flags=%s\n",
+ info.l2_len, rte_be_to_cpu_16(info.ethertype),
+ info.l3_len, info.l4_proto, info.l4_len, buf);
+ if (rx_ol_flags & PKT_RX_LRO)
+ printf("rx: m->lro_segsz=%u\n", m->tso_segsz);
+ if (info.is_tunnel == 1)
+ printf("rx: outer_l2_len=%d outer_ethertype=%x "
+ "outer_l3_len=%d\n", info.outer_l2_len,
+ rte_be_to_cpu_16(info.outer_ethertype),
+ info.outer_l3_len);
+ /* dump tx packet info */
+ if ((tx_offloads & (DEV_TX_OFFLOAD_IPV4_CKSUM |
+ DEV_TX_OFFLOAD_UDP_CKSUM |
+ DEV_TX_OFFLOAD_TCP_CKSUM |
+ DEV_TX_OFFLOAD_SCTP_CKSUM)) ||
+ info.tso_segsz != 0)
+ printf("tx: m->l2_len=%d m->l3_len=%d "
+ "m->l4_len=%d\n",
+ m->l2_len, m->l3_len, m->l4_len);
+ if (info.is_tunnel == 1) {
+ if ((tx_offloads &
+ DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM) ||
+ (tx_offloads &
+ DEV_TX_OFFLOAD_OUTER_UDP_CKSUM) ||
+ (tx_ol_flags & PKT_TX_OUTER_IPV6))
+ printf("tx: m->outer_l2_len=%d "
+ "m->outer_l3_len=%d\n",
+ m->outer_l2_len,
+ m->outer_l3_len);
+ if (info.tunnel_tso_segsz != 0 &&
+ (m->ol_flags & PKT_TX_TCP_SEG))
+ printf("tx: m->tso_segsz=%d\n",
+ m->tso_segsz);
+ } else if (info.tso_segsz != 0 &&
+ (m->ol_flags & PKT_TX_TCP_SEG))
+ printf("tx: m->tso_segsz=%d\n", m->tso_segsz);
+ rte_get_tx_ol_flag_list(m->ol_flags, buf, sizeof(buf));
+ printf("tx: flags=%s", buf);
+ printf("\n");
+ }
+ }
+
+ if (unlikely(gro_enable)) {
+ if (gro_flush_cycles == GRO_DEFAULT_FLUSH_CYCLES) {
+ nb_rx = rte_gro_reassemble_burst(pkts_burst, nb_rx,
+ &(gro_ports[fs->rx_port].param));
+ } else {
+ gro_ctx = current_fwd_lcore()->gro_ctx;
+ nb_rx = rte_gro_reassemble(pkts_burst, nb_rx, gro_ctx);
+
+ if (++fs->gro_times >= gro_flush_cycles) {
+ gro_pkts_num = rte_gro_get_pkt_count(gro_ctx);
+ if (gro_pkts_num > MAX_PKT_BURST - nb_rx)
+ gro_pkts_num = MAX_PKT_BURST - nb_rx;
+
+ nb_rx += rte_gro_timeout_flush(gro_ctx, 0,
+ RTE_GRO_TCP_IPV4,
+ &pkts_burst[nb_rx],
+ gro_pkts_num);
+ fs->gro_times = 0;
+ }
+ }
+ }
+
+ if (gso_ports[fs->tx_port].enable == 0)
+ tx_pkts_burst = pkts_burst;
+ else {
+ gso_ctx = &(current_fwd_lcore()->gso_ctx);
+ gso_ctx->gso_size = gso_max_segment_size;
+ for (i = 0; i < nb_rx; i++) {
+ ret = rte_gso_segment(pkts_burst[i], gso_ctx,
+ &gso_segments[nb_segments],
+ GSO_MAX_PKT_BURST - nb_segments);
+ if (ret >= 0)
+ nb_segments += ret;
+ else {
+ TESTPMD_LOG(DEBUG, "Unable to segment packet");
+ rte_pktmbuf_free(pkts_burst[i]);
+ }
+ }
+
+ tx_pkts_burst = gso_segments;
+ nb_rx = nb_segments;
+ }
+
+ nb_prep = rte_eth_tx_prepare(fs->tx_port, fs->tx_queue,
+ tx_pkts_burst, nb_rx);
+ if (nb_prep != nb_rx)
+ printf("Preparing packet burst to transmit failed: %s\n",
+ rte_strerror(rte_errno));
+
+ nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, tx_pkts_burst,
+ nb_prep);
+
+ /*
+ * Retry if necessary
+ */
+ if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) {
+ retry = 0;
+ while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
+ rte_delay_us(burst_tx_delay_time);
+ nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+ &tx_pkts_burst[nb_tx], nb_rx - nb_tx);
+ }
+ }
+ fs->tx_packets += nb_tx;
+ fs->rx_bad_ip_csum += rx_bad_ip_csum;
+ fs->rx_bad_l4_csum += rx_bad_l4_csum;
+ fs->rx_bad_outer_l4_csum += rx_bad_outer_l4_csum;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+#endif
+ if (unlikely(nb_tx < nb_rx)) {
+ fs->fwd_dropped += (nb_rx - nb_tx);
+ do {
+ rte_pktmbuf_free(tx_pkts_burst[nb_tx]);
+ } while (++nb_tx < nb_rx);
+ }
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ end_tsc = rte_rdtsc();
+ core_cycles = (end_tsc - start_tsc);
+ fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+#endif
+}
+
+struct fwd_engine csum_fwd_engine = {
+ .fwd_mode_name = "csum",
+ .port_fwd_begin = NULL,
+ .port_fwd_end = NULL,
+ .packet_fwd = pkt_burst_checksum_forward,
+};
diff --git a/src/spdk/dpdk/app/test-pmd/flowgen.c b/src/spdk/dpdk/app/test-pmd/flowgen.c
new file mode 100644
index 000000000..4bd351e67
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/flowgen.c
@@ -0,0 +1,222 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2014-2020 Mellanox Technologies, Ltd
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
+#include <rte_string_fns.h>
+#include <rte_flow.h>
+
+#include "testpmd.h"
+
+/* hardcoded configuration (for now) */
+static unsigned cfg_n_flows = 1024;
+static uint32_t cfg_ip_src = RTE_IPV4(10, 254, 0, 0);
+static uint32_t cfg_ip_dst = RTE_IPV4(10, 253, 0, 0);
+static uint16_t cfg_udp_src = 1000;
+static uint16_t cfg_udp_dst = 1001;
+static struct rte_ether_addr cfg_ether_src =
+ {{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x00 }};
+static struct rte_ether_addr cfg_ether_dst =
+ {{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x01 }};
+
+#define IP_DEFTTL 64 /* from RFC 1340. */
+
+static inline uint16_t
+ip_sum(const unaligned_uint16_t *hdr, int hdr_len)
+{
+ uint32_t sum = 0;
+
+ while (hdr_len > 1)
+ {
+ sum += *hdr++;
+ if (sum & 0x80000000)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ hdr_len -= 2;
+ }
+
+ while (sum >> 16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ return ~sum;
+}
+
+/*
+ * Multi-flow generation mode.
+ *
+ * We originate a bunch of flows (varying destination IP addresses), and
+ * terminate receive traffic. Received traffic is simply discarded, but we
+ * still do so in order to maintain traffic statistics.
+ */
+static void
+pkt_burst_flow_gen(struct fwd_stream *fs)
+{
+ unsigned pkt_size = tx_pkt_length - 4; /* Adjust FCS */
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_mempool *mbp;
+ struct rte_mbuf *pkt;
+ struct rte_ether_hdr *eth_hdr;
+ struct rte_ipv4_hdr *ip_hdr;
+ struct rte_udp_hdr *udp_hdr;
+ uint16_t vlan_tci, vlan_tci_outer;
+ uint64_t ol_flags = 0;
+ uint16_t nb_rx;
+ uint16_t nb_tx;
+ uint16_t nb_pkt;
+ uint16_t i;
+ uint32_t retry;
+ uint64_t tx_offloads;
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ uint64_t start_tsc;
+ uint64_t end_tsc;
+ uint64_t core_cycles;
+#endif
+ static int next_flow = 0;
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ start_tsc = rte_rdtsc();
+#endif
+
+ /* Receive a burst of packets and discard them. */
+ nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
+ nb_pkt_per_burst);
+ fs->rx_packets += nb_rx;
+
+ for (i = 0; i < nb_rx; i++)
+ rte_pktmbuf_free(pkts_burst[i]);
+
+ mbp = current_fwd_lcore()->mbp;
+ vlan_tci = ports[fs->tx_port].tx_vlan_id;
+ vlan_tci_outer = ports[fs->tx_port].tx_vlan_id_outer;
+
+ tx_offloads = ports[fs->tx_port].dev_conf.txmode.offloads;
+ if (tx_offloads & DEV_TX_OFFLOAD_VLAN_INSERT)
+ ol_flags |= PKT_TX_VLAN_PKT;
+ if (tx_offloads & DEV_TX_OFFLOAD_QINQ_INSERT)
+ ol_flags |= PKT_TX_QINQ_PKT;
+ if (tx_offloads & DEV_TX_OFFLOAD_MACSEC_INSERT)
+ ol_flags |= PKT_TX_MACSEC;
+
+ for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
+ pkt = rte_mbuf_raw_alloc(mbp);
+ if (!pkt)
+ break;
+
+ pkt->data_len = pkt_size;
+ pkt->next = NULL;
+
+ /* Initialize Ethernet header. */
+ eth_hdr = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
+ rte_ether_addr_copy(&cfg_ether_dst, &eth_hdr->d_addr);
+ rte_ether_addr_copy(&cfg_ether_src, &eth_hdr->s_addr);
+ eth_hdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+
+ /* Initialize IP header. */
+ ip_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1);
+ memset(ip_hdr, 0, sizeof(*ip_hdr));
+ ip_hdr->version_ihl = RTE_IPV4_VHL_DEF;
+ ip_hdr->type_of_service = 0;
+ ip_hdr->fragment_offset = 0;
+ ip_hdr->time_to_live = IP_DEFTTL;
+ ip_hdr->next_proto_id = IPPROTO_UDP;
+ ip_hdr->packet_id = 0;
+ ip_hdr->src_addr = rte_cpu_to_be_32(cfg_ip_src);
+ ip_hdr->dst_addr = rte_cpu_to_be_32(cfg_ip_dst +
+ next_flow);
+ ip_hdr->total_length = RTE_CPU_TO_BE_16(pkt_size -
+ sizeof(*eth_hdr));
+ ip_hdr->hdr_checksum = ip_sum((unaligned_uint16_t *)ip_hdr,
+ sizeof(*ip_hdr));
+
+ /* Initialize UDP header. */
+ udp_hdr = (struct rte_udp_hdr *)(ip_hdr + 1);
+ udp_hdr->src_port = rte_cpu_to_be_16(cfg_udp_src);
+ udp_hdr->dst_port = rte_cpu_to_be_16(cfg_udp_dst);
+ udp_hdr->dgram_cksum = 0; /* No UDP checksum. */
+ udp_hdr->dgram_len = RTE_CPU_TO_BE_16(pkt_size -
+ sizeof(*eth_hdr) -
+ sizeof(*ip_hdr));
+ pkt->nb_segs = 1;
+ pkt->pkt_len = pkt_size;
+ pkt->ol_flags &= EXT_ATTACHED_MBUF;
+ pkt->ol_flags |= ol_flags;
+ pkt->vlan_tci = vlan_tci;
+ pkt->vlan_tci_outer = vlan_tci_outer;
+ pkt->l2_len = sizeof(struct rte_ether_hdr);
+ pkt->l3_len = sizeof(struct rte_ipv4_hdr);
+ pkts_burst[nb_pkt] = pkt;
+
+ next_flow = (next_flow + 1) % cfg_n_flows;
+ }
+
+ nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_pkt);
+ /*
+ * Retry if necessary
+ */
+ if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) {
+ retry = 0;
+ while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
+ rte_delay_us(burst_tx_delay_time);
+ nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+ &pkts_burst[nb_tx], nb_rx - nb_tx);
+ }
+ }
+ fs->tx_packets += nb_tx;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+#endif
+ if (unlikely(nb_tx < nb_pkt)) {
+ /* Back out the flow counter. */
+ next_flow -= (nb_pkt - nb_tx);
+ while (next_flow < 0)
+ next_flow += cfg_n_flows;
+
+ do {
+ rte_pktmbuf_free(pkts_burst[nb_tx]);
+ } while (++nb_tx < nb_pkt);
+ }
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ end_tsc = rte_rdtsc();
+ core_cycles = (end_tsc - start_tsc);
+ fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+#endif
+}
+
+struct fwd_engine flow_gen_engine = {
+ .fwd_mode_name = "flowgen",
+ .port_fwd_begin = NULL,
+ .port_fwd_end = NULL,
+ .packet_fwd = pkt_burst_flow_gen,
+};
diff --git a/src/spdk/dpdk/app/test-pmd/icmpecho.c b/src/spdk/dpdk/app/test-pmd/icmpecho.c
new file mode 100644
index 000000000..65aece16c
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/icmpecho.c
@@ -0,0 +1,535 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2013 6WIND S.A.
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_memory.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_arp.h>
+#include <rte_ip.h>
+#include <rte_icmp.h>
+#include <rte_string_fns.h>
+#include <rte_flow.h>
+
+#include "testpmd.h"
+
+static const char *
+arp_op_name(uint16_t arp_op)
+{
+ switch (arp_op) {
+ case RTE_ARP_OP_REQUEST:
+ return "ARP Request";
+ case RTE_ARP_OP_REPLY:
+ return "ARP Reply";
+ case RTE_ARP_OP_REVREQUEST:
+ return "Reverse ARP Request";
+ case RTE_ARP_OP_REVREPLY:
+ return "Reverse ARP Reply";
+ case RTE_ARP_OP_INVREQUEST:
+ return "Peer Identify Request";
+ case RTE_ARP_OP_INVREPLY:
+ return "Peer Identify Reply";
+ default:
+ break;
+ }
+ return "Unkwown ARP op";
+}
+
+static const char *
+ip_proto_name(uint16_t ip_proto)
+{
+ static const char * ip_proto_names[] = {
+ "IP6HOPOPTS", /**< IP6 hop-by-hop options */
+ "ICMP", /**< control message protocol */
+ "IGMP", /**< group mgmt protocol */
+ "GGP", /**< gateway^2 (deprecated) */
+ "IPv4", /**< IPv4 encapsulation */
+
+ "UNASSIGNED",
+ "TCP", /**< transport control protocol */
+ "ST", /**< Stream protocol II */
+ "EGP", /**< exterior gateway protocol */
+ "PIGP", /**< private interior gateway */
+
+ "RCC_MON", /**< BBN RCC Monitoring */
+ "NVPII", /**< network voice protocol*/
+ "PUP", /**< pup */
+ "ARGUS", /**< Argus */
+ "EMCON", /**< EMCON */
+
+ "XNET", /**< Cross Net Debugger */
+ "CHAOS", /**< Chaos*/
+ "UDP", /**< user datagram protocol */
+ "MUX", /**< Multiplexing */
+ "DCN_MEAS", /**< DCN Measurement Subsystems */
+
+ "HMP", /**< Host Monitoring */
+ "PRM", /**< Packet Radio Measurement */
+ "XNS_IDP", /**< xns idp */
+ "TRUNK1", /**< Trunk-1 */
+ "TRUNK2", /**< Trunk-2 */
+
+ "LEAF1", /**< Leaf-1 */
+ "LEAF2", /**< Leaf-2 */
+ "RDP", /**< Reliable Data */
+ "IRTP", /**< Reliable Transaction */
+ "TP4", /**< tp-4 w/ class negotiation */
+
+ "BLT", /**< Bulk Data Transfer */
+ "NSP", /**< Network Services */
+ "INP", /**< Merit Internodal */
+ "SEP", /**< Sequential Exchange */
+ "3PC", /**< Third Party Connect */
+
+ "IDPR", /**< InterDomain Policy Routing */
+ "XTP", /**< XTP */
+ "DDP", /**< Datagram Delivery */
+ "CMTP", /**< Control Message Transport */
+ "TPXX", /**< TP++ Transport */
+
+ "ILTP", /**< IL transport protocol */
+ "IPv6_HDR", /**< IP6 header */
+ "SDRP", /**< Source Demand Routing */
+ "IPv6_RTG", /**< IP6 routing header */
+ "IPv6_FRAG", /**< IP6 fragmentation header */
+
+ "IDRP", /**< InterDomain Routing*/
+ "RSVP", /**< resource reservation */
+ "GRE", /**< General Routing Encap. */
+ "MHRP", /**< Mobile Host Routing */
+ "BHA", /**< BHA */
+
+ "ESP", /**< IP6 Encap Sec. Payload */
+ "AH", /**< IP6 Auth Header */
+ "INLSP", /**< Integ. Net Layer Security */
+ "SWIPE", /**< IP with encryption */
+ "NHRP", /**< Next Hop Resolution */
+
+ "UNASSIGNED",
+ "UNASSIGNED",
+ "UNASSIGNED",
+ "ICMPv6", /**< ICMP6 */
+ "IPv6NONEXT", /**< IP6 no next header */
+
+ "Ipv6DSTOPTS",/**< IP6 destination option */
+ "AHIP", /**< any host internal protocol */
+ "CFTP", /**< CFTP */
+ "HELLO", /**< "hello" routing protocol */
+ "SATEXPAK", /**< SATNET/Backroom EXPAK */
+
+ "KRYPTOLAN", /**< Kryptolan */
+ "RVD", /**< Remote Virtual Disk */
+ "IPPC", /**< Pluribus Packet Core */
+ "ADFS", /**< Any distributed FS */
+ "SATMON", /**< Satnet Monitoring */
+
+ "VISA", /**< VISA Protocol */
+ "IPCV", /**< Packet Core Utility */
+ "CPNX", /**< Comp. Prot. Net. Executive */
+ "CPHB", /**< Comp. Prot. HeartBeat */
+ "WSN", /**< Wang Span Network */
+
+ "PVP", /**< Packet Video Protocol */
+ "BRSATMON", /**< BackRoom SATNET Monitoring */
+ "ND", /**< Sun net disk proto (temp.) */
+ "WBMON", /**< WIDEBAND Monitoring */
+ "WBEXPAK", /**< WIDEBAND EXPAK */
+
+ "EON", /**< ISO cnlp */
+ "VMTP", /**< VMTP */
+ "SVMTP", /**< Secure VMTP */
+ "VINES", /**< Banyon VINES */
+ "TTP", /**< TTP */
+
+ "IGP", /**< NSFNET-IGP */
+ "DGP", /**< dissimilar gateway prot. */
+ "TCF", /**< TCF */
+ "IGRP", /**< Cisco/GXS IGRP */
+ "OSPFIGP", /**< OSPFIGP */
+
+ "SRPC", /**< Strite RPC protocol */
+ "LARP", /**< Locus Address Resolution */
+ "MTP", /**< Multicast Transport */
+ "AX25", /**< AX.25 Frames */
+ "4IN4", /**< IP encapsulated in IP */
+
+ "MICP", /**< Mobile Int.ing control */
+ "SCCSP", /**< Semaphore Comm. security */
+ "ETHERIP", /**< Ethernet IP encapsulation */
+ "ENCAP", /**< encapsulation header */
+ "AES", /**< any private encr. scheme */
+
+ "GMTP", /**< GMTP */
+ "IPCOMP", /**< payload compression (IPComp) */
+ "UNASSIGNED",
+ "UNASSIGNED",
+ "PIM", /**< Protocol Independent Mcast */
+ };
+
+ if (ip_proto < RTE_DIM(ip_proto_names))
+ return ip_proto_names[ip_proto];
+ switch (ip_proto) {
+#ifdef IPPROTO_PGM
+ case IPPROTO_PGM: /**< PGM */
+ return "PGM";
+#endif
+ case IPPROTO_SCTP: /**< Stream Control Transport Protocol */
+ return "SCTP";
+#ifdef IPPROTO_DIVERT
+ case IPPROTO_DIVERT: /**< divert pseudo-protocol */
+ return "DIVERT";
+#endif
+ case IPPROTO_RAW: /**< raw IP packet */
+ return "RAW";
+ default:
+ break;
+ }
+ return "UNASSIGNED";
+}
+
+static void
+ipv4_addr_to_dot(uint32_t be_ipv4_addr, char *buf)
+{
+ uint32_t ipv4_addr;
+
+ ipv4_addr = rte_be_to_cpu_32(be_ipv4_addr);
+ sprintf(buf, "%d.%d.%d.%d", (ipv4_addr >> 24) & 0xFF,
+ (ipv4_addr >> 16) & 0xFF, (ipv4_addr >> 8) & 0xFF,
+ ipv4_addr & 0xFF);
+}
+
+static void
+ether_addr_dump(const char *what, const struct rte_ether_addr *ea)
+{
+ char buf[RTE_ETHER_ADDR_FMT_SIZE];
+
+ rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, ea);
+ if (what)
+ printf("%s", what);
+ printf("%s", buf);
+}
+
+static void
+ipv4_addr_dump(const char *what, uint32_t be_ipv4_addr)
+{
+ char buf[16];
+
+ ipv4_addr_to_dot(be_ipv4_addr, buf);
+ if (what)
+ printf("%s", what);
+ printf("%s", buf);
+}
+
+static uint16_t
+ipv4_hdr_cksum(struct rte_ipv4_hdr *ip_h)
+{
+ uint16_t *v16_h;
+ uint32_t ip_cksum;
+
+ /*
+ * Compute the sum of successive 16-bit words of the IPv4 header,
+ * skipping the checksum field of the header.
+ */
+ v16_h = (unaligned_uint16_t *) ip_h;
+ ip_cksum = v16_h[0] + v16_h[1] + v16_h[2] + v16_h[3] +
+ v16_h[4] + v16_h[6] + v16_h[7] + v16_h[8] + v16_h[9];
+
+ /* reduce 32 bit checksum to 16 bits and complement it */
+ ip_cksum = (ip_cksum & 0xffff) + (ip_cksum >> 16);
+ ip_cksum = (ip_cksum & 0xffff) + (ip_cksum >> 16);
+ ip_cksum = (~ip_cksum) & 0x0000FFFF;
+ return (ip_cksum == 0) ? 0xFFFF : (uint16_t) ip_cksum;
+}
+
+#define is_multicast_ipv4_addr(ipv4_addr) \
+ (((rte_be_to_cpu_32((ipv4_addr)) >> 24) & 0x000000FF) == 0xE0)
+
+/*
+ * Receive a burst of packets, lookup for ICMP echo requests, and, if any,
+ * send back ICMP echo replies.
+ */
+static void
+reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_mbuf *pkt;
+ struct rte_ether_hdr *eth_h;
+ struct rte_vlan_hdr *vlan_h;
+ struct rte_arp_hdr *arp_h;
+ struct rte_ipv4_hdr *ip_h;
+ struct rte_icmp_hdr *icmp_h;
+ struct rte_ether_addr eth_addr;
+ uint32_t retry;
+ uint32_t ip_addr;
+ uint16_t nb_rx;
+ uint16_t nb_tx;
+ uint16_t nb_replies;
+ uint16_t eth_type;
+ uint16_t vlan_id;
+ uint16_t arp_op;
+ uint16_t arp_pro;
+ uint32_t cksum;
+ uint8_t i;
+ int l2_len;
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ uint64_t start_tsc;
+ uint64_t end_tsc;
+ uint64_t core_cycles;
+#endif
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ start_tsc = rte_rdtsc();
+#endif
+
+ /*
+ * First, receive a burst of packets.
+ */
+ nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
+ nb_pkt_per_burst);
+ if (unlikely(nb_rx == 0))
+ return;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
+#endif
+ fs->rx_packets += nb_rx;
+ nb_replies = 0;
+ for (i = 0; i < nb_rx; i++) {
+ if (likely(i < nb_rx - 1))
+ rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
+ void *));
+ pkt = pkts_burst[i];
+ eth_h = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
+ eth_type = RTE_BE_TO_CPU_16(eth_h->ether_type);
+ l2_len = sizeof(struct rte_ether_hdr);
+ if (verbose_level > 0) {
+ printf("\nPort %d pkt-len=%u nb-segs=%u\n",
+ fs->rx_port, pkt->pkt_len, pkt->nb_segs);
+ ether_addr_dump(" ETH: src=", &eth_h->s_addr);
+ ether_addr_dump(" dst=", &eth_h->d_addr);
+ }
+ if (eth_type == RTE_ETHER_TYPE_VLAN) {
+ vlan_h = (struct rte_vlan_hdr *)
+ ((char *)eth_h + sizeof(struct rte_ether_hdr));
+ l2_len += sizeof(struct rte_vlan_hdr);
+ eth_type = rte_be_to_cpu_16(vlan_h->eth_proto);
+ if (verbose_level > 0) {
+ vlan_id = rte_be_to_cpu_16(vlan_h->vlan_tci)
+ & 0xFFF;
+ printf(" [vlan id=%u]", vlan_id);
+ }
+ }
+ if (verbose_level > 0) {
+ printf(" type=0x%04x\n", eth_type);
+ }
+
+ /* Reply to ARP requests */
+ if (eth_type == RTE_ETHER_TYPE_ARP) {
+ arp_h = (struct rte_arp_hdr *) ((char *)eth_h + l2_len);
+ arp_op = RTE_BE_TO_CPU_16(arp_h->arp_opcode);
+ arp_pro = RTE_BE_TO_CPU_16(arp_h->arp_protocol);
+ if (verbose_level > 0) {
+ printf(" ARP: hrd=%d proto=0x%04x hln=%d "
+ "pln=%d op=%u (%s)\n",
+ RTE_BE_TO_CPU_16(arp_h->arp_hardware),
+ arp_pro, arp_h->arp_hlen,
+ arp_h->arp_plen, arp_op,
+ arp_op_name(arp_op));
+ }
+ if ((RTE_BE_TO_CPU_16(arp_h->arp_hardware) !=
+ RTE_ARP_HRD_ETHER) ||
+ (arp_pro != RTE_ETHER_TYPE_IPV4) ||
+ (arp_h->arp_hlen != 6) ||
+ (arp_h->arp_plen != 4)
+ ) {
+ rte_pktmbuf_free(pkt);
+ if (verbose_level > 0)
+ printf("\n");
+ continue;
+ }
+ if (verbose_level > 0) {
+ rte_ether_addr_copy(&arp_h->arp_data.arp_sha,
+ &eth_addr);
+ ether_addr_dump(" sha=", &eth_addr);
+ ip_addr = arp_h->arp_data.arp_sip;
+ ipv4_addr_dump(" sip=", ip_addr);
+ printf("\n");
+ rte_ether_addr_copy(&arp_h->arp_data.arp_tha,
+ &eth_addr);
+ ether_addr_dump(" tha=", &eth_addr);
+ ip_addr = arp_h->arp_data.arp_tip;
+ ipv4_addr_dump(" tip=", ip_addr);
+ printf("\n");
+ }
+ if (arp_op != RTE_ARP_OP_REQUEST) {
+ rte_pktmbuf_free(pkt);
+ continue;
+ }
+
+ /*
+ * Build ARP reply.
+ */
+
+ /* Use source MAC address as destination MAC address. */
+ rte_ether_addr_copy(&eth_h->s_addr, &eth_h->d_addr);
+ /* Set source MAC address with MAC address of TX port */
+ rte_ether_addr_copy(&ports[fs->tx_port].eth_addr,
+ &eth_h->s_addr);
+
+ arp_h->arp_opcode = rte_cpu_to_be_16(RTE_ARP_OP_REPLY);
+ rte_ether_addr_copy(&arp_h->arp_data.arp_tha,
+ &eth_addr);
+ rte_ether_addr_copy(&arp_h->arp_data.arp_sha,
+ &arp_h->arp_data.arp_tha);
+ rte_ether_addr_copy(&eth_h->s_addr,
+ &arp_h->arp_data.arp_sha);
+
+ /* Swap IP addresses in ARP payload */
+ ip_addr = arp_h->arp_data.arp_sip;
+ arp_h->arp_data.arp_sip = arp_h->arp_data.arp_tip;
+ arp_h->arp_data.arp_tip = ip_addr;
+ pkts_burst[nb_replies++] = pkt;
+ continue;
+ }
+
+ if (eth_type != RTE_ETHER_TYPE_IPV4) {
+ rte_pktmbuf_free(pkt);
+ continue;
+ }
+ ip_h = (struct rte_ipv4_hdr *) ((char *)eth_h + l2_len);
+ if (verbose_level > 0) {
+ ipv4_addr_dump(" IPV4: src=", ip_h->src_addr);
+ ipv4_addr_dump(" dst=", ip_h->dst_addr);
+ printf(" proto=%d (%s)\n",
+ ip_h->next_proto_id,
+ ip_proto_name(ip_h->next_proto_id));
+ }
+
+ /*
+ * Check if packet is a ICMP echo request.
+ */
+ icmp_h = (struct rte_icmp_hdr *) ((char *)ip_h +
+ sizeof(struct rte_ipv4_hdr));
+ if (! ((ip_h->next_proto_id == IPPROTO_ICMP) &&
+ (icmp_h->icmp_type == RTE_IP_ICMP_ECHO_REQUEST) &&
+ (icmp_h->icmp_code == 0))) {
+ rte_pktmbuf_free(pkt);
+ continue;
+ }
+
+ if (verbose_level > 0)
+ printf(" ICMP: echo request seq id=%d\n",
+ rte_be_to_cpu_16(icmp_h->icmp_seq_nb));
+
+ /*
+ * Prepare ICMP echo reply to be sent back.
+ * - switch ethernet source and destinations addresses,
+ * - use the request IP source address as the reply IP
+ * destination address,
+ * - if the request IP destination address is a multicast
+ * address:
+ * - choose a reply IP source address different from the
+ * request IP source address,
+ * - re-compute the IP header checksum.
+ * Otherwise:
+ * - switch the request IP source and destination
+ * addresses in the reply IP header,
+ * - keep the IP header checksum unchanged.
+ * - set RTE_IP_ICMP_ECHO_REPLY in ICMP header.
+ * ICMP checksum is computed by assuming it is valid in the
+ * echo request and not verified.
+ */
+ rte_ether_addr_copy(&eth_h->s_addr, &eth_addr);
+ rte_ether_addr_copy(&eth_h->d_addr, &eth_h->s_addr);
+ rte_ether_addr_copy(&eth_addr, &eth_h->d_addr);
+ ip_addr = ip_h->src_addr;
+ if (is_multicast_ipv4_addr(ip_h->dst_addr)) {
+ uint32_t ip_src;
+
+ ip_src = rte_be_to_cpu_32(ip_addr);
+ if ((ip_src & 0x00000003) == 1)
+ ip_src = (ip_src & 0xFFFFFFFC) | 0x00000002;
+ else
+ ip_src = (ip_src & 0xFFFFFFFC) | 0x00000001;
+ ip_h->src_addr = rte_cpu_to_be_32(ip_src);
+ ip_h->dst_addr = ip_addr;
+ ip_h->hdr_checksum = ipv4_hdr_cksum(ip_h);
+ } else {
+ ip_h->src_addr = ip_h->dst_addr;
+ ip_h->dst_addr = ip_addr;
+ }
+ icmp_h->icmp_type = RTE_IP_ICMP_ECHO_REPLY;
+ cksum = ~icmp_h->icmp_cksum & 0xffff;
+ cksum += ~htons(RTE_IP_ICMP_ECHO_REQUEST << 8) & 0xffff;
+ cksum += htons(RTE_IP_ICMP_ECHO_REPLY << 8);
+ cksum = (cksum & 0xffff) + (cksum >> 16);
+ cksum = (cksum & 0xffff) + (cksum >> 16);
+ icmp_h->icmp_cksum = ~cksum;
+ pkts_burst[nb_replies++] = pkt;
+ }
+
+ /* Send back ICMP echo replies, if any. */
+ if (nb_replies > 0) {
+ nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst,
+ nb_replies);
+ /*
+ * Retry if necessary
+ */
+ if (unlikely(nb_tx < nb_replies) && fs->retry_enabled) {
+ retry = 0;
+ while (nb_tx < nb_replies &&
+ retry++ < burst_tx_retry_num) {
+ rte_delay_us(burst_tx_delay_time);
+ nb_tx += rte_eth_tx_burst(fs->tx_port,
+ fs->tx_queue,
+ &pkts_burst[nb_tx],
+ nb_replies - nb_tx);
+ }
+ }
+ fs->tx_packets += nb_tx;
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+#endif
+ if (unlikely(nb_tx < nb_replies)) {
+ fs->fwd_dropped += (nb_replies - nb_tx);
+ do {
+ rte_pktmbuf_free(pkts_burst[nb_tx]);
+ } while (++nb_tx < nb_replies);
+ }
+ }
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ end_tsc = rte_rdtsc();
+ core_cycles = (end_tsc - start_tsc);
+ fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+#endif
+}
+
+struct fwd_engine icmp_echo_engine = {
+ .fwd_mode_name = "icmpecho",
+ .port_fwd_begin = NULL,
+ .port_fwd_end = NULL,
+ .packet_fwd = reply_to_icmp_echo_rqsts,
+};
diff --git a/src/spdk/dpdk/app/test-pmd/ieee1588fwd.c b/src/spdk/dpdk/app/test-pmd/ieee1588fwd.c
new file mode 100644
index 000000000..e3b98e3e0
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/ieee1588fwd.c
@@ -0,0 +1,218 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2015 Intel Corporation
+ */
+
+
+#include <rte_cycles.h>
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+
+#include "testpmd.h"
+
+/**
+ * The structure of a PTP V2 packet.
+ *
+ * Only the minimum fields used by the ieee1588 test are represented.
+ */
+struct ptpv2_msg {
+ uint8_t msg_id;
+ uint8_t version; /**< must be 0x02 */
+ uint8_t unused[34];
+};
+
+#define PTP_SYNC_MESSAGE 0x0
+#define PTP_DELAY_REQ_MESSAGE 0x1
+#define PTP_PATH_DELAY_REQ_MESSAGE 0x2
+#define PTP_PATH_DELAY_RESP_MESSAGE 0x3
+#define PTP_FOLLOWUP_MESSAGE 0x8
+#define PTP_DELAY_RESP_MESSAGE 0x9
+#define PTP_PATH_DELAY_FOLLOWUP_MESSAGE 0xA
+#define PTP_ANNOUNCE_MESSAGE 0xB
+#define PTP_SIGNALLING_MESSAGE 0xC
+#define PTP_MANAGEMENT_MESSAGE 0xD
+
+/*
+ * Forwarding of IEEE1588 Precise Time Protocol (PTP) packets.
+ *
+ * In this mode, packets are received one by one and are expected to be
+ * PTP V2 L2 Ethernet frames (with the specific Ethernet type "0x88F7")
+ * containing PTP "sync" messages (version 2 at offset 1, and message ID
+ * 0 at offset 0).
+ *
+ * Check that each received packet is a IEEE1588 PTP V2 packet of type
+ * PTP_SYNC_MESSAGE, and that it has been identified and timestamped
+ * by the hardware.
+ * Check that the value of the last RX timestamp recorded by the controller
+ * is greater than the previous one.
+ *
+ * If everything is OK, send the received packet back on the same port,
+ * requesting for it to be timestamped by the hardware.
+ * Check that the value of the last TX timestamp recorded by the controller
+ * is greater than the previous one.
+ */
+
+static void
+port_ieee1588_rx_timestamp_check(portid_t pi, uint32_t index)
+{
+ struct timespec timestamp = {0, 0};
+
+ if (rte_eth_timesync_read_rx_timestamp(pi, &timestamp, index) < 0) {
+ printf("Port %u RX timestamp registers not valid\n", pi);
+ return;
+ }
+ printf("Port %u RX timestamp value %lu s %lu ns\n",
+ pi, timestamp.tv_sec, timestamp.tv_nsec);
+}
+
+#define MAX_TX_TMST_WAIT_MICROSECS 1000 /**< 1 milli-second */
+
+static void
+port_ieee1588_tx_timestamp_check(portid_t pi)
+{
+ struct timespec timestamp = {0, 0};
+ unsigned wait_us = 0;
+
+ while ((rte_eth_timesync_read_tx_timestamp(pi, &timestamp) < 0) &&
+ (wait_us < MAX_TX_TMST_WAIT_MICROSECS)) {
+ rte_delay_us(1);
+ wait_us++;
+ }
+ if (wait_us >= MAX_TX_TMST_WAIT_MICROSECS) {
+ printf("Port %u TX timestamp registers not valid after "
+ "%u micro-seconds\n",
+ pi, MAX_TX_TMST_WAIT_MICROSECS);
+ return;
+ }
+ printf("Port %u TX timestamp value %lu s %lu ns validated after "
+ "%u micro-second%s\n",
+ pi, timestamp.tv_sec, timestamp.tv_nsec, wait_us,
+ (wait_us == 1) ? "" : "s");
+}
+
+static void
+ieee1588_packet_fwd(struct fwd_stream *fs)
+{
+ struct rte_mbuf *mb;
+ struct rte_ether_hdr *eth_hdr;
+ struct rte_ether_addr addr;
+ struct ptpv2_msg *ptp_hdr;
+ uint16_t eth_type;
+ uint32_t timesync_index;
+
+ /*
+ * Receive 1 packet at a time.
+ */
+ if (rte_eth_rx_burst(fs->rx_port, fs->rx_queue, &mb, 1) == 0)
+ return;
+
+ fs->rx_packets += 1;
+
+ /*
+ * Check that the received packet is a PTP packet that was detected
+ * by the hardware.
+ */
+ eth_hdr = rte_pktmbuf_mtod(mb, struct rte_ether_hdr *);
+ eth_type = rte_be_to_cpu_16(eth_hdr->ether_type);
+
+ if (! (mb->ol_flags & PKT_RX_IEEE1588_PTP)) {
+ if (eth_type == RTE_ETHER_TYPE_1588) {
+ printf("Port %u Received PTP packet not filtered"
+ " by hardware\n",
+ fs->rx_port);
+ } else {
+ printf("Port %u Received non PTP packet type=0x%4x "
+ "len=%u\n",
+ fs->rx_port, eth_type,
+ (unsigned) mb->pkt_len);
+ }
+ rte_pktmbuf_free(mb);
+ return;
+ }
+ if (eth_type != RTE_ETHER_TYPE_1588) {
+ printf("Port %u Received NON PTP packet incorrectly"
+ " detected by hardware\n",
+ fs->rx_port);
+ rte_pktmbuf_free(mb);
+ return;
+ }
+
+ /*
+ * Check that the received PTP packet is a PTP V2 packet of type
+ * PTP_SYNC_MESSAGE.
+ */
+ ptp_hdr = (struct ptpv2_msg *) (rte_pktmbuf_mtod(mb, char *) +
+ sizeof(struct rte_ether_hdr));
+ if (ptp_hdr->version != 0x02) {
+ printf("Port %u Received PTP V2 Ethernet frame with wrong PTP"
+ " protocol version 0x%x (should be 0x02)\n",
+ fs->rx_port, ptp_hdr->version);
+ rte_pktmbuf_free(mb);
+ return;
+ }
+ if (ptp_hdr->msg_id != PTP_SYNC_MESSAGE) {
+ printf("Port %u Received PTP V2 Ethernet frame with unexpected"
+ " message ID 0x%x (expected 0x0 - PTP_SYNC_MESSAGE)\n",
+ fs->rx_port, ptp_hdr->msg_id);
+ rte_pktmbuf_free(mb);
+ return;
+ }
+ printf("Port %u IEEE1588 PTP V2 SYNC Message filtered by hardware\n",
+ fs->rx_port);
+
+ /*
+ * Check that the received PTP packet has been timestamped by the
+ * hardware.
+ */
+ if (! (mb->ol_flags & PKT_RX_IEEE1588_TMST)) {
+ printf("Port %u Received PTP packet not timestamped"
+ " by hardware\n",
+ fs->rx_port);
+ rte_pktmbuf_free(mb);
+ return;
+ }
+
+ /* For i40e we need the timesync register index. It is ignored for the
+ * other PMDs. */
+ timesync_index = mb->timesync & 0x3;
+ /* Read and check the RX timestamp. */
+ port_ieee1588_rx_timestamp_check(fs->rx_port, timesync_index);
+
+ /* Swap dest and src mac addresses. */
+ rte_ether_addr_copy(&eth_hdr->d_addr, &addr);
+ rte_ether_addr_copy(&eth_hdr->s_addr, &eth_hdr->d_addr);
+ rte_ether_addr_copy(&addr, &eth_hdr->s_addr);
+
+ /* Forward PTP packet with hardware TX timestamp */
+ mb->ol_flags |= PKT_TX_IEEE1588_TMST;
+ fs->tx_packets += 1;
+ if (rte_eth_tx_burst(fs->rx_port, fs->tx_queue, &mb, 1) == 0) {
+ printf("Port %u sent PTP packet dropped\n", fs->rx_port);
+ fs->fwd_dropped += 1;
+ rte_pktmbuf_free(mb);
+ return;
+ }
+
+ /*
+ * Check the TX timestamp.
+ */
+ port_ieee1588_tx_timestamp_check(fs->rx_port);
+}
+
+static void
+port_ieee1588_fwd_begin(portid_t pi)
+{
+ rte_eth_timesync_enable(pi);
+}
+
+static void
+port_ieee1588_fwd_end(portid_t pi)
+{
+ rte_eth_timesync_disable(pi);
+}
+
+struct fwd_engine ieee1588_fwd_engine = {
+ .fwd_mode_name = "ieee1588",
+ .port_fwd_begin = port_ieee1588_fwd_begin,
+ .port_fwd_end = port_ieee1588_fwd_end,
+ .packet_fwd = ieee1588_packet_fwd,
+};
diff --git a/src/spdk/dpdk/app/test-pmd/iofwd.c b/src/spdk/dpdk/app/test-pmd/iofwd.c
new file mode 100644
index 000000000..9dce76efe
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/iofwd.c
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_memory.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_memcpy.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_string_fns.h>
+#include <rte_flow.h>
+
+#include "testpmd.h"
+
+/*
+ * Forwarding of packets in I/O mode.
+ * Forward packets "as-is".
+ * This is the fastest possible forwarding operation, as it does not access
+ * to packets data.
+ */
+static void
+pkt_burst_io_forward(struct fwd_stream *fs)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ uint16_t nb_rx;
+ uint16_t nb_tx;
+ uint32_t retry;
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ uint64_t start_tsc;
+ uint64_t end_tsc;
+ uint64_t core_cycles;
+#endif
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ start_tsc = rte_rdtsc();
+#endif
+
+ /*
+ * Receive a burst of packets and forward them.
+ */
+ nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,
+ pkts_burst, nb_pkt_per_burst);
+ if (unlikely(nb_rx == 0))
+ return;
+ fs->rx_packets += nb_rx;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
+#endif
+ nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+ pkts_burst, nb_rx);
+ /*
+ * Retry if necessary
+ */
+ if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) {
+ retry = 0;
+ while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
+ rte_delay_us(burst_tx_delay_time);
+ nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+ &pkts_burst[nb_tx], nb_rx - nb_tx);
+ }
+ }
+ fs->tx_packets += nb_tx;
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+#endif
+ if (unlikely(nb_tx < nb_rx)) {
+ fs->fwd_dropped += (nb_rx - nb_tx);
+ do {
+ rte_pktmbuf_free(pkts_burst[nb_tx]);
+ } while (++nb_tx < nb_rx);
+ }
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ end_tsc = rte_rdtsc();
+ core_cycles = (end_tsc - start_tsc);
+ fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+#endif
+}
+
+struct fwd_engine io_fwd_engine = {
+ .fwd_mode_name = "io",
+ .port_fwd_begin = NULL,
+ .port_fwd_end = NULL,
+ .packet_fwd = pkt_burst_io_forward,
+};
diff --git a/src/spdk/dpdk/app/test-pmd/macfwd.c b/src/spdk/dpdk/app/test-pmd/macfwd.c
new file mode 100644
index 000000000..d2ebb1105
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/macfwd.c
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ip.h>
+#include <rte_string_fns.h>
+#include <rte_flow.h>
+
+#include "testpmd.h"
+
+/*
+ * Forwarding of packets in MAC mode.
+ * Change the source and the destination Ethernet addressed of packets
+ * before forwarding them.
+ */
+static void
+pkt_burst_mac_forward(struct fwd_stream *fs)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_port *txp;
+ struct rte_mbuf *mb;
+ struct rte_ether_hdr *eth_hdr;
+ uint32_t retry;
+ uint16_t nb_rx;
+ uint16_t nb_tx;
+ uint16_t i;
+ uint64_t ol_flags = 0;
+ uint64_t tx_offloads;
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ uint64_t start_tsc;
+ uint64_t end_tsc;
+ uint64_t core_cycles;
+#endif
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ start_tsc = rte_rdtsc();
+#endif
+
+ /*
+ * Receive a burst of packets and forward them.
+ */
+ nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
+ nb_pkt_per_burst);
+ if (unlikely(nb_rx == 0))
+ return;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
+#endif
+ fs->rx_packets += nb_rx;
+ txp = &ports[fs->tx_port];
+ tx_offloads = txp->dev_conf.txmode.offloads;
+ if (tx_offloads & DEV_TX_OFFLOAD_VLAN_INSERT)
+ ol_flags = PKT_TX_VLAN_PKT;
+ if (tx_offloads & DEV_TX_OFFLOAD_QINQ_INSERT)
+ ol_flags |= PKT_TX_QINQ_PKT;
+ if (tx_offloads & DEV_TX_OFFLOAD_MACSEC_INSERT)
+ ol_flags |= PKT_TX_MACSEC;
+ for (i = 0; i < nb_rx; i++) {
+ if (likely(i < nb_rx - 1))
+ rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
+ void *));
+ mb = pkts_burst[i];
+ eth_hdr = rte_pktmbuf_mtod(mb, struct rte_ether_hdr *);
+ rte_ether_addr_copy(&peer_eth_addrs[fs->peer_addr],
+ &eth_hdr->d_addr);
+ rte_ether_addr_copy(&ports[fs->tx_port].eth_addr,
+ &eth_hdr->s_addr);
+ mb->ol_flags &= IND_ATTACHED_MBUF | EXT_ATTACHED_MBUF;
+ mb->ol_flags |= ol_flags;
+ mb->l2_len = sizeof(struct rte_ether_hdr);
+ mb->l3_len = sizeof(struct rte_ipv4_hdr);
+ mb->vlan_tci = txp->tx_vlan_id;
+ mb->vlan_tci_outer = txp->tx_vlan_id_outer;
+ }
+ nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_rx);
+ /*
+ * Retry if necessary
+ */
+ if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) {
+ retry = 0;
+ while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
+ rte_delay_us(burst_tx_delay_time);
+ nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+ &pkts_burst[nb_tx], nb_rx - nb_tx);
+ }
+ }
+
+ fs->tx_packets += nb_tx;
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+#endif
+ if (unlikely(nb_tx < nb_rx)) {
+ fs->fwd_dropped += (nb_rx - nb_tx);
+ do {
+ rte_pktmbuf_free(pkts_burst[nb_tx]);
+ } while (++nb_tx < nb_rx);
+ }
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ end_tsc = rte_rdtsc();
+ core_cycles = (end_tsc - start_tsc);
+ fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+#endif
+}
+
+struct fwd_engine mac_fwd_engine = {
+ .fwd_mode_name = "mac",
+ .port_fwd_begin = NULL,
+ .port_fwd_end = NULL,
+ .packet_fwd = pkt_burst_mac_forward,
+};
diff --git a/src/spdk/dpdk/app/test-pmd/macswap.c b/src/spdk/dpdk/app/test-pmd/macswap.c
new file mode 100644
index 000000000..8428c26d8
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/macswap.c
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2014-2020 Mellanox Technologies, Ltd
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ip.h>
+#include <rte_string_fns.h>
+#include <rte_flow.h>
+
+#include "testpmd.h"
+#if defined(RTE_ARCH_X86)
+#include "macswap_sse.h"
+#elif defined(RTE_MACHINE_CPUFLAG_NEON)
+#include "macswap_neon.h"
+#else
+#include "macswap.h"
+#endif
+
+/*
+ * MAC swap forwarding mode: Swap the source and the destination Ethernet
+ * addresses of packets before forwarding them.
+ */
+static void
+pkt_burst_mac_swap(struct fwd_stream *fs)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_port *txp;
+ uint16_t nb_rx;
+ uint16_t nb_tx;
+ uint32_t retry;
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ uint64_t start_tsc;
+ uint64_t end_tsc;
+ uint64_t core_cycles;
+#endif
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ start_tsc = rte_rdtsc();
+#endif
+
+ /*
+ * Receive a burst of packets and forward them.
+ */
+ nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
+ nb_pkt_per_burst);
+ if (unlikely(nb_rx == 0))
+ return;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
+#endif
+ fs->rx_packets += nb_rx;
+ txp = &ports[fs->tx_port];
+
+ do_macswap(pkts_burst, nb_rx, txp);
+
+ nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_rx);
+ /*
+ * Retry if necessary
+ */
+ if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) {
+ retry = 0;
+ while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
+ rte_delay_us(burst_tx_delay_time);
+ nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+ &pkts_burst[nb_tx], nb_rx - nb_tx);
+ }
+ }
+ fs->tx_packets += nb_tx;
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+#endif
+ if (unlikely(nb_tx < nb_rx)) {
+ fs->fwd_dropped += (nb_rx - nb_tx);
+ do {
+ rte_pktmbuf_free(pkts_burst[nb_tx]);
+ } while (++nb_tx < nb_rx);
+ }
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ end_tsc = rte_rdtsc();
+ core_cycles = (end_tsc - start_tsc);
+ fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+#endif
+}
+
+struct fwd_engine mac_swap_engine = {
+ .fwd_mode_name = "macswap",
+ .port_fwd_begin = NULL,
+ .port_fwd_end = NULL,
+ .packet_fwd = pkt_burst_mac_swap,
+};
diff --git a/src/spdk/dpdk/app/test-pmd/macswap.h b/src/spdk/dpdk/app/test-pmd/macswap.h
new file mode 100644
index 000000000..013844156
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/macswap.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef _MACSWAP_H_
+#define _MACSWAP_H_
+
+#include "macswap_common.h"
+
+static inline void
+do_macswap(struct rte_mbuf *pkts[], uint16_t nb,
+ struct rte_port *txp)
+{
+ struct rte_ether_hdr *eth_hdr;
+ struct rte_mbuf *mb;
+ struct rte_ether_addr addr;
+ uint64_t ol_flags;
+ int i;
+
+ ol_flags = ol_flags_init(txp->dev_conf.txmode.offloads);
+ vlan_qinq_set(pkts, nb, ol_flags,
+ txp->tx_vlan_id, txp->tx_vlan_id_outer);
+
+ for (i = 0; i < nb; i++) {
+ if (likely(i < nb - 1))
+ rte_prefetch0(rte_pktmbuf_mtod(pkts[i+1], void *));
+ mb = pkts[i];
+
+ eth_hdr = rte_pktmbuf_mtod(mb, struct rte_ether_hdr *);
+
+ /* Swap dest and src mac addresses. */
+ rte_ether_addr_copy(&eth_hdr->d_addr, &addr);
+ rte_ether_addr_copy(&eth_hdr->s_addr, &eth_hdr->d_addr);
+ rte_ether_addr_copy(&addr, &eth_hdr->s_addr);
+
+ mbuf_field_set(mb, ol_flags);
+ }
+}
+
+#endif /* _MACSWAP_H_ */
diff --git a/src/spdk/dpdk/app/test-pmd/macswap_common.h b/src/spdk/dpdk/app/test-pmd/macswap_common.h
new file mode 100644
index 000000000..7e9a3590a
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/macswap_common.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef _MACSWAP_COMMON_H_
+#define _MACSWAP_COMMON_H_
+
+static inline uint64_t
+ol_flags_init(uint64_t tx_offload)
+{
+ uint64_t ol_flags = 0;
+
+ ol_flags |= (tx_offload & DEV_TX_OFFLOAD_VLAN_INSERT) ?
+ PKT_TX_VLAN : 0;
+ ol_flags |= (tx_offload & DEV_TX_OFFLOAD_QINQ_INSERT) ?
+ PKT_TX_QINQ : 0;
+ ol_flags |= (tx_offload & DEV_TX_OFFLOAD_MACSEC_INSERT) ?
+ PKT_TX_MACSEC : 0;
+
+ return ol_flags;
+}
+
+static inline void
+vlan_qinq_set(struct rte_mbuf *pkts[], uint16_t nb,
+ uint64_t ol_flags, uint16_t vlan, uint16_t outer_vlan)
+{
+ int i;
+
+ if (ol_flags & PKT_TX_VLAN)
+ for (i = 0; i < nb; i++)
+ pkts[i]->vlan_tci = vlan;
+ if (ol_flags & PKT_TX_QINQ)
+ for (i = 0; i < nb; i++)
+ pkts[i]->vlan_tci_outer = outer_vlan;
+}
+
+static inline void
+mbuf_field_set(struct rte_mbuf *mb, uint64_t ol_flags)
+{
+ mb->ol_flags &= IND_ATTACHED_MBUF | EXT_ATTACHED_MBUF;
+ mb->ol_flags |= ol_flags;
+ mb->l2_len = sizeof(struct rte_ether_hdr);
+ mb->l3_len = sizeof(struct rte_ipv4_hdr);
+}
+
+#endif /* _MACSWAP_COMMON_H_ */
diff --git a/src/spdk/dpdk/app/test-pmd/macswap_neon.h b/src/spdk/dpdk/app/test-pmd/macswap_neon.h
new file mode 100644
index 000000000..df6c260cd
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/macswap_neon.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Arm Limited
+ *
+ * Copyright(c) 2019 Intel Corporation
+ *
+ * Derived do_macswap implementation from app/test-pmd/macswap_sse.h
+ */
+
+#ifndef _MACSWAP_NEON_H_
+#define _MACSWAP_NEON_H_
+
+#include "macswap_common.h"
+#include "rte_vect.h"
+
+static inline void
+do_macswap(struct rte_mbuf *pkts[], uint16_t nb,
+ struct rte_port *txp)
+{
+ struct rte_ether_hdr *eth_hdr[4];
+ struct rte_mbuf *mb[4];
+ uint64_t ol_flags;
+ int i;
+ int r;
+ uint8x16_t v0, v1, v2, v3;
+ /**
+ * Index map be used to shuffle the 16 bytes.
+ * byte 0-5 will be swapped with byte 6-11.
+ * byte 12-15 will keep unchanged.
+ */
+ const uint8x16_t idx_map = {6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5,
+ 12, 13, 14, 15};
+
+ ol_flags = ol_flags_init(txp->dev_conf.txmode.offloads);
+ vlan_qinq_set(pkts, nb, ol_flags,
+ txp->tx_vlan_id, txp->tx_vlan_id_outer);
+
+ i = 0;
+ r = nb;
+
+ while (r >= 4) {
+ if (r >= 8) {
+ rte_prefetch0(rte_pktmbuf_mtod(pkts[i + 4], void *));
+ rte_prefetch0(rte_pktmbuf_mtod(pkts[i + 5], void *));
+ rte_prefetch0(rte_pktmbuf_mtod(pkts[i + 6], void *));
+ rte_prefetch0(rte_pktmbuf_mtod(pkts[i + 7], void *));
+ }
+
+ mb[0] = pkts[i++];
+ eth_hdr[0] = rte_pktmbuf_mtod(mb[0], struct rte_ether_hdr *);
+
+ mb[1] = pkts[i++];
+ eth_hdr[1] = rte_pktmbuf_mtod(mb[1], struct rte_ether_hdr *);
+
+ mb[2] = pkts[i++];
+ eth_hdr[2] = rte_pktmbuf_mtod(mb[2], struct rte_ether_hdr *);
+
+ mb[3] = pkts[i++];
+ eth_hdr[3] = rte_pktmbuf_mtod(mb[3], struct rte_ether_hdr *);
+
+ v0 = vld1q_u8((uint8_t const *)eth_hdr[0]);
+ v1 = vld1q_u8((uint8_t const *)eth_hdr[1]);
+ v2 = vld1q_u8((uint8_t const *)eth_hdr[2]);
+ v3 = vld1q_u8((uint8_t const *)eth_hdr[3]);
+
+ v0 = vqtbl1q_u8(v0, idx_map);
+ v1 = vqtbl1q_u8(v1, idx_map);
+ v2 = vqtbl1q_u8(v2, idx_map);
+ v3 = vqtbl1q_u8(v3, idx_map);
+
+ vst1q_u8((uint8_t *)eth_hdr[0], v0);
+ vst1q_u8((uint8_t *)eth_hdr[1], v1);
+ vst1q_u8((uint8_t *)eth_hdr[2], v2);
+ vst1q_u8((uint8_t *)eth_hdr[3], v3);
+
+ mbuf_field_set(mb[0], ol_flags);
+ mbuf_field_set(mb[1], ol_flags);
+ mbuf_field_set(mb[2], ol_flags);
+ mbuf_field_set(mb[3], ol_flags);
+ r -= 4;
+ }
+
+ for ( ; i < nb; i++) {
+ if (i < nb - 1)
+ rte_prefetch0(rte_pktmbuf_mtod(pkts[i+1], void *));
+ mb[0] = pkts[i];
+ eth_hdr[0] = rte_pktmbuf_mtod(mb[0], struct rte_ether_hdr *);
+
+ /* Swap dest and src mac addresses. */
+ v0 = vld1q_u8((uint8_t const *)eth_hdr[0]);
+ v0 = vqtbl1q_u8(v0, idx_map);
+ vst1q_u8((uint8_t *)eth_hdr[0], v0);
+
+ mbuf_field_set(mb[0], ol_flags);
+ }
+}
+
+#endif /* _MACSWAP_NEON_H_ */
diff --git a/src/spdk/dpdk/app/test-pmd/macswap_sse.h b/src/spdk/dpdk/app/test-pmd/macswap_sse.h
new file mode 100644
index 000000000..223f87a53
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/macswap_sse.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef _MACSWAP_SSE_H_
+#define _MACSWAP_SSE_H_
+
+#include "macswap_common.h"
+
+static inline void
+do_macswap(struct rte_mbuf *pkts[], uint16_t nb,
+ struct rte_port *txp)
+{
+ struct rte_ether_hdr *eth_hdr[4];
+ struct rte_mbuf *mb[4];
+ uint64_t ol_flags;
+ int i;
+ int r;
+ __m128i addr0, addr1, addr2, addr3;
+ /**
+ * shuffle mask be used to shuffle the 16 bytes.
+ * byte 0-5 wills be swapped with byte 6-11.
+ * byte 12-15 will keep unchanged.
+ */
+ __m128i shfl_msk = _mm_set_epi8(15, 14, 13, 12,
+ 5, 4, 3, 2,
+ 1, 0, 11, 10,
+ 9, 8, 7, 6);
+
+ ol_flags = ol_flags_init(txp->dev_conf.txmode.offloads);
+ vlan_qinq_set(pkts, nb, ol_flags,
+ txp->tx_vlan_id, txp->tx_vlan_id_outer);
+
+ i = 0;
+ r = nb;
+
+ while (r >= 4) {
+ if (r >= 8) {
+ rte_prefetch0(rte_pktmbuf_mtod(pkts[i + 4], void *));
+ rte_prefetch0(rte_pktmbuf_mtod(pkts[i + 5], void *));
+ rte_prefetch0(rte_pktmbuf_mtod(pkts[i + 6], void *));
+ rte_prefetch0(rte_pktmbuf_mtod(pkts[i + 7], void *));
+ }
+
+ mb[0] = pkts[i++];
+ eth_hdr[0] = rte_pktmbuf_mtod(mb[0], struct rte_ether_hdr *);
+ addr0 = _mm_loadu_si128((__m128i *)eth_hdr[0]);
+
+ mb[1] = pkts[i++];
+ eth_hdr[1] = rte_pktmbuf_mtod(mb[1], struct rte_ether_hdr *);
+ addr1 = _mm_loadu_si128((__m128i *)eth_hdr[1]);
+
+
+ mb[2] = pkts[i++];
+ eth_hdr[2] = rte_pktmbuf_mtod(mb[2], struct rte_ether_hdr *);
+ addr2 = _mm_loadu_si128((__m128i *)eth_hdr[2]);
+
+ mb[3] = pkts[i++];
+ eth_hdr[3] = rte_pktmbuf_mtod(mb[3], struct rte_ether_hdr *);
+ addr3 = _mm_loadu_si128((__m128i *)eth_hdr[3]);
+
+ addr0 = _mm_shuffle_epi8(addr0, shfl_msk);
+ addr1 = _mm_shuffle_epi8(addr1, shfl_msk);
+ addr2 = _mm_shuffle_epi8(addr2, shfl_msk);
+ addr3 = _mm_shuffle_epi8(addr3, shfl_msk);
+
+ _mm_storeu_si128((__m128i *)eth_hdr[0], addr0);
+ _mm_storeu_si128((__m128i *)eth_hdr[1], addr1);
+ _mm_storeu_si128((__m128i *)eth_hdr[2], addr2);
+ _mm_storeu_si128((__m128i *)eth_hdr[3], addr3);
+
+ mbuf_field_set(mb[0], ol_flags);
+ mbuf_field_set(mb[1], ol_flags);
+ mbuf_field_set(mb[2], ol_flags);
+ mbuf_field_set(mb[3], ol_flags);
+ r -= 4;
+ }
+
+ for ( ; i < nb; i++) {
+ if (i < nb - 1)
+ rte_prefetch0(rte_pktmbuf_mtod(pkts[i+1], void *));
+ mb[0] = pkts[i];
+ eth_hdr[0] = rte_pktmbuf_mtod(mb[0], struct rte_ether_hdr *);
+
+ /* Swap dest and src mac addresses. */
+ addr0 = _mm_loadu_si128((__m128i *)eth_hdr[0]);
+ addr0 = _mm_shuffle_epi8(addr0, shfl_msk);
+ _mm_storeu_si128((__m128i *)eth_hdr[0], addr0);
+
+ mbuf_field_set(mb[0], ol_flags);
+ }
+}
+
+#endif /* _MACSWAP_SSE_H_ */
diff --git a/src/spdk/dpdk/app/test-pmd/meson.build b/src/spdk/dpdk/app/test-pmd/meson.build
new file mode 100644
index 000000000..487288297
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/meson.build
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2017 Intel Corporation
+
+# override default name to drop the hyphen
+name = 'testpmd'
+cflags += '-Wno-deprecated-declarations'
+sources = files('cmdline.c',
+ 'cmdline_flow.c',
+ 'cmdline_mtr.c',
+ 'cmdline_tm.c',
+ 'config.c',
+ 'csumonly.c',
+ 'flowgen.c',
+ 'icmpecho.c',
+ 'ieee1588fwd.c',
+ 'iofwd.c',
+ 'macfwd.c',
+ 'macswap.c',
+ 'noisy_vnf.c',
+ 'parameters.c',
+ 'rxonly.c',
+ 'testpmd.c',
+ 'txonly.c',
+ 'util.c')
+
+deps += ['ethdev', 'gro', 'gso', 'cmdline', 'metrics', 'meter', 'bus_pci']
+if dpdk_conf.has('RTE_LIBRTE_PDUMP')
+ deps += 'pdump'
+endif
+if dpdk_conf.has('RTE_LIBRTE_BNXT_PMD')
+ deps += 'pmd_bnxt'
+endif
+if dpdk_conf.has('RTE_LIBRTE_I40E_PMD')
+ deps += 'pmd_i40e'
+endif
+if dpdk_conf.has('RTE_LIBRTE_IXGBE_PMD')
+ deps += 'pmd_ixgbe'
+endif
+if dpdk_conf.has('RTE_LIBRTE_SOFTNIC_PMD')
+ sources += files('softnicfwd.c')
+ deps += 'pmd_softnic'
+endif
+if dpdk_conf.has('RTE_LIBRTE_DPAA_PMD')
+ deps += ['bus_dpaa', 'mempool_dpaa', 'pmd_dpaa']
+endif
+if dpdk_conf.has('RTE_LIBRTE_BPF')
+ sources += files('bpf_cmd.c')
+ deps += 'bpf'
+endif
diff --git a/src/spdk/dpdk/app/test-pmd/noisy_vnf.c b/src/spdk/dpdk/app/test-pmd/noisy_vnf.c
new file mode 100644
index 000000000..58c4ee925
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/noisy_vnf.c
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Red Hat Corp.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_memory.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_memcpy.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_malloc.h>
+
+#include "testpmd.h"
+
+struct noisy_config {
+ struct rte_ring *f;
+ uint64_t prev_time;
+ char *vnf_mem;
+ bool do_buffering;
+ bool do_flush;
+ bool do_sim;
+};
+
+struct noisy_config *noisy_cfg[RTE_MAX_ETHPORTS];
+
+static inline void
+do_write(char *vnf_mem)
+{
+ uint64_t i = rte_rand();
+ uint64_t w = rte_rand();
+
+ vnf_mem[i % ((noisy_lkup_mem_sz * 1024 * 1024) /
+ RTE_CACHE_LINE_SIZE)] = w;
+}
+
+static inline void
+do_read(char *vnf_mem)
+{
+ uint64_t i = rte_rand();
+ uint64_t r;
+
+ r = vnf_mem[i % ((noisy_lkup_mem_sz * 1024 * 1024) /
+ RTE_CACHE_LINE_SIZE)];
+ r++;
+}
+
+static inline void
+do_readwrite(char *vnf_mem)
+{
+ do_read(vnf_mem);
+ do_write(vnf_mem);
+}
+
+/*
+ * Simulate route lookups as defined by commandline parameters
+ */
+static void
+sim_memory_lookups(struct noisy_config *ncf, uint16_t nb_pkts)
+{
+ uint16_t i, j;
+
+ if (!ncf->do_sim)
+ return;
+
+ for (i = 0; i < nb_pkts; i++) {
+ for (j = 0; j < noisy_lkup_num_writes; j++)
+ do_write(ncf->vnf_mem);
+ for (j = 0; j < noisy_lkup_num_reads; j++)
+ do_read(ncf->vnf_mem);
+ for (j = 0; j < noisy_lkup_num_reads_writes; j++)
+ do_readwrite(ncf->vnf_mem);
+ }
+}
+
+static uint16_t
+do_retry(uint16_t nb_rx, uint16_t nb_tx, struct rte_mbuf **pkts,
+ struct fwd_stream *fs)
+{
+ uint32_t retry = 0;
+
+ while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
+ rte_delay_us(burst_tx_delay_time);
+ nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+ &pkts[nb_tx], nb_rx - nb_tx);
+ }
+
+ return nb_tx;
+}
+
+static uint32_t
+drop_pkts(struct rte_mbuf **pkts, uint16_t nb_rx, uint16_t nb_tx)
+{
+ if (nb_tx < nb_rx) {
+ do {
+ rte_pktmbuf_free(pkts[nb_tx]);
+ } while (++nb_tx < nb_rx);
+ }
+
+ return nb_rx - nb_tx;
+}
+
+/*
+ * Forwarding of packets in noisy VNF mode. Forward packets but perform
+ * memory operations first as specified on cmdline.
+ *
+ * Depending on which commandline parameters are specified we have
+ * different cases to handle:
+ *
+ * 1. No FIFO size was given, so we don't do buffering of incoming
+ * packets. This case is pretty much what iofwd does but in this case
+ * we also do simulation of memory accesses (depending on which
+ * parameters were specified for it).
+ * 2. User wants do buffer packets in a FIFO and sent out overflowing
+ * packets.
+ * 3. User wants a FIFO and specifies a time in ms to flush all packets
+ * out of the FIFO
+ * 4. Cases 2 and 3 combined
+ */
+static void
+pkt_burst_noisy_vnf(struct fwd_stream *fs)
+{
+ const uint64_t freq_khz = rte_get_timer_hz() / 1000;
+ struct noisy_config *ncf = noisy_cfg[fs->rx_port];
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_mbuf *tmp_pkts[MAX_PKT_BURST];
+ uint16_t nb_deqd = 0;
+ uint16_t nb_rx = 0;
+ uint16_t nb_tx = 0;
+ uint16_t nb_enqd;
+ unsigned int fifo_free;
+ uint64_t delta_ms;
+ bool needs_flush = false;
+ uint64_t now;
+
+ nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,
+ pkts_burst, nb_pkt_per_burst);
+ if (unlikely(nb_rx == 0))
+ goto flush;
+ fs->rx_packets += nb_rx;
+
+ if (!ncf->do_buffering) {
+ sim_memory_lookups(ncf, nb_rx);
+ nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+ pkts_burst, nb_rx);
+ if (unlikely(nb_tx < nb_rx) && fs->retry_enabled)
+ nb_tx += do_retry(nb_rx, nb_tx, pkts_burst, fs);
+ fs->tx_packets += nb_tx;
+ fs->fwd_dropped += drop_pkts(pkts_burst, nb_rx, nb_tx);
+ return;
+ }
+
+ fifo_free = rte_ring_free_count(ncf->f);
+ if (fifo_free >= nb_rx) {
+ nb_enqd = rte_ring_enqueue_burst(ncf->f,
+ (void **) pkts_burst, nb_rx, NULL);
+ if (nb_enqd < nb_rx)
+ fs->fwd_dropped += drop_pkts(pkts_burst,
+ nb_rx, nb_enqd);
+ } else {
+ nb_deqd = rte_ring_dequeue_burst(ncf->f,
+ (void **) tmp_pkts, nb_rx, NULL);
+ nb_enqd = rte_ring_enqueue_burst(ncf->f,
+ (void **) pkts_burst, nb_deqd, NULL);
+ if (nb_deqd > 0) {
+ nb_tx = rte_eth_tx_burst(fs->tx_port,
+ fs->tx_queue, tmp_pkts,
+ nb_deqd);
+ if (unlikely(nb_tx < nb_rx) && fs->retry_enabled)
+ nb_tx += do_retry(nb_rx, nb_tx, tmp_pkts, fs);
+ fs->fwd_dropped += drop_pkts(tmp_pkts, nb_deqd, nb_tx);
+ }
+ }
+
+ sim_memory_lookups(ncf, nb_enqd);
+
+flush:
+ if (ncf->do_flush) {
+ if (!ncf->prev_time)
+ now = ncf->prev_time = rte_get_timer_cycles();
+ else
+ now = rte_get_timer_cycles();
+ delta_ms = (now - ncf->prev_time) / freq_khz;
+ needs_flush = delta_ms >= noisy_tx_sw_buf_flush_time &&
+ noisy_tx_sw_buf_flush_time > 0 && !nb_tx;
+ }
+ while (needs_flush && !rte_ring_empty(ncf->f)) {
+ unsigned int sent;
+ nb_deqd = rte_ring_dequeue_burst(ncf->f, (void **)tmp_pkts,
+ MAX_PKT_BURST, NULL);
+ sent = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+ tmp_pkts, nb_deqd);
+ if (unlikely(sent < nb_deqd) && fs->retry_enabled)
+ nb_tx += do_retry(nb_rx, nb_tx, tmp_pkts, fs);
+ fs->fwd_dropped += drop_pkts(tmp_pkts, nb_deqd, sent);
+ ncf->prev_time = rte_get_timer_cycles();
+ }
+}
+
+#define NOISY_STRSIZE 256
+#define NOISY_RING "noisy_ring_%d\n"
+
+static void
+noisy_fwd_end(portid_t pi)
+{
+ rte_ring_free(noisy_cfg[pi]->f);
+ rte_free(noisy_cfg[pi]->vnf_mem);
+ rte_free(noisy_cfg[pi]);
+}
+
+static void
+noisy_fwd_begin(portid_t pi)
+{
+ struct noisy_config *n;
+ char name[NOISY_STRSIZE];
+
+ noisy_cfg[pi] = rte_zmalloc("testpmd noisy fifo and timers",
+ sizeof(struct noisy_config),
+ RTE_CACHE_LINE_SIZE);
+ if (noisy_cfg[pi] == NULL) {
+ rte_exit(EXIT_FAILURE,
+ "rte_zmalloc(%d) struct noisy_config) failed\n",
+ (int) pi);
+ }
+ n = noisy_cfg[pi];
+ n->do_buffering = noisy_tx_sw_bufsz > 0;
+ n->do_sim = noisy_lkup_num_writes + noisy_lkup_num_reads +
+ noisy_lkup_num_reads_writes;
+ n->do_flush = noisy_tx_sw_buf_flush_time > 0;
+
+ if (n->do_buffering) {
+ snprintf(name, NOISY_STRSIZE, NOISY_RING, pi);
+ n->f = rte_ring_create(name, noisy_tx_sw_bufsz,
+ rte_socket_id(), 0);
+ if (!n->f)
+ rte_exit(EXIT_FAILURE,
+ "rte_ring_create(%d), size %d) failed\n",
+ (int) pi,
+ noisy_tx_sw_bufsz);
+ }
+ if (noisy_lkup_mem_sz > 0) {
+ n->vnf_mem = (char *) rte_zmalloc("vnf sim memory",
+ noisy_lkup_mem_sz * 1024 * 1024,
+ RTE_CACHE_LINE_SIZE);
+ if (!n->vnf_mem)
+ rte_exit(EXIT_FAILURE,
+ "rte_zmalloc(%" PRIu64 ") for vnf memory) failed\n",
+ noisy_lkup_mem_sz);
+ } else if (n->do_sim) {
+ rte_exit(EXIT_FAILURE,
+ "--noisy-lkup-memory-size must be > 0\n");
+ }
+}
+
+struct fwd_engine noisy_vnf_engine = {
+ .fwd_mode_name = "noisy",
+ .port_fwd_begin = noisy_fwd_begin,
+ .port_fwd_end = noisy_fwd_end,
+ .packet_fwd = pkt_burst_noisy_vnf,
+};
diff --git a/src/spdk/dpdk/app/test-pmd/parameters.c b/src/spdk/dpdk/app/test-pmd/parameters.c
new file mode 100644
index 000000000..f761e1470
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/parameters.c
@@ -0,0 +1,1413 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2017 Intel Corporation
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <arpa/inet.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_memory.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_mempool.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_string_fns.h>
+#ifdef RTE_LIBRTE_PMD_BOND
+#include <rte_eth_bond.h>
+#endif
+#include <rte_flow.h>
+
+#include "testpmd.h"
+
+static void
+usage(char* progname)
+{
+ printf("usage: %s [EAL options] -- "
+#ifdef RTE_LIBRTE_CMDLINE
+ "[--interactive|-i] "
+ "[--cmdline-file=FILENAME] "
+#endif
+ "[--help|-h] | [--auto-start|-a] | ["
+ "--tx-first | --stats-period=PERIOD | "
+ "--coremask=COREMASK --portmask=PORTMASK --numa "
+ "--portlist=PORTLIST "
+ "--mbuf-size= | --total-num-mbufs= | "
+ "--nb-cores= | --nb-ports= | "
+#ifdef RTE_LIBRTE_CMDLINE
+ "--eth-peers-configfile= | "
+ "--eth-peer=X,M:M:M:M:M:M | "
+ "--tx-ip=SRC,DST | --tx-udp=PORT | "
+#endif
+ "--pkt-filter-mode= |"
+ "--rss-ip | --rss-udp | "
+ "--rxpt= | --rxht= | --rxwt= | --rxfreet= | "
+ "--txpt= | --txht= | --txwt= | --txfreet= | "
+ "--txrst= | --tx-offloads= | | --rx-offloads= | "
+ "--vxlan-gpe-port= ]\n",
+ progname);
+#ifdef RTE_LIBRTE_CMDLINE
+ printf(" --interactive: run in interactive mode.\n");
+ printf(" --cmdline-file: execute cli commands before startup.\n");
+#endif
+ printf(" --auto-start: start forwarding on init "
+ "[always when non-interactive].\n");
+ printf(" --help: display this message and quit.\n");
+ printf(" --tx-first: start forwarding sending a burst first "
+ "(only if interactive is disabled).\n");
+ printf(" --stats-period=PERIOD: statistics will be shown "
+ "every PERIOD seconds (only if interactive is disabled).\n");
+ printf(" --nb-cores=N: set the number of forwarding cores "
+ "(1 <= N <= %d).\n", nb_lcores);
+ printf(" --nb-ports=N: set the number of forwarding ports "
+ "(1 <= N <= %d).\n", nb_ports);
+ printf(" --coremask=COREMASK: hexadecimal bitmask of cores running "
+ "the packet forwarding test. The master lcore is reserved for "
+ "command line parsing only, and cannot be masked on for "
+ "packet forwarding.\n");
+ printf(" --portmask=PORTMASK: hexadecimal bitmask of ports used "
+ "by the packet forwarding test.\n");
+ printf(" --portlist=PORTLIST: list of forwarding ports\n");
+ printf(" --numa: enable NUMA-aware allocation of RX/TX rings and of "
+ "RX memory buffers (mbufs).\n");
+ printf(" --port-numa-config=(port,socket)[,(port,socket)]: "
+ "specify the socket on which the memory pool "
+ "used by the port will be allocated.\n");
+ printf(" --ring-numa-config=(port,flag,socket)[,(port,flag,socket)]: "
+ "specify the socket on which the TX/RX rings for "
+ "the port will be allocated "
+ "(flag: 1 for RX; 2 for TX; 3 for RX and TX).\n");
+ printf(" --socket-num=N: set socket from which all memory is allocated "
+ "in NUMA mode.\n");
+ printf(" --mbuf-size=N: set the data size of mbuf to N bytes.\n");
+ printf(" --total-num-mbufs=N: set the number of mbufs to be allocated "
+ "in mbuf pools.\n");
+ printf(" --max-pkt-len=N: set the maximum size of packet to N bytes.\n");
+ printf(" --max-lro-pkt-size=N: set the maximum LRO aggregated packet "
+ "size to N bytes.\n");
+#ifdef RTE_LIBRTE_CMDLINE
+ printf(" --eth-peers-configfile=name: config file with ethernet addresses "
+ "of peer ports.\n");
+ printf(" --eth-peer=X,M:M:M:M:M:M: set the MAC address of the X peer "
+ "port (0 <= X < %d).\n", RTE_MAX_ETHPORTS);
+#endif
+ printf(" --pkt-filter-mode=N: set Flow Director mode "
+ "(N: none (default mode) or signature or perfect).\n");
+ printf(" --pkt-filter-report-hash=N: set Flow Director report mode "
+ "(N: none or match (default) or always).\n");
+ printf(" --pkt-filter-size=N: set Flow Director mode "
+ "(N: 64K (default mode) or 128K or 256K).\n");
+ printf(" --pkt-filter-drop-queue=N: set drop-queue. "
+ "In perfect mode, when you add a rule with queue = -1 "
+ "the packet will be enqueued into the rx drop-queue. "
+ "If the drop-queue doesn't exist, the packet is dropped. "
+ "By default drop-queue=127.\n");
+#ifdef RTE_LIBRTE_LATENCY_STATS
+ printf(" --latencystats=N: enable latency and jitter statistcs "
+ "monitoring on forwarding lcore id N.\n");
+#endif
+ printf(" --disable-crc-strip: disable CRC stripping by hardware.\n");
+ printf(" --enable-lro: enable large receive offload.\n");
+ printf(" --enable-rx-cksum: enable rx hardware checksum offload.\n");
+ printf(" --enable-rx-timestamp: enable rx hardware timestamp offload.\n");
+ printf(" --enable-hw-vlan: enable hardware vlan.\n");
+ printf(" --enable-hw-vlan-filter: enable hardware vlan filter.\n");
+ printf(" --enable-hw-vlan-strip: enable hardware vlan strip.\n");
+ printf(" --enable-hw-vlan-extend: enable hardware vlan extend.\n");
+ printf(" --enable-hw-qinq-strip: enable hardware qinq strip.\n");
+ printf(" --enable-drop-en: enable per queue packet drop.\n");
+ printf(" --disable-rss: disable rss.\n");
+ printf(" --port-topology=<paired|chained|loop>: set port topology (paired "
+ "is default).\n");
+ printf(" --forward-mode=N: set forwarding mode (N: %s).\n",
+ list_pkt_forwarding_modes());
+ printf(" --rss-ip: set RSS functions to IPv4/IPv6 only .\n");
+ printf(" --rss-udp: set RSS functions to IPv4/IPv6 + UDP.\n");
+ printf(" --rxq=N: set the number of RX queues per port to N.\n");
+ printf(" --rxd=N: set the number of descriptors in RX rings to N.\n");
+ printf(" --txq=N: set the number of TX queues per port to N.\n");
+ printf(" --txd=N: set the number of descriptors in TX rings to N.\n");
+ printf(" --hairpinq=N: set the number of hairpin queues per port to "
+ "N.\n");
+ printf(" --burst=N: set the number of packets per burst to N.\n");
+ printf(" --mbcache=N: set the cache of mbuf memory pool to N.\n");
+ printf(" --rxpt=N: set prefetch threshold register of RX rings to N.\n");
+ printf(" --rxht=N: set the host threshold register of RX rings to N.\n");
+ printf(" --rxfreet=N: set the free threshold of RX descriptors to N "
+ "(0 <= N < value of rxd).\n");
+ printf(" --rxwt=N: set the write-back threshold register of RX rings to N.\n");
+ printf(" --txpt=N: set the prefetch threshold register of TX rings to N.\n");
+ printf(" --txht=N: set the nhost threshold register of TX rings to N.\n");
+ printf(" --txwt=N: set the write-back threshold register of TX rings to N.\n");
+ printf(" --txfreet=N: set the transmit free threshold of TX rings to N "
+ "(0 <= N <= value of txd).\n");
+ printf(" --txrst=N: set the transmit RS bit threshold of TX rings to N "
+ "(0 <= N <= value of txd).\n");
+ printf(" --tx-queue-stats-mapping=(port,queue,mapping)[,(port,queue,mapping]: "
+ "tx queues statistics counters mapping "
+ "(0 <= mapping <= %d).\n", RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
+ printf(" --rx-queue-stats-mapping=(port,queue,mapping)[,(port,queue,mapping]: "
+ "rx queues statistics counters mapping "
+ "(0 <= mapping <= %d).\n", RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
+ printf(" --no-flush-rx: Don't flush RX streams before forwarding."
+ " Used mainly with PCAP drivers.\n");
+ printf(" --txpkts=X[,Y]*: set TX segment sizes"
+ " or total packet length.\n");
+ printf(" --txonly-multi-flow: generate multiple flows in txonly mode\n");
+ printf(" --disable-link-check: disable check on link status when "
+ "starting/stopping ports.\n");
+ printf(" --disable-device-start: do not automatically start port\n");
+ printf(" --no-lsc-interrupt: disable link status change interrupt.\n");
+ printf(" --no-rmv-interrupt: disable device removal interrupt.\n");
+ printf(" --bitrate-stats=N: set the logical core N to perform "
+ "bit-rate calculation.\n");
+ printf(" --print-event <unknown|intr_lsc|queue_state|intr_reset|vf_mbox|macsec|intr_rmv|flow_aged|all>: "
+ "enable print of designated event or all of them.\n");
+ printf(" --mask-event <unknown|intr_lsc|queue_state|intr_reset|vf_mbox|macsec|intr_rmv|flow_aged|all>: "
+ "disable print of designated event or all of them.\n");
+ printf(" --flow-isolate-all: "
+ "requests flow API isolated mode on all ports at initialization time.\n");
+ printf(" --tx-offloads=0xXXXXXXXX: hexadecimal bitmask of TX queue offloads\n");
+ printf(" --rx-offloads=0xXXXXXXXX: hexadecimal bitmask of RX queue offloads\n");
+ printf(" --hot-plug: enable hot plug for device.\n");
+ printf(" --vxlan-gpe-port=N: UPD port of tunnel VXLAN-GPE\n");
+ printf(" --mlockall: lock all memory\n");
+ printf(" --no-mlockall: do not lock all memory\n");
+ printf(" --mp-alloc <native|anon|xmem|xmemhuge>: mempool allocation method.\n"
+ " native: use regular DPDK memory to create and populate mempool\n"
+ " anon: use regular DPDK memory to create and anonymous memory to populate mempool\n"
+ " xmem: use anonymous memory to create and populate mempool\n"
+ " xmemhuge: use anonymous hugepage memory to create and populate mempool\n");
+ printf(" --noisy-tx-sw-buffer-size=N: size of FIFO buffer\n");
+ printf(" --noisy-tx-sw-buffer-flushtime=N: flush FIFO after N ms\n");
+ printf(" --noisy-lkup-memory=N: allocate N MB of VNF memory\n");
+ printf(" --noisy-lkup-num-writes=N: do N random writes per packet\n");
+ printf(" --noisy-lkup-num-reads=N: do N random reads per packet\n");
+ printf(" --noisy-lkup-num-writes=N: do N random reads and writes per packet\n");
+ printf(" --no-iova-contig: mempool memory can be IOVA non contiguous. "
+ "valid only with --mp-alloc=anon\n");
+ printf(" --rx-mq-mode=0xX: hexadecimal bitmask of RX mq mode can be "
+ "enabled\n");
+}
+
+#ifdef RTE_LIBRTE_CMDLINE
+static int
+init_peer_eth_addrs(char *config_filename)
+{
+ FILE *config_file;
+ portid_t i;
+ char buf[50];
+
+ config_file = fopen(config_filename, "r");
+ if (config_file == NULL) {
+ perror("Failed to open eth config file\n");
+ return -1;
+ }
+
+ for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+
+ if (fgets(buf, sizeof(buf), config_file) == NULL)
+ break;
+
+ if (rte_ether_unformat_addr(buf, &peer_eth_addrs[i]) < 0) {
+ printf("Bad MAC address format on line %d\n", i+1);
+ fclose(config_file);
+ return -1;
+ }
+ }
+ fclose(config_file);
+ nb_peer_eth_addrs = (portid_t) i;
+ return 0;
+}
+#endif
+
+/*
+ * Parse the coremask given as argument (hexadecimal string) and set
+ * the global configuration of forwarding cores.
+ */
+static void
+parse_fwd_coremask(const char *coremask)
+{
+ char *end;
+ unsigned long long int cm;
+
+ /* parse hexadecimal string */
+ end = NULL;
+ cm = strtoull(coremask, &end, 16);
+ if ((coremask[0] == '\0') || (end == NULL) || (*end != '\0'))
+ rte_exit(EXIT_FAILURE, "Invalid fwd core mask\n");
+ else if (set_fwd_lcores_mask((uint64_t) cm) < 0)
+ rte_exit(EXIT_FAILURE, "coremask is not valid\n");
+}
+
+/*
+ * Parse the coremask given as argument (hexadecimal string) and set
+ * the global configuration of forwarding cores.
+ */
+static void
+parse_fwd_portmask(const char *portmask)
+{
+ char *end;
+ unsigned long long int pm;
+
+ /* parse hexadecimal string */
+ end = NULL;
+ pm = strtoull(portmask, &end, 16);
+ if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+ rte_exit(EXIT_FAILURE, "Invalid fwd port mask\n");
+ else
+ set_fwd_ports_mask((uint64_t) pm);
+}
+
+
+static int
+parse_queue_stats_mapping_config(const char *q_arg, int is_rx)
+{
+ char s[256];
+ const char *p, *p0 = q_arg;
+ char *end;
+ enum fieldnames {
+ FLD_PORT = 0,
+ FLD_QUEUE,
+ FLD_STATS_COUNTER,
+ _NUM_FLD
+ };
+ unsigned long int_fld[_NUM_FLD];
+ char *str_fld[_NUM_FLD];
+ int i;
+ unsigned size;
+
+ /* reset from value set at definition */
+ is_rx ? (nb_rx_queue_stats_mappings = 0) : (nb_tx_queue_stats_mappings = 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;
+ }
+ /* Check mapping field is in correct range (0..RTE_ETHDEV_QUEUE_STAT_CNTRS-1) */
+ if (int_fld[FLD_STATS_COUNTER] >= RTE_ETHDEV_QUEUE_STAT_CNTRS) {
+ printf("Stats counter not in the correct range 0..%d\n",
+ RTE_ETHDEV_QUEUE_STAT_CNTRS - 1);
+ return -1;
+ }
+
+ if (!is_rx) {
+ if ((nb_tx_queue_stats_mappings >=
+ MAX_TX_QUEUE_STATS_MAPPINGS)) {
+ printf("exceeded max number of TX queue "
+ "statistics mappings: %hu\n",
+ nb_tx_queue_stats_mappings);
+ return -1;
+ }
+ tx_queue_stats_mappings_array[nb_tx_queue_stats_mappings].port_id =
+ (uint8_t)int_fld[FLD_PORT];
+ tx_queue_stats_mappings_array[nb_tx_queue_stats_mappings].queue_id =
+ (uint8_t)int_fld[FLD_QUEUE];
+ tx_queue_stats_mappings_array[nb_tx_queue_stats_mappings].stats_counter_id =
+ (uint8_t)int_fld[FLD_STATS_COUNTER];
+ ++nb_tx_queue_stats_mappings;
+ }
+ else {
+ if ((nb_rx_queue_stats_mappings >=
+ MAX_RX_QUEUE_STATS_MAPPINGS)) {
+ printf("exceeded max number of RX queue "
+ "statistics mappings: %hu\n",
+ nb_rx_queue_stats_mappings);
+ return -1;
+ }
+ rx_queue_stats_mappings_array[nb_rx_queue_stats_mappings].port_id =
+ (uint8_t)int_fld[FLD_PORT];
+ rx_queue_stats_mappings_array[nb_rx_queue_stats_mappings].queue_id =
+ (uint8_t)int_fld[FLD_QUEUE];
+ rx_queue_stats_mappings_array[nb_rx_queue_stats_mappings].stats_counter_id =
+ (uint8_t)int_fld[FLD_STATS_COUNTER];
+ ++nb_rx_queue_stats_mappings;
+ }
+
+ }
+/* Reassign the rx/tx_queue_stats_mappings pointer to point to this newly populated array rather */
+/* than to the default array (that was set at its definition) */
+ is_rx ? (rx_queue_stats_mappings = rx_queue_stats_mappings_array) :
+ (tx_queue_stats_mappings = tx_queue_stats_mappings_array);
+ return 0;
+}
+
+static void
+print_invalid_socket_id_error(void)
+{
+ unsigned int i = 0;
+
+ printf("Invalid socket id, options are: ");
+ for (i = 0; i < num_sockets; i++) {
+ printf("%u%s", socket_ids[i],
+ (i == num_sockets - 1) ? "\n" : ",");
+ }
+}
+
+static int
+parse_portnuma_config(const char *q_arg)
+{
+ char s[256];
+ const char *p, *p0 = q_arg;
+ char *end;
+ uint8_t i, socket_id;
+ portid_t port_id;
+ unsigned size;
+ enum fieldnames {
+ FLD_PORT = 0,
+ FLD_SOCKET,
+ _NUM_FLD
+ };
+ unsigned long int_fld[_NUM_FLD];
+ char *str_fld[_NUM_FLD];
+
+ /* reset from value set at definition */
+ 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;
+ }
+ port_id = (portid_t)int_fld[FLD_PORT];
+ if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL) {
+ print_valid_ports();
+ return -1;
+ }
+ socket_id = (uint8_t)int_fld[FLD_SOCKET];
+ if (new_socket_id(socket_id)) {
+ if (num_sockets >= RTE_MAX_NUMA_NODES) {
+ print_invalid_socket_id_error();
+ return -1;
+ }
+ socket_ids[num_sockets++] = socket_id;
+ }
+ port_numa[port_id] = socket_id;
+ }
+
+ return 0;
+}
+
+static int
+parse_ringnuma_config(const char *q_arg)
+{
+ char s[256];
+ const char *p, *p0 = q_arg;
+ char *end;
+ uint8_t i, ring_flag, socket_id;
+ portid_t port_id;
+ unsigned size;
+ enum fieldnames {
+ FLD_PORT = 0,
+ FLD_FLAG,
+ FLD_SOCKET,
+ _NUM_FLD
+ };
+ unsigned long int_fld[_NUM_FLD];
+ char *str_fld[_NUM_FLD];
+ #define RX_RING_ONLY 0x1
+ #define TX_RING_ONLY 0x2
+ #define RXTX_RING 0x3
+
+ /* reset from value set at definition */
+ 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;
+ }
+ port_id = (portid_t)int_fld[FLD_PORT];
+ if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL) {
+ print_valid_ports();
+ return -1;
+ }
+ socket_id = (uint8_t)int_fld[FLD_SOCKET];
+ if (new_socket_id(socket_id)) {
+ if (num_sockets >= RTE_MAX_NUMA_NODES) {
+ print_invalid_socket_id_error();
+ return -1;
+ }
+ socket_ids[num_sockets++] = socket_id;
+ }
+ ring_flag = (uint8_t)int_fld[FLD_FLAG];
+ if ((ring_flag < RX_RING_ONLY) || (ring_flag > RXTX_RING)) {
+ printf("Invalid ring-flag=%d config for port =%d\n",
+ ring_flag,port_id);
+ return -1;
+ }
+
+ switch (ring_flag & RXTX_RING) {
+ case RX_RING_ONLY:
+ rxring_numa[port_id] = socket_id;
+ break;
+ case TX_RING_ONLY:
+ txring_numa[port_id] = socket_id;
+ break;
+ case RXTX_RING:
+ rxring_numa[port_id] = socket_id;
+ txring_numa[port_id] = socket_id;
+ break;
+ default:
+ printf("Invalid ring-flag=%d config for port=%d\n",
+ ring_flag,port_id);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int
+parse_event_printing_config(const char *optarg, int enable)
+{
+ uint32_t mask = 0;
+
+ if (!strcmp(optarg, "unknown"))
+ mask = UINT32_C(1) << RTE_ETH_EVENT_UNKNOWN;
+ else if (!strcmp(optarg, "intr_lsc"))
+ mask = UINT32_C(1) << RTE_ETH_EVENT_INTR_LSC;
+ else if (!strcmp(optarg, "queue_state"))
+ mask = UINT32_C(1) << RTE_ETH_EVENT_QUEUE_STATE;
+ else if (!strcmp(optarg, "intr_reset"))
+ mask = UINT32_C(1) << RTE_ETH_EVENT_INTR_RESET;
+ else if (!strcmp(optarg, "vf_mbox"))
+ mask = UINT32_C(1) << RTE_ETH_EVENT_VF_MBOX;
+ else if (!strcmp(optarg, "ipsec"))
+ mask = UINT32_C(1) << RTE_ETH_EVENT_IPSEC;
+ else if (!strcmp(optarg, "macsec"))
+ mask = UINT32_C(1) << RTE_ETH_EVENT_MACSEC;
+ else if (!strcmp(optarg, "intr_rmv"))
+ mask = UINT32_C(1) << RTE_ETH_EVENT_INTR_RMV;
+ else if (!strcmp(optarg, "dev_probed"))
+ mask = UINT32_C(1) << RTE_ETH_EVENT_NEW;
+ else if (!strcmp(optarg, "dev_released"))
+ mask = UINT32_C(1) << RTE_ETH_EVENT_DESTROY;
+ else if (!strcmp(optarg, "flow_aged"))
+ mask = UINT32_C(1) << RTE_ETH_EVENT_FLOW_AGED;
+ else if (!strcmp(optarg, "all"))
+ mask = ~UINT32_C(0);
+ else {
+ fprintf(stderr, "Invalid event: %s\n", optarg);
+ return -1;
+ }
+ if (enable)
+ event_print_mask |= mask;
+ else
+ event_print_mask &= ~mask;
+ return 0;
+}
+
+void
+launch_args_parse(int argc, char** argv)
+{
+ int n, opt;
+ char **argvopt;
+ int opt_idx;
+ portid_t pid;
+ enum { TX, RX };
+ /* Default offloads for all ports. */
+ uint64_t rx_offloads = rx_mode.offloads;
+ uint64_t tx_offloads = tx_mode.offloads;
+ struct rte_eth_dev_info dev_info;
+ uint16_t rec_nb_pkts;
+ int ret;
+
+ static struct option lgopts[] = {
+ { "help", 0, 0, 0 },
+#ifdef RTE_LIBRTE_CMDLINE
+ { "interactive", 0, 0, 0 },
+ { "cmdline-file", 1, 0, 0 },
+ { "auto-start", 0, 0, 0 },
+ { "eth-peers-configfile", 1, 0, 0 },
+ { "eth-peer", 1, 0, 0 },
+#endif
+ { "tx-first", 0, 0, 0 },
+ { "stats-period", 1, 0, 0 },
+ { "ports", 1, 0, 0 },
+ { "nb-cores", 1, 0, 0 },
+ { "nb-ports", 1, 0, 0 },
+ { "coremask", 1, 0, 0 },
+ { "portmask", 1, 0, 0 },
+ { "portlist", 1, 0, 0 },
+ { "numa", 0, 0, 0 },
+ { "no-numa", 0, 0, 0 },
+ { "mp-anon", 0, 0, 0 },
+ { "port-numa-config", 1, 0, 0 },
+ { "ring-numa-config", 1, 0, 0 },
+ { "socket-num", 1, 0, 0 },
+ { "mbuf-size", 1, 0, 0 },
+ { "total-num-mbufs", 1, 0, 0 },
+ { "max-pkt-len", 1, 0, 0 },
+ { "max-lro-pkt-size", 1, 0, 0 },
+ { "pkt-filter-mode", 1, 0, 0 },
+ { "pkt-filter-report-hash", 1, 0, 0 },
+ { "pkt-filter-size", 1, 0, 0 },
+ { "pkt-filter-drop-queue", 1, 0, 0 },
+#ifdef RTE_LIBRTE_LATENCY_STATS
+ { "latencystats", 1, 0, 0 },
+#endif
+#ifdef RTE_LIBRTE_BITRATE
+ { "bitrate-stats", 1, 0, 0 },
+#endif
+ { "disable-crc-strip", 0, 0, 0 },
+ { "enable-lro", 0, 0, 0 },
+ { "enable-rx-cksum", 0, 0, 0 },
+ { "enable-rx-timestamp", 0, 0, 0 },
+ { "enable-scatter", 0, 0, 0 },
+ { "enable-hw-vlan", 0, 0, 0 },
+ { "enable-hw-vlan-filter", 0, 0, 0 },
+ { "enable-hw-vlan-strip", 0, 0, 0 },
+ { "enable-hw-vlan-extend", 0, 0, 0 },
+ { "enable-hw-qinq-strip", 0, 0, 0 },
+ { "enable-drop-en", 0, 0, 0 },
+ { "disable-rss", 0, 0, 0 },
+ { "port-topology", 1, 0, 0 },
+ { "forward-mode", 1, 0, 0 },
+ { "rss-ip", 0, 0, 0 },
+ { "rss-udp", 0, 0, 0 },
+ { "rxq", 1, 0, 0 },
+ { "txq", 1, 0, 0 },
+ { "rxd", 1, 0, 0 },
+ { "txd", 1, 0, 0 },
+ { "hairpinq", 1, 0, 0 },
+ { "burst", 1, 0, 0 },
+ { "mbcache", 1, 0, 0 },
+ { "txpt", 1, 0, 0 },
+ { "txht", 1, 0, 0 },
+ { "txwt", 1, 0, 0 },
+ { "txfreet", 1, 0, 0 },
+ { "txrst", 1, 0, 0 },
+ { "rxpt", 1, 0, 0 },
+ { "rxht", 1, 0, 0 },
+ { "rxwt", 1, 0, 0 },
+ { "rxfreet", 1, 0, 0 },
+ { "tx-queue-stats-mapping", 1, 0, 0 },
+ { "rx-queue-stats-mapping", 1, 0, 0 },
+ { "no-flush-rx", 0, 0, 0 },
+ { "flow-isolate-all", 0, 0, 0 },
+ { "txpkts", 1, 0, 0 },
+ { "txonly-multi-flow", 0, 0, 0 },
+ { "disable-link-check", 0, 0, 0 },
+ { "disable-device-start", 0, 0, 0 },
+ { "no-lsc-interrupt", 0, 0, 0 },
+ { "no-rmv-interrupt", 0, 0, 0 },
+ { "print-event", 1, 0, 0 },
+ { "mask-event", 1, 0, 0 },
+ { "tx-offloads", 1, 0, 0 },
+ { "rx-offloads", 1, 0, 0 },
+ { "hot-plug", 0, 0, 0 },
+ { "vxlan-gpe-port", 1, 0, 0 },
+ { "mlockall", 0, 0, 0 },
+ { "no-mlockall", 0, 0, 0 },
+ { "mp-alloc", 1, 0, 0 },
+ { "tx-ip", 1, 0, 0 },
+ { "tx-udp", 1, 0, 0 },
+ { "noisy-tx-sw-buffer-size", 1, 0, 0 },
+ { "noisy-tx-sw-buffer-flushtime", 1, 0, 0 },
+ { "noisy-lkup-memory", 1, 0, 0 },
+ { "noisy-lkup-num-writes", 1, 0, 0 },
+ { "noisy-lkup-num-reads", 1, 0, 0 },
+ { "noisy-lkup-num-reads-writes", 1, 0, 0 },
+ { "no-iova-contig", 0, 0, 0 },
+ { "rx-mq-mode", 1, 0, 0 },
+ { 0, 0, 0, 0 },
+ };
+
+ argvopt = argv;
+
+#ifdef RTE_LIBRTE_CMDLINE
+#define SHORTOPTS "i"
+#else
+#define SHORTOPTS ""
+#endif
+ while ((opt = getopt_long(argc, argvopt, SHORTOPTS "ah",
+ lgopts, &opt_idx)) != EOF) {
+ switch (opt) {
+#ifdef RTE_LIBRTE_CMDLINE
+ case 'i':
+ printf("Interactive-mode selected\n");
+ interactive = 1;
+ break;
+#endif
+ case 'a':
+ printf("Auto-start selected\n");
+ auto_start = 1;
+ break;
+
+ case 0: /*long options */
+ if (!strcmp(lgopts[opt_idx].name, "help")) {
+ usage(argv[0]);
+ rte_exit(EXIT_SUCCESS, "Displayed help\n");
+ }
+#ifdef RTE_LIBRTE_CMDLINE
+ if (!strcmp(lgopts[opt_idx].name, "interactive")) {
+ printf("Interactive-mode selected\n");
+ interactive = 1;
+ }
+ if (!strcmp(lgopts[opt_idx].name, "cmdline-file")) {
+ printf("CLI commands to be read from %s\n",
+ optarg);
+ strlcpy(cmdline_filename, optarg,
+ sizeof(cmdline_filename));
+ }
+ if (!strcmp(lgopts[opt_idx].name, "auto-start")) {
+ printf("Auto-start selected\n");
+ auto_start = 1;
+ }
+ if (!strcmp(lgopts[opt_idx].name, "tx-first")) {
+ printf("Ports to start sending a burst of "
+ "packets first\n");
+ tx_first = 1;
+ }
+ if (!strcmp(lgopts[opt_idx].name, "stats-period")) {
+ char *end = NULL;
+ unsigned int n;
+
+ n = strtoul(optarg, &end, 10);
+ if ((optarg[0] == '\0') || (end == NULL) ||
+ (*end != '\0'))
+ break;
+
+ stats_period = n;
+ break;
+ }
+ if (!strcmp(lgopts[opt_idx].name,
+ "eth-peers-configfile")) {
+ if (init_peer_eth_addrs(optarg) != 0)
+ rte_exit(EXIT_FAILURE,
+ "Cannot open logfile\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "eth-peer")) {
+ char *port_end;
+
+ errno = 0;
+ n = strtoul(optarg, &port_end, 10);
+ if (errno != 0 || port_end == optarg || *port_end++ != ',')
+ rte_exit(EXIT_FAILURE,
+ "Invalid eth-peer: %s", optarg);
+ if (n >= RTE_MAX_ETHPORTS)
+ rte_exit(EXIT_FAILURE,
+ "eth-peer: port %d >= RTE_MAX_ETHPORTS(%d)\n",
+ n, RTE_MAX_ETHPORTS);
+
+ if (rte_ether_unformat_addr(port_end,
+ &peer_eth_addrs[n]) < 0)
+ rte_exit(EXIT_FAILURE,
+ "Invalid ethernet address: %s\n",
+ port_end);
+ nb_peer_eth_addrs++;
+ }
+#endif
+ if (!strcmp(lgopts[opt_idx].name, "tx-ip")) {
+ struct in_addr in;
+ char *end;
+
+ end = strchr(optarg, ',');
+ if (end == optarg || !end)
+ rte_exit(EXIT_FAILURE,
+ "Invalid tx-ip: %s", optarg);
+
+ *end++ = 0;
+ if (inet_aton(optarg, &in) == 0)
+ rte_exit(EXIT_FAILURE,
+ "Invalid source IP address: %s\n",
+ optarg);
+ tx_ip_src_addr = rte_be_to_cpu_32(in.s_addr);
+
+ if (inet_aton(end, &in) == 0)
+ rte_exit(EXIT_FAILURE,
+ "Invalid destination IP address: %s\n",
+ optarg);
+ tx_ip_dst_addr = rte_be_to_cpu_32(in.s_addr);
+ }
+ if (!strcmp(lgopts[opt_idx].name, "tx-udp")) {
+ char *end = NULL;
+
+ errno = 0;
+ n = strtoul(optarg, &end, 10);
+ if (errno != 0 || end == optarg ||
+ n > UINT16_MAX ||
+ !(*end == '\0' || *end == ','))
+ rte_exit(EXIT_FAILURE,
+ "Invalid UDP port: %s\n",
+ optarg);
+ tx_udp_src_port = n;
+ if (*end == ',') {
+ char *dst = end + 1;
+
+ n = strtoul(dst, &end, 10);
+ if (errno != 0 || end == dst ||
+ n > UINT16_MAX || *end)
+ rte_exit(EXIT_FAILURE,
+ "Invalid destination UDP port: %s\n",
+ dst);
+ tx_udp_dst_port = n;
+ } else {
+ tx_udp_dst_port = n;
+ }
+
+ }
+ if (!strcmp(lgopts[opt_idx].name, "nb-ports")) {
+ n = atoi(optarg);
+ if (n > 0 && n <= nb_ports)
+ nb_fwd_ports = n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "Invalid port %d\n", n);
+ }
+ if (!strcmp(lgopts[opt_idx].name, "nb-cores")) {
+ n = atoi(optarg);
+ if (n > 0 && n <= nb_lcores)
+ nb_fwd_lcores = (uint8_t) n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "nb-cores should be > 0 and <= %d\n",
+ nb_lcores);
+ }
+ if (!strcmp(lgopts[opt_idx].name, "coremask"))
+ parse_fwd_coremask(optarg);
+ if (!strcmp(lgopts[opt_idx].name, "portmask"))
+ parse_fwd_portmask(optarg);
+ if (!strcmp(lgopts[opt_idx].name, "portlist"))
+ parse_fwd_portlist(optarg);
+ if (!strcmp(lgopts[opt_idx].name, "no-numa"))
+ numa_support = 0;
+ if (!strcmp(lgopts[opt_idx].name, "numa"))
+ numa_support = 1;
+ if (!strcmp(lgopts[opt_idx].name, "mp-anon")) {
+ mp_alloc_type = MP_ALLOC_ANON;
+ }
+ if (!strcmp(lgopts[opt_idx].name, "mp-alloc")) {
+ if (!strcmp(optarg, "native"))
+ mp_alloc_type = MP_ALLOC_NATIVE;
+ else if (!strcmp(optarg, "anon"))
+ mp_alloc_type = MP_ALLOC_ANON;
+ else if (!strcmp(optarg, "xmem"))
+ mp_alloc_type = MP_ALLOC_XMEM;
+ else if (!strcmp(optarg, "xmemhuge"))
+ mp_alloc_type = MP_ALLOC_XMEM_HUGE;
+ else if (!strcmp(optarg, "xbuf"))
+ mp_alloc_type = MP_ALLOC_XBUF;
+ else
+ rte_exit(EXIT_FAILURE,
+ "mp-alloc %s invalid - must be: "
+ "native, anon, xmem or xmemhuge\n",
+ optarg);
+ }
+ if (!strcmp(lgopts[opt_idx].name, "port-numa-config")) {
+ if (parse_portnuma_config(optarg))
+ rte_exit(EXIT_FAILURE,
+ "invalid port-numa configuration\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "ring-numa-config"))
+ if (parse_ringnuma_config(optarg))
+ rte_exit(EXIT_FAILURE,
+ "invalid ring-numa configuration\n");
+ if (!strcmp(lgopts[opt_idx].name, "socket-num")) {
+ n = atoi(optarg);
+ if (!new_socket_id((uint8_t)n)) {
+ socket_num = (uint8_t)n;
+ } else {
+ print_invalid_socket_id_error();
+ rte_exit(EXIT_FAILURE,
+ "Invalid socket id");
+ }
+ }
+ if (!strcmp(lgopts[opt_idx].name, "mbuf-size")) {
+ n = atoi(optarg);
+ if (n > 0 && n <= 0xFFFF)
+ mbuf_data_size = (uint16_t) n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "mbuf-size should be > 0 and < 65536\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "total-num-mbufs")) {
+ n = atoi(optarg);
+ if (n > 1024)
+ param_total_num_mbufs = (unsigned)n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "total-num-mbufs should be > 1024\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "max-pkt-len")) {
+ n = atoi(optarg);
+ if (n >= RTE_ETHER_MIN_LEN) {
+ rx_mode.max_rx_pkt_len = (uint32_t) n;
+ if (n > RTE_ETHER_MAX_LEN)
+ rx_offloads |=
+ DEV_RX_OFFLOAD_JUMBO_FRAME;
+ } else
+ rte_exit(EXIT_FAILURE,
+ "Invalid max-pkt-len=%d - should be > %d\n",
+ n, RTE_ETHER_MIN_LEN);
+ }
+ if (!strcmp(lgopts[opt_idx].name, "max-lro-pkt-size")) {
+ n = atoi(optarg);
+ rx_mode.max_lro_pkt_size = (uint32_t) n;
+ }
+ if (!strcmp(lgopts[opt_idx].name, "pkt-filter-mode")) {
+ if (!strcmp(optarg, "signature"))
+ fdir_conf.mode =
+ RTE_FDIR_MODE_SIGNATURE;
+ else if (!strcmp(optarg, "perfect"))
+ fdir_conf.mode = RTE_FDIR_MODE_PERFECT;
+ else if (!strcmp(optarg, "perfect-mac-vlan"))
+ fdir_conf.mode = RTE_FDIR_MODE_PERFECT_MAC_VLAN;
+ else if (!strcmp(optarg, "perfect-tunnel"))
+ fdir_conf.mode = RTE_FDIR_MODE_PERFECT_TUNNEL;
+ else if (!strcmp(optarg, "none"))
+ fdir_conf.mode = RTE_FDIR_MODE_NONE;
+ else
+ rte_exit(EXIT_FAILURE,
+ "pkt-mode-invalid %s invalid - must be: "
+ "none, signature, perfect, perfect-mac-vlan"
+ " or perfect-tunnel\n",
+ optarg);
+ }
+ if (!strcmp(lgopts[opt_idx].name,
+ "pkt-filter-report-hash")) {
+ if (!strcmp(optarg, "none"))
+ fdir_conf.status =
+ RTE_FDIR_NO_REPORT_STATUS;
+ else if (!strcmp(optarg, "match"))
+ fdir_conf.status =
+ RTE_FDIR_REPORT_STATUS;
+ else if (!strcmp(optarg, "always"))
+ fdir_conf.status =
+ RTE_FDIR_REPORT_STATUS_ALWAYS;
+ else
+ rte_exit(EXIT_FAILURE,
+ "pkt-filter-report-hash %s invalid "
+ "- must be: none or match or always\n",
+ optarg);
+ }
+ if (!strcmp(lgopts[opt_idx].name, "pkt-filter-size")) {
+ if (!strcmp(optarg, "64K"))
+ fdir_conf.pballoc =
+ RTE_FDIR_PBALLOC_64K;
+ else if (!strcmp(optarg, "128K"))
+ fdir_conf.pballoc =
+ RTE_FDIR_PBALLOC_128K;
+ else if (!strcmp(optarg, "256K"))
+ fdir_conf.pballoc =
+ RTE_FDIR_PBALLOC_256K;
+ else
+ rte_exit(EXIT_FAILURE, "pkt-filter-size %s invalid -"
+ " must be: 64K or 128K or 256K\n",
+ optarg);
+ }
+ if (!strcmp(lgopts[opt_idx].name,
+ "pkt-filter-drop-queue")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ fdir_conf.drop_queue = (uint8_t) n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "drop queue %d invalid - must"
+ "be >= 0 \n", n);
+ }
+#ifdef RTE_LIBRTE_LATENCY_STATS
+ if (!strcmp(lgopts[opt_idx].name,
+ "latencystats")) {
+ n = atoi(optarg);
+ if (n >= 0) {
+ latencystats_lcore_id = (lcoreid_t) n;
+ latencystats_enabled = 1;
+ } else
+ rte_exit(EXIT_FAILURE,
+ "invalid lcore id %d for latencystats"
+ " must be >= 0\n", n);
+ }
+#endif
+#ifdef RTE_LIBRTE_BITRATE
+ if (!strcmp(lgopts[opt_idx].name, "bitrate-stats")) {
+ n = atoi(optarg);
+ if (n >= 0) {
+ bitrate_lcore_id = (lcoreid_t) n;
+ bitrate_enabled = 1;
+ } else
+ rte_exit(EXIT_FAILURE,
+ "invalid lcore id %d for bitrate stats"
+ " must be >= 0\n", n);
+ }
+#endif
+ if (!strcmp(lgopts[opt_idx].name, "disable-crc-strip"))
+ rx_offloads |= DEV_RX_OFFLOAD_KEEP_CRC;
+ if (!strcmp(lgopts[opt_idx].name, "enable-lro"))
+ rx_offloads |= DEV_RX_OFFLOAD_TCP_LRO;
+ if (!strcmp(lgopts[opt_idx].name, "enable-scatter"))
+ rx_offloads |= DEV_RX_OFFLOAD_SCATTER;
+ if (!strcmp(lgopts[opt_idx].name, "enable-rx-cksum"))
+ rx_offloads |= DEV_RX_OFFLOAD_CHECKSUM;
+ if (!strcmp(lgopts[opt_idx].name,
+ "enable-rx-timestamp"))
+ rx_offloads |= DEV_RX_OFFLOAD_TIMESTAMP;
+ if (!strcmp(lgopts[opt_idx].name, "enable-hw-vlan"))
+ rx_offloads |= DEV_RX_OFFLOAD_VLAN;
+
+ if (!strcmp(lgopts[opt_idx].name,
+ "enable-hw-vlan-filter"))
+ rx_offloads |= DEV_RX_OFFLOAD_VLAN_FILTER;
+
+ if (!strcmp(lgopts[opt_idx].name,
+ "enable-hw-vlan-strip"))
+ rx_offloads |= DEV_RX_OFFLOAD_VLAN_STRIP;
+
+ if (!strcmp(lgopts[opt_idx].name,
+ "enable-hw-vlan-extend"))
+ rx_offloads |= DEV_RX_OFFLOAD_VLAN_EXTEND;
+
+ if (!strcmp(lgopts[opt_idx].name,
+ "enable-hw-qinq-strip"))
+ rx_offloads |= DEV_RX_OFFLOAD_QINQ_STRIP;
+
+ if (!strcmp(lgopts[opt_idx].name, "enable-drop-en"))
+ rx_drop_en = 1;
+
+ if (!strcmp(lgopts[opt_idx].name, "disable-rss"))
+ rss_hf = 0;
+ if (!strcmp(lgopts[opt_idx].name, "port-topology")) {
+ if (!strcmp(optarg, "paired"))
+ port_topology = PORT_TOPOLOGY_PAIRED;
+ else if (!strcmp(optarg, "chained"))
+ port_topology = PORT_TOPOLOGY_CHAINED;
+ else if (!strcmp(optarg, "loop"))
+ port_topology = PORT_TOPOLOGY_LOOP;
+ else
+ rte_exit(EXIT_FAILURE, "port-topology %s invalid -"
+ " must be: paired, chained or loop\n",
+ optarg);
+ }
+ if (!strcmp(lgopts[opt_idx].name, "forward-mode"))
+ set_pkt_forwarding_mode(optarg);
+ if (!strcmp(lgopts[opt_idx].name, "rss-ip"))
+ rss_hf = ETH_RSS_IP;
+ if (!strcmp(lgopts[opt_idx].name, "rss-udp"))
+ rss_hf = ETH_RSS_UDP;
+ if (!strcmp(lgopts[opt_idx].name, "rxq")) {
+ n = atoi(optarg);
+ if (n >= 0 && check_nb_rxq((queueid_t)n) == 0)
+ nb_rxq = (queueid_t) n;
+ else
+ rte_exit(EXIT_FAILURE, "rxq %d invalid - must be"
+ " >= 0 && <= %u\n", n,
+ get_allowed_max_nb_rxq(&pid));
+ }
+ if (!strcmp(lgopts[opt_idx].name, "txq")) {
+ n = atoi(optarg);
+ if (n >= 0 && check_nb_txq((queueid_t)n) == 0)
+ nb_txq = (queueid_t) n;
+ else
+ rte_exit(EXIT_FAILURE, "txq %d invalid - must be"
+ " >= 0 && <= %u\n", n,
+ get_allowed_max_nb_txq(&pid));
+ }
+ if (!strcmp(lgopts[opt_idx].name, "hairpinq")) {
+ n = atoi(optarg);
+ if (n >= 0 &&
+ check_nb_hairpinq((queueid_t)n) == 0)
+ nb_hairpinq = (queueid_t) n;
+ else
+ rte_exit(EXIT_FAILURE, "txq %d invalid - must be"
+ " >= 0 && <= %u\n", n,
+ get_allowed_max_nb_hairpinq
+ (&pid));
+ if ((n + nb_txq) < 0 ||
+ check_nb_txq((queueid_t)(n + nb_txq)) != 0)
+ rte_exit(EXIT_FAILURE, "txq + hairpinq "
+ "%d invalid - must be"
+ " >= 0 && <= %u\n",
+ n + nb_txq,
+ get_allowed_max_nb_txq(&pid));
+ if ((n + nb_rxq) < 0 ||
+ check_nb_rxq((queueid_t)(n + nb_rxq)) != 0)
+ rte_exit(EXIT_FAILURE, "rxq + hairpinq "
+ "%d invalid - must be"
+ " >= 0 && <= %u\n",
+ n + nb_rxq,
+ get_allowed_max_nb_rxq(&pid));
+ }
+ if (!nb_rxq && !nb_txq) {
+ rte_exit(EXIT_FAILURE, "Either rx or tx queues should "
+ "be non-zero\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "burst")) {
+ n = atoi(optarg);
+ if (n == 0) {
+ /* A burst size of zero means that the
+ * PMD should be queried for
+ * recommended Rx burst size. Since
+ * testpmd uses a single size for all
+ * ports, port 0 is queried for the
+ * value, on the assumption that all
+ * ports are of the same NIC model.
+ */
+ ret = eth_dev_info_get_print_err(
+ 0,
+ &dev_info);
+ if (ret != 0)
+ return;
+
+ rec_nb_pkts = dev_info
+ .default_rxportconf.burst_size;
+
+ if (rec_nb_pkts == 0)
+ rte_exit(EXIT_FAILURE,
+ "PMD does not recommend a burst size. "
+ "Provided value must be between "
+ "1 and %d\n", MAX_PKT_BURST);
+ else if (rec_nb_pkts > MAX_PKT_BURST)
+ rte_exit(EXIT_FAILURE,
+ "PMD recommended burst size of %d"
+ " exceeds maximum value of %d\n",
+ rec_nb_pkts, MAX_PKT_BURST);
+ printf("Using PMD-provided burst value of %d\n",
+ rec_nb_pkts);
+ nb_pkt_per_burst = rec_nb_pkts;
+ } else if (n > MAX_PKT_BURST)
+ rte_exit(EXIT_FAILURE,
+ "burst must be between1 and %d\n",
+ MAX_PKT_BURST);
+ else
+ nb_pkt_per_burst = (uint16_t) n;
+ }
+ if (!strcmp(lgopts[opt_idx].name, "mbcache")) {
+ n = atoi(optarg);
+ if ((n >= 0) &&
+ (n <= RTE_MEMPOOL_CACHE_MAX_SIZE))
+ mb_mempool_cache = (uint16_t) n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "mbcache must be >= 0 and <= %d\n",
+ RTE_MEMPOOL_CACHE_MAX_SIZE);
+ }
+ if (!strcmp(lgopts[opt_idx].name, "txfreet")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ tx_free_thresh = (int16_t)n;
+ else
+ rte_exit(EXIT_FAILURE, "txfreet must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "txrst")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ tx_rs_thresh = (int16_t)n;
+ else
+ rte_exit(EXIT_FAILURE, "txrst must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "rxd")) {
+ n = atoi(optarg);
+ if (n > 0) {
+ if (rx_free_thresh >= n)
+ rte_exit(EXIT_FAILURE,
+ "rxd must be > "
+ "rx_free_thresh(%d)\n",
+ (int)rx_free_thresh);
+ else
+ nb_rxd = (uint16_t) n;
+ } else
+ rte_exit(EXIT_FAILURE,
+ "rxd(%d) invalid - must be > 0\n",
+ n);
+ }
+ if (!strcmp(lgopts[opt_idx].name, "txd")) {
+ n = atoi(optarg);
+ if (n > 0)
+ nb_txd = (uint16_t) n;
+ else
+ rte_exit(EXIT_FAILURE, "txd must be in > 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "txpt")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ tx_pthresh = (int8_t)n;
+ else
+ rte_exit(EXIT_FAILURE, "txpt must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "txht")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ tx_hthresh = (int8_t)n;
+ else
+ rte_exit(EXIT_FAILURE, "txht must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "txwt")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ tx_wthresh = (int8_t)n;
+ else
+ rte_exit(EXIT_FAILURE, "txwt must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "rxpt")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ rx_pthresh = (int8_t)n;
+ else
+ rte_exit(EXIT_FAILURE, "rxpt must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "rxht")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ rx_hthresh = (int8_t)n;
+ else
+ rte_exit(EXIT_FAILURE, "rxht must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "rxwt")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ rx_wthresh = (int8_t)n;
+ else
+ rte_exit(EXIT_FAILURE, "rxwt must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "rxfreet")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ rx_free_thresh = (int16_t)n;
+ else
+ rte_exit(EXIT_FAILURE, "rxfreet must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "tx-queue-stats-mapping")) {
+ if (parse_queue_stats_mapping_config(optarg, TX)) {
+ rte_exit(EXIT_FAILURE,
+ "invalid TX queue statistics mapping config entered\n");
+ }
+ }
+ if (!strcmp(lgopts[opt_idx].name, "rx-queue-stats-mapping")) {
+ if (parse_queue_stats_mapping_config(optarg, RX)) {
+ rte_exit(EXIT_FAILURE,
+ "invalid RX queue statistics mapping config entered\n");
+ }
+ }
+ if (!strcmp(lgopts[opt_idx].name, "txpkts")) {
+ unsigned seg_lengths[RTE_MAX_SEGS_PER_PKT];
+ unsigned int nb_segs;
+
+ nb_segs = parse_item_list(optarg, "txpkt segments",
+ RTE_MAX_SEGS_PER_PKT, seg_lengths, 0);
+ if (nb_segs > 0)
+ set_tx_pkt_segments(seg_lengths, nb_segs);
+ else
+ rte_exit(EXIT_FAILURE, "bad txpkts\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "txonly-multi-flow"))
+ txonly_multi_flow = 1;
+ if (!strcmp(lgopts[opt_idx].name, "no-flush-rx"))
+ no_flush_rx = 1;
+ if (!strcmp(lgopts[opt_idx].name, "disable-link-check"))
+ no_link_check = 1;
+ if (!strcmp(lgopts[opt_idx].name, "disable-device-start"))
+ no_device_start = 1;
+ if (!strcmp(lgopts[opt_idx].name, "no-lsc-interrupt"))
+ lsc_interrupt = 0;
+ if (!strcmp(lgopts[opt_idx].name, "no-rmv-interrupt"))
+ rmv_interrupt = 0;
+ if (!strcmp(lgopts[opt_idx].name, "flow-isolate-all"))
+ flow_isolate_all = 1;
+ if (!strcmp(lgopts[opt_idx].name, "tx-offloads")) {
+ char *end = NULL;
+ n = strtoull(optarg, &end, 16);
+ if (n >= 0)
+ tx_offloads = (uint64_t)n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "tx-offloads must be >= 0\n");
+ }
+
+ if (!strcmp(lgopts[opt_idx].name, "rx-offloads")) {
+ char *end = NULL;
+ n = strtoull(optarg, &end, 16);
+ if (n >= 0)
+ rx_offloads = (uint64_t)n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "rx-offloads must be >= 0\n");
+ }
+
+ if (!strcmp(lgopts[opt_idx].name, "vxlan-gpe-port")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ vxlan_gpe_udp_port = (uint16_t)n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "vxlan-gpe-port must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "print-event"))
+ if (parse_event_printing_config(optarg, 1)) {
+ rte_exit(EXIT_FAILURE,
+ "invalid print-event argument\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "mask-event"))
+ if (parse_event_printing_config(optarg, 0)) {
+ rte_exit(EXIT_FAILURE,
+ "invalid mask-event argument\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "hot-plug"))
+ hot_plug = 1;
+ if (!strcmp(lgopts[opt_idx].name, "mlockall"))
+ do_mlockall = 1;
+ if (!strcmp(lgopts[opt_idx].name, "no-mlockall"))
+ do_mlockall = 0;
+ if (!strcmp(lgopts[opt_idx].name,
+ "noisy-tx-sw-buffer-size")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ noisy_tx_sw_bufsz = n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "noisy-tx-sw-buffer-size must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name,
+ "noisy-tx-sw-buffer-flushtime")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ noisy_tx_sw_buf_flush_time = n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "noisy-tx-sw-buffer-flushtime must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name,
+ "noisy-lkup-memory")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ noisy_lkup_mem_sz = n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "noisy-lkup-memory must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name,
+ "noisy-lkup-num-writes")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ noisy_lkup_num_writes = n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "noisy-lkup-num-writes must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name,
+ "noisy-lkup-num-reads")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ noisy_lkup_num_reads = n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "noisy-lkup-num-reads must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name,
+ "noisy-lkup-num-reads-writes")) {
+ n = atoi(optarg);
+ if (n >= 0)
+ noisy_lkup_num_reads_writes = n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "noisy-lkup-num-reads-writes must be >= 0\n");
+ }
+ if (!strcmp(lgopts[opt_idx].name, "no-iova-contig"))
+ mempool_flags = MEMPOOL_F_NO_IOVA_CONTIG;
+
+ if (!strcmp(lgopts[opt_idx].name, "rx-mq-mode")) {
+ char *end = NULL;
+ n = strtoul(optarg, &end, 16);
+ if (n >= 0 && n <= ETH_MQ_RX_VMDQ_DCB_RSS)
+ rx_mq_mode = (enum rte_eth_rx_mq_mode)n;
+ else
+ rte_exit(EXIT_FAILURE,
+ "rx-mq-mode must be >= 0 and <= %d\n",
+ ETH_MQ_RX_VMDQ_DCB_RSS);
+ }
+ break;
+ case 'h':
+ usage(argv[0]);
+ rte_exit(EXIT_SUCCESS, "Displayed help\n");
+ break;
+ default:
+ usage(argv[0]);
+ printf("Invalid option: %s\n", argv[optind]);
+ rte_exit(EXIT_FAILURE,
+ "Command line is incomplete or incorrect\n");
+ break;
+ }
+ }
+
+ if (optind != argc) {
+ usage(argv[0]);
+ printf("Invalid parameter: %s\n", argv[optind]);
+ rte_exit(EXIT_FAILURE, "Command line is incorrect\n");
+ }
+
+ /* Set offload configuration from command line parameters. */
+ rx_mode.offloads = rx_offloads;
+ tx_mode.offloads = tx_offloads;
+
+ if (mempool_flags & MEMPOOL_F_NO_IOVA_CONTIG &&
+ mp_alloc_type != MP_ALLOC_ANON) {
+ TESTPMD_LOG(WARNING, "cannot use no-iova-contig without "
+ "mp-alloc=anon. mempool no-iova-contig is "
+ "ignored\n");
+ mempool_flags = 0;
+ }
+}
diff --git a/src/spdk/dpdk/app/test-pmd/rxonly.c b/src/spdk/dpdk/app/test-pmd/rxonly.c
new file mode 100644
index 000000000..5c65fc42d
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/rxonly.c
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_string_fns.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+#include <rte_net.h>
+#include <rte_flow.h>
+
+#include "testpmd.h"
+
+/*
+ * Received a burst of packets.
+ */
+static void
+pkt_burst_receive(struct fwd_stream *fs)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ uint16_t nb_rx;
+ uint16_t i;
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ uint64_t start_tsc;
+ uint64_t end_tsc;
+ uint64_t core_cycles;
+
+ start_tsc = rte_rdtsc();
+#endif
+
+ /*
+ * Receive a burst of packets.
+ */
+ nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
+ nb_pkt_per_burst);
+ if (unlikely(nb_rx == 0))
+ return;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
+#endif
+ fs->rx_packets += nb_rx;
+ for (i = 0; i < nb_rx; i++)
+ rte_pktmbuf_free(pkts_burst[i]);
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ end_tsc = rte_rdtsc();
+ core_cycles = (end_tsc - start_tsc);
+ fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+#endif
+}
+
+struct fwd_engine rx_only_engine = {
+ .fwd_mode_name = "rxonly",
+ .port_fwd_begin = NULL,
+ .port_fwd_end = NULL,
+ .packet_fwd = pkt_burst_receive,
+};
diff --git a/src/spdk/dpdk/app/test-pmd/softnicfwd.c b/src/spdk/dpdk/app/test-pmd/softnicfwd.c
new file mode 100644
index 000000000..e9d437364
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/softnicfwd.c
@@ -0,0 +1,686 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation
+ */
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include <rte_cycles.h>
+#include <rte_mbuf.h>
+#include <rte_malloc.h>
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_meter.h>
+#include <rte_eth_softnic.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+
+#define SUBPORT_NODES_PER_PORT 1
+#define PIPE_NODES_PER_SUBPORT 4096
+#define TC_NODES_PER_PIPE 4
+#define QUEUE_NODES_PER_TC 4
+
+#define NUM_PIPE_NODES \
+ (SUBPORT_NODES_PER_PORT * PIPE_NODES_PER_SUBPORT)
+
+#define NUM_TC_NODES \
+ (NUM_PIPE_NODES * TC_NODES_PER_PIPE)
+
+#define ROOT_NODE_ID 1000000
+#define SUBPORT_NODES_START_ID 900000
+#define PIPE_NODES_START_ID 800000
+#define TC_NODES_START_ID 700000
+
+#define STATS_MASK_DEFAULT \
+ (RTE_TM_STATS_N_PKTS | \
+ RTE_TM_STATS_N_BYTES | \
+ RTE_TM_STATS_N_PKTS_GREEN_DROPPED | \
+ RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
+
+#define STATS_MASK_QUEUE \
+ (STATS_MASK_DEFAULT | \
+ RTE_TM_STATS_N_PKTS_QUEUED)
+
+#define BYTES_IN_MBPS (1000 * 1000 / 8)
+#define TOKEN_BUCKET_SIZE 1000000
+
+/* TM Hierarchy Levels */
+enum tm_hierarchy_level {
+ TM_NODE_LEVEL_PORT = 0,
+ TM_NODE_LEVEL_SUBPORT,
+ TM_NODE_LEVEL_PIPE,
+ TM_NODE_LEVEL_TC,
+ TM_NODE_LEVEL_QUEUE,
+ TM_NODE_LEVEL_MAX,
+};
+
+struct tm_hierarchy {
+ /* TM Nodes */
+ uint32_t root_node_id;
+ uint32_t subport_node_id[SUBPORT_NODES_PER_PORT];
+ uint32_t pipe_node_id[SUBPORT_NODES_PER_PORT][PIPE_NODES_PER_SUBPORT];
+ uint32_t tc_node_id[NUM_PIPE_NODES][TC_NODES_PER_PIPE];
+ uint32_t queue_node_id[NUM_TC_NODES][QUEUE_NODES_PER_TC];
+
+ /* TM Hierarchy Nodes Shaper Rates */
+ uint32_t root_node_shaper_rate;
+ uint32_t subport_node_shaper_rate;
+ uint32_t pipe_node_shaper_rate;
+ uint32_t tc_node_shaper_rate;
+ uint32_t tc_node_shared_shaper_rate;
+
+ uint32_t n_shapers;
+};
+
+static struct fwd_lcore *softnic_fwd_lcore;
+static uint16_t softnic_port_id;
+struct fwd_engine softnic_fwd_engine;
+
+/*
+ * Softnic packet forward
+ */
+static void
+softnic_fwd(struct fwd_stream *fs)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ uint16_t nb_rx;
+ uint16_t nb_tx;
+ uint32_t retry;
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ uint64_t start_tsc;
+ uint64_t end_tsc;
+ uint64_t core_cycles;
+#endif
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ start_tsc = rte_rdtsc();
+#endif
+
+ /* Packets Receive */
+ nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,
+ pkts_burst, nb_pkt_per_burst);
+ fs->rx_packets += nb_rx;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
+#endif
+
+ nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+ pkts_burst, nb_rx);
+
+ /* Retry if necessary */
+ if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) {
+ retry = 0;
+ while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
+ rte_delay_us(burst_tx_delay_time);
+ nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+ &pkts_burst[nb_tx], nb_rx - nb_tx);
+ }
+ }
+ fs->tx_packets += nb_tx;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+#endif
+
+ if (unlikely(nb_tx < nb_rx)) {
+ fs->fwd_dropped += (nb_rx - nb_tx);
+ do {
+ rte_pktmbuf_free(pkts_burst[nb_tx]);
+ } while (++nb_tx < nb_rx);
+ }
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ end_tsc = rte_rdtsc();
+ core_cycles = (end_tsc - start_tsc);
+ fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+#endif
+}
+
+static void
+softnic_fwd_run(struct fwd_stream *fs)
+{
+ rte_pmd_softnic_run(softnic_port_id);
+ softnic_fwd(fs);
+}
+
+/**
+ * Softnic init
+ */
+static int
+softnic_begin(void *arg __rte_unused)
+{
+ for (;;) {
+ if (!softnic_fwd_lcore->stopped)
+ break;
+ }
+
+ do {
+ /* Run softnic */
+ rte_pmd_softnic_run(softnic_port_id);
+ } while (!softnic_fwd_lcore->stopped);
+
+ return 0;
+}
+
+static int
+set_tm_hiearchy_nodes_shaper_rate(portid_t port_id,
+ struct tm_hierarchy *h)
+{
+ struct rte_eth_link link_params;
+ uint64_t tm_port_rate;
+ int ret;
+
+ memset(&link_params, 0, sizeof(link_params));
+
+ ret = rte_eth_link_get(port_id, &link_params);
+ if (ret < 0) {
+ printf("Error during getting device (port %u) link info: %s\n",
+ port_id, rte_strerror(-ret));
+ return ret;
+ }
+ tm_port_rate = (uint64_t)ETH_SPEED_NUM_10G * BYTES_IN_MBPS;
+
+ /* Set tm hierarchy shapers rate */
+ h->root_node_shaper_rate = tm_port_rate;
+ h->subport_node_shaper_rate =
+ tm_port_rate / SUBPORT_NODES_PER_PORT;
+ h->pipe_node_shaper_rate
+ = h->subport_node_shaper_rate / PIPE_NODES_PER_SUBPORT;
+ h->tc_node_shaper_rate = h->pipe_node_shaper_rate;
+ h->tc_node_shared_shaper_rate = h->subport_node_shaper_rate;
+
+ return 0;
+}
+
+static int
+softport_tm_root_node_add(portid_t port_id, struct tm_hierarchy *h,
+ struct rte_tm_error *error)
+{
+ struct rte_tm_node_params rnp;
+ struct rte_tm_shaper_params rsp;
+ uint32_t priority, weight, level_id, shaper_profile_id;
+
+ memset(&rsp, 0, sizeof(struct rte_tm_shaper_params));
+ memset(&rnp, 0, sizeof(struct rte_tm_node_params));
+
+ /* Shaper profile Parameters */
+ rsp.peak.rate = h->root_node_shaper_rate;
+ rsp.peak.size = TOKEN_BUCKET_SIZE;
+ rsp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+ shaper_profile_id = 0;
+
+ if (rte_tm_shaper_profile_add(port_id, shaper_profile_id,
+ &rsp, error)) {
+ printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+ __func__, error->type, error->message,
+ shaper_profile_id);
+ return -1;
+ }
+
+ /* Root Node Parameters */
+ h->root_node_id = ROOT_NODE_ID;
+ weight = 1;
+ priority = 0;
+ level_id = TM_NODE_LEVEL_PORT;
+ rnp.shaper_profile_id = shaper_profile_id;
+ rnp.nonleaf.n_sp_priorities = 1;
+ rnp.stats_mask = STATS_MASK_DEFAULT;
+
+ /* Add Node to TM Hierarchy */
+ if (rte_tm_node_add(port_id, h->root_node_id, RTE_TM_NODE_ID_NULL,
+ priority, weight, level_id, &rnp, error)) {
+ printf("%s ERROR(%d)-%s!(node_id %u, parent_id %u, level %u)\n",
+ __func__, error->type, error->message,
+ h->root_node_id, RTE_TM_NODE_ID_NULL,
+ level_id);
+ return -1;
+ }
+ /* Update */
+ h->n_shapers++;
+
+ printf(" Root node added (Start id %u, Count %u, level %u)\n",
+ h->root_node_id, 1, level_id);
+
+ return 0;
+}
+
+static int
+softport_tm_subport_node_add(portid_t port_id,
+ struct tm_hierarchy *h,
+ struct rte_tm_error *error)
+{
+ uint32_t subport_parent_node_id, subport_node_id = 0;
+ struct rte_tm_node_params snp;
+ struct rte_tm_shaper_params ssp;
+ uint32_t priority, weight, level_id, shaper_profile_id;
+ uint32_t i;
+
+ memset(&ssp, 0, sizeof(struct rte_tm_shaper_params));
+ memset(&snp, 0, sizeof(struct rte_tm_node_params));
+
+ shaper_profile_id = h->n_shapers;
+
+ /* Add Shaper Profile to TM Hierarchy */
+ for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+ ssp.peak.rate = h->subport_node_shaper_rate;
+ ssp.peak.size = TOKEN_BUCKET_SIZE;
+ ssp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+ if (rte_tm_shaper_profile_add(port_id, shaper_profile_id,
+ &ssp, error)) {
+ printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+ __func__, error->type, error->message,
+ shaper_profile_id);
+ return -1;
+ }
+
+ /* Node Parameters */
+ h->subport_node_id[i] = SUBPORT_NODES_START_ID + i;
+ subport_parent_node_id = h->root_node_id;
+ weight = 1;
+ priority = 0;
+ level_id = TM_NODE_LEVEL_SUBPORT;
+ snp.shaper_profile_id = shaper_profile_id;
+ snp.nonleaf.n_sp_priorities = 1;
+ snp.stats_mask = STATS_MASK_DEFAULT;
+
+ /* Add Node to TM Hiearchy */
+ if (rte_tm_node_add(port_id,
+ h->subport_node_id[i],
+ subport_parent_node_id,
+ priority, weight,
+ level_id,
+ &snp,
+ error)) {
+ printf("%s ERROR(%d)-%s!(node %u,parent %u,level %u)\n",
+ __func__,
+ error->type,
+ error->message,
+ h->subport_node_id[i],
+ subport_parent_node_id,
+ level_id);
+ return -1;
+ }
+ shaper_profile_id++;
+ subport_node_id++;
+ }
+ /* Update */
+ h->n_shapers = shaper_profile_id;
+
+ printf(" Subport nodes added (Start id %u, Count %u, level %u)\n",
+ h->subport_node_id[0], SUBPORT_NODES_PER_PORT, level_id);
+
+ return 0;
+}
+
+static int
+softport_tm_pipe_node_add(portid_t port_id,
+ struct tm_hierarchy *h,
+ struct rte_tm_error *error)
+{
+ uint32_t pipe_parent_node_id;
+ struct rte_tm_node_params pnp;
+ struct rte_tm_shaper_params psp;
+ uint32_t priority, weight, level_id, shaper_profile_id;
+ uint32_t i, j;
+
+ memset(&psp, 0, sizeof(struct rte_tm_shaper_params));
+ memset(&pnp, 0, sizeof(struct rte_tm_node_params));
+
+ shaper_profile_id = h->n_shapers;
+
+ /* Shaper Profile Parameters */
+ psp.peak.rate = h->pipe_node_shaper_rate;
+ psp.peak.size = TOKEN_BUCKET_SIZE;
+ psp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+ /* Pipe Node Parameters */
+ weight = 1;
+ priority = 0;
+ level_id = TM_NODE_LEVEL_PIPE;
+ pnp.nonleaf.n_sp_priorities = 4;
+ pnp.stats_mask = STATS_MASK_DEFAULT;
+
+ /* Add Shaper Profiles and Nodes to TM Hierarchy */
+ for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+ for (j = 0; j < PIPE_NODES_PER_SUBPORT; j++) {
+ if (rte_tm_shaper_profile_add(port_id,
+ shaper_profile_id, &psp, error)) {
+ printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+ __func__, error->type, error->message,
+ shaper_profile_id);
+ return -1;
+ }
+ pnp.shaper_profile_id = shaper_profile_id;
+ pipe_parent_node_id = h->subport_node_id[i];
+ h->pipe_node_id[i][j] = PIPE_NODES_START_ID +
+ (i * PIPE_NODES_PER_SUBPORT) + j;
+
+ if (rte_tm_node_add(port_id,
+ h->pipe_node_id[i][j],
+ pipe_parent_node_id,
+ priority, weight, level_id,
+ &pnp,
+ error)) {
+ printf("%s ERROR(%d)-%s!(node %u,parent %u )\n",
+ __func__,
+ error->type,
+ error->message,
+ h->pipe_node_id[i][j],
+ pipe_parent_node_id);
+
+ return -1;
+ }
+ shaper_profile_id++;
+ }
+ }
+ /* Update */
+ h->n_shapers = shaper_profile_id;
+
+ printf(" Pipe nodes added (Start id %u, Count %u, level %u)\n",
+ h->pipe_node_id[0][0], NUM_PIPE_NODES, level_id);
+
+ return 0;
+}
+
+static int
+softport_tm_tc_node_add(portid_t port_id,
+ struct tm_hierarchy *h,
+ struct rte_tm_error *error)
+{
+ uint32_t tc_parent_node_id;
+ struct rte_tm_node_params tnp;
+ struct rte_tm_shaper_params tsp, tssp;
+ uint32_t shared_shaper_profile_id[TC_NODES_PER_PIPE];
+ uint32_t priority, weight, level_id, shaper_profile_id;
+ uint32_t pos, n_tc_nodes, i, j, k;
+
+ memset(&tsp, 0, sizeof(struct rte_tm_shaper_params));
+ memset(&tssp, 0, sizeof(struct rte_tm_shaper_params));
+ memset(&tnp, 0, sizeof(struct rte_tm_node_params));
+
+ shaper_profile_id = h->n_shapers;
+
+ /* Private Shaper Profile (TC) Parameters */
+ tsp.peak.rate = h->tc_node_shaper_rate;
+ tsp.peak.size = TOKEN_BUCKET_SIZE;
+ tsp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+ /* Shared Shaper Profile (TC) Parameters */
+ tssp.peak.rate = h->tc_node_shared_shaper_rate;
+ tssp.peak.size = TOKEN_BUCKET_SIZE;
+ tssp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+ /* TC Node Parameters */
+ weight = 1;
+ level_id = TM_NODE_LEVEL_TC;
+ tnp.n_shared_shapers = 1;
+ tnp.nonleaf.n_sp_priorities = 1;
+ tnp.stats_mask = STATS_MASK_DEFAULT;
+
+ /* Add Shared Shaper Profiles to TM Hierarchy */
+ for (i = 0; i < TC_NODES_PER_PIPE; i++) {
+ shared_shaper_profile_id[i] = shaper_profile_id;
+
+ if (rte_tm_shaper_profile_add(port_id,
+ shared_shaper_profile_id[i], &tssp, error)) {
+ printf("%s ERROR(%d)-%s!(Shared shaper profileid %u)\n",
+ __func__, error->type, error->message,
+ shared_shaper_profile_id[i]);
+
+ return -1;
+ }
+ if (rte_tm_shared_shaper_add_update(port_id, i,
+ shared_shaper_profile_id[i], error)) {
+ printf("%s ERROR(%d)-%s!(Shared shaper id %u)\n",
+ __func__, error->type, error->message, i);
+
+ return -1;
+ }
+ shaper_profile_id++;
+ }
+
+ /* Add Shaper Profiles and Nodes to TM Hierarchy */
+ n_tc_nodes = 0;
+ for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+ for (j = 0; j < PIPE_NODES_PER_SUBPORT; j++) {
+ for (k = 0; k < TC_NODES_PER_PIPE ; k++) {
+ priority = k;
+ tc_parent_node_id = h->pipe_node_id[i][j];
+ tnp.shared_shaper_id =
+ (uint32_t *)calloc(1, sizeof(uint32_t));
+ if (tnp.shared_shaper_id == NULL) {
+ printf("Shared shaper mem alloc err\n");
+ return -1;
+ }
+ tnp.shared_shaper_id[0] = k;
+ pos = j + (i * PIPE_NODES_PER_SUBPORT);
+ h->tc_node_id[pos][k] =
+ TC_NODES_START_ID + n_tc_nodes;
+
+ if (rte_tm_shaper_profile_add(port_id,
+ shaper_profile_id, &tsp, error)) {
+ printf("%s ERROR(%d)-%s!(shaper %u)\n",
+ __func__, error->type,
+ error->message,
+ shaper_profile_id);
+
+ free(tnp.shared_shaper_id);
+ return -1;
+ }
+ tnp.shaper_profile_id = shaper_profile_id;
+ if (rte_tm_node_add(port_id,
+ h->tc_node_id[pos][k],
+ tc_parent_node_id,
+ priority, weight,
+ level_id,
+ &tnp, error)) {
+ printf("%s ERROR(%d)-%s!(node id %u)\n",
+ __func__,
+ error->type,
+ error->message,
+ h->tc_node_id[pos][k]);
+
+ free(tnp.shared_shaper_id);
+ return -1;
+ }
+ shaper_profile_id++;
+ n_tc_nodes++;
+ }
+ }
+ }
+ /* Update */
+ h->n_shapers = shaper_profile_id;
+
+ printf(" TC nodes added (Start id %u, Count %u, level %u)\n",
+ h->tc_node_id[0][0], n_tc_nodes, level_id);
+
+ return 0;
+}
+
+static int
+softport_tm_queue_node_add(portid_t port_id, struct tm_hierarchy *h,
+ struct rte_tm_error *error)
+{
+ uint32_t queue_parent_node_id;
+ struct rte_tm_node_params qnp;
+ uint32_t priority, weight, level_id, pos;
+ uint32_t n_queue_nodes, i, j, k;
+
+ memset(&qnp, 0, sizeof(struct rte_tm_node_params));
+
+ /* Queue Node Parameters */
+ priority = 0;
+ weight = 1;
+ level_id = TM_NODE_LEVEL_QUEUE;
+ qnp.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE;
+ qnp.leaf.cman = RTE_TM_CMAN_TAIL_DROP;
+ qnp.stats_mask = STATS_MASK_QUEUE;
+
+ /* Add Queue Nodes to TM Hierarchy */
+ n_queue_nodes = 0;
+ for (i = 0; i < NUM_PIPE_NODES; i++) {
+ for (j = 0; j < TC_NODES_PER_PIPE; j++) {
+ queue_parent_node_id = h->tc_node_id[i][j];
+ for (k = 0; k < QUEUE_NODES_PER_TC; k++) {
+ pos = j + (i * TC_NODES_PER_PIPE);
+ h->queue_node_id[pos][k] = n_queue_nodes;
+ if (rte_tm_node_add(port_id,
+ h->queue_node_id[pos][k],
+ queue_parent_node_id,
+ priority,
+ weight,
+ level_id,
+ &qnp, error)) {
+ printf("%s ERROR(%d)-%s!(node %u)\n",
+ __func__,
+ error->type,
+ error->message,
+ h->queue_node_id[pos][k]);
+
+ return -1;
+ }
+ n_queue_nodes++;
+ }
+ }
+ }
+ printf(" Queue nodes added (Start id %u, Count %u, level %u)\n",
+ h->queue_node_id[0][0], n_queue_nodes, level_id);
+
+ return 0;
+}
+
+static int
+softport_tm_hierarchy_specify(portid_t port_id,
+ struct rte_tm_error *error)
+{
+
+ struct tm_hierarchy h;
+ int status;
+
+ memset(&h, 0, sizeof(struct tm_hierarchy));
+
+ /* TM hierarchy shapers rate */
+ status = set_tm_hiearchy_nodes_shaper_rate(port_id, &h);
+ if (status)
+ return status;
+
+ /* Add root node (level 0) */
+ status = softport_tm_root_node_add(port_id, &h, error);
+ if (status)
+ return status;
+
+ /* Add subport node (level 1) */
+ status = softport_tm_subport_node_add(port_id, &h, error);
+ if (status)
+ return status;
+
+ /* Add pipe nodes (level 2) */
+ status = softport_tm_pipe_node_add(port_id, &h, error);
+ if (status)
+ return status;
+
+ /* Add traffic class nodes (level 3) */
+ status = softport_tm_tc_node_add(port_id, &h, error);
+ if (status)
+ return status;
+
+ /* Add queue nodes (level 4) */
+ status = softport_tm_queue_node_add(port_id, &h, error);
+ if (status)
+ return status;
+
+ return 0;
+}
+
+/*
+ * Softnic TM default configuration
+ */
+static void
+softnic_tm_default_config(portid_t pi)
+{
+ struct rte_port *port = &ports[pi];
+ struct rte_tm_error error;
+ int status;
+
+ /* Stop port */
+ rte_eth_dev_stop(pi);
+
+ /* TM hierarchy specification */
+ status = softport_tm_hierarchy_specify(pi, &error);
+ if (status) {
+ printf(" TM Hierarchy built error(%d) - %s\n",
+ error.type, error.message);
+ return;
+ }
+ printf("\n TM Hierarchy Specified!\n");
+
+ /* TM hierarchy commit */
+ status = rte_tm_hierarchy_commit(pi, 0, &error);
+ if (status) {
+ printf(" Hierarchy commit error(%d) - %s\n",
+ error.type, error.message);
+ return;
+ }
+ printf(" Hierarchy Committed (port %u)!\n", pi);
+
+ /* Start port */
+ status = rte_eth_dev_start(pi);
+ if (status) {
+ printf("\n Port %u start error!\n", pi);
+ return;
+ }
+
+ /* Reset the default hierarchy flag */
+ port->softport.default_tm_hierarchy_enable = 0;
+}
+
+/*
+ * Softnic forwarding init
+ */
+static void
+softnic_fwd_begin(portid_t pi)
+{
+ struct rte_port *port = &ports[pi];
+ uint32_t lcore, fwd_core_present = 0, softnic_run_launch = 0;
+ int status;
+
+ softnic_fwd_lcore = port->softport.fwd_lcore_arg[0];
+ softnic_port_id = pi;
+
+ /* Launch softnic_run function on lcores */
+ for (lcore = 0; lcore < RTE_MAX_LCORE; lcore++) {
+ if (!rte_lcore_is_enabled(lcore))
+ continue;
+
+ if (lcore == rte_get_master_lcore())
+ continue;
+
+ if (fwd_core_present == 0) {
+ fwd_core_present++;
+ continue;
+ }
+
+ status = rte_eal_remote_launch(softnic_begin, NULL, lcore);
+ if (status)
+ printf("softnic launch on lcore %u failed (%d)\n",
+ lcore, status);
+
+ softnic_run_launch = 1;
+ }
+
+ if (!softnic_run_launch)
+ softnic_fwd_engine.packet_fwd = softnic_fwd_run;
+
+ /* Softnic TM default configuration */
+ if (port->softport.default_tm_hierarchy_enable == 1)
+ softnic_tm_default_config(pi);
+}
+
+struct fwd_engine softnic_fwd_engine = {
+ .fwd_mode_name = "softnic",
+ .port_fwd_begin = softnic_fwd_begin,
+ .port_fwd_end = NULL,
+ .packet_fwd = softnic_fwd,
+};
diff --git a/src/spdk/dpdk/app/test-pmd/testpmd.c b/src/spdk/dpdk/app/test-pmd/testpmd.c
new file mode 100644
index 000000000..4989d22ca
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/testpmd.c
@@ -0,0 +1,3859 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2017 Intel Corporation
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <rte_common.h>
+#include <rte_errno.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_alarm.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_mempool.h>
+#include <rte_malloc.h>
+#include <rte_mbuf.h>
+#include <rte_mbuf_pool_ops.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_dev.h>
+#include <rte_string_fns.h>
+#ifdef RTE_LIBRTE_IXGBE_PMD
+#include <rte_pmd_ixgbe.h>
+#endif
+#ifdef RTE_LIBRTE_PDUMP
+#include <rte_pdump.h>
+#endif
+#include <rte_flow.h>
+#include <rte_metrics.h>
+#ifdef RTE_LIBRTE_BITRATE
+#include <rte_bitrate.h>
+#endif
+#ifdef RTE_LIBRTE_LATENCY_STATS
+#include <rte_latencystats.h>
+#endif
+
+#include "testpmd.h"
+
+#ifndef MAP_HUGETLB
+/* FreeBSD may not have MAP_HUGETLB (in fact, it probably doesn't) */
+#define HUGE_FLAG (0x40000)
+#else
+#define HUGE_FLAG MAP_HUGETLB
+#endif
+
+#ifndef MAP_HUGE_SHIFT
+/* older kernels (or FreeBSD) will not have this define */
+#define HUGE_SHIFT (26)
+#else
+#define HUGE_SHIFT MAP_HUGE_SHIFT
+#endif
+
+#define EXTMEM_HEAP_NAME "extmem"
+#define EXTBUF_ZONE_SIZE RTE_PGSIZE_2M
+
+uint16_t verbose_level = 0; /**< Silent by default. */
+int testpmd_logtype; /**< Log type for testpmd logs */
+
+/* use master core for command line ? */
+uint8_t interactive = 0;
+uint8_t auto_start = 0;
+uint8_t tx_first;
+char cmdline_filename[PATH_MAX] = {0};
+
+/*
+ * NUMA support configuration.
+ * When set, the NUMA support attempts to dispatch the allocation of the
+ * RX and TX memory rings, and of the DMA memory buffers (mbufs) for the
+ * probed ports among the CPU sockets 0 and 1.
+ * Otherwise, all memory is allocated from CPU socket 0.
+ */
+uint8_t numa_support = 1; /**< numa enabled by default */
+
+/*
+ * In UMA mode,all memory is allocated from socket 0 if --socket-num is
+ * not configured.
+ */
+uint8_t socket_num = UMA_NO_CONFIG;
+
+/*
+ * Select mempool allocation type:
+ * - native: use regular DPDK memory
+ * - anon: use regular DPDK memory to create mempool, but populate using
+ * anonymous memory (may not be IOVA-contiguous)
+ * - xmem: use externally allocated hugepage memory
+ */
+uint8_t mp_alloc_type = MP_ALLOC_NATIVE;
+
+/*
+ * Store specified sockets on which memory pool to be used by ports
+ * is allocated.
+ */
+uint8_t port_numa[RTE_MAX_ETHPORTS];
+
+/*
+ * Store specified sockets on which RX ring to be used by ports
+ * is allocated.
+ */
+uint8_t rxring_numa[RTE_MAX_ETHPORTS];
+
+/*
+ * Store specified sockets on which TX ring to be used by ports
+ * is allocated.
+ */
+uint8_t txring_numa[RTE_MAX_ETHPORTS];
+
+/*
+ * Record the Ethernet address of peer target ports to which packets are
+ * forwarded.
+ * Must be instantiated with the ethernet addresses of peer traffic generator
+ * ports.
+ */
+struct rte_ether_addr peer_eth_addrs[RTE_MAX_ETHPORTS];
+portid_t nb_peer_eth_addrs = 0;
+
+/*
+ * Probed Target Environment.
+ */
+struct rte_port *ports; /**< For all probed ethernet ports. */
+portid_t nb_ports; /**< Number of probed ethernet ports. */
+struct fwd_lcore **fwd_lcores; /**< For all probed logical cores. */
+lcoreid_t nb_lcores; /**< Number of probed logical cores. */
+
+portid_t ports_ids[RTE_MAX_ETHPORTS]; /**< Store all port ids. */
+
+/*
+ * Test Forwarding Configuration.
+ * nb_fwd_lcores <= nb_cfg_lcores <= nb_lcores
+ * nb_fwd_ports <= nb_cfg_ports <= nb_ports
+ */
+lcoreid_t nb_cfg_lcores; /**< Number of configured logical cores. */
+lcoreid_t nb_fwd_lcores; /**< Number of forwarding logical cores. */
+portid_t nb_cfg_ports; /**< Number of configured ports. */
+portid_t nb_fwd_ports; /**< Number of forwarding ports. */
+
+unsigned int fwd_lcores_cpuids[RTE_MAX_LCORE]; /**< CPU ids configuration. */
+portid_t fwd_ports_ids[RTE_MAX_ETHPORTS]; /**< Port ids configuration. */
+
+struct fwd_stream **fwd_streams; /**< For each RX queue of each port. */
+streamid_t nb_fwd_streams; /**< Is equal to (nb_ports * nb_rxq). */
+
+/*
+ * Forwarding engines.
+ */
+struct fwd_engine * fwd_engines[] = {
+ &io_fwd_engine,
+ &mac_fwd_engine,
+ &mac_swap_engine,
+ &flow_gen_engine,
+ &rx_only_engine,
+ &tx_only_engine,
+ &csum_fwd_engine,
+ &icmp_echo_engine,
+ &noisy_vnf_engine,
+#if defined RTE_LIBRTE_PMD_SOFTNIC
+ &softnic_fwd_engine,
+#endif
+#ifdef RTE_LIBRTE_IEEE1588
+ &ieee1588_fwd_engine,
+#endif
+ NULL,
+};
+
+struct rte_mempool *mempools[RTE_MAX_NUMA_NODES];
+uint16_t mempool_flags;
+
+struct fwd_config cur_fwd_config;
+struct fwd_engine *cur_fwd_eng = &io_fwd_engine; /**< IO mode by default. */
+uint32_t retry_enabled;
+uint32_t burst_tx_delay_time = BURST_TX_WAIT_US;
+uint32_t burst_tx_retry_num = BURST_TX_RETRIES;
+
+uint16_t mbuf_data_size = DEFAULT_MBUF_DATA_SIZE; /**< Mbuf data space size. */
+uint32_t param_total_num_mbufs = 0; /**< number of mbufs in all pools - if
+ * specified on command-line. */
+uint16_t stats_period; /**< Period to show statistics (disabled by default) */
+
+/*
+ * In container, it cannot terminate the process which running with 'stats-period'
+ * option. Set flag to exit stats period loop after received SIGINT/SIGTERM.
+ */
+uint8_t f_quit;
+
+/*
+ * Configuration of packet segments used by the "txonly" processing engine.
+ */
+uint16_t tx_pkt_length = TXONLY_DEF_PACKET_LEN; /**< TXONLY packet length. */
+uint16_t tx_pkt_seg_lengths[RTE_MAX_SEGS_PER_PKT] = {
+ TXONLY_DEF_PACKET_LEN,
+};
+uint8_t tx_pkt_nb_segs = 1; /**< Number of segments in TXONLY packets */
+
+enum tx_pkt_split tx_pkt_split = TX_PKT_SPLIT_OFF;
+/**< Split policy for packets to TX. */
+
+uint8_t txonly_multi_flow;
+/**< Whether multiple flows are generated in TXONLY mode. */
+
+uint16_t nb_pkt_per_burst = DEF_PKT_BURST; /**< Number of packets per burst. */
+uint16_t mb_mempool_cache = DEF_MBUF_CACHE; /**< Size of mbuf mempool cache. */
+
+/* current configuration is in DCB or not,0 means it is not in DCB mode */
+uint8_t dcb_config = 0;
+
+/* Whether the dcb is in testing status */
+uint8_t dcb_test = 0;
+
+/*
+ * Configurable number of RX/TX queues.
+ */
+queueid_t nb_hairpinq; /**< Number of hairpin queues per port. */
+queueid_t nb_rxq = 1; /**< Number of RX queues per port. */
+queueid_t nb_txq = 1; /**< Number of TX queues per port. */
+
+/*
+ * Configurable number of RX/TX ring descriptors.
+ * Defaults are supplied by drivers via ethdev.
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 0
+#define RTE_TEST_TX_DESC_DEFAULT 0
+uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; /**< Number of RX descriptors. */
+uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; /**< Number of TX descriptors. */
+
+#define RTE_PMD_PARAM_UNSET -1
+/*
+ * Configurable values of RX and TX ring threshold registers.
+ */
+
+int8_t rx_pthresh = RTE_PMD_PARAM_UNSET;
+int8_t rx_hthresh = RTE_PMD_PARAM_UNSET;
+int8_t rx_wthresh = RTE_PMD_PARAM_UNSET;
+
+int8_t tx_pthresh = RTE_PMD_PARAM_UNSET;
+int8_t tx_hthresh = RTE_PMD_PARAM_UNSET;
+int8_t tx_wthresh = RTE_PMD_PARAM_UNSET;
+
+/*
+ * Configurable value of RX free threshold.
+ */
+int16_t rx_free_thresh = RTE_PMD_PARAM_UNSET;
+
+/*
+ * Configurable value of RX drop enable.
+ */
+int8_t rx_drop_en = RTE_PMD_PARAM_UNSET;
+
+/*
+ * Configurable value of TX free threshold.
+ */
+int16_t tx_free_thresh = RTE_PMD_PARAM_UNSET;
+
+/*
+ * Configurable value of TX RS bit threshold.
+ */
+int16_t tx_rs_thresh = RTE_PMD_PARAM_UNSET;
+
+/*
+ * Configurable value of buffered packets before sending.
+ */
+uint16_t noisy_tx_sw_bufsz;
+
+/*
+ * Configurable value of packet buffer timeout.
+ */
+uint16_t noisy_tx_sw_buf_flush_time;
+
+/*
+ * Configurable value for size of VNF internal memory area
+ * used for simulating noisy neighbour behaviour
+ */
+uint64_t noisy_lkup_mem_sz;
+
+/*
+ * Configurable value of number of random writes done in
+ * VNF simulation memory area.
+ */
+uint64_t noisy_lkup_num_writes;
+
+/*
+ * Configurable value of number of random reads done in
+ * VNF simulation memory area.
+ */
+uint64_t noisy_lkup_num_reads;
+
+/*
+ * Configurable value of number of random reads/writes done in
+ * VNF simulation memory area.
+ */
+uint64_t noisy_lkup_num_reads_writes;
+
+/*
+ * Receive Side Scaling (RSS) configuration.
+ */
+uint64_t rss_hf = ETH_RSS_IP; /* RSS IP by default. */
+
+/*
+ * Port topology configuration
+ */
+uint16_t port_topology = PORT_TOPOLOGY_PAIRED; /* Ports are paired by default */
+
+/*
+ * Avoids to flush all the RX streams before starts forwarding.
+ */
+uint8_t no_flush_rx = 0; /* flush by default */
+
+/*
+ * Flow API isolated mode.
+ */
+uint8_t flow_isolate_all;
+
+/*
+ * Avoids to check link status when starting/stopping a port.
+ */
+uint8_t no_link_check = 0; /* check by default */
+
+/*
+ * Don't automatically start all ports in interactive mode.
+ */
+uint8_t no_device_start = 0;
+
+/*
+ * Enable link status change notification
+ */
+uint8_t lsc_interrupt = 1; /* enabled by default */
+
+/*
+ * Enable device removal notification.
+ */
+uint8_t rmv_interrupt = 1; /* enabled by default */
+
+uint8_t hot_plug = 0; /**< hotplug disabled by default. */
+
+/* After attach, port setup is called on event or by iterator */
+bool setup_on_probe_event = true;
+
+/* Clear ptypes on port initialization. */
+uint8_t clear_ptypes = true;
+
+/* Pretty printing of ethdev events */
+static const char * const eth_event_desc[] = {
+ [RTE_ETH_EVENT_UNKNOWN] = "unknown",
+ [RTE_ETH_EVENT_INTR_LSC] = "link state change",
+ [RTE_ETH_EVENT_QUEUE_STATE] = "queue state",
+ [RTE_ETH_EVENT_INTR_RESET] = "reset",
+ [RTE_ETH_EVENT_VF_MBOX] = "VF mbox",
+ [RTE_ETH_EVENT_IPSEC] = "IPsec",
+ [RTE_ETH_EVENT_MACSEC] = "MACsec",
+ [RTE_ETH_EVENT_INTR_RMV] = "device removal",
+ [RTE_ETH_EVENT_NEW] = "device probed",
+ [RTE_ETH_EVENT_DESTROY] = "device released",
+ [RTE_ETH_EVENT_FLOW_AGED] = "flow aged",
+ [RTE_ETH_EVENT_MAX] = NULL,
+};
+
+/*
+ * Display or mask ether events
+ * Default to all events except VF_MBOX
+ */
+uint32_t event_print_mask = (UINT32_C(1) << RTE_ETH_EVENT_UNKNOWN) |
+ (UINT32_C(1) << RTE_ETH_EVENT_INTR_LSC) |
+ (UINT32_C(1) << RTE_ETH_EVENT_QUEUE_STATE) |
+ (UINT32_C(1) << RTE_ETH_EVENT_INTR_RESET) |
+ (UINT32_C(1) << RTE_ETH_EVENT_IPSEC) |
+ (UINT32_C(1) << RTE_ETH_EVENT_MACSEC) |
+ (UINT32_C(1) << RTE_ETH_EVENT_INTR_RMV) |
+ (UINT32_C(1) << RTE_ETH_EVENT_FLOW_AGED);
+/*
+ * Decide if all memory are locked for performance.
+ */
+int do_mlockall = 0;
+
+/*
+ * NIC bypass mode configuration options.
+ */
+
+#if defined RTE_LIBRTE_IXGBE_PMD && defined RTE_LIBRTE_IXGBE_BYPASS
+/* The NIC bypass watchdog timeout. */
+uint32_t bypass_timeout = RTE_PMD_IXGBE_BYPASS_TMT_OFF;
+#endif
+
+
+#ifdef RTE_LIBRTE_LATENCY_STATS
+
+/*
+ * Set when latency stats is enabled in the commandline
+ */
+uint8_t latencystats_enabled;
+
+/*
+ * Lcore ID to serive latency statistics.
+ */
+lcoreid_t latencystats_lcore_id = -1;
+
+#endif
+
+/*
+ * Ethernet device configuration.
+ */
+struct rte_eth_rxmode rx_mode = {
+ .max_rx_pkt_len = RTE_ETHER_MAX_LEN,
+ /**< Default maximum frame length. */
+};
+
+struct rte_eth_txmode tx_mode = {
+ .offloads = DEV_TX_OFFLOAD_MBUF_FAST_FREE,
+};
+
+struct rte_fdir_conf fdir_conf = {
+ .mode = RTE_FDIR_MODE_NONE,
+ .pballoc = RTE_FDIR_PBALLOC_64K,
+ .status = RTE_FDIR_REPORT_STATUS,
+ .mask = {
+ .vlan_tci_mask = 0xFFEF,
+ .ipv4_mask = {
+ .src_ip = 0xFFFFFFFF,
+ .dst_ip = 0xFFFFFFFF,
+ },
+ .ipv6_mask = {
+ .src_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
+ .dst_ip = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
+ },
+ .src_port_mask = 0xFFFF,
+ .dst_port_mask = 0xFFFF,
+ .mac_addr_byte_mask = 0xFF,
+ .tunnel_type_mask = 1,
+ .tunnel_id_mask = 0xFFFFFFFF,
+ },
+ .drop_queue = 127,
+};
+
+volatile int test_done = 1; /* stop packet forwarding when set to 1. */
+
+struct queue_stats_mappings tx_queue_stats_mappings_array[MAX_TX_QUEUE_STATS_MAPPINGS];
+struct queue_stats_mappings rx_queue_stats_mappings_array[MAX_RX_QUEUE_STATS_MAPPINGS];
+
+struct queue_stats_mappings *tx_queue_stats_mappings = tx_queue_stats_mappings_array;
+struct queue_stats_mappings *rx_queue_stats_mappings = rx_queue_stats_mappings_array;
+
+uint16_t nb_tx_queue_stats_mappings = 0;
+uint16_t nb_rx_queue_stats_mappings = 0;
+
+/*
+ * Display zero values by default for xstats
+ */
+uint8_t xstats_hide_zero;
+
+unsigned int num_sockets = 0;
+unsigned int socket_ids[RTE_MAX_NUMA_NODES];
+
+#ifdef RTE_LIBRTE_BITRATE
+/* Bitrate statistics */
+struct rte_stats_bitrates *bitrate_data;
+lcoreid_t bitrate_lcore_id;
+uint8_t bitrate_enabled;
+#endif
+
+struct gro_status gro_ports[RTE_MAX_ETHPORTS];
+uint8_t gro_flush_cycles = GRO_DEFAULT_FLUSH_CYCLES;
+
+/*
+ * hexadecimal bitmask of RX mq mode can be enabled.
+ */
+enum rte_eth_rx_mq_mode rx_mq_mode = ETH_MQ_RX_VMDQ_DCB_RSS;
+
+/* Forward function declarations */
+static void setup_attached_port(portid_t pi);
+static void map_port_queue_stats_mapping_registers(portid_t pi,
+ struct rte_port *port);
+static void check_all_ports_link_status(uint32_t port_mask);
+static int eth_event_callback(portid_t port_id,
+ enum rte_eth_event_type type,
+ void *param, void *ret_param);
+static void dev_event_callback(const char *device_name,
+ enum rte_dev_event_type type,
+ void *param);
+
+/*
+ * Check if all the ports are started.
+ * If yes, return positive value. If not, return zero.
+ */
+static int all_ports_started(void);
+
+struct gso_status gso_ports[RTE_MAX_ETHPORTS];
+uint16_t gso_max_segment_size = RTE_ETHER_MAX_LEN - RTE_ETHER_CRC_LEN;
+
+/* Holds the registered mbuf dynamic flags names. */
+char dynf_names[64][RTE_MBUF_DYN_NAMESIZE];
+
+/*
+ * Helper function to check if socket is already discovered.
+ * If yes, return positive value. If not, return zero.
+ */
+int
+new_socket_id(unsigned int socket_id)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_sockets; i++) {
+ if (socket_ids[i] == socket_id)
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Setup default configuration.
+ */
+static void
+set_default_fwd_lcores_config(void)
+{
+ unsigned int i;
+ unsigned int nb_lc;
+ unsigned int sock_num;
+
+ nb_lc = 0;
+ for (i = 0; i < RTE_MAX_LCORE; i++) {
+ if (!rte_lcore_is_enabled(i))
+ continue;
+ sock_num = rte_lcore_to_socket_id(i);
+ if (new_socket_id(sock_num)) {
+ if (num_sockets >= RTE_MAX_NUMA_NODES) {
+ rte_exit(EXIT_FAILURE,
+ "Total sockets greater than %u\n",
+ RTE_MAX_NUMA_NODES);
+ }
+ socket_ids[num_sockets++] = sock_num;
+ }
+ if (i == rte_get_master_lcore())
+ continue;
+ fwd_lcores_cpuids[nb_lc++] = i;
+ }
+ nb_lcores = (lcoreid_t) nb_lc;
+ nb_cfg_lcores = nb_lcores;
+ nb_fwd_lcores = 1;
+}
+
+static void
+set_def_peer_eth_addrs(void)
+{
+ portid_t i;
+
+ for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+ peer_eth_addrs[i].addr_bytes[0] = RTE_ETHER_LOCAL_ADMIN_ADDR;
+ peer_eth_addrs[i].addr_bytes[5] = i;
+ }
+}
+
+static void
+set_default_fwd_ports_config(void)
+{
+ portid_t pt_id;
+ int i = 0;
+
+ RTE_ETH_FOREACH_DEV(pt_id) {
+ fwd_ports_ids[i++] = pt_id;
+
+ /* Update sockets info according to the attached device */
+ int socket_id = rte_eth_dev_socket_id(pt_id);
+ if (socket_id >= 0 && new_socket_id(socket_id)) {
+ if (num_sockets >= RTE_MAX_NUMA_NODES) {
+ rte_exit(EXIT_FAILURE,
+ "Total sockets greater than %u\n",
+ RTE_MAX_NUMA_NODES);
+ }
+ socket_ids[num_sockets++] = socket_id;
+ }
+ }
+
+ nb_cfg_ports = nb_ports;
+ nb_fwd_ports = nb_ports;
+}
+
+void
+set_def_fwd_config(void)
+{
+ set_default_fwd_lcores_config();
+ set_def_peer_eth_addrs();
+ set_default_fwd_ports_config();
+}
+
+/* extremely pessimistic estimation of memory required to create a mempool */
+static int
+calc_mem_size(uint32_t nb_mbufs, uint32_t mbuf_sz, size_t pgsz, size_t *out)
+{
+ unsigned int n_pages, mbuf_per_pg, leftover;
+ uint64_t total_mem, mbuf_mem, obj_sz;
+
+ /* there is no good way to predict how much space the mempool will
+ * occupy because it will allocate chunks on the fly, and some of those
+ * will come from default DPDK memory while some will come from our
+ * external memory, so just assume 128MB will be enough for everyone.
+ */
+ uint64_t hdr_mem = 128 << 20;
+
+ /* account for possible non-contiguousness */
+ obj_sz = rte_mempool_calc_obj_size(mbuf_sz, 0, NULL);
+ if (obj_sz > pgsz) {
+ TESTPMD_LOG(ERR, "Object size is bigger than page size\n");
+ return -1;
+ }
+
+ mbuf_per_pg = pgsz / obj_sz;
+ leftover = (nb_mbufs % mbuf_per_pg) > 0;
+ n_pages = (nb_mbufs / mbuf_per_pg) + leftover;
+
+ mbuf_mem = n_pages * pgsz;
+
+ total_mem = RTE_ALIGN(hdr_mem + mbuf_mem, pgsz);
+
+ if (total_mem > SIZE_MAX) {
+ TESTPMD_LOG(ERR, "Memory size too big\n");
+ return -1;
+ }
+ *out = (size_t)total_mem;
+
+ return 0;
+}
+
+static int
+pagesz_flags(uint64_t page_sz)
+{
+ /* as per mmap() manpage, all page sizes are log2 of page size
+ * shifted by MAP_HUGE_SHIFT
+ */
+ int log2 = rte_log2_u64(page_sz);
+
+ return (log2 << HUGE_SHIFT);
+}
+
+static void *
+alloc_mem(size_t memsz, size_t pgsz, bool huge)
+{
+ void *addr;
+ int flags;
+
+ /* allocate anonymous hugepages */
+ flags = MAP_ANONYMOUS | MAP_PRIVATE;
+ if (huge)
+ flags |= HUGE_FLAG | pagesz_flags(pgsz);
+
+ addr = mmap(NULL, memsz, PROT_READ | PROT_WRITE, flags, -1, 0);
+ if (addr == MAP_FAILED)
+ return NULL;
+
+ return addr;
+}
+
+struct extmem_param {
+ void *addr;
+ size_t len;
+ size_t pgsz;
+ rte_iova_t *iova_table;
+ unsigned int iova_table_len;
+};
+
+static int
+create_extmem(uint32_t nb_mbufs, uint32_t mbuf_sz, struct extmem_param *param,
+ bool huge)
+{
+ uint64_t pgsizes[] = {RTE_PGSIZE_2M, RTE_PGSIZE_1G, /* x86_64, ARM */
+ RTE_PGSIZE_16M, RTE_PGSIZE_16G}; /* POWER */
+ unsigned int cur_page, n_pages, pgsz_idx;
+ size_t mem_sz, cur_pgsz;
+ rte_iova_t *iovas = NULL;
+ void *addr;
+ int ret;
+
+ for (pgsz_idx = 0; pgsz_idx < RTE_DIM(pgsizes); pgsz_idx++) {
+ /* skip anything that is too big */
+ if (pgsizes[pgsz_idx] > SIZE_MAX)
+ continue;
+
+ cur_pgsz = pgsizes[pgsz_idx];
+
+ /* if we were told not to allocate hugepages, override */
+ if (!huge)
+ cur_pgsz = sysconf(_SC_PAGESIZE);
+
+ ret = calc_mem_size(nb_mbufs, mbuf_sz, cur_pgsz, &mem_sz);
+ if (ret < 0) {
+ TESTPMD_LOG(ERR, "Cannot calculate memory size\n");
+ return -1;
+ }
+
+ /* allocate our memory */
+ addr = alloc_mem(mem_sz, cur_pgsz, huge);
+
+ /* if we couldn't allocate memory with a specified page size,
+ * that doesn't mean we can't do it with other page sizes, so
+ * try another one.
+ */
+ if (addr == NULL)
+ continue;
+
+ /* store IOVA addresses for every page in this memory area */
+ n_pages = mem_sz / cur_pgsz;
+
+ iovas = malloc(sizeof(*iovas) * n_pages);
+
+ if (iovas == NULL) {
+ TESTPMD_LOG(ERR, "Cannot allocate memory for iova addresses\n");
+ goto fail;
+ }
+ /* lock memory if it's not huge pages */
+ if (!huge)
+ mlock(addr, mem_sz);
+
+ /* populate IOVA addresses */
+ for (cur_page = 0; cur_page < n_pages; cur_page++) {
+ rte_iova_t iova;
+ size_t offset;
+ void *cur;
+
+ offset = cur_pgsz * cur_page;
+ cur = RTE_PTR_ADD(addr, offset);
+
+ /* touch the page before getting its IOVA */
+ *(volatile char *)cur = 0;
+
+ iova = rte_mem_virt2iova(cur);
+
+ iovas[cur_page] = iova;
+ }
+
+ break;
+ }
+ /* if we couldn't allocate anything */
+ if (iovas == NULL)
+ return -1;
+
+ param->addr = addr;
+ param->len = mem_sz;
+ param->pgsz = cur_pgsz;
+ param->iova_table = iovas;
+ param->iova_table_len = n_pages;
+
+ return 0;
+fail:
+ if (iovas)
+ free(iovas);
+ if (addr)
+ munmap(addr, mem_sz);
+
+ return -1;
+}
+
+static int
+setup_extmem(uint32_t nb_mbufs, uint32_t mbuf_sz, bool huge)
+{
+ struct extmem_param param;
+ int socket_id, ret;
+
+ memset(&param, 0, sizeof(param));
+
+ /* check if our heap exists */
+ socket_id = rte_malloc_heap_get_socket(EXTMEM_HEAP_NAME);
+ if (socket_id < 0) {
+ /* create our heap */
+ ret = rte_malloc_heap_create(EXTMEM_HEAP_NAME);
+ if (ret < 0) {
+ TESTPMD_LOG(ERR, "Cannot create heap\n");
+ return -1;
+ }
+ }
+
+ ret = create_extmem(nb_mbufs, mbuf_sz, &param, huge);
+ if (ret < 0) {
+ TESTPMD_LOG(ERR, "Cannot create memory area\n");
+ return -1;
+ }
+
+ /* we now have a valid memory area, so add it to heap */
+ ret = rte_malloc_heap_memory_add(EXTMEM_HEAP_NAME,
+ param.addr, param.len, param.iova_table,
+ param.iova_table_len, param.pgsz);
+
+ /* when using VFIO, memory is automatically mapped for DMA by EAL */
+
+ /* not needed any more */
+ free(param.iova_table);
+
+ if (ret < 0) {
+ TESTPMD_LOG(ERR, "Cannot add memory to heap\n");
+ munmap(param.addr, param.len);
+ return -1;
+ }
+
+ /* success */
+
+ TESTPMD_LOG(DEBUG, "Allocated %zuMB of external memory\n",
+ param.len >> 20);
+
+ return 0;
+}
+static void
+dma_unmap_cb(struct rte_mempool *mp __rte_unused, void *opaque __rte_unused,
+ struct rte_mempool_memhdr *memhdr, unsigned mem_idx __rte_unused)
+{
+ uint16_t pid = 0;
+ int ret;
+
+ RTE_ETH_FOREACH_DEV(pid) {
+ struct rte_eth_dev *dev =
+ &rte_eth_devices[pid];
+
+ ret = rte_dev_dma_unmap(dev->device, memhdr->addr, 0,
+ memhdr->len);
+ if (ret) {
+ TESTPMD_LOG(DEBUG,
+ "unable to DMA unmap addr 0x%p "
+ "for device %s\n",
+ memhdr->addr, dev->data->name);
+ }
+ }
+ ret = rte_extmem_unregister(memhdr->addr, memhdr->len);
+ if (ret) {
+ TESTPMD_LOG(DEBUG,
+ "unable to un-register addr 0x%p\n", memhdr->addr);
+ }
+}
+
+static void
+dma_map_cb(struct rte_mempool *mp __rte_unused, void *opaque __rte_unused,
+ struct rte_mempool_memhdr *memhdr, unsigned mem_idx __rte_unused)
+{
+ uint16_t pid = 0;
+ size_t page_size = sysconf(_SC_PAGESIZE);
+ int ret;
+
+ ret = rte_extmem_register(memhdr->addr, memhdr->len, NULL, 0,
+ page_size);
+ if (ret) {
+ TESTPMD_LOG(DEBUG,
+ "unable to register addr 0x%p\n", memhdr->addr);
+ return;
+ }
+ RTE_ETH_FOREACH_DEV(pid) {
+ struct rte_eth_dev *dev =
+ &rte_eth_devices[pid];
+
+ ret = rte_dev_dma_map(dev->device, memhdr->addr, 0,
+ memhdr->len);
+ if (ret) {
+ TESTPMD_LOG(DEBUG,
+ "unable to DMA map addr 0x%p "
+ "for device %s\n",
+ memhdr->addr, dev->data->name);
+ }
+ }
+}
+
+static unsigned int
+setup_extbuf(uint32_t nb_mbufs, uint16_t mbuf_sz, unsigned int socket_id,
+ char *pool_name, struct rte_pktmbuf_extmem **ext_mem)
+{
+ struct rte_pktmbuf_extmem *xmem;
+ unsigned int ext_num, zone_num, elt_num;
+ uint16_t elt_size;
+
+ elt_size = RTE_ALIGN_CEIL(mbuf_sz, RTE_CACHE_LINE_SIZE);
+ elt_num = EXTBUF_ZONE_SIZE / elt_size;
+ zone_num = (nb_mbufs + elt_num - 1) / elt_num;
+
+ xmem = malloc(sizeof(struct rte_pktmbuf_extmem) * zone_num);
+ if (xmem == NULL) {
+ TESTPMD_LOG(ERR, "Cannot allocate memory for "
+ "external buffer descriptors\n");
+ *ext_mem = NULL;
+ return 0;
+ }
+ for (ext_num = 0; ext_num < zone_num; ext_num++) {
+ struct rte_pktmbuf_extmem *xseg = xmem + ext_num;
+ const struct rte_memzone *mz;
+ char mz_name[RTE_MEMZONE_NAMESIZE];
+ int ret;
+
+ ret = snprintf(mz_name, sizeof(mz_name),
+ RTE_MEMPOOL_MZ_FORMAT "_xb_%u", pool_name, ext_num);
+ if (ret < 0 || ret >= (int)sizeof(mz_name)) {
+ errno = ENAMETOOLONG;
+ ext_num = 0;
+ break;
+ }
+ mz = rte_memzone_reserve_aligned(mz_name, EXTBUF_ZONE_SIZE,
+ socket_id,
+ RTE_MEMZONE_IOVA_CONTIG |
+ RTE_MEMZONE_1GB |
+ RTE_MEMZONE_SIZE_HINT_ONLY,
+ EXTBUF_ZONE_SIZE);
+ if (mz == NULL) {
+ /*
+ * The caller exits on external buffer creation
+ * error, so there is no need to free memzones.
+ */
+ errno = ENOMEM;
+ ext_num = 0;
+ break;
+ }
+ xseg->buf_ptr = mz->addr;
+ xseg->buf_iova = mz->iova;
+ xseg->buf_len = EXTBUF_ZONE_SIZE;
+ xseg->elt_size = elt_size;
+ }
+ if (ext_num == 0 && xmem != NULL) {
+ free(xmem);
+ xmem = NULL;
+ }
+ *ext_mem = xmem;
+ return ext_num;
+}
+
+/*
+ * Configuration initialisation done once at init time.
+ */
+static struct rte_mempool *
+mbuf_pool_create(uint16_t mbuf_seg_size, unsigned nb_mbuf,
+ unsigned int socket_id)
+{
+ char pool_name[RTE_MEMPOOL_NAMESIZE];
+ struct rte_mempool *rte_mp = NULL;
+ uint32_t mb_size;
+
+ mb_size = sizeof(struct rte_mbuf) + mbuf_seg_size;
+ mbuf_poolname_build(socket_id, pool_name, sizeof(pool_name));
+
+ TESTPMD_LOG(INFO,
+ "create a new mbuf pool <%s>: n=%u, size=%u, socket=%u\n",
+ pool_name, nb_mbuf, mbuf_seg_size, socket_id);
+
+ switch (mp_alloc_type) {
+ case MP_ALLOC_NATIVE:
+ {
+ /* wrapper to rte_mempool_create() */
+ TESTPMD_LOG(INFO, "preferred mempool ops selected: %s\n",
+ rte_mbuf_best_mempool_ops());
+ rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf,
+ mb_mempool_cache, 0, mbuf_seg_size, socket_id);
+ break;
+ }
+ case MP_ALLOC_ANON:
+ {
+ rte_mp = rte_mempool_create_empty(pool_name, nb_mbuf,
+ mb_size, (unsigned int) mb_mempool_cache,
+ sizeof(struct rte_pktmbuf_pool_private),
+ socket_id, mempool_flags);
+ if (rte_mp == NULL)
+ goto err;
+
+ if (rte_mempool_populate_anon(rte_mp) == 0) {
+ rte_mempool_free(rte_mp);
+ rte_mp = NULL;
+ goto err;
+ }
+ rte_pktmbuf_pool_init(rte_mp, NULL);
+ rte_mempool_obj_iter(rte_mp, rte_pktmbuf_init, NULL);
+ rte_mempool_mem_iter(rte_mp, dma_map_cb, NULL);
+ break;
+ }
+ case MP_ALLOC_XMEM:
+ case MP_ALLOC_XMEM_HUGE:
+ {
+ int heap_socket;
+ bool huge = mp_alloc_type == MP_ALLOC_XMEM_HUGE;
+
+ if (setup_extmem(nb_mbuf, mbuf_seg_size, huge) < 0)
+ rte_exit(EXIT_FAILURE, "Could not create external memory\n");
+
+ heap_socket =
+ rte_malloc_heap_get_socket(EXTMEM_HEAP_NAME);
+ if (heap_socket < 0)
+ rte_exit(EXIT_FAILURE, "Could not get external memory socket ID\n");
+
+ TESTPMD_LOG(INFO, "preferred mempool ops selected: %s\n",
+ rte_mbuf_best_mempool_ops());
+ rte_mp = rte_pktmbuf_pool_create(pool_name, nb_mbuf,
+ mb_mempool_cache, 0, mbuf_seg_size,
+ heap_socket);
+ break;
+ }
+ case MP_ALLOC_XBUF:
+ {
+ struct rte_pktmbuf_extmem *ext_mem;
+ unsigned int ext_num;
+
+ ext_num = setup_extbuf(nb_mbuf, mbuf_seg_size,
+ socket_id, pool_name, &ext_mem);
+ if (ext_num == 0)
+ rte_exit(EXIT_FAILURE,
+ "Can't create pinned data buffers\n");
+
+ TESTPMD_LOG(INFO, "preferred mempool ops selected: %s\n",
+ rte_mbuf_best_mempool_ops());
+ rte_mp = rte_pktmbuf_pool_create_extbuf
+ (pool_name, nb_mbuf, mb_mempool_cache,
+ 0, mbuf_seg_size, socket_id,
+ ext_mem, ext_num);
+ free(ext_mem);
+ break;
+ }
+ default:
+ {
+ rte_exit(EXIT_FAILURE, "Invalid mempool creation mode\n");
+ }
+ }
+
+err:
+ if (rte_mp == NULL) {
+ rte_exit(EXIT_FAILURE,
+ "Creation of mbuf pool for socket %u failed: %s\n",
+ socket_id, rte_strerror(rte_errno));
+ } else if (verbose_level > 0) {
+ rte_mempool_dump(stdout, rte_mp);
+ }
+ return rte_mp;
+}
+
+/*
+ * Check given socket id is valid or not with NUMA mode,
+ * if valid, return 0, else return -1
+ */
+static int
+check_socket_id(const unsigned int socket_id)
+{
+ static int warning_once = 0;
+
+ if (new_socket_id(socket_id)) {
+ if (!warning_once && numa_support)
+ printf("Warning: NUMA should be configured manually by"
+ " using --port-numa-config and"
+ " --ring-numa-config parameters along with"
+ " --numa.\n");
+ warning_once = 1;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Get the allowed maximum number of RX queues.
+ * *pid return the port id which has minimal value of
+ * max_rx_queues in all ports.
+ */
+queueid_t
+get_allowed_max_nb_rxq(portid_t *pid)
+{
+ queueid_t allowed_max_rxq = RTE_MAX_QUEUES_PER_PORT;
+ bool max_rxq_valid = false;
+ portid_t pi;
+ struct rte_eth_dev_info dev_info;
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (eth_dev_info_get_print_err(pi, &dev_info) != 0)
+ continue;
+
+ max_rxq_valid = true;
+ if (dev_info.max_rx_queues < allowed_max_rxq) {
+ allowed_max_rxq = dev_info.max_rx_queues;
+ *pid = pi;
+ }
+ }
+ return max_rxq_valid ? allowed_max_rxq : 0;
+}
+
+/*
+ * Check input rxq is valid or not.
+ * If input rxq is not greater than any of maximum number
+ * of RX queues of all ports, it is valid.
+ * if valid, return 0, else return -1
+ */
+int
+check_nb_rxq(queueid_t rxq)
+{
+ queueid_t allowed_max_rxq;
+ portid_t pid = 0;
+
+ allowed_max_rxq = get_allowed_max_nb_rxq(&pid);
+ if (rxq > allowed_max_rxq) {
+ printf("Fail: input rxq (%u) can't be greater "
+ "than max_rx_queues (%u) of port %u\n",
+ rxq,
+ allowed_max_rxq,
+ pid);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Get the allowed maximum number of TX queues.
+ * *pid return the port id which has minimal value of
+ * max_tx_queues in all ports.
+ */
+queueid_t
+get_allowed_max_nb_txq(portid_t *pid)
+{
+ queueid_t allowed_max_txq = RTE_MAX_QUEUES_PER_PORT;
+ bool max_txq_valid = false;
+ portid_t pi;
+ struct rte_eth_dev_info dev_info;
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (eth_dev_info_get_print_err(pi, &dev_info) != 0)
+ continue;
+
+ max_txq_valid = true;
+ if (dev_info.max_tx_queues < allowed_max_txq) {
+ allowed_max_txq = dev_info.max_tx_queues;
+ *pid = pi;
+ }
+ }
+ return max_txq_valid ? allowed_max_txq : 0;
+}
+
+/*
+ * Check input txq is valid or not.
+ * If input txq is not greater than any of maximum number
+ * of TX queues of all ports, it is valid.
+ * if valid, return 0, else return -1
+ */
+int
+check_nb_txq(queueid_t txq)
+{
+ queueid_t allowed_max_txq;
+ portid_t pid = 0;
+
+ allowed_max_txq = get_allowed_max_nb_txq(&pid);
+ if (txq > allowed_max_txq) {
+ printf("Fail: input txq (%u) can't be greater "
+ "than max_tx_queues (%u) of port %u\n",
+ txq,
+ allowed_max_txq,
+ pid);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Get the allowed maximum number of RXDs of every rx queue.
+ * *pid return the port id which has minimal value of
+ * max_rxd in all queues of all ports.
+ */
+static uint16_t
+get_allowed_max_nb_rxd(portid_t *pid)
+{
+ uint16_t allowed_max_rxd = UINT16_MAX;
+ portid_t pi;
+ struct rte_eth_dev_info dev_info;
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (eth_dev_info_get_print_err(pi, &dev_info) != 0)
+ continue;
+
+ if (dev_info.rx_desc_lim.nb_max < allowed_max_rxd) {
+ allowed_max_rxd = dev_info.rx_desc_lim.nb_max;
+ *pid = pi;
+ }
+ }
+ return allowed_max_rxd;
+}
+
+/*
+ * Get the allowed minimal number of RXDs of every rx queue.
+ * *pid return the port id which has minimal value of
+ * min_rxd in all queues of all ports.
+ */
+static uint16_t
+get_allowed_min_nb_rxd(portid_t *pid)
+{
+ uint16_t allowed_min_rxd = 0;
+ portid_t pi;
+ struct rte_eth_dev_info dev_info;
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (eth_dev_info_get_print_err(pi, &dev_info) != 0)
+ continue;
+
+ if (dev_info.rx_desc_lim.nb_min > allowed_min_rxd) {
+ allowed_min_rxd = dev_info.rx_desc_lim.nb_min;
+ *pid = pi;
+ }
+ }
+
+ return allowed_min_rxd;
+}
+
+/*
+ * Check input rxd is valid or not.
+ * If input rxd is not greater than any of maximum number
+ * of RXDs of every Rx queues and is not less than any of
+ * minimal number of RXDs of every Rx queues, it is valid.
+ * if valid, return 0, else return -1
+ */
+int
+check_nb_rxd(queueid_t rxd)
+{
+ uint16_t allowed_max_rxd;
+ uint16_t allowed_min_rxd;
+ portid_t pid = 0;
+
+ allowed_max_rxd = get_allowed_max_nb_rxd(&pid);
+ if (rxd > allowed_max_rxd) {
+ printf("Fail: input rxd (%u) can't be greater "
+ "than max_rxds (%u) of port %u\n",
+ rxd,
+ allowed_max_rxd,
+ pid);
+ return -1;
+ }
+
+ allowed_min_rxd = get_allowed_min_nb_rxd(&pid);
+ if (rxd < allowed_min_rxd) {
+ printf("Fail: input rxd (%u) can't be less "
+ "than min_rxds (%u) of port %u\n",
+ rxd,
+ allowed_min_rxd,
+ pid);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Get the allowed maximum number of TXDs of every rx queues.
+ * *pid return the port id which has minimal value of
+ * max_txd in every tx queue.
+ */
+static uint16_t
+get_allowed_max_nb_txd(portid_t *pid)
+{
+ uint16_t allowed_max_txd = UINT16_MAX;
+ portid_t pi;
+ struct rte_eth_dev_info dev_info;
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (eth_dev_info_get_print_err(pi, &dev_info) != 0)
+ continue;
+
+ if (dev_info.tx_desc_lim.nb_max < allowed_max_txd) {
+ allowed_max_txd = dev_info.tx_desc_lim.nb_max;
+ *pid = pi;
+ }
+ }
+ return allowed_max_txd;
+}
+
+/*
+ * Get the allowed maximum number of TXDs of every tx queues.
+ * *pid return the port id which has minimal value of
+ * min_txd in every tx queue.
+ */
+static uint16_t
+get_allowed_min_nb_txd(portid_t *pid)
+{
+ uint16_t allowed_min_txd = 0;
+ portid_t pi;
+ struct rte_eth_dev_info dev_info;
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (eth_dev_info_get_print_err(pi, &dev_info) != 0)
+ continue;
+
+ if (dev_info.tx_desc_lim.nb_min > allowed_min_txd) {
+ allowed_min_txd = dev_info.tx_desc_lim.nb_min;
+ *pid = pi;
+ }
+ }
+
+ return allowed_min_txd;
+}
+
+/*
+ * Check input txd is valid or not.
+ * If input txd is not greater than any of maximum number
+ * of TXDs of every Rx queues, it is valid.
+ * if valid, return 0, else return -1
+ */
+int
+check_nb_txd(queueid_t txd)
+{
+ uint16_t allowed_max_txd;
+ uint16_t allowed_min_txd;
+ portid_t pid = 0;
+
+ allowed_max_txd = get_allowed_max_nb_txd(&pid);
+ if (txd > allowed_max_txd) {
+ printf("Fail: input txd (%u) can't be greater "
+ "than max_txds (%u) of port %u\n",
+ txd,
+ allowed_max_txd,
+ pid);
+ return -1;
+ }
+
+ allowed_min_txd = get_allowed_min_nb_txd(&pid);
+ if (txd < allowed_min_txd) {
+ printf("Fail: input txd (%u) can't be less "
+ "than min_txds (%u) of port %u\n",
+ txd,
+ allowed_min_txd,
+ pid);
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+ * Get the allowed maximum number of hairpin queues.
+ * *pid return the port id which has minimal value of
+ * max_hairpin_queues in all ports.
+ */
+queueid_t
+get_allowed_max_nb_hairpinq(portid_t *pid)
+{
+ queueid_t allowed_max_hairpinq = RTE_MAX_QUEUES_PER_PORT;
+ portid_t pi;
+ struct rte_eth_hairpin_cap cap;
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (rte_eth_dev_hairpin_capability_get(pi, &cap) != 0) {
+ *pid = pi;
+ return 0;
+ }
+ if (cap.max_nb_queues < allowed_max_hairpinq) {
+ allowed_max_hairpinq = cap.max_nb_queues;
+ *pid = pi;
+ }
+ }
+ return allowed_max_hairpinq;
+}
+
+/*
+ * Check input hairpin is valid or not.
+ * If input hairpin is not greater than any of maximum number
+ * of hairpin queues of all ports, it is valid.
+ * if valid, return 0, else return -1
+ */
+int
+check_nb_hairpinq(queueid_t hairpinq)
+{
+ queueid_t allowed_max_hairpinq;
+ portid_t pid = 0;
+
+ allowed_max_hairpinq = get_allowed_max_nb_hairpinq(&pid);
+ if (hairpinq > allowed_max_hairpinq) {
+ printf("Fail: input hairpin (%u) can't be greater "
+ "than max_hairpin_queues (%u) of port %u\n",
+ hairpinq, allowed_max_hairpinq, pid);
+ return -1;
+ }
+ return 0;
+}
+
+static void
+init_config(void)
+{
+ portid_t pid;
+ struct rte_port *port;
+ struct rte_mempool *mbp;
+ unsigned int nb_mbuf_per_pool;
+ lcoreid_t lc_id;
+ uint8_t port_per_socket[RTE_MAX_NUMA_NODES];
+ struct rte_gro_param gro_param;
+ uint32_t gso_types;
+ uint16_t data_size;
+ bool warning = 0;
+ int k;
+ int ret;
+
+ memset(port_per_socket,0,RTE_MAX_NUMA_NODES);
+
+ /* Configuration of logical cores. */
+ fwd_lcores = rte_zmalloc("testpmd: fwd_lcores",
+ sizeof(struct fwd_lcore *) * nb_lcores,
+ RTE_CACHE_LINE_SIZE);
+ if (fwd_lcores == NULL) {
+ rte_exit(EXIT_FAILURE, "rte_zmalloc(%d (struct fwd_lcore *)) "
+ "failed\n", nb_lcores);
+ }
+ for (lc_id = 0; lc_id < nb_lcores; lc_id++) {
+ fwd_lcores[lc_id] = rte_zmalloc("testpmd: struct fwd_lcore",
+ sizeof(struct fwd_lcore),
+ RTE_CACHE_LINE_SIZE);
+ if (fwd_lcores[lc_id] == NULL) {
+ rte_exit(EXIT_FAILURE, "rte_zmalloc(struct fwd_lcore) "
+ "failed\n");
+ }
+ fwd_lcores[lc_id]->cpuid_idx = lc_id;
+ }
+
+ RTE_ETH_FOREACH_DEV(pid) {
+ port = &ports[pid];
+ /* Apply default TxRx configuration for all ports */
+ port->dev_conf.txmode = tx_mode;
+ port->dev_conf.rxmode = rx_mode;
+
+ ret = eth_dev_info_get_print_err(pid, &port->dev_info);
+ if (ret != 0)
+ rte_exit(EXIT_FAILURE,
+ "rte_eth_dev_info_get() failed\n");
+
+ if (!(port->dev_info.tx_offload_capa &
+ DEV_TX_OFFLOAD_MBUF_FAST_FREE))
+ port->dev_conf.txmode.offloads &=
+ ~DEV_TX_OFFLOAD_MBUF_FAST_FREE;
+ if (numa_support) {
+ if (port_numa[pid] != NUMA_NO_CONFIG)
+ port_per_socket[port_numa[pid]]++;
+ else {
+ uint32_t socket_id = rte_eth_dev_socket_id(pid);
+
+ /*
+ * if socket_id is invalid,
+ * set to the first available socket.
+ */
+ if (check_socket_id(socket_id) < 0)
+ socket_id = socket_ids[0];
+ port_per_socket[socket_id]++;
+ }
+ }
+
+ /* Apply Rx offloads configuration */
+ for (k = 0; k < port->dev_info.max_rx_queues; k++)
+ port->rx_conf[k].offloads =
+ port->dev_conf.rxmode.offloads;
+ /* Apply Tx offloads configuration */
+ for (k = 0; k < port->dev_info.max_tx_queues; k++)
+ port->tx_conf[k].offloads =
+ port->dev_conf.txmode.offloads;
+
+ /* set flag to initialize port/queue */
+ port->need_reconfig = 1;
+ port->need_reconfig_queues = 1;
+ port->tx_metadata = 0;
+
+ /* Check for maximum number of segments per MTU. Accordingly
+ * update the mbuf data size.
+ */
+ if (port->dev_info.rx_desc_lim.nb_mtu_seg_max != UINT16_MAX &&
+ port->dev_info.rx_desc_lim.nb_mtu_seg_max != 0) {
+ data_size = rx_mode.max_rx_pkt_len /
+ port->dev_info.rx_desc_lim.nb_mtu_seg_max;
+
+ if ((data_size + RTE_PKTMBUF_HEADROOM) >
+ mbuf_data_size) {
+ mbuf_data_size = data_size +
+ RTE_PKTMBUF_HEADROOM;
+ warning = 1;
+ }
+ }
+ }
+
+ if (warning)
+ TESTPMD_LOG(WARNING, "Configured mbuf size %hu\n",
+ mbuf_data_size);
+
+ /*
+ * Create pools of mbuf.
+ * If NUMA support is disabled, create a single pool of mbuf in
+ * socket 0 memory by default.
+ * Otherwise, create a pool of mbuf in the memory of sockets 0 and 1.
+ *
+ * Use the maximum value of nb_rxd and nb_txd here, then nb_rxd and
+ * nb_txd can be configured at run time.
+ */
+ if (param_total_num_mbufs)
+ nb_mbuf_per_pool = param_total_num_mbufs;
+ else {
+ nb_mbuf_per_pool = RTE_TEST_RX_DESC_MAX +
+ (nb_lcores * mb_mempool_cache) +
+ RTE_TEST_TX_DESC_MAX + MAX_PKT_BURST;
+ nb_mbuf_per_pool *= RTE_MAX_ETHPORTS;
+ }
+
+ if (numa_support) {
+ uint8_t i;
+
+ for (i = 0; i < num_sockets; i++)
+ mempools[i] = mbuf_pool_create(mbuf_data_size,
+ nb_mbuf_per_pool,
+ socket_ids[i]);
+ } else {
+ if (socket_num == UMA_NO_CONFIG)
+ mempools[0] = mbuf_pool_create(mbuf_data_size,
+ nb_mbuf_per_pool, 0);
+ else
+ mempools[socket_num] = mbuf_pool_create
+ (mbuf_data_size,
+ nb_mbuf_per_pool,
+ socket_num);
+ }
+
+ init_port_config();
+
+ gso_types = DEV_TX_OFFLOAD_TCP_TSO | DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
+ DEV_TX_OFFLOAD_GRE_TNL_TSO | DEV_TX_OFFLOAD_UDP_TSO;
+ /*
+ * Records which Mbuf pool to use by each logical core, if needed.
+ */
+ for (lc_id = 0; lc_id < nb_lcores; lc_id++) {
+ mbp = mbuf_pool_find(
+ rte_lcore_to_socket_id(fwd_lcores_cpuids[lc_id]));
+
+ if (mbp == NULL)
+ mbp = mbuf_pool_find(0);
+ fwd_lcores[lc_id]->mbp = mbp;
+ /* initialize GSO context */
+ fwd_lcores[lc_id]->gso_ctx.direct_pool = mbp;
+ fwd_lcores[lc_id]->gso_ctx.indirect_pool = mbp;
+ fwd_lcores[lc_id]->gso_ctx.gso_types = gso_types;
+ fwd_lcores[lc_id]->gso_ctx.gso_size = RTE_ETHER_MAX_LEN -
+ RTE_ETHER_CRC_LEN;
+ fwd_lcores[lc_id]->gso_ctx.flag = 0;
+ }
+
+ /* Configuration of packet forwarding streams. */
+ if (init_fwd_streams() < 0)
+ rte_exit(EXIT_FAILURE, "FAIL from init_fwd_streams()\n");
+
+ fwd_config_setup();
+
+ /* create a gro context for each lcore */
+ gro_param.gro_types = RTE_GRO_TCP_IPV4;
+ gro_param.max_flow_num = GRO_MAX_FLUSH_CYCLES;
+ gro_param.max_item_per_flow = MAX_PKT_BURST;
+ for (lc_id = 0; lc_id < nb_lcores; lc_id++) {
+ gro_param.socket_id = rte_lcore_to_socket_id(
+ fwd_lcores_cpuids[lc_id]);
+ fwd_lcores[lc_id]->gro_ctx = rte_gro_ctx_create(&gro_param);
+ if (fwd_lcores[lc_id]->gro_ctx == NULL) {
+ rte_exit(EXIT_FAILURE,
+ "rte_gro_ctx_create() failed\n");
+ }
+ }
+
+#if defined RTE_LIBRTE_PMD_SOFTNIC
+ if (strcmp(cur_fwd_eng->fwd_mode_name, "softnic") == 0) {
+ RTE_ETH_FOREACH_DEV(pid) {
+ port = &ports[pid];
+ const char *driver = port->dev_info.driver_name;
+
+ if (strcmp(driver, "net_softnic") == 0)
+ port->softport.fwd_lcore_arg = fwd_lcores;
+ }
+ }
+#endif
+
+}
+
+
+void
+reconfig(portid_t new_port_id, unsigned socket_id)
+{
+ struct rte_port *port;
+ int ret;
+
+ /* Reconfiguration of Ethernet ports. */
+ port = &ports[new_port_id];
+
+ ret = eth_dev_info_get_print_err(new_port_id, &port->dev_info);
+ if (ret != 0)
+ return;
+
+ /* set flag to initialize port/queue */
+ port->need_reconfig = 1;
+ port->need_reconfig_queues = 1;
+ port->socket_id = socket_id;
+
+ init_port_config();
+}
+
+
+int
+init_fwd_streams(void)
+{
+ portid_t pid;
+ struct rte_port *port;
+ streamid_t sm_id, nb_fwd_streams_new;
+ queueid_t q;
+
+ /* set socket id according to numa or not */
+ RTE_ETH_FOREACH_DEV(pid) {
+ port = &ports[pid];
+ if (nb_rxq > port->dev_info.max_rx_queues) {
+ printf("Fail: nb_rxq(%d) is greater than "
+ "max_rx_queues(%d)\n", nb_rxq,
+ port->dev_info.max_rx_queues);
+ return -1;
+ }
+ if (nb_txq > port->dev_info.max_tx_queues) {
+ printf("Fail: nb_txq(%d) is greater than "
+ "max_tx_queues(%d)\n", nb_txq,
+ port->dev_info.max_tx_queues);
+ return -1;
+ }
+ if (numa_support) {
+ if (port_numa[pid] != NUMA_NO_CONFIG)
+ port->socket_id = port_numa[pid];
+ else {
+ port->socket_id = rte_eth_dev_socket_id(pid);
+
+ /*
+ * if socket_id is invalid,
+ * set to the first available socket.
+ */
+ if (check_socket_id(port->socket_id) < 0)
+ port->socket_id = socket_ids[0];
+ }
+ }
+ else {
+ if (socket_num == UMA_NO_CONFIG)
+ port->socket_id = 0;
+ else
+ port->socket_id = socket_num;
+ }
+ }
+
+ q = RTE_MAX(nb_rxq, nb_txq);
+ if (q == 0) {
+ printf("Fail: Cannot allocate fwd streams as number of queues is 0\n");
+ return -1;
+ }
+ nb_fwd_streams_new = (streamid_t)(nb_ports * q);
+ if (nb_fwd_streams_new == nb_fwd_streams)
+ return 0;
+ /* clear the old */
+ if (fwd_streams != NULL) {
+ for (sm_id = 0; sm_id < nb_fwd_streams; sm_id++) {
+ if (fwd_streams[sm_id] == NULL)
+ continue;
+ rte_free(fwd_streams[sm_id]);
+ fwd_streams[sm_id] = NULL;
+ }
+ rte_free(fwd_streams);
+ fwd_streams = NULL;
+ }
+
+ /* init new */
+ nb_fwd_streams = nb_fwd_streams_new;
+ if (nb_fwd_streams) {
+ fwd_streams = rte_zmalloc("testpmd: fwd_streams",
+ sizeof(struct fwd_stream *) * nb_fwd_streams,
+ RTE_CACHE_LINE_SIZE);
+ if (fwd_streams == NULL)
+ rte_exit(EXIT_FAILURE, "rte_zmalloc(%d"
+ " (struct fwd_stream *)) failed\n",
+ nb_fwd_streams);
+
+ for (sm_id = 0; sm_id < nb_fwd_streams; sm_id++) {
+ fwd_streams[sm_id] = rte_zmalloc("testpmd:"
+ " struct fwd_stream", sizeof(struct fwd_stream),
+ RTE_CACHE_LINE_SIZE);
+ if (fwd_streams[sm_id] == NULL)
+ rte_exit(EXIT_FAILURE, "rte_zmalloc"
+ "(struct fwd_stream) failed\n");
+ }
+ }
+
+ return 0;
+}
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+static void
+pkt_burst_stats_display(const char *rx_tx, struct pkt_burst_stats *pbs)
+{
+ unsigned int total_burst;
+ unsigned int nb_burst;
+ unsigned int burst_stats[3];
+ uint16_t pktnb_stats[3];
+ uint16_t nb_pkt;
+ int burst_percent[3];
+
+ /*
+ * First compute the total number of packet bursts and the
+ * two highest numbers of bursts of the same number of packets.
+ */
+ total_burst = 0;
+ burst_stats[0] = burst_stats[1] = burst_stats[2] = 0;
+ pktnb_stats[0] = pktnb_stats[1] = pktnb_stats[2] = 0;
+ for (nb_pkt = 0; nb_pkt < MAX_PKT_BURST; nb_pkt++) {
+ nb_burst = pbs->pkt_burst_spread[nb_pkt];
+ if (nb_burst == 0)
+ continue;
+ total_burst += nb_burst;
+ if (nb_burst > burst_stats[0]) {
+ burst_stats[1] = burst_stats[0];
+ pktnb_stats[1] = pktnb_stats[0];
+ burst_stats[0] = nb_burst;
+ pktnb_stats[0] = nb_pkt;
+ } else if (nb_burst > burst_stats[1]) {
+ burst_stats[1] = nb_burst;
+ pktnb_stats[1] = nb_pkt;
+ }
+ }
+ if (total_burst == 0)
+ return;
+ burst_percent[0] = (burst_stats[0] * 100) / total_burst;
+ printf(" %s-bursts : %u [%d%% of %d pkts", rx_tx, total_burst,
+ burst_percent[0], (int) pktnb_stats[0]);
+ if (burst_stats[0] == total_burst) {
+ printf("]\n");
+ return;
+ }
+ if (burst_stats[0] + burst_stats[1] == total_burst) {
+ printf(" + %d%% of %d pkts]\n",
+ 100 - burst_percent[0], pktnb_stats[1]);
+ return;
+ }
+ burst_percent[1] = (burst_stats[1] * 100) / total_burst;
+ burst_percent[2] = 100 - (burst_percent[0] + burst_percent[1]);
+ if ((burst_percent[1] == 0) || (burst_percent[2] == 0)) {
+ printf(" + %d%% of others]\n", 100 - burst_percent[0]);
+ return;
+ }
+ printf(" + %d%% of %d pkts + %d%% of others]\n",
+ burst_percent[1], (int) pktnb_stats[1], burst_percent[2]);
+}
+#endif /* RTE_TEST_PMD_RECORD_BURST_STATS */
+
+static void
+fwd_stream_stats_display(streamid_t stream_id)
+{
+ struct fwd_stream *fs;
+ static const char *fwd_top_stats_border = "-------";
+
+ fs = fwd_streams[stream_id];
+ if ((fs->rx_packets == 0) && (fs->tx_packets == 0) &&
+ (fs->fwd_dropped == 0))
+ return;
+ printf("\n %s Forward Stats for RX Port=%2d/Queue=%2d -> "
+ "TX Port=%2d/Queue=%2d %s\n",
+ fwd_top_stats_border, fs->rx_port, fs->rx_queue,
+ fs->tx_port, fs->tx_queue, fwd_top_stats_border);
+ printf(" RX-packets: %-14"PRIu64" TX-packets: %-14"PRIu64
+ " TX-dropped: %-14"PRIu64,
+ fs->rx_packets, fs->tx_packets, fs->fwd_dropped);
+
+ /* if checksum mode */
+ if (cur_fwd_eng == &csum_fwd_engine) {
+ printf(" RX- bad IP checksum: %-14"PRIu64
+ " Rx- bad L4 checksum: %-14"PRIu64
+ " Rx- bad outer L4 checksum: %-14"PRIu64"\n",
+ fs->rx_bad_ip_csum, fs->rx_bad_l4_csum,
+ fs->rx_bad_outer_l4_csum);
+ } else {
+ printf("\n");
+ }
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ pkt_burst_stats_display("RX", &fs->rx_burst_stats);
+ pkt_burst_stats_display("TX", &fs->tx_burst_stats);
+#endif
+}
+
+void
+fwd_stats_display(void)
+{
+ static const char *fwd_stats_border = "----------------------";
+ static const char *acc_stats_border = "+++++++++++++++";
+ struct {
+ struct fwd_stream *rx_stream;
+ struct fwd_stream *tx_stream;
+ uint64_t tx_dropped;
+ uint64_t rx_bad_ip_csum;
+ uint64_t rx_bad_l4_csum;
+ uint64_t rx_bad_outer_l4_csum;
+ } ports_stats[RTE_MAX_ETHPORTS];
+ uint64_t total_rx_dropped = 0;
+ uint64_t total_tx_dropped = 0;
+ uint64_t total_rx_nombuf = 0;
+ struct rte_eth_stats stats;
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ uint64_t fwd_cycles = 0;
+#endif
+ uint64_t total_recv = 0;
+ uint64_t total_xmit = 0;
+ struct rte_port *port;
+ streamid_t sm_id;
+ portid_t pt_id;
+ int i;
+
+ memset(ports_stats, 0, sizeof(ports_stats));
+
+ for (sm_id = 0; sm_id < cur_fwd_config.nb_fwd_streams; sm_id++) {
+ struct fwd_stream *fs = fwd_streams[sm_id];
+
+ if (cur_fwd_config.nb_fwd_streams >
+ cur_fwd_config.nb_fwd_ports) {
+ fwd_stream_stats_display(sm_id);
+ } else {
+ ports_stats[fs->tx_port].tx_stream = fs;
+ ports_stats[fs->rx_port].rx_stream = fs;
+ }
+
+ ports_stats[fs->tx_port].tx_dropped += fs->fwd_dropped;
+
+ ports_stats[fs->rx_port].rx_bad_ip_csum += fs->rx_bad_ip_csum;
+ ports_stats[fs->rx_port].rx_bad_l4_csum += fs->rx_bad_l4_csum;
+ ports_stats[fs->rx_port].rx_bad_outer_l4_csum +=
+ fs->rx_bad_outer_l4_csum;
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ fwd_cycles += fs->core_cycles;
+#endif
+ }
+ for (i = 0; i < cur_fwd_config.nb_fwd_ports; i++) {
+ uint8_t j;
+
+ pt_id = fwd_ports_ids[i];
+ port = &ports[pt_id];
+
+ rte_eth_stats_get(pt_id, &stats);
+ stats.ipackets -= port->stats.ipackets;
+ stats.opackets -= port->stats.opackets;
+ stats.ibytes -= port->stats.ibytes;
+ stats.obytes -= port->stats.obytes;
+ stats.imissed -= port->stats.imissed;
+ stats.oerrors -= port->stats.oerrors;
+ stats.rx_nombuf -= port->stats.rx_nombuf;
+
+ total_recv += stats.ipackets;
+ total_xmit += stats.opackets;
+ total_rx_dropped += stats.imissed;
+ total_tx_dropped += ports_stats[pt_id].tx_dropped;
+ total_tx_dropped += stats.oerrors;
+ total_rx_nombuf += stats.rx_nombuf;
+
+ printf("\n %s Forward statistics for port %-2d %s\n",
+ fwd_stats_border, pt_id, fwd_stats_border);
+
+ if (!port->rx_queue_stats_mapping_enabled &&
+ !port->tx_queue_stats_mapping_enabled) {
+ printf(" RX-packets: %-14"PRIu64
+ " RX-dropped: %-14"PRIu64
+ "RX-total: %-"PRIu64"\n",
+ stats.ipackets, stats.imissed,
+ stats.ipackets + stats.imissed);
+
+ if (cur_fwd_eng == &csum_fwd_engine)
+ printf(" Bad-ipcsum: %-14"PRIu64
+ " Bad-l4csum: %-14"PRIu64
+ "Bad-outer-l4csum: %-14"PRIu64"\n",
+ ports_stats[pt_id].rx_bad_ip_csum,
+ ports_stats[pt_id].rx_bad_l4_csum,
+ ports_stats[pt_id].rx_bad_outer_l4_csum);
+ if (stats.ierrors + stats.rx_nombuf > 0) {
+ printf(" RX-error: %-"PRIu64"\n",
+ stats.ierrors);
+ printf(" RX-nombufs: %-14"PRIu64"\n",
+ stats.rx_nombuf);
+ }
+
+ printf(" TX-packets: %-14"PRIu64
+ " TX-dropped: %-14"PRIu64
+ "TX-total: %-"PRIu64"\n",
+ stats.opackets, ports_stats[pt_id].tx_dropped,
+ stats.opackets + ports_stats[pt_id].tx_dropped);
+ } else {
+ printf(" RX-packets: %14"PRIu64
+ " RX-dropped:%14"PRIu64
+ " RX-total:%14"PRIu64"\n",
+ stats.ipackets, stats.imissed,
+ stats.ipackets + stats.imissed);
+
+ if (cur_fwd_eng == &csum_fwd_engine)
+ printf(" Bad-ipcsum:%14"PRIu64
+ " Bad-l4csum:%14"PRIu64
+ " Bad-outer-l4csum: %-14"PRIu64"\n",
+ ports_stats[pt_id].rx_bad_ip_csum,
+ ports_stats[pt_id].rx_bad_l4_csum,
+ ports_stats[pt_id].rx_bad_outer_l4_csum);
+ if ((stats.ierrors + stats.rx_nombuf) > 0) {
+ printf(" RX-error:%"PRIu64"\n", stats.ierrors);
+ printf(" RX-nombufs: %14"PRIu64"\n",
+ stats.rx_nombuf);
+ }
+
+ printf(" TX-packets: %14"PRIu64
+ " TX-dropped:%14"PRIu64
+ " TX-total:%14"PRIu64"\n",
+ stats.opackets, ports_stats[pt_id].tx_dropped,
+ stats.opackets + ports_stats[pt_id].tx_dropped);
+ }
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ if (ports_stats[pt_id].rx_stream)
+ pkt_burst_stats_display("RX",
+ &ports_stats[pt_id].rx_stream->rx_burst_stats);
+ if (ports_stats[pt_id].tx_stream)
+ pkt_burst_stats_display("TX",
+ &ports_stats[pt_id].tx_stream->tx_burst_stats);
+#endif
+
+ if (port->rx_queue_stats_mapping_enabled) {
+ printf("\n");
+ for (j = 0; j < RTE_ETHDEV_QUEUE_STAT_CNTRS; j++) {
+ printf(" Stats reg %2d RX-packets:%14"PRIu64
+ " RX-errors:%14"PRIu64
+ " RX-bytes:%14"PRIu64"\n",
+ j, stats.q_ipackets[j],
+ stats.q_errors[j], stats.q_ibytes[j]);
+ }
+ printf("\n");
+ }
+ if (port->tx_queue_stats_mapping_enabled) {
+ for (j = 0; j < RTE_ETHDEV_QUEUE_STAT_CNTRS; j++) {
+ printf(" Stats reg %2d TX-packets:%14"PRIu64
+ " TX-bytes:%14"
+ PRIu64"\n",
+ j, stats.q_opackets[j],
+ stats.q_obytes[j]);
+ }
+ }
+
+ printf(" %s--------------------------------%s\n",
+ fwd_stats_border, fwd_stats_border);
+ }
+
+ printf("\n %s Accumulated forward statistics for all ports"
+ "%s\n",
+ acc_stats_border, acc_stats_border);
+ printf(" RX-packets: %-14"PRIu64" RX-dropped: %-14"PRIu64"RX-total: "
+ "%-"PRIu64"\n"
+ " TX-packets: %-14"PRIu64" TX-dropped: %-14"PRIu64"TX-total: "
+ "%-"PRIu64"\n",
+ total_recv, total_rx_dropped, total_recv + total_rx_dropped,
+ total_xmit, total_tx_dropped, total_xmit + total_tx_dropped);
+ if (total_rx_nombuf > 0)
+ printf(" RX-nombufs: %-14"PRIu64"\n", total_rx_nombuf);
+ printf(" %s++++++++++++++++++++++++++++++++++++++++++++++"
+ "%s\n",
+ acc_stats_border, acc_stats_border);
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+#define CYC_PER_MHZ 1E6
+ if (total_recv > 0)
+ printf("\n CPU cycles/packet=%.2F (total cycles="
+ "%"PRIu64" / total RX packets=%"PRIu64") at %"PRIu64
+ " MHz Clock\n",
+ (double) fwd_cycles / total_recv,
+ fwd_cycles, total_recv,
+ (uint64_t)(rte_get_tsc_hz() / CYC_PER_MHZ));
+#endif
+}
+
+void
+fwd_stats_reset(void)
+{
+ streamid_t sm_id;
+ portid_t pt_id;
+ int i;
+
+ for (i = 0; i < cur_fwd_config.nb_fwd_ports; i++) {
+ pt_id = fwd_ports_ids[i];
+ rte_eth_stats_get(pt_id, &ports[pt_id].stats);
+ }
+ for (sm_id = 0; sm_id < cur_fwd_config.nb_fwd_streams; sm_id++) {
+ struct fwd_stream *fs = fwd_streams[sm_id];
+
+ fs->rx_packets = 0;
+ fs->tx_packets = 0;
+ fs->fwd_dropped = 0;
+ fs->rx_bad_ip_csum = 0;
+ fs->rx_bad_l4_csum = 0;
+ fs->rx_bad_outer_l4_csum = 0;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ memset(&fs->rx_burst_stats, 0, sizeof(fs->rx_burst_stats));
+ memset(&fs->tx_burst_stats, 0, sizeof(fs->tx_burst_stats));
+#endif
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ fs->core_cycles = 0;
+#endif
+ }
+}
+
+static void
+flush_fwd_rx_queues(void)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ portid_t rxp;
+ portid_t port_id;
+ queueid_t rxq;
+ uint16_t nb_rx;
+ uint16_t i;
+ uint8_t j;
+ uint64_t prev_tsc = 0, diff_tsc, cur_tsc, timer_tsc = 0;
+ uint64_t timer_period;
+
+ /* convert to number of cycles */
+ timer_period = rte_get_timer_hz(); /* 1 second timeout */
+
+ for (j = 0; j < 2; j++) {
+ for (rxp = 0; rxp < cur_fwd_config.nb_fwd_ports; rxp++) {
+ for (rxq = 0; rxq < nb_rxq; rxq++) {
+ port_id = fwd_ports_ids[rxp];
+ /**
+ * testpmd can stuck in the below do while loop
+ * if rte_eth_rx_burst() always returns nonzero
+ * packets. So timer is added to exit this loop
+ * after 1sec timer expiry.
+ */
+ prev_tsc = rte_rdtsc();
+ do {
+ nb_rx = rte_eth_rx_burst(port_id, rxq,
+ pkts_burst, MAX_PKT_BURST);
+ for (i = 0; i < nb_rx; i++)
+ rte_pktmbuf_free(pkts_burst[i]);
+
+ cur_tsc = rte_rdtsc();
+ diff_tsc = cur_tsc - prev_tsc;
+ timer_tsc += diff_tsc;
+ } while ((nb_rx > 0) &&
+ (timer_tsc < timer_period));
+ timer_tsc = 0;
+ }
+ }
+ rte_delay_ms(10); /* wait 10 milli-seconds before retrying */
+ }
+}
+
+static void
+run_pkt_fwd_on_lcore(struct fwd_lcore *fc, packet_fwd_t pkt_fwd)
+{
+ struct fwd_stream **fsm;
+ streamid_t nb_fs;
+ streamid_t sm_id;
+#ifdef RTE_LIBRTE_BITRATE
+ uint64_t tics_per_1sec;
+ uint64_t tics_datum;
+ uint64_t tics_current;
+ uint16_t i, cnt_ports;
+
+ cnt_ports = nb_ports;
+ tics_datum = rte_rdtsc();
+ tics_per_1sec = rte_get_timer_hz();
+#endif
+ fsm = &fwd_streams[fc->stream_idx];
+ nb_fs = fc->stream_nb;
+ do {
+ for (sm_id = 0; sm_id < nb_fs; sm_id++)
+ (*pkt_fwd)(fsm[sm_id]);
+#ifdef RTE_LIBRTE_BITRATE
+ if (bitrate_enabled != 0 &&
+ bitrate_lcore_id == rte_lcore_id()) {
+ tics_current = rte_rdtsc();
+ if (tics_current - tics_datum >= tics_per_1sec) {
+ /* Periodic bitrate calculation */
+ for (i = 0; i < cnt_ports; i++)
+ rte_stats_bitrate_calc(bitrate_data,
+ ports_ids[i]);
+ tics_datum = tics_current;
+ }
+ }
+#endif
+#ifdef RTE_LIBRTE_LATENCY_STATS
+ if (latencystats_enabled != 0 &&
+ latencystats_lcore_id == rte_lcore_id())
+ rte_latencystats_update();
+#endif
+
+ } while (! fc->stopped);
+}
+
+static int
+start_pkt_forward_on_core(void *fwd_arg)
+{
+ run_pkt_fwd_on_lcore((struct fwd_lcore *) fwd_arg,
+ cur_fwd_config.fwd_eng->packet_fwd);
+ return 0;
+}
+
+/*
+ * Run the TXONLY packet forwarding engine to send a single burst of packets.
+ * Used to start communication flows in network loopback test configurations.
+ */
+static int
+run_one_txonly_burst_on_core(void *fwd_arg)
+{
+ struct fwd_lcore *fwd_lc;
+ struct fwd_lcore tmp_lcore;
+
+ fwd_lc = (struct fwd_lcore *) fwd_arg;
+ tmp_lcore = *fwd_lc;
+ tmp_lcore.stopped = 1;
+ run_pkt_fwd_on_lcore(&tmp_lcore, tx_only_engine.packet_fwd);
+ return 0;
+}
+
+/*
+ * Launch packet forwarding:
+ * - Setup per-port forwarding context.
+ * - launch logical cores with their forwarding configuration.
+ */
+static void
+launch_packet_forwarding(lcore_function_t *pkt_fwd_on_lcore)
+{
+ port_fwd_begin_t port_fwd_begin;
+ unsigned int i;
+ unsigned int lc_id;
+ int diag;
+
+ port_fwd_begin = cur_fwd_config.fwd_eng->port_fwd_begin;
+ if (port_fwd_begin != NULL) {
+ for (i = 0; i < cur_fwd_config.nb_fwd_ports; i++)
+ (*port_fwd_begin)(fwd_ports_ids[i]);
+ }
+ for (i = 0; i < cur_fwd_config.nb_fwd_lcores; i++) {
+ lc_id = fwd_lcores_cpuids[i];
+ if ((interactive == 0) || (lc_id != rte_lcore_id())) {
+ fwd_lcores[i]->stopped = 0;
+ diag = rte_eal_remote_launch(pkt_fwd_on_lcore,
+ fwd_lcores[i], lc_id);
+ if (diag != 0)
+ printf("launch lcore %u failed - diag=%d\n",
+ lc_id, diag);
+ }
+ }
+}
+
+/*
+ * Launch packet forwarding configuration.
+ */
+void
+start_packet_forwarding(int with_tx_first)
+{
+ port_fwd_begin_t port_fwd_begin;
+ port_fwd_end_t port_fwd_end;
+ struct rte_port *port;
+ unsigned int i;
+ portid_t pt_id;
+
+ if (strcmp(cur_fwd_eng->fwd_mode_name, "rxonly") == 0 && !nb_rxq)
+ rte_exit(EXIT_FAILURE, "rxq are 0, cannot use rxonly fwd mode\n");
+
+ if (strcmp(cur_fwd_eng->fwd_mode_name, "txonly") == 0 && !nb_txq)
+ rte_exit(EXIT_FAILURE, "txq are 0, cannot use txonly fwd mode\n");
+
+ if ((strcmp(cur_fwd_eng->fwd_mode_name, "rxonly") != 0 &&
+ strcmp(cur_fwd_eng->fwd_mode_name, "txonly") != 0) &&
+ (!nb_rxq || !nb_txq))
+ rte_exit(EXIT_FAILURE,
+ "Either rxq or txq are 0, cannot use %s fwd mode\n",
+ cur_fwd_eng->fwd_mode_name);
+
+ if (all_ports_started() == 0) {
+ printf("Not all ports were started\n");
+ return;
+ }
+ if (test_done == 0) {
+ printf("Packet forwarding already started\n");
+ return;
+ }
+
+
+ if(dcb_test) {
+ for (i = 0; i < nb_fwd_ports; i++) {
+ pt_id = fwd_ports_ids[i];
+ port = &ports[pt_id];
+ if (!port->dcb_flag) {
+ printf("In DCB mode, all forwarding ports must "
+ "be configured in this mode.\n");
+ return;
+ }
+ }
+ if (nb_fwd_lcores == 1) {
+ printf("In DCB mode,the nb forwarding cores "
+ "should be larger than 1.\n");
+ return;
+ }
+ }
+ test_done = 0;
+
+ fwd_config_setup();
+
+ if(!no_flush_rx)
+ flush_fwd_rx_queues();
+
+ pkt_fwd_config_display(&cur_fwd_config);
+ rxtx_config_display();
+
+ fwd_stats_reset();
+ for (i = 0; i < cur_fwd_config.nb_fwd_ports; i++) {
+ pt_id = fwd_ports_ids[i];
+ port = &ports[pt_id];
+ map_port_queue_stats_mapping_registers(pt_id, port);
+ }
+ if (with_tx_first) {
+ port_fwd_begin = tx_only_engine.port_fwd_begin;
+ if (port_fwd_begin != NULL) {
+ for (i = 0; i < cur_fwd_config.nb_fwd_ports; i++)
+ (*port_fwd_begin)(fwd_ports_ids[i]);
+ }
+ while (with_tx_first--) {
+ launch_packet_forwarding(
+ run_one_txonly_burst_on_core);
+ rte_eal_mp_wait_lcore();
+ }
+ port_fwd_end = tx_only_engine.port_fwd_end;
+ if (port_fwd_end != NULL) {
+ for (i = 0; i < cur_fwd_config.nb_fwd_ports; i++)
+ (*port_fwd_end)(fwd_ports_ids[i]);
+ }
+ }
+ launch_packet_forwarding(start_pkt_forward_on_core);
+}
+
+void
+stop_packet_forwarding(void)
+{
+ port_fwd_end_t port_fwd_end;
+ lcoreid_t lc_id;
+ portid_t pt_id;
+ int i;
+
+ if (test_done) {
+ printf("Packet forwarding not started\n");
+ return;
+ }
+ printf("Telling cores to stop...");
+ for (lc_id = 0; lc_id < cur_fwd_config.nb_fwd_lcores; lc_id++)
+ fwd_lcores[lc_id]->stopped = 1;
+ printf("\nWaiting for lcores to finish...\n");
+ rte_eal_mp_wait_lcore();
+ port_fwd_end = cur_fwd_config.fwd_eng->port_fwd_end;
+ if (port_fwd_end != NULL) {
+ for (i = 0; i < cur_fwd_config.nb_fwd_ports; i++) {
+ pt_id = fwd_ports_ids[i];
+ (*port_fwd_end)(pt_id);
+ }
+ }
+
+ fwd_stats_display();
+
+ printf("\nDone.\n");
+ test_done = 1;
+}
+
+void
+dev_set_link_up(portid_t pid)
+{
+ if (rte_eth_dev_set_link_up(pid) < 0)
+ printf("\nSet link up fail.\n");
+}
+
+void
+dev_set_link_down(portid_t pid)
+{
+ if (rte_eth_dev_set_link_down(pid) < 0)
+ printf("\nSet link down fail.\n");
+}
+
+static int
+all_ports_started(void)
+{
+ portid_t pi;
+ struct rte_port *port;
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ port = &ports[pi];
+ /* Check if there is a port which is not started */
+ if ((port->port_status != RTE_PORT_STARTED) &&
+ (port->slave_flag == 0))
+ return 0;
+ }
+
+ /* No port is not started */
+ return 1;
+}
+
+int
+port_is_stopped(portid_t port_id)
+{
+ struct rte_port *port = &ports[port_id];
+
+ if ((port->port_status != RTE_PORT_STOPPED) &&
+ (port->slave_flag == 0))
+ return 0;
+ return 1;
+}
+
+int
+all_ports_stopped(void)
+{
+ portid_t pi;
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (!port_is_stopped(pi))
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+port_is_started(portid_t port_id)
+{
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return 0;
+
+ if (ports[port_id].port_status != RTE_PORT_STARTED)
+ return 0;
+
+ return 1;
+}
+
+/* Configure the Rx and Tx hairpin queues for the selected port. */
+static int
+setup_hairpin_queues(portid_t pi)
+{
+ queueid_t qi;
+ struct rte_eth_hairpin_conf hairpin_conf = {
+ .peer_count = 1,
+ };
+ int i;
+ int diag;
+ struct rte_port *port = &ports[pi];
+
+ for (qi = nb_txq, i = 0; qi < nb_hairpinq + nb_txq; qi++) {
+ hairpin_conf.peers[0].port = pi;
+ hairpin_conf.peers[0].queue = i + nb_rxq;
+ diag = rte_eth_tx_hairpin_queue_setup
+ (pi, qi, nb_txd, &hairpin_conf);
+ i++;
+ if (diag == 0)
+ continue;
+
+ /* Fail to setup rx queue, return */
+ if (rte_atomic16_cmpset(&(port->port_status),
+ RTE_PORT_HANDLING,
+ RTE_PORT_STOPPED) == 0)
+ printf("Port %d can not be set back "
+ "to stopped\n", pi);
+ printf("Fail to configure port %d hairpin "
+ "queues\n", pi);
+ /* try to reconfigure queues next time */
+ port->need_reconfig_queues = 1;
+ return -1;
+ }
+ for (qi = nb_rxq, i = 0; qi < nb_hairpinq + nb_rxq; qi++) {
+ hairpin_conf.peers[0].port = pi;
+ hairpin_conf.peers[0].queue = i + nb_txq;
+ diag = rte_eth_rx_hairpin_queue_setup
+ (pi, qi, nb_rxd, &hairpin_conf);
+ i++;
+ if (diag == 0)
+ continue;
+
+ /* Fail to setup rx queue, return */
+ if (rte_atomic16_cmpset(&(port->port_status),
+ RTE_PORT_HANDLING,
+ RTE_PORT_STOPPED) == 0)
+ printf("Port %d can not be set back "
+ "to stopped\n", pi);
+ printf("Fail to configure port %d hairpin "
+ "queues\n", pi);
+ /* try to reconfigure queues next time */
+ port->need_reconfig_queues = 1;
+ return -1;
+ }
+ return 0;
+}
+
+int
+start_port(portid_t pid)
+{
+ int diag, need_check_link_status = -1;
+ portid_t pi;
+ queueid_t qi;
+ struct rte_port *port;
+ struct rte_ether_addr mac_addr;
+ struct rte_eth_hairpin_cap cap;
+
+ if (port_id_is_invalid(pid, ENABLED_WARN))
+ return 0;
+
+ if(dcb_config)
+ dcb_test = 1;
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (pid != pi && pid != (portid_t)RTE_PORT_ALL)
+ continue;
+
+ need_check_link_status = 0;
+ port = &ports[pi];
+ if (rte_atomic16_cmpset(&(port->port_status), RTE_PORT_STOPPED,
+ RTE_PORT_HANDLING) == 0) {
+ printf("Port %d is now not stopped\n", pi);
+ continue;
+ }
+
+ if (port->need_reconfig > 0) {
+ port->need_reconfig = 0;
+
+ if (flow_isolate_all) {
+ int ret = port_flow_isolate(pi, 1);
+ if (ret) {
+ printf("Failed to apply isolated"
+ " mode on port %d\n", pi);
+ return -1;
+ }
+ }
+ configure_rxtx_dump_callbacks(0);
+ printf("Configuring Port %d (socket %u)\n", pi,
+ port->socket_id);
+ if (nb_hairpinq > 0 &&
+ rte_eth_dev_hairpin_capability_get(pi, &cap)) {
+ printf("Port %d doesn't support hairpin "
+ "queues\n", pi);
+ return -1;
+ }
+ /* configure port */
+ diag = rte_eth_dev_configure(pi, nb_rxq + nb_hairpinq,
+ nb_txq + nb_hairpinq,
+ &(port->dev_conf));
+ if (diag != 0) {
+ if (rte_atomic16_cmpset(&(port->port_status),
+ RTE_PORT_HANDLING, RTE_PORT_STOPPED) == 0)
+ printf("Port %d can not be set back "
+ "to stopped\n", pi);
+ printf("Fail to configure port %d\n", pi);
+ /* try to reconfigure port next time */
+ port->need_reconfig = 1;
+ return -1;
+ }
+ }
+ if (port->need_reconfig_queues > 0) {
+ port->need_reconfig_queues = 0;
+ /* setup tx queues */
+ for (qi = 0; qi < nb_txq; qi++) {
+ if ((numa_support) &&
+ (txring_numa[pi] != NUMA_NO_CONFIG))
+ diag = rte_eth_tx_queue_setup(pi, qi,
+ port->nb_tx_desc[qi],
+ txring_numa[pi],
+ &(port->tx_conf[qi]));
+ else
+ diag = rte_eth_tx_queue_setup(pi, qi,
+ port->nb_tx_desc[qi],
+ port->socket_id,
+ &(port->tx_conf[qi]));
+
+ if (diag == 0)
+ continue;
+
+ /* Fail to setup tx queue, return */
+ if (rte_atomic16_cmpset(&(port->port_status),
+ RTE_PORT_HANDLING,
+ RTE_PORT_STOPPED) == 0)
+ printf("Port %d can not be set back "
+ "to stopped\n", pi);
+ printf("Fail to configure port %d tx queues\n",
+ pi);
+ /* try to reconfigure queues next time */
+ port->need_reconfig_queues = 1;
+ return -1;
+ }
+ for (qi = 0; qi < nb_rxq; qi++) {
+ /* setup rx queues */
+ if ((numa_support) &&
+ (rxring_numa[pi] != NUMA_NO_CONFIG)) {
+ struct rte_mempool * mp =
+ mbuf_pool_find(rxring_numa[pi]);
+ if (mp == NULL) {
+ printf("Failed to setup RX queue:"
+ "No mempool allocation"
+ " on the socket %d\n",
+ rxring_numa[pi]);
+ return -1;
+ }
+
+ diag = rte_eth_rx_queue_setup(pi, qi,
+ port->nb_rx_desc[qi],
+ rxring_numa[pi],
+ &(port->rx_conf[qi]),
+ mp);
+ } else {
+ struct rte_mempool *mp =
+ mbuf_pool_find(port->socket_id);
+ if (mp == NULL) {
+ printf("Failed to setup RX queue:"
+ "No mempool allocation"
+ " on the socket %d\n",
+ port->socket_id);
+ return -1;
+ }
+ diag = rte_eth_rx_queue_setup(pi, qi,
+ port->nb_rx_desc[qi],
+ port->socket_id,
+ &(port->rx_conf[qi]),
+ mp);
+ }
+ if (diag == 0)
+ continue;
+
+ /* Fail to setup rx queue, return */
+ if (rte_atomic16_cmpset(&(port->port_status),
+ RTE_PORT_HANDLING,
+ RTE_PORT_STOPPED) == 0)
+ printf("Port %d can not be set back "
+ "to stopped\n", pi);
+ printf("Fail to configure port %d rx queues\n",
+ pi);
+ /* try to reconfigure queues next time */
+ port->need_reconfig_queues = 1;
+ return -1;
+ }
+ /* setup hairpin queues */
+ if (setup_hairpin_queues(pi) != 0)
+ return -1;
+ }
+ configure_rxtx_dump_callbacks(verbose_level);
+ if (clear_ptypes) {
+ diag = rte_eth_dev_set_ptypes(pi, RTE_PTYPE_UNKNOWN,
+ NULL, 0);
+ if (diag < 0)
+ printf(
+ "Port %d: Failed to disable Ptype parsing\n",
+ pi);
+ }
+
+ /* start port */
+ if (rte_eth_dev_start(pi) < 0) {
+ printf("Fail to start port %d\n", pi);
+
+ /* Fail to setup rx queue, return */
+ if (rte_atomic16_cmpset(&(port->port_status),
+ RTE_PORT_HANDLING, RTE_PORT_STOPPED) == 0)
+ printf("Port %d can not be set back to "
+ "stopped\n", pi);
+ continue;
+ }
+
+ if (rte_atomic16_cmpset(&(port->port_status),
+ RTE_PORT_HANDLING, RTE_PORT_STARTED) == 0)
+ printf("Port %d can not be set into started\n", pi);
+
+ if (eth_macaddr_get_print_err(pi, &mac_addr) == 0)
+ printf("Port %d: %02X:%02X:%02X:%02X:%02X:%02X\n", pi,
+ mac_addr.addr_bytes[0], mac_addr.addr_bytes[1],
+ mac_addr.addr_bytes[2], mac_addr.addr_bytes[3],
+ mac_addr.addr_bytes[4], mac_addr.addr_bytes[5]);
+
+ /* at least one port started, need checking link status */
+ need_check_link_status = 1;
+ }
+
+ if (need_check_link_status == 1 && !no_link_check)
+ check_all_ports_link_status(RTE_PORT_ALL);
+ else if (need_check_link_status == 0)
+ printf("Please stop the ports first\n");
+
+ printf("Done\n");
+ return 0;
+}
+
+void
+stop_port(portid_t pid)
+{
+ portid_t pi;
+ struct rte_port *port;
+ int need_check_link_status = 0;
+
+ if (dcb_test) {
+ dcb_test = 0;
+ dcb_config = 0;
+ }
+
+ if (port_id_is_invalid(pid, ENABLED_WARN))
+ return;
+
+ printf("Stopping ports...\n");
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (pid != pi && pid != (portid_t)RTE_PORT_ALL)
+ continue;
+
+ if (port_is_forwarding(pi) != 0 && test_done == 0) {
+ printf("Please remove port %d from forwarding configuration.\n", pi);
+ continue;
+ }
+
+ if (port_is_bonding_slave(pi)) {
+ printf("Please remove port %d from bonded device.\n", pi);
+ continue;
+ }
+
+ port = &ports[pi];
+ if (rte_atomic16_cmpset(&(port->port_status), RTE_PORT_STARTED,
+ RTE_PORT_HANDLING) == 0)
+ continue;
+
+ rte_eth_dev_stop(pi);
+
+ if (rte_atomic16_cmpset(&(port->port_status),
+ RTE_PORT_HANDLING, RTE_PORT_STOPPED) == 0)
+ printf("Port %d can not be set into stopped\n", pi);
+ need_check_link_status = 1;
+ }
+ if (need_check_link_status && !no_link_check)
+ check_all_ports_link_status(RTE_PORT_ALL);
+
+ printf("Done\n");
+}
+
+static void
+remove_invalid_ports_in(portid_t *array, portid_t *total)
+{
+ portid_t i;
+ portid_t new_total = 0;
+
+ for (i = 0; i < *total; i++)
+ if (!port_id_is_invalid(array[i], DISABLED_WARN)) {
+ array[new_total] = array[i];
+ new_total++;
+ }
+ *total = new_total;
+}
+
+static void
+remove_invalid_ports(void)
+{
+ remove_invalid_ports_in(ports_ids, &nb_ports);
+ remove_invalid_ports_in(fwd_ports_ids, &nb_fwd_ports);
+ nb_cfg_ports = nb_fwd_ports;
+}
+
+void
+close_port(portid_t pid)
+{
+ portid_t pi;
+ struct rte_port *port;
+
+ if (port_id_is_invalid(pid, ENABLED_WARN))
+ return;
+
+ printf("Closing ports...\n");
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (pid != pi && pid != (portid_t)RTE_PORT_ALL)
+ continue;
+
+ if (port_is_forwarding(pi) != 0 && test_done == 0) {
+ printf("Please remove port %d from forwarding configuration.\n", pi);
+ continue;
+ }
+
+ if (port_is_bonding_slave(pi)) {
+ printf("Please remove port %d from bonded device.\n", pi);
+ continue;
+ }
+
+ port = &ports[pi];
+ if (rte_atomic16_cmpset(&(port->port_status),
+ RTE_PORT_CLOSED, RTE_PORT_CLOSED) == 1) {
+ printf("Port %d is already closed\n", pi);
+ continue;
+ }
+
+ if (rte_atomic16_cmpset(&(port->port_status),
+ RTE_PORT_STOPPED, RTE_PORT_HANDLING) == 0) {
+ printf("Port %d is now not stopped\n", pi);
+ continue;
+ }
+
+ if (port->flow_list)
+ port_flow_flush(pi);
+ rte_eth_dev_close(pi);
+
+ remove_invalid_ports();
+
+ if (rte_atomic16_cmpset(&(port->port_status),
+ RTE_PORT_HANDLING, RTE_PORT_CLOSED) == 0)
+ printf("Port %d cannot be set to closed\n", pi);
+ }
+
+ printf("Done\n");
+}
+
+void
+reset_port(portid_t pid)
+{
+ int diag;
+ portid_t pi;
+ struct rte_port *port;
+
+ if (port_id_is_invalid(pid, ENABLED_WARN))
+ return;
+
+ if ((pid == (portid_t)RTE_PORT_ALL && !all_ports_stopped()) ||
+ (pid != (portid_t)RTE_PORT_ALL && !port_is_stopped(pid))) {
+ printf("Can not reset port(s), please stop port(s) first.\n");
+ return;
+ }
+
+ printf("Resetting ports...\n");
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (pid != pi && pid != (portid_t)RTE_PORT_ALL)
+ continue;
+
+ if (port_is_forwarding(pi) != 0 && test_done == 0) {
+ printf("Please remove port %d from forwarding "
+ "configuration.\n", pi);
+ continue;
+ }
+
+ if (port_is_bonding_slave(pi)) {
+ printf("Please remove port %d from bonded device.\n",
+ pi);
+ continue;
+ }
+
+ diag = rte_eth_dev_reset(pi);
+ if (diag == 0) {
+ port = &ports[pi];
+ port->need_reconfig = 1;
+ port->need_reconfig_queues = 1;
+ } else {
+ printf("Failed to reset port %d. diag=%d\n", pi, diag);
+ }
+ }
+
+ printf("Done\n");
+}
+
+void
+attach_port(char *identifier)
+{
+ portid_t pi;
+ struct rte_dev_iterator iterator;
+
+ printf("Attaching a new port...\n");
+
+ if (identifier == NULL) {
+ printf("Invalid parameters are specified\n");
+ return;
+ }
+
+ if (rte_dev_probe(identifier) < 0) {
+ TESTPMD_LOG(ERR, "Failed to attach port %s\n", identifier);
+ return;
+ }
+
+ /* first attach mode: event */
+ if (setup_on_probe_event) {
+ /* new ports are detected on RTE_ETH_EVENT_NEW event */
+ for (pi = 0; pi < RTE_MAX_ETHPORTS; pi++)
+ if (ports[pi].port_status == RTE_PORT_HANDLING &&
+ ports[pi].need_setup != 0)
+ setup_attached_port(pi);
+ return;
+ }
+
+ /* second attach mode: iterator */
+ RTE_ETH_FOREACH_MATCHING_DEV(pi, identifier, &iterator) {
+ /* setup ports matching the devargs used for probing */
+ if (port_is_forwarding(pi))
+ continue; /* port was already attached before */
+ setup_attached_port(pi);
+ }
+}
+
+static void
+setup_attached_port(portid_t pi)
+{
+ unsigned int socket_id;
+ int ret;
+
+ socket_id = (unsigned)rte_eth_dev_socket_id(pi);
+ /* if socket_id is invalid, set to the first available socket. */
+ if (check_socket_id(socket_id) < 0)
+ socket_id = socket_ids[0];
+ reconfig(pi, socket_id);
+ ret = rte_eth_promiscuous_enable(pi);
+ if (ret != 0)
+ printf("Error during enabling promiscuous mode for port %u: %s - ignore\n",
+ pi, rte_strerror(-ret));
+
+ ports_ids[nb_ports++] = pi;
+ fwd_ports_ids[nb_fwd_ports++] = pi;
+ nb_cfg_ports = nb_fwd_ports;
+ ports[pi].need_setup = 0;
+ ports[pi].port_status = RTE_PORT_STOPPED;
+
+ printf("Port %d is attached. Now total ports is %d\n", pi, nb_ports);
+ printf("Done\n");
+}
+
+static void
+detach_device(struct rte_device *dev)
+{
+ portid_t sibling;
+
+ if (dev == NULL) {
+ printf("Device already removed\n");
+ return;
+ }
+
+ printf("Removing a device...\n");
+
+ if (rte_dev_remove(dev) < 0) {
+ TESTPMD_LOG(ERR, "Failed to detach device %s\n", dev->name);
+ return;
+ }
+ RTE_ETH_FOREACH_DEV_OF(sibling, dev) {
+ /* reset mapping between old ports and removed device */
+ rte_eth_devices[sibling].device = NULL;
+ if (ports[sibling].port_status != RTE_PORT_CLOSED) {
+ /* sibling ports are forced to be closed */
+ ports[sibling].port_status = RTE_PORT_CLOSED;
+ printf("Port %u is closed\n", sibling);
+ }
+ }
+
+ remove_invalid_ports();
+
+ printf("Device is detached\n");
+ printf("Now total ports is %d\n", nb_ports);
+ printf("Done\n");
+ return;
+}
+
+void
+detach_port_device(portid_t port_id)
+{
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+
+ if (ports[port_id].port_status != RTE_PORT_CLOSED) {
+ if (ports[port_id].port_status != RTE_PORT_STOPPED) {
+ printf("Port not stopped\n");
+ return;
+ }
+ printf("Port was not closed\n");
+ if (ports[port_id].flow_list)
+ port_flow_flush(port_id);
+ }
+
+ detach_device(rte_eth_devices[port_id].device);
+}
+
+void
+detach_devargs(char *identifier)
+{
+ struct rte_dev_iterator iterator;
+ struct rte_devargs da;
+ portid_t port_id;
+
+ printf("Removing a device...\n");
+
+ memset(&da, 0, sizeof(da));
+ if (rte_devargs_parsef(&da, "%s", identifier)) {
+ printf("cannot parse identifier\n");
+ if (da.args)
+ free(da.args);
+ return;
+ }
+
+ RTE_ETH_FOREACH_MATCHING_DEV(port_id, identifier, &iterator) {
+ if (ports[port_id].port_status != RTE_PORT_CLOSED) {
+ if (ports[port_id].port_status != RTE_PORT_STOPPED) {
+ printf("Port %u not stopped\n", port_id);
+ rte_eth_iterator_cleanup(&iterator);
+ return;
+ }
+
+ /* sibling ports are forced to be closed */
+ if (ports[port_id].flow_list)
+ port_flow_flush(port_id);
+ ports[port_id].port_status = RTE_PORT_CLOSED;
+ printf("Port %u is now closed\n", port_id);
+ }
+ }
+
+ if (rte_eal_hotplug_remove(da.bus->name, da.name) != 0) {
+ TESTPMD_LOG(ERR, "Failed to detach device %s(%s)\n",
+ da.name, da.bus->name);
+ return;
+ }
+
+ remove_invalid_ports();
+
+ printf("Device %s is detached\n", identifier);
+ printf("Now total ports is %d\n", nb_ports);
+ printf("Done\n");
+}
+
+void
+pmd_test_exit(void)
+{
+ portid_t pt_id;
+ int ret;
+ int i;
+
+ if (test_done == 0)
+ stop_packet_forwarding();
+
+ for (i = 0 ; i < RTE_MAX_NUMA_NODES ; i++) {
+ if (mempools[i]) {
+ if (mp_alloc_type == MP_ALLOC_ANON)
+ rte_mempool_mem_iter(mempools[i], dma_unmap_cb,
+ NULL);
+ }
+ }
+ if (ports != NULL) {
+ no_link_check = 1;
+ RTE_ETH_FOREACH_DEV(pt_id) {
+ printf("\nStopping port %d...\n", pt_id);
+ fflush(stdout);
+ stop_port(pt_id);
+ }
+ RTE_ETH_FOREACH_DEV(pt_id) {
+ printf("\nShutting down port %d...\n", pt_id);
+ fflush(stdout);
+ close_port(pt_id);
+ }
+ }
+
+ if (hot_plug) {
+ ret = rte_dev_event_monitor_stop();
+ if (ret) {
+ RTE_LOG(ERR, EAL,
+ "fail to stop device event monitor.");
+ return;
+ }
+
+ ret = rte_dev_event_callback_unregister(NULL,
+ dev_event_callback, NULL);
+ if (ret < 0) {
+ RTE_LOG(ERR, EAL,
+ "fail to unregister device event callback.\n");
+ return;
+ }
+
+ ret = rte_dev_hotplug_handle_disable();
+ if (ret) {
+ RTE_LOG(ERR, EAL,
+ "fail to disable hotplug handling.\n");
+ return;
+ }
+ }
+ for (i = 0 ; i < RTE_MAX_NUMA_NODES ; i++) {
+ if (mempools[i])
+ rte_mempool_free(mempools[i]);
+ }
+
+ printf("\nBye...\n");
+}
+
+typedef void (*cmd_func_t)(void);
+struct pmd_test_command {
+ const char *cmd_name;
+ cmd_func_t cmd_func;
+};
+
+/* 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 */
+ portid_t portid;
+ uint8_t count, all_ports_up, print_flag = 0;
+ struct rte_eth_link link;
+ int ret;
+
+ printf("Checking link statuses...\n");
+ 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"));
+ 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) {
+ 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;
+ }
+
+ if (lsc_interrupt)
+ break;
+ }
+}
+
+/*
+ * This callback is for remove a port for a device. It has limitation because
+ * it is not for multiple port removal for a device.
+ * TODO: the device detach invoke will plan to be removed from user side to
+ * eal. And convert all PMDs to free port resources on ether device closing.
+ */
+static void
+rmv_port_callback(void *arg)
+{
+ int need_to_start = 0;
+ int org_no_link_check = no_link_check;
+ portid_t port_id = (intptr_t)arg;
+ struct rte_device *dev;
+
+ RTE_ETH_VALID_PORTID_OR_RET(port_id);
+
+ if (!test_done && port_is_forwarding(port_id)) {
+ need_to_start = 1;
+ stop_packet_forwarding();
+ }
+ no_link_check = 1;
+ stop_port(port_id);
+ no_link_check = org_no_link_check;
+
+ /* Save rte_device pointer before closing ethdev port */
+ dev = rte_eth_devices[port_id].device;
+ close_port(port_id);
+ detach_device(dev); /* might be already removed or have more ports */
+
+ if (need_to_start)
+ start_packet_forwarding(0);
+}
+
+/* This function is used by the interrupt thread */
+static int
+eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param,
+ void *ret_param)
+{
+ RTE_SET_USED(param);
+ RTE_SET_USED(ret_param);
+
+ if (type >= RTE_ETH_EVENT_MAX) {
+ fprintf(stderr, "\nPort %" PRIu16 ": %s called upon invalid event %d\n",
+ port_id, __func__, type);
+ fflush(stderr);
+ } else if (event_print_mask & (UINT32_C(1) << type)) {
+ printf("\nPort %" PRIu16 ": %s event\n", port_id,
+ eth_event_desc[type]);
+ fflush(stdout);
+ }
+
+ switch (type) {
+ case RTE_ETH_EVENT_NEW:
+ ports[port_id].need_setup = 1;
+ ports[port_id].port_status = RTE_PORT_HANDLING;
+ break;
+ case RTE_ETH_EVENT_INTR_RMV:
+ if (port_id_is_invalid(port_id, DISABLED_WARN))
+ break;
+ if (rte_eal_alarm_set(100000,
+ rmv_port_callback, (void *)(intptr_t)port_id))
+ fprintf(stderr, "Could not set up deferred device removal\n");
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int
+register_eth_event_callback(void)
+{
+ int ret;
+ enum rte_eth_event_type event;
+
+ for (event = RTE_ETH_EVENT_UNKNOWN;
+ event < RTE_ETH_EVENT_MAX; event++) {
+ ret = rte_eth_dev_callback_register(RTE_ETH_ALL,
+ event,
+ eth_event_callback,
+ NULL);
+ if (ret != 0) {
+ TESTPMD_LOG(ERR, "Failed to register callback for "
+ "%s event\n", eth_event_desc[event]);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* This function is used by the interrupt thread */
+static void
+dev_event_callback(const char *device_name, enum rte_dev_event_type type,
+ __rte_unused void *arg)
+{
+ uint16_t port_id;
+ int ret;
+
+ if (type >= RTE_DEV_EVENT_MAX) {
+ fprintf(stderr, "%s called upon invalid event %d\n",
+ __func__, type);
+ fflush(stderr);
+ }
+
+ switch (type) {
+ case RTE_DEV_EVENT_REMOVE:
+ RTE_LOG(DEBUG, EAL, "The device: %s has been removed!\n",
+ device_name);
+ ret = rte_eth_dev_get_port_by_name(device_name, &port_id);
+ if (ret) {
+ RTE_LOG(ERR, EAL, "can not get port by device %s!\n",
+ device_name);
+ return;
+ }
+ /*
+ * Because the user's callback is invoked in eal interrupt
+ * callback, the interrupt callback need to be finished before
+ * it can be unregistered when detaching device. So finish
+ * callback soon and use a deferred removal to detach device
+ * is need. It is a workaround, once the device detaching be
+ * moved into the eal in the future, the deferred removal could
+ * be deleted.
+ */
+ if (rte_eal_alarm_set(100000,
+ rmv_port_callback, (void *)(intptr_t)port_id))
+ RTE_LOG(ERR, EAL,
+ "Could not set up deferred device removal\n");
+ break;
+ case RTE_DEV_EVENT_ADD:
+ RTE_LOG(ERR, EAL, "The device: %s has been added!\n",
+ device_name);
+ /* TODO: After finish kernel driver binding,
+ * begin to attach port.
+ */
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+set_tx_queue_stats_mapping_registers(portid_t port_id, struct rte_port *port)
+{
+ uint16_t i;
+ int diag;
+ uint8_t mapping_found = 0;
+
+ for (i = 0; i < nb_tx_queue_stats_mappings; i++) {
+ if ((tx_queue_stats_mappings[i].port_id == port_id) &&
+ (tx_queue_stats_mappings[i].queue_id < nb_txq )) {
+ diag = rte_eth_dev_set_tx_queue_stats_mapping(port_id,
+ tx_queue_stats_mappings[i].queue_id,
+ tx_queue_stats_mappings[i].stats_counter_id);
+ if (diag != 0)
+ return diag;
+ mapping_found = 1;
+ }
+ }
+ if (mapping_found)
+ port->tx_queue_stats_mapping_enabled = 1;
+ return 0;
+}
+
+static int
+set_rx_queue_stats_mapping_registers(portid_t port_id, struct rte_port *port)
+{
+ uint16_t i;
+ int diag;
+ uint8_t mapping_found = 0;
+
+ for (i = 0; i < nb_rx_queue_stats_mappings; i++) {
+ if ((rx_queue_stats_mappings[i].port_id == port_id) &&
+ (rx_queue_stats_mappings[i].queue_id < nb_rxq )) {
+ diag = rte_eth_dev_set_rx_queue_stats_mapping(port_id,
+ rx_queue_stats_mappings[i].queue_id,
+ rx_queue_stats_mappings[i].stats_counter_id);
+ if (diag != 0)
+ return diag;
+ mapping_found = 1;
+ }
+ }
+ if (mapping_found)
+ port->rx_queue_stats_mapping_enabled = 1;
+ return 0;
+}
+
+static void
+map_port_queue_stats_mapping_registers(portid_t pi, struct rte_port *port)
+{
+ int diag = 0;
+
+ diag = set_tx_queue_stats_mapping_registers(pi, port);
+ if (diag != 0) {
+ if (diag == -ENOTSUP) {
+ port->tx_queue_stats_mapping_enabled = 0;
+ printf("TX queue stats mapping not supported port id=%d\n", pi);
+ }
+ else
+ rte_exit(EXIT_FAILURE,
+ "set_tx_queue_stats_mapping_registers "
+ "failed for port id=%d diag=%d\n",
+ pi, diag);
+ }
+
+ diag = set_rx_queue_stats_mapping_registers(pi, port);
+ if (diag != 0) {
+ if (diag == -ENOTSUP) {
+ port->rx_queue_stats_mapping_enabled = 0;
+ printf("RX queue stats mapping not supported port id=%d\n", pi);
+ }
+ else
+ rte_exit(EXIT_FAILURE,
+ "set_rx_queue_stats_mapping_registers "
+ "failed for port id=%d diag=%d\n",
+ pi, diag);
+ }
+}
+
+static void
+rxtx_port_config(struct rte_port *port)
+{
+ uint16_t qid;
+ uint64_t offloads;
+
+ for (qid = 0; qid < nb_rxq; qid++) {
+ offloads = port->rx_conf[qid].offloads;
+ port->rx_conf[qid] = port->dev_info.default_rxconf;
+ if (offloads != 0)
+ port->rx_conf[qid].offloads = offloads;
+
+ /* Check if any Rx parameters have been passed */
+ if (rx_pthresh != RTE_PMD_PARAM_UNSET)
+ port->rx_conf[qid].rx_thresh.pthresh = rx_pthresh;
+
+ if (rx_hthresh != RTE_PMD_PARAM_UNSET)
+ port->rx_conf[qid].rx_thresh.hthresh = rx_hthresh;
+
+ if (rx_wthresh != RTE_PMD_PARAM_UNSET)
+ port->rx_conf[qid].rx_thresh.wthresh = rx_wthresh;
+
+ if (rx_free_thresh != RTE_PMD_PARAM_UNSET)
+ port->rx_conf[qid].rx_free_thresh = rx_free_thresh;
+
+ if (rx_drop_en != RTE_PMD_PARAM_UNSET)
+ port->rx_conf[qid].rx_drop_en = rx_drop_en;
+
+ port->nb_rx_desc[qid] = nb_rxd;
+ }
+
+ for (qid = 0; qid < nb_txq; qid++) {
+ offloads = port->tx_conf[qid].offloads;
+ port->tx_conf[qid] = port->dev_info.default_txconf;
+ if (offloads != 0)
+ port->tx_conf[qid].offloads = offloads;
+
+ /* Check if any Tx parameters have been passed */
+ if (tx_pthresh != RTE_PMD_PARAM_UNSET)
+ port->tx_conf[qid].tx_thresh.pthresh = tx_pthresh;
+
+ if (tx_hthresh != RTE_PMD_PARAM_UNSET)
+ port->tx_conf[qid].tx_thresh.hthresh = tx_hthresh;
+
+ if (tx_wthresh != RTE_PMD_PARAM_UNSET)
+ port->tx_conf[qid].tx_thresh.wthresh = tx_wthresh;
+
+ if (tx_rs_thresh != RTE_PMD_PARAM_UNSET)
+ port->tx_conf[qid].tx_rs_thresh = tx_rs_thresh;
+
+ if (tx_free_thresh != RTE_PMD_PARAM_UNSET)
+ port->tx_conf[qid].tx_free_thresh = tx_free_thresh;
+
+ port->nb_tx_desc[qid] = nb_txd;
+ }
+}
+
+void
+init_port_config(void)
+{
+ portid_t pid;
+ struct rte_port *port;
+ int ret;
+
+ RTE_ETH_FOREACH_DEV(pid) {
+ port = &ports[pid];
+ port->dev_conf.fdir_conf = fdir_conf;
+
+ ret = eth_dev_info_get_print_err(pid, &port->dev_info);
+ if (ret != 0)
+ return;
+
+ if (nb_rxq > 1) {
+ port->dev_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+ port->dev_conf.rx_adv_conf.rss_conf.rss_hf =
+ rss_hf & port->dev_info.flow_type_rss_offloads;
+ } else {
+ port->dev_conf.rx_adv_conf.rss_conf.rss_key = NULL;
+ port->dev_conf.rx_adv_conf.rss_conf.rss_hf = 0;
+ }
+
+ if (port->dcb_flag == 0) {
+ if( port->dev_conf.rx_adv_conf.rss_conf.rss_hf != 0)
+ port->dev_conf.rxmode.mq_mode =
+ (enum rte_eth_rx_mq_mode)
+ (rx_mq_mode & ETH_MQ_RX_RSS);
+ else
+ port->dev_conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
+ }
+
+ rxtx_port_config(port);
+
+ ret = eth_macaddr_get_print_err(pid, &port->eth_addr);
+ if (ret != 0)
+ return;
+
+ map_port_queue_stats_mapping_registers(pid, port);
+#if defined RTE_LIBRTE_IXGBE_PMD && defined RTE_LIBRTE_IXGBE_BYPASS
+ rte_pmd_ixgbe_bypass_init(pid);
+#endif
+
+ if (lsc_interrupt &&
+ (rte_eth_devices[pid].data->dev_flags &
+ RTE_ETH_DEV_INTR_LSC))
+ port->dev_conf.intr_conf.lsc = 1;
+ if (rmv_interrupt &&
+ (rte_eth_devices[pid].data->dev_flags &
+ RTE_ETH_DEV_INTR_RMV))
+ port->dev_conf.intr_conf.rmv = 1;
+ }
+}
+
+void set_port_slave_flag(portid_t slave_pid)
+{
+ struct rte_port *port;
+
+ port = &ports[slave_pid];
+ port->slave_flag = 1;
+}
+
+void clear_port_slave_flag(portid_t slave_pid)
+{
+ struct rte_port *port;
+
+ port = &ports[slave_pid];
+ port->slave_flag = 0;
+}
+
+uint8_t port_is_bonding_slave(portid_t slave_pid)
+{
+ struct rte_port *port;
+
+ port = &ports[slave_pid];
+ if ((rte_eth_devices[slave_pid].data->dev_flags &
+ RTE_ETH_DEV_BONDED_SLAVE) || (port->slave_flag == 1))
+ return 1;
+ return 0;
+}
+
+const uint16_t vlan_tags[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31
+};
+
+static int
+get_eth_dcb_conf(portid_t pid, struct rte_eth_conf *eth_conf,
+ enum dcb_mode_enable dcb_mode,
+ enum rte_eth_nb_tcs num_tcs,
+ uint8_t pfc_en)
+{
+ uint8_t i;
+ int32_t rc;
+ struct rte_eth_rss_conf rss_conf;
+
+ /*
+ * Builds up the correct configuration for dcb+vt based on the vlan tags array
+ * given above, and the number of traffic classes available for use.
+ */
+ if (dcb_mode == DCB_VT_ENABLED) {
+ struct rte_eth_vmdq_dcb_conf *vmdq_rx_conf =
+ &eth_conf->rx_adv_conf.vmdq_dcb_conf;
+ struct rte_eth_vmdq_dcb_tx_conf *vmdq_tx_conf =
+ &eth_conf->tx_adv_conf.vmdq_dcb_tx_conf;
+
+ /* VMDQ+DCB RX and TX configurations */
+ vmdq_rx_conf->enable_default_pool = 0;
+ vmdq_rx_conf->default_pool = 0;
+ vmdq_rx_conf->nb_queue_pools =
+ (num_tcs == ETH_4_TCS ? ETH_32_POOLS : ETH_16_POOLS);
+ vmdq_tx_conf->nb_queue_pools =
+ (num_tcs == ETH_4_TCS ? ETH_32_POOLS : ETH_16_POOLS);
+
+ vmdq_rx_conf->nb_pool_maps = vmdq_rx_conf->nb_queue_pools;
+ for (i = 0; i < vmdq_rx_conf->nb_pool_maps; i++) {
+ vmdq_rx_conf->pool_map[i].vlan_id = vlan_tags[i];
+ vmdq_rx_conf->pool_map[i].pools =
+ 1 << (i % vmdq_rx_conf->nb_queue_pools);
+ }
+ for (i = 0; i < ETH_DCB_NUM_USER_PRIORITIES; i++) {
+ vmdq_rx_conf->dcb_tc[i] = i % num_tcs;
+ vmdq_tx_conf->dcb_tc[i] = i % num_tcs;
+ }
+
+ /* set DCB mode of RX and TX of multiple queues */
+ eth_conf->rxmode.mq_mode =
+ (enum rte_eth_rx_mq_mode)
+ (rx_mq_mode & ETH_MQ_RX_VMDQ_DCB);
+ eth_conf->txmode.mq_mode = ETH_MQ_TX_VMDQ_DCB;
+ } else {
+ struct rte_eth_dcb_rx_conf *rx_conf =
+ &eth_conf->rx_adv_conf.dcb_rx_conf;
+ struct rte_eth_dcb_tx_conf *tx_conf =
+ &eth_conf->tx_adv_conf.dcb_tx_conf;
+
+ memset(&rss_conf, 0, sizeof(struct rte_eth_rss_conf));
+
+ rc = rte_eth_dev_rss_hash_conf_get(pid, &rss_conf);
+ if (rc != 0)
+ return rc;
+
+ rx_conf->nb_tcs = num_tcs;
+ tx_conf->nb_tcs = num_tcs;
+
+ for (i = 0; i < ETH_DCB_NUM_USER_PRIORITIES; i++) {
+ rx_conf->dcb_tc[i] = i % num_tcs;
+ tx_conf->dcb_tc[i] = i % num_tcs;
+ }
+
+ eth_conf->rxmode.mq_mode =
+ (enum rte_eth_rx_mq_mode)
+ (rx_mq_mode & ETH_MQ_RX_DCB_RSS);
+ eth_conf->rx_adv_conf.rss_conf = rss_conf;
+ eth_conf->txmode.mq_mode = ETH_MQ_TX_DCB;
+ }
+
+ if (pfc_en)
+ eth_conf->dcb_capability_en =
+ ETH_DCB_PG_SUPPORT | ETH_DCB_PFC_SUPPORT;
+ else
+ eth_conf->dcb_capability_en = ETH_DCB_PG_SUPPORT;
+
+ return 0;
+}
+
+int
+init_port_dcb_config(portid_t pid,
+ enum dcb_mode_enable dcb_mode,
+ enum rte_eth_nb_tcs num_tcs,
+ uint8_t pfc_en)
+{
+ struct rte_eth_conf port_conf;
+ struct rte_port *rte_port;
+ int retval;
+ uint16_t i;
+
+ rte_port = &ports[pid];
+
+ memset(&port_conf, 0, sizeof(struct rte_eth_conf));
+ /* Enter DCB configuration status */
+ dcb_config = 1;
+
+ port_conf.rxmode = rte_port->dev_conf.rxmode;
+ port_conf.txmode = rte_port->dev_conf.txmode;
+
+ /*set configuration of DCB in vt mode and DCB in non-vt mode*/
+ retval = get_eth_dcb_conf(pid, &port_conf, dcb_mode, num_tcs, pfc_en);
+ if (retval < 0)
+ return retval;
+ port_conf.rxmode.offloads |= DEV_RX_OFFLOAD_VLAN_FILTER;
+
+ /* re-configure the device . */
+ retval = rte_eth_dev_configure(pid, nb_rxq, nb_rxq, &port_conf);
+ if (retval < 0)
+ return retval;
+
+ retval = eth_dev_info_get_print_err(pid, &rte_port->dev_info);
+ if (retval != 0)
+ return retval;
+
+ /* If dev_info.vmdq_pool_base is greater than 0,
+ * the queue id of vmdq pools is started after pf queues.
+ */
+ if (dcb_mode == DCB_VT_ENABLED &&
+ rte_port->dev_info.vmdq_pool_base > 0) {
+ printf("VMDQ_DCB multi-queue mode is nonsensical"
+ " for port %d.", pid);
+ return -1;
+ }
+
+ /* Assume the ports in testpmd have the same dcb capability
+ * and has the same number of rxq and txq in dcb mode
+ */
+ if (dcb_mode == DCB_VT_ENABLED) {
+ if (rte_port->dev_info.max_vfs > 0) {
+ nb_rxq = rte_port->dev_info.nb_rx_queues;
+ nb_txq = rte_port->dev_info.nb_tx_queues;
+ } else {
+ nb_rxq = rte_port->dev_info.max_rx_queues;
+ nb_txq = rte_port->dev_info.max_tx_queues;
+ }
+ } else {
+ /*if vt is disabled, use all pf queues */
+ if (rte_port->dev_info.vmdq_pool_base == 0) {
+ nb_rxq = rte_port->dev_info.max_rx_queues;
+ nb_txq = rte_port->dev_info.max_tx_queues;
+ } else {
+ nb_rxq = (queueid_t)num_tcs;
+ nb_txq = (queueid_t)num_tcs;
+
+ }
+ }
+ rx_free_thresh = 64;
+
+ memcpy(&rte_port->dev_conf, &port_conf, sizeof(struct rte_eth_conf));
+
+ rxtx_port_config(rte_port);
+ /* VLAN filter */
+ rte_port->dev_conf.rxmode.offloads |= DEV_RX_OFFLOAD_VLAN_FILTER;
+ for (i = 0; i < RTE_DIM(vlan_tags); i++)
+ rx_vft_set(pid, vlan_tags[i], 1);
+
+ retval = eth_macaddr_get_print_err(pid, &rte_port->eth_addr);
+ if (retval != 0)
+ return retval;
+
+ map_port_queue_stats_mapping_registers(pid, rte_port);
+
+ rte_port->dcb_flag = 1;
+
+ return 0;
+}
+
+static void
+init_port(void)
+{
+ /* Configuration of Ethernet ports. */
+ ports = rte_zmalloc("testpmd: ports",
+ sizeof(struct rte_port) * RTE_MAX_ETHPORTS,
+ RTE_CACHE_LINE_SIZE);
+ if (ports == NULL) {
+ rte_exit(EXIT_FAILURE,
+ "rte_zmalloc(%d struct rte_port) failed\n",
+ RTE_MAX_ETHPORTS);
+ }
+
+ /* Initialize ports NUMA structures */
+ memset(port_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);
+ memset(rxring_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);
+ memset(txring_numa, NUMA_NO_CONFIG, RTE_MAX_ETHPORTS);
+}
+
+static void
+force_quit(void)
+{
+ pmd_test_exit();
+ prompt_exit();
+}
+
+static void
+print_stats(void)
+{
+ uint8_t i;
+ const char clr[] = { 27, '[', '2', 'J', '\0' };
+ const char top_left[] = { 27, '[', '1', ';', '1', 'H', '\0' };
+
+ /* Clear screen and move to top left */
+ printf("%s%s", clr, top_left);
+
+ printf("\nPort statistics ====================================");
+ for (i = 0; i < cur_fwd_config.nb_fwd_ports; i++)
+ nic_stats_display(fwd_ports_ids[i]);
+
+ fflush(stdout);
+}
+
+static void
+signal_handler(int signum)
+{
+ if (signum == SIGINT || signum == SIGTERM) {
+ printf("\nSignal %d received, preparing to exit...\n",
+ signum);
+#ifdef RTE_LIBRTE_PDUMP
+ /* uninitialize packet capture framework */
+ rte_pdump_uninit();
+#endif
+#ifdef RTE_LIBRTE_LATENCY_STATS
+ if (latencystats_enabled != 0)
+ rte_latencystats_uninit();
+#endif
+ force_quit();
+ /* Set flag to indicate the force termination. */
+ f_quit = 1;
+ /* exit with the expected status */
+ signal(signum, SIG_DFL);
+ kill(getpid(), signum);
+ }
+}
+
+int
+main(int argc, char** argv)
+{
+ int diag;
+ portid_t port_id;
+ uint16_t count;
+ int ret;
+
+ signal(SIGINT, signal_handler);
+ signal(SIGTERM, signal_handler);
+
+ testpmd_logtype = rte_log_register("testpmd");
+ if (testpmd_logtype < 0)
+ rte_exit(EXIT_FAILURE, "Cannot register log type");
+ rte_log_set_level(testpmd_logtype, RTE_LOG_DEBUG);
+
+ diag = rte_eal_init(argc, argv);
+ if (diag < 0)
+ rte_exit(EXIT_FAILURE, "Cannot init EAL: %s\n",
+ rte_strerror(rte_errno));
+
+ if (rte_eal_process_type() == RTE_PROC_SECONDARY)
+ rte_exit(EXIT_FAILURE,
+ "Secondary process type not supported.\n");
+
+ ret = register_eth_event_callback();
+ if (ret != 0)
+ rte_exit(EXIT_FAILURE, "Cannot register for ethdev events");
+
+#ifdef RTE_LIBRTE_PDUMP
+ /* initialize packet capture framework */
+ rte_pdump_init();
+#endif
+
+ count = 0;
+ RTE_ETH_FOREACH_DEV(port_id) {
+ ports_ids[count] = port_id;
+ count++;
+ }
+ nb_ports = (portid_t) count;
+ if (nb_ports == 0)
+ TESTPMD_LOG(WARNING, "No probed ethernet devices\n");
+
+ /* allocate port structures, and init them */
+ init_port();
+
+ set_def_fwd_config();
+ if (nb_lcores == 0)
+ rte_exit(EXIT_FAILURE, "No cores defined for forwarding\n"
+ "Check the core mask argument\n");
+
+ /* Bitrate/latency stats disabled by default */
+#ifdef RTE_LIBRTE_BITRATE
+ bitrate_enabled = 0;
+#endif
+#ifdef RTE_LIBRTE_LATENCY_STATS
+ latencystats_enabled = 0;
+#endif
+
+ /* on FreeBSD, mlockall() is disabled by default */
+#ifdef RTE_EXEC_ENV_FREEBSD
+ do_mlockall = 0;
+#else
+ do_mlockall = 1;
+#endif
+
+ argc -= diag;
+ argv += diag;
+ if (argc > 1)
+ launch_args_parse(argc, argv);
+
+ if (do_mlockall && mlockall(MCL_CURRENT | MCL_FUTURE)) {
+ TESTPMD_LOG(NOTICE, "mlockall() failed with error \"%s\"\n",
+ strerror(errno));
+ }
+
+ if (tx_first && interactive)
+ rte_exit(EXIT_FAILURE, "--tx-first cannot be used on "
+ "interactive mode.\n");
+
+ if (tx_first && lsc_interrupt) {
+ printf("Warning: lsc_interrupt needs to be off when "
+ " using tx_first. Disabling.\n");
+ lsc_interrupt = 0;
+ }
+
+ if (!nb_rxq && !nb_txq)
+ printf("Warning: Either rx or tx queues should be non-zero\n");
+
+ if (nb_rxq > 1 && nb_rxq > nb_txq)
+ printf("Warning: nb_rxq=%d enables RSS configuration, "
+ "but nb_txq=%d will prevent to fully test it.\n",
+ nb_rxq, nb_txq);
+
+ init_config();
+
+ if (hot_plug) {
+ ret = rte_dev_hotplug_handle_enable();
+ if (ret) {
+ RTE_LOG(ERR, EAL,
+ "fail to enable hotplug handling.");
+ return -1;
+ }
+
+ ret = rte_dev_event_monitor_start();
+ if (ret) {
+ RTE_LOG(ERR, EAL,
+ "fail to start device event monitoring.");
+ return -1;
+ }
+
+ ret = rte_dev_event_callback_register(NULL,
+ dev_event_callback, NULL);
+ if (ret) {
+ RTE_LOG(ERR, EAL,
+ "fail to register device event callback\n");
+ return -1;
+ }
+ }
+
+ if (!no_device_start && start_port(RTE_PORT_ALL) != 0)
+ rte_exit(EXIT_FAILURE, "Start ports failed\n");
+
+ /* set all ports to promiscuous mode by default */
+ RTE_ETH_FOREACH_DEV(port_id) {
+ ret = rte_eth_promiscuous_enable(port_id);
+ if (ret != 0)
+ printf("Error during enabling promiscuous mode for port %u: %s - ignore\n",
+ port_id, rte_strerror(-ret));
+ }
+
+ /* Init metrics library */
+ rte_metrics_init(rte_socket_id());
+
+#ifdef RTE_LIBRTE_LATENCY_STATS
+ if (latencystats_enabled != 0) {
+ int ret = rte_latencystats_init(1, NULL);
+ if (ret)
+ printf("Warning: latencystats init()"
+ " returned error %d\n", ret);
+ printf("Latencystats running on lcore %d\n",
+ latencystats_lcore_id);
+ }
+#endif
+
+ /* Setup bitrate stats */
+#ifdef RTE_LIBRTE_BITRATE
+ if (bitrate_enabled != 0) {
+ bitrate_data = rte_stats_bitrate_create();
+ if (bitrate_data == NULL)
+ rte_exit(EXIT_FAILURE,
+ "Could not allocate bitrate data.\n");
+ rte_stats_bitrate_reg(bitrate_data);
+ }
+#endif
+
+#ifdef RTE_LIBRTE_CMDLINE
+ if (strlen(cmdline_filename) != 0)
+ cmdline_read_from_file(cmdline_filename);
+
+ if (interactive == 1) {
+ if (auto_start) {
+ printf("Start automatic packet forwarding\n");
+ start_packet_forwarding(0);
+ }
+ prompt();
+ pmd_test_exit();
+ } else
+#endif
+ {
+ char c;
+ int rc;
+
+ f_quit = 0;
+
+ printf("No commandline core given, start packet forwarding\n");
+ start_packet_forwarding(tx_first);
+ if (stats_period != 0) {
+ uint64_t prev_time = 0, cur_time, diff_time = 0;
+ uint64_t timer_period;
+
+ /* Convert to number of cycles */
+ timer_period = stats_period * rte_get_timer_hz();
+
+ while (f_quit == 0) {
+ cur_time = rte_get_timer_cycles();
+ diff_time += cur_time - prev_time;
+
+ if (diff_time >= timer_period) {
+ print_stats();
+ /* Reset the timer */
+ diff_time = 0;
+ }
+ /* Sleep to avoid unnecessary checks */
+ prev_time = cur_time;
+ sleep(1);
+ }
+ }
+
+ printf("Press enter to exit\n");
+ rc = read(0, &c, 1);
+ pmd_test_exit();
+ if (rc < 0)
+ return 1;
+ }
+
+ ret = rte_eal_cleanup();
+ if (ret != 0)
+ rte_exit(EXIT_FAILURE,
+ "EAL cleanup failed: %s\n", strerror(-ret));
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/spdk/dpdk/app/test-pmd/testpmd.h b/src/spdk/dpdk/app/test-pmd/testpmd.h
new file mode 100644
index 000000000..a80375093
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/testpmd.h
@@ -0,0 +1,938 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2017 Intel Corporation
+ */
+
+#ifndef _TESTPMD_H_
+#define _TESTPMD_H_
+
+#include <stdbool.h>
+
+#include <rte_pci.h>
+#include <rte_bus_pci.h>
+#include <rte_gro.h>
+#include <rte_gso.h>
+#include <cmdline.h>
+
+#define RTE_PORT_ALL (~(portid_t)0x0)
+
+#define RTE_TEST_RX_DESC_MAX 2048
+#define RTE_TEST_TX_DESC_MAX 2048
+
+#define RTE_PORT_STOPPED (uint16_t)0
+#define RTE_PORT_STARTED (uint16_t)1
+#define RTE_PORT_CLOSED (uint16_t)2
+#define RTE_PORT_HANDLING (uint16_t)3
+
+/*
+ * It is used to allocate the memory for hash key.
+ * The hash key size is NIC dependent.
+ */
+#define RSS_HASH_KEY_LENGTH 64
+
+/*
+ * Default size of the mbuf data buffer to receive standard 1518-byte
+ * Ethernet frames in a mono-segment memory buffer.
+ */
+#define DEFAULT_MBUF_DATA_SIZE RTE_MBUF_DEFAULT_BUF_SIZE
+/**< Default size of mbuf data buffer. */
+
+/*
+ * The maximum number of segments per packet is used when creating
+ * scattered transmit packets composed of a list of mbufs.
+ */
+#define RTE_MAX_SEGS_PER_PKT 255 /**< nb_segs is a 8-bit unsigned char. */
+
+#define MAX_PKT_BURST 512
+#define DEF_PKT_BURST 32
+
+#define DEF_MBUF_CACHE 250
+
+#define RTE_CACHE_LINE_SIZE_ROUNDUP(size) \
+ (RTE_CACHE_LINE_SIZE * ((size + RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE))
+
+#define NUMA_NO_CONFIG 0xFF
+#define UMA_NO_CONFIG 0xFF
+
+typedef uint8_t lcoreid_t;
+typedef uint16_t portid_t;
+typedef uint16_t queueid_t;
+typedef uint16_t streamid_t;
+
+#if defined RTE_LIBRTE_PMD_SOFTNIC
+#define SOFTNIC 1
+#else
+#define SOFTNIC 0
+#endif
+
+enum {
+ PORT_TOPOLOGY_PAIRED,
+ PORT_TOPOLOGY_CHAINED,
+ PORT_TOPOLOGY_LOOP,
+};
+
+enum {
+ MP_ALLOC_NATIVE, /**< allocate and populate mempool natively */
+ MP_ALLOC_ANON,
+ /**< allocate mempool natively, but populate using anonymous memory */
+ MP_ALLOC_XMEM,
+ /**< allocate and populate mempool using anonymous memory */
+ MP_ALLOC_XMEM_HUGE,
+ /**< allocate and populate mempool using anonymous hugepage memory */
+ MP_ALLOC_XBUF
+ /**< allocate mempool natively, use rte_pktmbuf_pool_create_extbuf */
+};
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+/**
+ * The data structure associated with RX and TX packet burst statistics
+ * that are recorded for each forwarding stream.
+ */
+struct pkt_burst_stats {
+ unsigned int pkt_burst_spread[MAX_PKT_BURST];
+};
+#endif
+
+/** Information for a given RSS type. */
+struct rss_type_info {
+ const char *str; /**< Type name. */
+ uint64_t rss_type; /**< Type value. */
+};
+
+/**
+ * RSS type information table.
+ *
+ * An entry with a NULL type name terminates the list.
+ */
+extern const struct rss_type_info rss_type_table[];
+
+/**
+ * Dynf name array.
+ *
+ * Array that holds the name for each dynf.
+ */
+extern char dynf_names[64][RTE_MBUF_DYN_NAMESIZE];
+
+/**
+ * The data structure associated with a forwarding stream between a receive
+ * port/queue and a transmit port/queue.
+ */
+struct fwd_stream {
+ /* "read-only" data */
+ portid_t rx_port; /**< port to poll for received packets */
+ queueid_t rx_queue; /**< RX queue to poll on "rx_port" */
+ portid_t tx_port; /**< forwarding port of received packets */
+ queueid_t tx_queue; /**< TX queue to send forwarded packets */
+ streamid_t peer_addr; /**< index of peer ethernet address of packets */
+
+ unsigned int retry_enabled;
+
+ /* "read-write" results */
+ uint64_t rx_packets; /**< received packets */
+ uint64_t tx_packets; /**< received packets transmitted */
+ uint64_t fwd_dropped; /**< received packets not forwarded */
+ uint64_t rx_bad_ip_csum ; /**< received packets has bad ip checksum */
+ uint64_t rx_bad_l4_csum ; /**< received packets has bad l4 checksum */
+ uint64_t rx_bad_outer_l4_csum;
+ /**< received packets has bad outer l4 checksum */
+ unsigned int gro_times; /**< GRO operation times */
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ uint64_t core_cycles; /**< used for RX and TX processing */
+#endif
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ struct pkt_burst_stats rx_burst_stats;
+ struct pkt_burst_stats tx_burst_stats;
+#endif
+};
+
+/** Descriptor for a single flow. */
+struct port_flow {
+ struct port_flow *next; /**< Next flow in list. */
+ struct port_flow *tmp; /**< Temporary linking. */
+ uint32_t id; /**< Flow rule ID. */
+ struct rte_flow *flow; /**< Opaque flow object returned by PMD. */
+ struct rte_flow_conv_rule rule; /* Saved flow rule description. */
+ uint8_t data[]; /**< Storage for flow rule description */
+};
+
+#ifdef SOFTNIC
+/**
+ * The data structure associate with softnic port
+ */
+struct softnic_port {
+ uint32_t default_tm_hierarchy_enable; /**< default tm hierarchy */
+ struct fwd_lcore **fwd_lcore_arg; /**< softnic fwd core parameters */
+};
+#endif
+
+/**
+ * The data structure associated with each port.
+ */
+struct rte_port {
+ struct rte_eth_dev_info dev_info; /**< PCI info + driver name */
+ struct rte_eth_conf dev_conf; /**< Port configuration. */
+ struct rte_ether_addr eth_addr; /**< Port ethernet address */
+ struct rte_eth_stats stats; /**< Last port statistics */
+ unsigned int socket_id; /**< For NUMA support */
+ uint16_t parse_tunnel:1; /**< Parse internal headers */
+ uint16_t tso_segsz; /**< Segmentation offload MSS for non-tunneled packets. */
+ uint16_t tunnel_tso_segsz; /**< Segmentation offload MSS for tunneled pkts. */
+ uint16_t tx_vlan_id;/**< The tag ID */
+ uint16_t tx_vlan_id_outer;/**< The outer tag ID */
+ uint8_t tx_queue_stats_mapping_enabled;
+ uint8_t rx_queue_stats_mapping_enabled;
+ volatile uint16_t port_status; /**< port started or not */
+ uint8_t need_setup; /**< port just attached */
+ uint8_t need_reconfig; /**< need reconfiguring port or not */
+ uint8_t need_reconfig_queues; /**< need reconfiguring queues or not */
+ uint8_t rss_flag; /**< enable rss or not */
+ uint8_t dcb_flag; /**< enable dcb */
+ uint16_t nb_rx_desc[RTE_MAX_QUEUES_PER_PORT+1]; /**< per queue rx desc number */
+ uint16_t nb_tx_desc[RTE_MAX_QUEUES_PER_PORT+1]; /**< per queue tx desc number */
+ struct rte_eth_rxconf rx_conf[RTE_MAX_QUEUES_PER_PORT+1]; /**< per queue rx configuration */
+ struct rte_eth_txconf tx_conf[RTE_MAX_QUEUES_PER_PORT+1]; /**< per queue tx configuration */
+ struct rte_ether_addr *mc_addr_pool; /**< pool of multicast addrs */
+ uint32_t mc_addr_nb; /**< nb. of addr. in mc_addr_pool */
+ uint8_t slave_flag; /**< bonding slave port */
+ struct port_flow *flow_list; /**< Associated flows. */
+ const struct rte_eth_rxtx_callback *rx_dump_cb[RTE_MAX_QUEUES_PER_PORT+1];
+ const struct rte_eth_rxtx_callback *tx_dump_cb[RTE_MAX_QUEUES_PER_PORT+1];
+#ifdef SOFTNIC
+ struct softnic_port softport; /**< softnic params */
+#endif
+ /**< metadata value to insert in Tx packets. */
+ uint32_t tx_metadata;
+ const struct rte_eth_rxtx_callback *tx_set_md_cb[RTE_MAX_QUEUES_PER_PORT+1];
+ /**< dynamic flags. */
+ uint64_t mbuf_dynf;
+ const struct rte_eth_rxtx_callback *tx_set_dynf_cb[RTE_MAX_QUEUES_PER_PORT+1];
+};
+
+/**
+ * The data structure associated with each forwarding logical core.
+ * The logical cores are internally numbered by a core index from 0 to
+ * the maximum number of logical cores - 1.
+ * The system CPU identifier of all logical cores are setup in a global
+ * CPU id. configuration table.
+ */
+struct fwd_lcore {
+ struct rte_gso_ctx gso_ctx; /**< GSO context */
+ struct rte_mempool *mbp; /**< The mbuf pool to use by this core */
+ void *gro_ctx; /**< GRO context */
+ streamid_t stream_idx; /**< index of 1st stream in "fwd_streams" */
+ streamid_t stream_nb; /**< number of streams in "fwd_streams" */
+ lcoreid_t cpuid_idx; /**< index of logical core in CPU id table */
+ queueid_t tx_queue; /**< TX queue to send forwarded packets */
+ volatile char stopped; /**< stop forwarding when set */
+};
+
+/*
+ * Forwarding mode operations:
+ * - IO forwarding mode (default mode)
+ * Forwards packets unchanged.
+ *
+ * - MAC forwarding mode
+ * Set the source and the destination Ethernet addresses of packets
+ * before forwarding them.
+ *
+ * - IEEE1588 forwarding mode
+ * Check that received IEEE1588 Precise Time Protocol (PTP) packets are
+ * filtered and timestamped by the hardware.
+ * Forwards packets unchanged on the same port.
+ * Check that sent IEEE1588 PTP packets are timestamped by the hardware.
+ */
+typedef void (*port_fwd_begin_t)(portid_t pi);
+typedef void (*port_fwd_end_t)(portid_t pi);
+typedef void (*packet_fwd_t)(struct fwd_stream *fs);
+
+struct fwd_engine {
+ const char *fwd_mode_name; /**< Forwarding mode name. */
+ port_fwd_begin_t port_fwd_begin; /**< NULL if nothing special to do. */
+ port_fwd_end_t port_fwd_end; /**< NULL if nothing special to do. */
+ packet_fwd_t packet_fwd; /**< Mandatory. */
+};
+
+#define BURST_TX_WAIT_US 1
+#define BURST_TX_RETRIES 64
+
+extern uint32_t burst_tx_delay_time;
+extern uint32_t burst_tx_retry_num;
+
+extern struct fwd_engine io_fwd_engine;
+extern struct fwd_engine mac_fwd_engine;
+extern struct fwd_engine mac_swap_engine;
+extern struct fwd_engine flow_gen_engine;
+extern struct fwd_engine rx_only_engine;
+extern struct fwd_engine tx_only_engine;
+extern struct fwd_engine csum_fwd_engine;
+extern struct fwd_engine icmp_echo_engine;
+extern struct fwd_engine noisy_vnf_engine;
+#ifdef SOFTNIC
+extern struct fwd_engine softnic_fwd_engine;
+#endif
+#ifdef RTE_LIBRTE_IEEE1588
+extern struct fwd_engine ieee1588_fwd_engine;
+#endif
+
+extern struct fwd_engine * fwd_engines[]; /**< NULL terminated array. */
+extern cmdline_parse_inst_t cmd_set_raw;
+extern cmdline_parse_inst_t cmd_show_set_raw;
+extern cmdline_parse_inst_t cmd_show_set_raw_all;
+
+extern uint16_t mempool_flags;
+
+/**
+ * Forwarding Configuration
+ *
+ */
+struct fwd_config {
+ struct fwd_engine *fwd_eng; /**< Packet forwarding mode. */
+ streamid_t nb_fwd_streams; /**< Nb. of forward streams to process. */
+ lcoreid_t nb_fwd_lcores; /**< Nb. of logical cores to launch. */
+ portid_t nb_fwd_ports; /**< Nb. of ports involved. */
+};
+
+/**
+ * DCB mode enable
+ */
+enum dcb_mode_enable
+{
+ DCB_VT_ENABLED,
+ DCB_ENABLED
+};
+
+#define MAX_TX_QUEUE_STATS_MAPPINGS 1024 /* MAX_PORT of 32 @ 32 tx_queues/port */
+#define MAX_RX_QUEUE_STATS_MAPPINGS 4096 /* MAX_PORT of 32 @ 128 rx_queues/port */
+
+struct queue_stats_mappings {
+ portid_t port_id;
+ uint16_t queue_id;
+ uint8_t stats_counter_id;
+} __rte_cache_aligned;
+
+extern struct queue_stats_mappings tx_queue_stats_mappings_array[];
+extern struct queue_stats_mappings rx_queue_stats_mappings_array[];
+
+/* Assign both tx and rx queue stats mappings to the same default values */
+extern struct queue_stats_mappings *tx_queue_stats_mappings;
+extern struct queue_stats_mappings *rx_queue_stats_mappings;
+
+extern uint16_t nb_tx_queue_stats_mappings;
+extern uint16_t nb_rx_queue_stats_mappings;
+
+extern uint8_t xstats_hide_zero; /**< Hide zero values for xstats display */
+
+/* globals used for configuration */
+extern uint16_t verbose_level; /**< Drives messages being displayed, if any. */
+extern int testpmd_logtype; /**< Log type for testpmd logs */
+extern uint8_t interactive;
+extern uint8_t auto_start;
+extern uint8_t tx_first;
+extern char cmdline_filename[PATH_MAX]; /**< offline commands file */
+extern uint8_t numa_support; /**< set by "--numa" parameter */
+extern uint16_t port_topology; /**< set by "--port-topology" parameter */
+extern uint8_t no_flush_rx; /**<set by "--no-flush-rx" parameter */
+extern uint8_t flow_isolate_all; /**< set by "--flow-isolate-all */
+extern uint8_t mp_alloc_type;
+/**< set by "--mp-anon" or "--mp-alloc" parameter */
+extern uint8_t no_link_check; /**<set by "--disable-link-check" parameter */
+extern uint8_t no_device_start; /**<set by "--disable-device-start" parameter */
+extern volatile int test_done; /* stop packet forwarding when set to 1. */
+extern uint8_t lsc_interrupt; /**< disabled by "--no-lsc-interrupt" parameter */
+extern uint8_t rmv_interrupt; /**< disabled by "--no-rmv-interrupt" parameter */
+extern uint32_t event_print_mask;
+/**< set by "--print-event xxxx" and "--mask-event xxxx parameters */
+extern bool setup_on_probe_event; /**< disabled by port setup-on iterator */
+extern uint8_t hot_plug; /**< enable by "--hot-plug" parameter */
+extern int do_mlockall; /**< set by "--mlockall" or "--no-mlockall" parameter */
+extern uint8_t clear_ptypes; /**< disabled by set ptype cmd */
+
+#ifdef RTE_LIBRTE_IXGBE_BYPASS
+extern uint32_t bypass_timeout; /**< Store the NIC bypass watchdog timeout */
+#endif
+
+/*
+ * Store specified sockets on which memory pool to be used by ports
+ * is allocated.
+ */
+extern uint8_t port_numa[RTE_MAX_ETHPORTS];
+
+/*
+ * Store specified sockets on which RX ring to be used by ports
+ * is allocated.
+ */
+extern uint8_t rxring_numa[RTE_MAX_ETHPORTS];
+
+/*
+ * Store specified sockets on which TX ring to be used by ports
+ * is allocated.
+ */
+extern uint8_t txring_numa[RTE_MAX_ETHPORTS];
+
+extern uint8_t socket_num;
+
+/*
+ * Configuration of logical cores:
+ * nb_fwd_lcores <= nb_cfg_lcores <= nb_lcores
+ */
+extern lcoreid_t nb_lcores; /**< Number of logical cores probed at init time. */
+extern lcoreid_t nb_cfg_lcores; /**< Number of configured logical cores. */
+extern lcoreid_t nb_fwd_lcores; /**< Number of forwarding logical cores. */
+extern unsigned int fwd_lcores_cpuids[RTE_MAX_LCORE];
+extern unsigned int num_sockets;
+extern unsigned int socket_ids[RTE_MAX_NUMA_NODES];
+
+/*
+ * Configuration of Ethernet ports:
+ * nb_fwd_ports <= nb_cfg_ports <= nb_ports
+ */
+extern portid_t nb_ports; /**< Number of ethernet ports probed at init time. */
+extern portid_t nb_cfg_ports; /**< Number of configured ports. */
+extern portid_t nb_fwd_ports; /**< Number of forwarding ports. */
+extern portid_t fwd_ports_ids[RTE_MAX_ETHPORTS];
+extern struct rte_port *ports;
+
+extern struct rte_eth_rxmode rx_mode;
+extern struct rte_eth_txmode tx_mode;
+
+extern uint64_t rss_hf;
+
+extern queueid_t nb_hairpinq;
+extern queueid_t nb_rxq;
+extern queueid_t nb_txq;
+
+extern uint16_t nb_rxd;
+extern uint16_t nb_txd;
+
+extern int16_t rx_free_thresh;
+extern int8_t rx_drop_en;
+extern int16_t tx_free_thresh;
+extern int16_t tx_rs_thresh;
+
+extern uint16_t noisy_tx_sw_bufsz;
+extern uint16_t noisy_tx_sw_buf_flush_time;
+extern uint64_t noisy_lkup_mem_sz;
+extern uint64_t noisy_lkup_num_writes;
+extern uint64_t noisy_lkup_num_reads;
+extern uint64_t noisy_lkup_num_reads_writes;
+
+extern uint8_t dcb_config;
+extern uint8_t dcb_test;
+
+extern uint16_t mbuf_data_size; /**< Mbuf data space size. */
+extern uint32_t param_total_num_mbufs;
+
+extern uint16_t stats_period;
+
+#ifdef RTE_LIBRTE_LATENCY_STATS
+extern uint8_t latencystats_enabled;
+extern lcoreid_t latencystats_lcore_id;
+#endif
+
+#ifdef RTE_LIBRTE_BITRATE
+extern lcoreid_t bitrate_lcore_id;
+extern uint8_t bitrate_enabled;
+#endif
+
+extern struct rte_fdir_conf fdir_conf;
+
+/*
+ * Configuration of packet segments used by the "txonly" processing engine.
+ */
+#define TXONLY_DEF_PACKET_LEN 64
+extern uint16_t tx_pkt_length; /**< Length of TXONLY packet */
+extern uint16_t tx_pkt_seg_lengths[RTE_MAX_SEGS_PER_PKT]; /**< Seg. lengths */
+extern uint8_t tx_pkt_nb_segs; /**< Number of segments in TX packets */
+
+enum tx_pkt_split {
+ TX_PKT_SPLIT_OFF,
+ TX_PKT_SPLIT_ON,
+ TX_PKT_SPLIT_RND,
+};
+
+extern enum tx_pkt_split tx_pkt_split;
+
+extern uint8_t txonly_multi_flow;
+
+extern uint16_t nb_pkt_per_burst;
+extern uint16_t mb_mempool_cache;
+extern int8_t rx_pthresh;
+extern int8_t rx_hthresh;
+extern int8_t rx_wthresh;
+extern int8_t tx_pthresh;
+extern int8_t tx_hthresh;
+extern int8_t tx_wthresh;
+
+extern uint16_t tx_udp_src_port;
+extern uint16_t tx_udp_dst_port;
+
+extern uint32_t tx_ip_src_addr;
+extern uint32_t tx_ip_dst_addr;
+
+extern struct fwd_config cur_fwd_config;
+extern struct fwd_engine *cur_fwd_eng;
+extern uint32_t retry_enabled;
+extern struct fwd_lcore **fwd_lcores;
+extern struct fwd_stream **fwd_streams;
+
+extern uint16_t vxlan_gpe_udp_port; /**< UDP port of tunnel VXLAN-GPE. */
+
+extern portid_t nb_peer_eth_addrs; /**< Number of peer ethernet addresses. */
+extern struct rte_ether_addr peer_eth_addrs[RTE_MAX_ETHPORTS];
+
+extern uint32_t burst_tx_delay_time; /**< Burst tx delay time(us) for mac-retry. */
+extern uint32_t burst_tx_retry_num; /**< Burst tx retry number for mac-retry. */
+
+#define GRO_DEFAULT_ITEM_NUM_PER_FLOW 32
+#define GRO_DEFAULT_FLOW_NUM (RTE_GRO_MAX_BURST_ITEM_NUM / \
+ GRO_DEFAULT_ITEM_NUM_PER_FLOW)
+
+#define GRO_DEFAULT_FLUSH_CYCLES 1
+#define GRO_MAX_FLUSH_CYCLES 4
+
+struct gro_status {
+ struct rte_gro_param param;
+ uint8_t enable;
+};
+extern struct gro_status gro_ports[RTE_MAX_ETHPORTS];
+extern uint8_t gro_flush_cycles;
+
+#define GSO_MAX_PKT_BURST 2048
+struct gso_status {
+ uint8_t enable;
+};
+extern struct gso_status gso_ports[RTE_MAX_ETHPORTS];
+extern uint16_t gso_max_segment_size;
+
+/* VXLAN encap/decap parameters. */
+struct vxlan_encap_conf {
+ uint32_t select_ipv4:1;
+ uint32_t select_vlan:1;
+ uint32_t select_tos_ttl:1;
+ uint8_t vni[3];
+ rte_be16_t udp_src;
+ rte_be16_t udp_dst;
+ rte_be32_t ipv4_src;
+ rte_be32_t ipv4_dst;
+ uint8_t ipv6_src[16];
+ uint8_t ipv6_dst[16];
+ rte_be16_t vlan_tci;
+ uint8_t ip_tos;
+ uint8_t ip_ttl;
+ uint8_t eth_src[RTE_ETHER_ADDR_LEN];
+ uint8_t eth_dst[RTE_ETHER_ADDR_LEN];
+};
+
+extern struct vxlan_encap_conf vxlan_encap_conf;
+
+/* NVGRE encap/decap parameters. */
+struct nvgre_encap_conf {
+ uint32_t select_ipv4:1;
+ uint32_t select_vlan:1;
+ uint8_t tni[3];
+ rte_be32_t ipv4_src;
+ rte_be32_t ipv4_dst;
+ uint8_t ipv6_src[16];
+ uint8_t ipv6_dst[16];
+ rte_be16_t vlan_tci;
+ uint8_t eth_src[RTE_ETHER_ADDR_LEN];
+ uint8_t eth_dst[RTE_ETHER_ADDR_LEN];
+};
+
+extern struct nvgre_encap_conf nvgre_encap_conf;
+
+/* L2 encap parameters. */
+struct l2_encap_conf {
+ uint32_t select_ipv4:1;
+ uint32_t select_vlan:1;
+ rte_be16_t vlan_tci;
+ uint8_t eth_src[RTE_ETHER_ADDR_LEN];
+ uint8_t eth_dst[RTE_ETHER_ADDR_LEN];
+};
+extern struct l2_encap_conf l2_encap_conf;
+
+/* L2 decap parameters. */
+struct l2_decap_conf {
+ uint32_t select_vlan:1;
+};
+extern struct l2_decap_conf l2_decap_conf;
+
+/* MPLSoGRE encap parameters. */
+struct mplsogre_encap_conf {
+ uint32_t select_ipv4:1;
+ uint32_t select_vlan:1;
+ uint8_t label[3];
+ rte_be32_t ipv4_src;
+ rte_be32_t ipv4_dst;
+ uint8_t ipv6_src[16];
+ uint8_t ipv6_dst[16];
+ rte_be16_t vlan_tci;
+ uint8_t eth_src[RTE_ETHER_ADDR_LEN];
+ uint8_t eth_dst[RTE_ETHER_ADDR_LEN];
+};
+extern struct mplsogre_encap_conf mplsogre_encap_conf;
+
+/* MPLSoGRE decap parameters. */
+struct mplsogre_decap_conf {
+ uint32_t select_ipv4:1;
+ uint32_t select_vlan:1;
+};
+extern struct mplsogre_decap_conf mplsogre_decap_conf;
+
+/* MPLSoUDP encap parameters. */
+struct mplsoudp_encap_conf {
+ uint32_t select_ipv4:1;
+ uint32_t select_vlan:1;
+ uint8_t label[3];
+ rte_be16_t udp_src;
+ rte_be16_t udp_dst;
+ rte_be32_t ipv4_src;
+ rte_be32_t ipv4_dst;
+ uint8_t ipv6_src[16];
+ uint8_t ipv6_dst[16];
+ rte_be16_t vlan_tci;
+ uint8_t eth_src[RTE_ETHER_ADDR_LEN];
+ uint8_t eth_dst[RTE_ETHER_ADDR_LEN];
+};
+extern struct mplsoudp_encap_conf mplsoudp_encap_conf;
+
+/* MPLSoUDP decap parameters. */
+struct mplsoudp_decap_conf {
+ uint32_t select_ipv4:1;
+ uint32_t select_vlan:1;
+};
+extern struct mplsoudp_decap_conf mplsoudp_decap_conf;
+
+extern enum rte_eth_rx_mq_mode rx_mq_mode;
+
+static inline unsigned int
+lcore_num(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < RTE_MAX_LCORE; ++i)
+ if (fwd_lcores_cpuids[i] == rte_lcore_id())
+ return i;
+
+ rte_panic("lcore_id of current thread not found in fwd_lcores_cpuids\n");
+}
+
+void
+parse_fwd_portlist(const char *port);
+
+static inline struct fwd_lcore *
+current_fwd_lcore(void)
+{
+ return fwd_lcores[lcore_num()];
+}
+
+/* Mbuf Pools */
+static inline void
+mbuf_poolname_build(unsigned int sock_id, char* mp_name, int name_size)
+{
+ snprintf(mp_name, name_size, "mbuf_pool_socket_%u", sock_id);
+}
+
+static inline struct rte_mempool *
+mbuf_pool_find(unsigned int sock_id)
+{
+ char pool_name[RTE_MEMPOOL_NAMESIZE];
+
+ mbuf_poolname_build(sock_id, pool_name, sizeof(pool_name));
+ return rte_mempool_lookup((const char *)pool_name);
+}
+
+/**
+ * Read/Write operations on a PCI register of a port.
+ */
+static inline uint32_t
+port_pci_reg_read(struct rte_port *port, uint32_t reg_off)
+{
+ const struct rte_pci_device *pci_dev;
+ const struct rte_bus *bus;
+ void *reg_addr;
+ uint32_t reg_v;
+
+ if (!port->dev_info.device) {
+ printf("Invalid device\n");
+ return 0;
+ }
+
+ bus = rte_bus_find_by_device(port->dev_info.device);
+ if (bus && !strcmp(bus->name, "pci")) {
+ pci_dev = RTE_DEV_TO_PCI(port->dev_info.device);
+ } else {
+ printf("Not a PCI device\n");
+ return 0;
+ }
+
+ reg_addr = ((char *)pci_dev->mem_resource[0].addr + reg_off);
+ reg_v = *((volatile uint32_t *)reg_addr);
+ return rte_le_to_cpu_32(reg_v);
+}
+
+#define port_id_pci_reg_read(pt_id, reg_off) \
+ port_pci_reg_read(&ports[(pt_id)], (reg_off))
+
+static inline void
+port_pci_reg_write(struct rte_port *port, uint32_t reg_off, uint32_t reg_v)
+{
+ const struct rte_pci_device *pci_dev;
+ const struct rte_bus *bus;
+ void *reg_addr;
+
+ if (!port->dev_info.device) {
+ printf("Invalid device\n");
+ return;
+ }
+
+ bus = rte_bus_find_by_device(port->dev_info.device);
+ if (bus && !strcmp(bus->name, "pci")) {
+ pci_dev = RTE_DEV_TO_PCI(port->dev_info.device);
+ } else {
+ printf("Not a PCI device\n");
+ return;
+ }
+
+ reg_addr = ((char *)pci_dev->mem_resource[0].addr + reg_off);
+ *((volatile uint32_t *)reg_addr) = rte_cpu_to_le_32(reg_v);
+}
+
+#define port_id_pci_reg_write(pt_id, reg_off, reg_value) \
+ port_pci_reg_write(&ports[(pt_id)], (reg_off), (reg_value))
+
+/* Prototypes */
+unsigned int parse_item_list(char* str, const char* item_name,
+ unsigned int max_items,
+ unsigned int *parsed_items, int check_unique_values);
+void launch_args_parse(int argc, char** argv);
+void cmdline_read_from_file(const char *filename);
+void prompt(void);
+void prompt_exit(void);
+void nic_stats_display(portid_t port_id);
+void nic_stats_clear(portid_t port_id);
+void nic_xstats_display(portid_t port_id);
+void nic_xstats_clear(portid_t port_id);
+void nic_stats_mapping_display(portid_t port_id);
+void device_infos_display(const char *identifier);
+void port_infos_display(portid_t port_id);
+void port_summary_display(portid_t port_id);
+void port_summary_header_display(void);
+void port_offload_cap_display(portid_t port_id);
+void rx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
+void tx_queue_infos_display(portid_t port_idi, uint16_t queue_id);
+void fwd_lcores_config_display(void);
+void pkt_fwd_config_display(struct fwd_config *cfg);
+void rxtx_config_display(void);
+void fwd_config_setup(void);
+void set_def_fwd_config(void);
+void reconfig(portid_t new_port_id, unsigned socket_id);
+int init_fwd_streams(void);
+void update_fwd_ports(portid_t new_pid);
+
+void set_fwd_eth_peer(portid_t port_id, char *peer_addr);
+
+void port_mtu_set(portid_t port_id, uint16_t mtu);
+void port_reg_bit_display(portid_t port_id, uint32_t reg_off, uint8_t bit_pos);
+void port_reg_bit_set(portid_t port_id, uint32_t reg_off, uint8_t bit_pos,
+ uint8_t bit_v);
+void port_reg_bit_field_display(portid_t port_id, uint32_t reg_off,
+ uint8_t bit1_pos, uint8_t bit2_pos);
+void port_reg_bit_field_set(portid_t port_id, uint32_t reg_off,
+ uint8_t bit1_pos, uint8_t bit2_pos, uint32_t value);
+void port_reg_display(portid_t port_id, uint32_t reg_off);
+void port_reg_set(portid_t port_id, uint32_t reg_off, uint32_t value);
+int port_flow_validate(portid_t port_id,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item *pattern,
+ const struct rte_flow_action *actions);
+int port_flow_create(portid_t port_id,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item *pattern,
+ const struct rte_flow_action *actions);
+void update_age_action_context(const struct rte_flow_action *actions,
+ struct port_flow *pf);
+int port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule);
+int port_flow_flush(portid_t port_id);
+int port_flow_dump(portid_t port_id, const char *file_name);
+int port_flow_query(portid_t port_id, uint32_t rule,
+ const struct rte_flow_action *action);
+void port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group);
+void port_flow_aged(portid_t port_id, uint8_t destroy);
+int port_flow_isolate(portid_t port_id, int set);
+
+void rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id);
+void tx_ring_desc_display(portid_t port_id, queueid_t txq_id, uint16_t txd_id);
+
+int set_fwd_lcores_list(unsigned int *lcorelist, unsigned int nb_lc);
+int set_fwd_lcores_mask(uint64_t lcoremask);
+void set_fwd_lcores_number(uint16_t nb_lc);
+
+void set_fwd_ports_list(unsigned int *portlist, unsigned int nb_pt);
+void set_fwd_ports_mask(uint64_t portmask);
+void set_fwd_ports_number(uint16_t nb_pt);
+int port_is_forwarding(portid_t port_id);
+
+void rx_vlan_strip_set(portid_t port_id, int on);
+void rx_vlan_strip_set_on_queue(portid_t port_id, uint16_t queue_id, int on);
+
+void rx_vlan_filter_set(portid_t port_id, int on);
+void rx_vlan_all_filter_set(portid_t port_id, int on);
+void rx_vlan_qinq_strip_set(portid_t port_id, int on);
+int rx_vft_set(portid_t port_id, uint16_t vlan_id, int on);
+void vlan_extend_set(portid_t port_id, int on);
+void vlan_tpid_set(portid_t port_id, enum rte_vlan_type vlan_type,
+ uint16_t tp_id);
+void tx_vlan_set(portid_t port_id, uint16_t vlan_id);
+void tx_qinq_set(portid_t port_id, uint16_t vlan_id, uint16_t vlan_id_outer);
+void tx_vlan_reset(portid_t port_id);
+void tx_vlan_pvid_set(portid_t port_id, uint16_t vlan_id, int on);
+
+void set_qmap(portid_t port_id, uint8_t is_rx, uint16_t queue_id, uint8_t map_value);
+
+void set_xstats_hide_zero(uint8_t on_off);
+
+void set_verbose_level(uint16_t vb_level);
+void set_tx_pkt_segments(unsigned *seg_lengths, unsigned nb_segs);
+void show_tx_pkt_segments(void);
+void set_tx_pkt_split(const char *name);
+void set_nb_pkt_per_burst(uint16_t pkt_burst);
+char *list_pkt_forwarding_modes(void);
+char *list_pkt_forwarding_retry_modes(void);
+void set_pkt_forwarding_mode(const char *fwd_mode);
+void start_packet_forwarding(int with_tx_first);
+void fwd_stats_display(void);
+void fwd_stats_reset(void);
+void stop_packet_forwarding(void);
+void dev_set_link_up(portid_t pid);
+void dev_set_link_down(portid_t pid);
+void init_port_config(void);
+void set_port_slave_flag(portid_t slave_pid);
+void clear_port_slave_flag(portid_t slave_pid);
+uint8_t port_is_bonding_slave(portid_t slave_pid);
+
+int init_port_dcb_config(portid_t pid, enum dcb_mode_enable dcb_mode,
+ enum rte_eth_nb_tcs num_tcs,
+ uint8_t pfc_en);
+int start_port(portid_t pid);
+void stop_port(portid_t pid);
+void close_port(portid_t pid);
+void reset_port(portid_t pid);
+void attach_port(char *identifier);
+void detach_devargs(char *identifier);
+void detach_port_device(portid_t port_id);
+int all_ports_stopped(void);
+int port_is_stopped(portid_t port_id);
+int port_is_started(portid_t port_id);
+void pmd_test_exit(void);
+void fdir_get_infos(portid_t port_id);
+void fdir_set_flex_mask(portid_t port_id,
+ struct rte_eth_fdir_flex_mask *cfg);
+void fdir_set_flex_payload(portid_t port_id,
+ struct rte_eth_flex_payload_cfg *cfg);
+void port_rss_reta_info(portid_t port_id,
+ struct rte_eth_rss_reta_entry64 *reta_conf,
+ uint16_t nb_entries);
+
+void set_vf_traffic(portid_t port_id, uint8_t is_rx, uint16_t vf, uint8_t on);
+
+int set_queue_rate_limit(portid_t port_id, uint16_t queue_idx, uint16_t rate);
+int set_vf_rate_limit(portid_t port_id, uint16_t vf, uint16_t rate,
+ uint64_t q_msk);
+
+void port_rss_hash_conf_show(portid_t port_id, int show_rss_key);
+void port_rss_hash_key_update(portid_t port_id, char rss_type[],
+ uint8_t *hash_key, uint hash_key_len);
+int rx_queue_id_is_invalid(queueid_t rxq_id);
+int tx_queue_id_is_invalid(queueid_t txq_id);
+void setup_gro(const char *onoff, portid_t port_id);
+void setup_gro_flush_cycles(uint8_t cycles);
+void show_gro(portid_t port_id);
+void setup_gso(const char *mode, portid_t port_id);
+int eth_dev_info_get_print_err(uint16_t port_id,
+ struct rte_eth_dev_info *dev_info);
+void eth_set_promisc_mode(uint16_t port_id, int enable);
+void eth_set_allmulticast_mode(uint16_t port, int enable);
+int eth_link_get_nowait_print_err(uint16_t port_id, struct rte_eth_link *link);
+int eth_macaddr_get_print_err(uint16_t port_id,
+ struct rte_ether_addr *mac_addr);
+
+/* Functions to display the set of MAC addresses added to a port*/
+void show_macs(portid_t port_id);
+void show_mcast_macs(portid_t port_id);
+
+/* Functions to manage the set of filtered Multicast MAC addresses */
+void mcast_addr_add(portid_t port_id, struct rte_ether_addr *mc_addr);
+void mcast_addr_remove(portid_t port_id, struct rte_ether_addr *mc_addr);
+void port_dcb_info_display(portid_t port_id);
+
+uint8_t *open_file(const char *file_path, uint32_t *size);
+int save_file(const char *file_path, uint8_t *buf, uint32_t size);
+int close_file(uint8_t *buf);
+
+void port_queue_region_info_display(portid_t port_id, void *buf);
+
+enum print_warning {
+ ENABLED_WARN = 0,
+ DISABLED_WARN
+};
+int port_id_is_invalid(portid_t port_id, enum print_warning warning);
+void print_valid_ports(void);
+int new_socket_id(unsigned int socket_id);
+
+queueid_t get_allowed_max_nb_rxq(portid_t *pid);
+int check_nb_rxq(queueid_t rxq);
+queueid_t get_allowed_max_nb_txq(portid_t *pid);
+int check_nb_txq(queueid_t txq);
+int check_nb_rxd(queueid_t rxd);
+int check_nb_txd(queueid_t txd);
+queueid_t get_allowed_max_nb_hairpinq(portid_t *pid);
+int check_nb_hairpinq(queueid_t hairpinq);
+
+uint16_t dump_rx_pkts(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
+ uint16_t nb_pkts, __rte_unused uint16_t max_pkts,
+ __rte_unused void *user_param);
+
+uint16_t dump_tx_pkts(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
+ uint16_t nb_pkts, __rte_unused void *user_param);
+
+void add_rx_dump_callbacks(portid_t portid);
+void remove_rx_dump_callbacks(portid_t portid);
+void add_tx_dump_callbacks(portid_t portid);
+void remove_tx_dump_callbacks(portid_t portid);
+void configure_rxtx_dump_callbacks(uint16_t verbose);
+
+uint16_t tx_pkt_set_md(uint16_t port_id, __rte_unused uint16_t queue,
+ struct rte_mbuf *pkts[], uint16_t nb_pkts,
+ __rte_unused void *user_param);
+void add_tx_md_callback(portid_t portid);
+void remove_tx_md_callback(portid_t portid);
+
+uint16_t tx_pkt_set_dynf(uint16_t port_id, __rte_unused uint16_t queue,
+ struct rte_mbuf *pkts[], uint16_t nb_pkts,
+ __rte_unused void *user_param);
+void add_tx_dynf_callback(portid_t portid);
+void remove_tx_dynf_callback(portid_t portid);
+
+/*
+ * Work-around of a compilation error with ICC on invocations of the
+ * rte_be_to_cpu_16() function.
+ */
+#ifdef __GCC__
+#define RTE_BE_TO_CPU_16(be_16_v) rte_be_to_cpu_16((be_16_v))
+#define RTE_CPU_TO_BE_16(cpu_16_v) rte_cpu_to_be_16((cpu_16_v))
+#else
+#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+#define RTE_BE_TO_CPU_16(be_16_v) (be_16_v)
+#define RTE_CPU_TO_BE_16(cpu_16_v) (cpu_16_v)
+#else
+#define RTE_BE_TO_CPU_16(be_16_v) \
+ (uint16_t) ((((be_16_v) & 0xFF) << 8) | ((be_16_v) >> 8))
+#define RTE_CPU_TO_BE_16(cpu_16_v) \
+ (uint16_t) ((((cpu_16_v) & 0xFF) << 8) | ((cpu_16_v) >> 8))
+#endif
+#endif /* __GCC__ */
+
+#define TESTPMD_LOG(level, fmt, args...) \
+ rte_log(RTE_LOG_ ## level, testpmd_logtype, "testpmd: " fmt, ## args)
+
+#endif /* _TESTPMD_H_ */
diff --git a/src/spdk/dpdk/app/test-pmd/txonly.c b/src/spdk/dpdk/app/test-pmd/txonly.c
new file mode 100644
index 000000000..076ccaf8f
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/txonly.c
@@ -0,0 +1,361 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
+#include <rte_udp.h>
+#include <rte_string_fns.h>
+#include <rte_flow.h>
+
+#include "testpmd.h"
+
+/* use RFC863 Discard Protocol */
+uint16_t tx_udp_src_port = 9;
+uint16_t tx_udp_dst_port = 9;
+
+/* use RFC5735 / RFC2544 reserved network test addresses */
+uint32_t tx_ip_src_addr = (198U << 24) | (18 << 16) | (0 << 8) | 1;
+uint32_t tx_ip_dst_addr = (198U << 24) | (18 << 16) | (0 << 8) | 2;
+
+#define IP_DEFTTL 64 /* from RFC 1340. */
+
+static struct rte_ipv4_hdr pkt_ip_hdr; /**< IP header of transmitted packets. */
+RTE_DEFINE_PER_LCORE(uint8_t, _ip_var); /**< IP address variation */
+static struct rte_udp_hdr pkt_udp_hdr; /**< UDP header of tx packets. */
+
+static void
+copy_buf_to_pkt_segs(void* buf, unsigned len, struct rte_mbuf *pkt,
+ unsigned offset)
+{
+ struct rte_mbuf *seg;
+ void *seg_buf;
+ unsigned copy_len;
+
+ seg = pkt;
+ while (offset >= seg->data_len) {
+ offset -= seg->data_len;
+ seg = seg->next;
+ }
+ copy_len = seg->data_len - offset;
+ seg_buf = rte_pktmbuf_mtod_offset(seg, char *, offset);
+ while (len > copy_len) {
+ rte_memcpy(seg_buf, buf, (size_t) copy_len);
+ len -= copy_len;
+ buf = ((char*) buf + copy_len);
+ seg = seg->next;
+ seg_buf = rte_pktmbuf_mtod(seg, char *);
+ copy_len = seg->data_len;
+ }
+ rte_memcpy(seg_buf, buf, (size_t) len);
+}
+
+static inline void
+copy_buf_to_pkt(void* buf, unsigned len, struct rte_mbuf *pkt, unsigned offset)
+{
+ if (offset + len <= pkt->data_len) {
+ rte_memcpy(rte_pktmbuf_mtod_offset(pkt, char *, offset),
+ buf, (size_t) len);
+ return;
+ }
+ copy_buf_to_pkt_segs(buf, len, pkt, offset);
+}
+
+static void
+setup_pkt_udp_ip_headers(struct rte_ipv4_hdr *ip_hdr,
+ struct rte_udp_hdr *udp_hdr,
+ uint16_t pkt_data_len)
+{
+ uint16_t *ptr16;
+ uint32_t ip_cksum;
+ uint16_t pkt_len;
+
+ /*
+ * Initialize UDP header.
+ */
+ pkt_len = (uint16_t) (pkt_data_len + sizeof(struct rte_udp_hdr));
+ udp_hdr->src_port = rte_cpu_to_be_16(tx_udp_src_port);
+ udp_hdr->dst_port = rte_cpu_to_be_16(tx_udp_dst_port);
+ udp_hdr->dgram_len = RTE_CPU_TO_BE_16(pkt_len);
+ udp_hdr->dgram_cksum = 0; /* No UDP checksum. */
+
+ /*
+ * Initialize IP header.
+ */
+ pkt_len = (uint16_t) (pkt_len + sizeof(struct rte_ipv4_hdr));
+ ip_hdr->version_ihl = RTE_IPV4_VHL_DEF;
+ ip_hdr->type_of_service = 0;
+ ip_hdr->fragment_offset = 0;
+ ip_hdr->time_to_live = IP_DEFTTL;
+ ip_hdr->next_proto_id = IPPROTO_UDP;
+ ip_hdr->packet_id = 0;
+ ip_hdr->total_length = RTE_CPU_TO_BE_16(pkt_len);
+ ip_hdr->src_addr = rte_cpu_to_be_32(tx_ip_src_addr);
+ ip_hdr->dst_addr = rte_cpu_to_be_32(tx_ip_dst_addr);
+
+ /*
+ * Compute IP header checksum.
+ */
+ ptr16 = (unaligned_uint16_t*) ip_hdr;
+ ip_cksum = 0;
+ ip_cksum += ptr16[0]; ip_cksum += ptr16[1];
+ ip_cksum += ptr16[2]; ip_cksum += ptr16[3];
+ ip_cksum += ptr16[4];
+ ip_cksum += ptr16[6]; ip_cksum += ptr16[7];
+ ip_cksum += ptr16[8]; ip_cksum += ptr16[9];
+
+ /*
+ * Reduce 32 bit checksum to 16 bits and complement it.
+ */
+ ip_cksum = ((ip_cksum & 0xFFFF0000) >> 16) +
+ (ip_cksum & 0x0000FFFF);
+ if (ip_cksum > 65535)
+ ip_cksum -= 65535;
+ ip_cksum = (~ip_cksum) & 0x0000FFFF;
+ if (ip_cksum == 0)
+ ip_cksum = 0xFFFF;
+ ip_hdr->hdr_checksum = (uint16_t) ip_cksum;
+}
+
+static inline bool
+pkt_burst_prepare(struct rte_mbuf *pkt, struct rte_mempool *mbp,
+ struct rte_ether_hdr *eth_hdr, const uint16_t vlan_tci,
+ const uint16_t vlan_tci_outer, const uint64_t ol_flags)
+{
+ struct rte_mbuf *pkt_segs[RTE_MAX_SEGS_PER_PKT];
+ struct rte_mbuf *pkt_seg;
+ uint32_t nb_segs, pkt_len;
+ uint8_t i;
+
+ if (unlikely(tx_pkt_split == TX_PKT_SPLIT_RND))
+ nb_segs = rte_rand() % tx_pkt_nb_segs + 1;
+ else
+ nb_segs = tx_pkt_nb_segs;
+
+ if (nb_segs > 1) {
+ if (rte_mempool_get_bulk(mbp, (void **)pkt_segs, nb_segs - 1))
+ return false;
+ }
+
+ rte_pktmbuf_reset_headroom(pkt);
+ pkt->data_len = tx_pkt_seg_lengths[0];
+ pkt->ol_flags &= EXT_ATTACHED_MBUF;
+ pkt->ol_flags |= ol_flags;
+ pkt->vlan_tci = vlan_tci;
+ pkt->vlan_tci_outer = vlan_tci_outer;
+ pkt->l2_len = sizeof(struct rte_ether_hdr);
+ pkt->l3_len = sizeof(struct rte_ipv4_hdr);
+
+ pkt_len = pkt->data_len;
+ pkt_seg = pkt;
+ for (i = 1; i < nb_segs; i++) {
+ pkt_seg->next = pkt_segs[i - 1];
+ pkt_seg = pkt_seg->next;
+ pkt_seg->data_len = tx_pkt_seg_lengths[i];
+ pkt_len += pkt_seg->data_len;
+ }
+ pkt_seg->next = NULL; /* Last segment of packet. */
+ /*
+ * Copy headers in first packet segment(s).
+ */
+ copy_buf_to_pkt(eth_hdr, sizeof(*eth_hdr), pkt, 0);
+ copy_buf_to_pkt(&pkt_ip_hdr, sizeof(pkt_ip_hdr), pkt,
+ sizeof(struct rte_ether_hdr));
+ if (txonly_multi_flow) {
+ uint8_t ip_var = RTE_PER_LCORE(_ip_var);
+ struct rte_ipv4_hdr *ip_hdr;
+ uint32_t addr;
+
+ ip_hdr = rte_pktmbuf_mtod_offset(pkt,
+ struct rte_ipv4_hdr *,
+ sizeof(struct rte_ether_hdr));
+ /*
+ * Generate multiple flows by varying IP src addr. This
+ * enables packets are well distributed by RSS in
+ * receiver side if any and txonly mode can be a decent
+ * packet generator for developer's quick performance
+ * regression test.
+ */
+ addr = (tx_ip_dst_addr | (ip_var++ << 8)) + rte_lcore_id();
+ ip_hdr->src_addr = rte_cpu_to_be_32(addr);
+ RTE_PER_LCORE(_ip_var) = ip_var;
+ }
+ copy_buf_to_pkt(&pkt_udp_hdr, sizeof(pkt_udp_hdr), pkt,
+ sizeof(struct rte_ether_hdr) +
+ sizeof(struct rte_ipv4_hdr));
+ /*
+ * Complete first mbuf of packet and append it to the
+ * burst of packets to be transmitted.
+ */
+ pkt->nb_segs = nb_segs;
+ pkt->pkt_len = pkt_len;
+
+ return true;
+}
+
+/*
+ * Transmit a burst of multi-segments packets.
+ */
+static void
+pkt_burst_transmit(struct fwd_stream *fs)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_port *txp;
+ struct rte_mbuf *pkt;
+ struct rte_mempool *mbp;
+ struct rte_ether_hdr eth_hdr;
+ uint16_t nb_tx;
+ uint16_t nb_pkt;
+ uint16_t vlan_tci, vlan_tci_outer;
+ uint32_t retry;
+ uint64_t ol_flags = 0;
+ uint64_t tx_offloads;
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ uint64_t start_tsc;
+ uint64_t end_tsc;
+ uint64_t core_cycles;
+#endif
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ start_tsc = rte_rdtsc();
+#endif
+
+ mbp = current_fwd_lcore()->mbp;
+ txp = &ports[fs->tx_port];
+ tx_offloads = txp->dev_conf.txmode.offloads;
+ vlan_tci = txp->tx_vlan_id;
+ vlan_tci_outer = txp->tx_vlan_id_outer;
+ if (tx_offloads & DEV_TX_OFFLOAD_VLAN_INSERT)
+ ol_flags = PKT_TX_VLAN_PKT;
+ if (tx_offloads & DEV_TX_OFFLOAD_QINQ_INSERT)
+ ol_flags |= PKT_TX_QINQ_PKT;
+ if (tx_offloads & DEV_TX_OFFLOAD_MACSEC_INSERT)
+ ol_flags |= PKT_TX_MACSEC;
+
+ /*
+ * Initialize Ethernet header.
+ */
+ rte_ether_addr_copy(&peer_eth_addrs[fs->peer_addr], &eth_hdr.d_addr);
+ rte_ether_addr_copy(&ports[fs->tx_port].eth_addr, &eth_hdr.s_addr);
+ eth_hdr.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+
+ if (rte_mempool_get_bulk(mbp, (void **)pkts_burst,
+ nb_pkt_per_burst) == 0) {
+ for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
+ if (unlikely(!pkt_burst_prepare(pkts_burst[nb_pkt], mbp,
+ &eth_hdr, vlan_tci,
+ vlan_tci_outer,
+ ol_flags))) {
+ rte_mempool_put_bulk(mbp,
+ (void **)&pkts_burst[nb_pkt],
+ nb_pkt_per_burst - nb_pkt);
+ break;
+ }
+ }
+ } else {
+ for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
+ pkt = rte_mbuf_raw_alloc(mbp);
+ if (pkt == NULL)
+ break;
+ if (unlikely(!pkt_burst_prepare(pkt, mbp, &eth_hdr,
+ vlan_tci,
+ vlan_tci_outer,
+ ol_flags))) {
+ rte_pktmbuf_free(pkt);
+ break;
+ }
+ pkts_burst[nb_pkt] = pkt;
+ }
+ }
+
+ if (nb_pkt == 0)
+ return;
+
+ nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_pkt);
+ /*
+ * Retry if necessary
+ */
+ if (unlikely(nb_tx < nb_pkt) && fs->retry_enabled) {
+ retry = 0;
+ while (nb_tx < nb_pkt && retry++ < burst_tx_retry_num) {
+ rte_delay_us(burst_tx_delay_time);
+ nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+ &pkts_burst[nb_tx], nb_pkt - nb_tx);
+ }
+ }
+ fs->tx_packets += nb_tx;
+
+ if (txonly_multi_flow)
+ RTE_PER_LCORE(_ip_var) -= nb_pkt - nb_tx;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+#endif
+ if (unlikely(nb_tx < nb_pkt)) {
+ if (verbose_level > 0 && fs->fwd_dropped == 0)
+ printf("port %d tx_queue %d - drop "
+ "(nb_pkt:%u - nb_tx:%u)=%u packets\n",
+ fs->tx_port, fs->tx_queue,
+ (unsigned) nb_pkt, (unsigned) nb_tx,
+ (unsigned) (nb_pkt - nb_tx));
+ fs->fwd_dropped += (nb_pkt - nb_tx);
+ do {
+ rte_pktmbuf_free(pkts_burst[nb_tx]);
+ } while (++nb_tx < nb_pkt);
+ }
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+ end_tsc = rte_rdtsc();
+ core_cycles = (end_tsc - start_tsc);
+ fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+#endif
+}
+
+static void
+tx_only_begin(__rte_unused portid_t pi)
+{
+ uint16_t pkt_data_len;
+
+ pkt_data_len = (uint16_t) (tx_pkt_length - (
+ sizeof(struct rte_ether_hdr) +
+ sizeof(struct rte_ipv4_hdr) +
+ sizeof(struct rte_udp_hdr)));
+ setup_pkt_udp_ip_headers(&pkt_ip_hdr, &pkt_udp_hdr, pkt_data_len);
+}
+
+struct fwd_engine tx_only_engine = {
+ .fwd_mode_name = "txonly",
+ .port_fwd_begin = tx_only_begin,
+ .port_fwd_end = NULL,
+ .packet_fwd = pkt_burst_transmit,
+};
diff --git a/src/spdk/dpdk/app/test-pmd/util.c b/src/spdk/dpdk/app/test-pmd/util.c
new file mode 100644
index 000000000..8488fa1a8
--- /dev/null
+++ b/src/spdk/dpdk/app/test-pmd/util.c
@@ -0,0 +1,377 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
+ * Copyright 2018 Mellanox Technologies, Ltd
+ */
+
+#include <stdio.h>
+
+#include <rte_net.h>
+#include <rte_mbuf.h>
+#include <rte_ether.h>
+#include <rte_vxlan.h>
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+
+#include "testpmd.h"
+
+static inline void
+print_ether_addr(const char *what, 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", what, buf);
+}
+
+static inline void
+dump_pkt_burst(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
+ uint16_t nb_pkts, int is_rx)
+{
+ struct rte_mbuf *mb;
+ const struct rte_ether_hdr *eth_hdr;
+ struct rte_ether_hdr _eth_hdr;
+ uint16_t eth_type;
+ uint64_t ol_flags;
+ uint16_t i, packet_type;
+ uint16_t is_encapsulation;
+ char buf[256];
+ struct rte_net_hdr_lens hdr_lens;
+ uint32_t sw_packet_type;
+ uint16_t udp_port;
+ uint32_t vx_vni;
+ const char *reason;
+ int dynf_index;
+
+ if (!nb_pkts)
+ return;
+ printf("port %u/queue %u: %s %u packets\n",
+ port_id, queue,
+ is_rx ? "received" : "sent",
+ (unsigned int) nb_pkts);
+ for (i = 0; i < nb_pkts; i++) {
+ mb = pkts[i];
+ eth_hdr = rte_pktmbuf_read(mb, 0, sizeof(_eth_hdr), &_eth_hdr);
+ eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
+ ol_flags = mb->ol_flags;
+ packet_type = mb->packet_type;
+ is_encapsulation = RTE_ETH_IS_TUNNEL_PKT(packet_type);
+
+ print_ether_addr(" src=", &eth_hdr->s_addr);
+ print_ether_addr(" - dst=", &eth_hdr->d_addr);
+ printf(" - type=0x%04x - length=%u - nb_segs=%d",
+ eth_type, (unsigned int) mb->pkt_len,
+ (int)mb->nb_segs);
+ if (ol_flags & PKT_RX_RSS_HASH) {
+ printf(" - RSS hash=0x%x", (unsigned int) mb->hash.rss);
+ printf(" - RSS queue=0x%x", (unsigned int) queue);
+ }
+ if (ol_flags & PKT_RX_FDIR) {
+ printf(" - FDIR matched ");
+ if (ol_flags & PKT_RX_FDIR_ID)
+ printf("ID=0x%x",
+ mb->hash.fdir.hi);
+ else if (ol_flags & PKT_RX_FDIR_FLX)
+ printf("flex bytes=0x%08x %08x",
+ mb->hash.fdir.hi, mb->hash.fdir.lo);
+ else
+ printf("hash=0x%x ID=0x%x ",
+ mb->hash.fdir.hash, mb->hash.fdir.id);
+ }
+ if (ol_flags & PKT_RX_TIMESTAMP)
+ printf(" - timestamp %"PRIu64" ", mb->timestamp);
+ if (ol_flags & PKT_RX_QINQ)
+ printf(" - QinQ VLAN tci=0x%x, VLAN tci outer=0x%x",
+ mb->vlan_tci, mb->vlan_tci_outer);
+ else if (ol_flags & PKT_RX_VLAN)
+ printf(" - VLAN tci=0x%x", mb->vlan_tci);
+ if (!is_rx && (ol_flags & PKT_TX_DYNF_METADATA))
+ printf(" - Tx metadata: 0x%x",
+ *RTE_FLOW_DYNF_METADATA(mb));
+ if (is_rx && (ol_flags & PKT_RX_DYNF_METADATA))
+ printf(" - Rx metadata: 0x%x",
+ *RTE_FLOW_DYNF_METADATA(mb));
+ for (dynf_index = 0; dynf_index < 64; dynf_index++) {
+ if (dynf_names[dynf_index][0] != '\0')
+ printf(" - dynf %s: %d",
+ dynf_names[dynf_index],
+ !!(ol_flags & (1UL << dynf_index)));
+ }
+ if (mb->packet_type) {
+ rte_get_ptype_name(mb->packet_type, buf, sizeof(buf));
+ printf(" - hw ptype: %s", buf);
+ }
+ sw_packet_type = rte_net_get_ptype(mb, &hdr_lens,
+ RTE_PTYPE_ALL_MASK);
+ rte_get_ptype_name(sw_packet_type, buf, sizeof(buf));
+ printf(" - sw ptype: %s", buf);
+ if (sw_packet_type & RTE_PTYPE_L2_MASK)
+ printf(" - l2_len=%d", hdr_lens.l2_len);
+ if (sw_packet_type & RTE_PTYPE_L3_MASK)
+ printf(" - l3_len=%d", hdr_lens.l3_len);
+ if (sw_packet_type & RTE_PTYPE_L4_MASK)
+ printf(" - l4_len=%d", hdr_lens.l4_len);
+ if (sw_packet_type & RTE_PTYPE_TUNNEL_MASK)
+ printf(" - tunnel_len=%d", hdr_lens.tunnel_len);
+ if (sw_packet_type & RTE_PTYPE_INNER_L2_MASK)
+ printf(" - inner_l2_len=%d", hdr_lens.inner_l2_len);
+ if (sw_packet_type & RTE_PTYPE_INNER_L3_MASK)
+ printf(" - inner_l3_len=%d", hdr_lens.inner_l3_len);
+ if (sw_packet_type & RTE_PTYPE_INNER_L4_MASK)
+ printf(" - inner_l4_len=%d", hdr_lens.inner_l4_len);
+ if (is_encapsulation) {
+ struct rte_ipv4_hdr *ipv4_hdr;
+ struct rte_ipv6_hdr *ipv6_hdr;
+ struct rte_udp_hdr *udp_hdr;
+ uint8_t l2_len;
+ uint8_t l3_len;
+ uint8_t l4_len;
+ uint8_t l4_proto;
+ struct rte_vxlan_hdr *vxlan_hdr;
+
+ l2_len = sizeof(struct rte_ether_hdr);
+
+ /* Do not support ipv4 option field */
+ if (RTE_ETH_IS_IPV4_HDR(packet_type)) {
+ l3_len = sizeof(struct rte_ipv4_hdr);
+ ipv4_hdr = rte_pktmbuf_mtod_offset(mb,
+ struct rte_ipv4_hdr *,
+ l2_len);
+ l4_proto = ipv4_hdr->next_proto_id;
+ } else {
+ l3_len = sizeof(struct rte_ipv6_hdr);
+ ipv6_hdr = rte_pktmbuf_mtod_offset(mb,
+ struct rte_ipv6_hdr *,
+ l2_len);
+ l4_proto = ipv6_hdr->proto;
+ }
+ if (l4_proto == IPPROTO_UDP) {
+ udp_hdr = rte_pktmbuf_mtod_offset(mb,
+ struct rte_udp_hdr *,
+ l2_len + l3_len);
+ l4_len = sizeof(struct rte_udp_hdr);
+ vxlan_hdr = rte_pktmbuf_mtod_offset(mb,
+ struct rte_vxlan_hdr *,
+ l2_len + l3_len + l4_len);
+ udp_port = RTE_BE_TO_CPU_16(udp_hdr->dst_port);
+ vx_vni = rte_be_to_cpu_32(vxlan_hdr->vx_vni);
+ printf(" - VXLAN packet: packet type =%d, "
+ "Destination UDP port =%d, VNI = %d",
+ packet_type, udp_port, vx_vni >> 8);
+ }
+ }
+ printf(" - %s queue=0x%x", is_rx ? "Receive" : "Send",
+ (unsigned int) queue);
+ printf("\n");
+ rte_get_rx_ol_flag_list(mb->ol_flags, buf, sizeof(buf));
+ printf(" ol_flags: %s\n", buf);
+ if (rte_mbuf_check(mb, 1, &reason) < 0)
+ printf("INVALID mbuf: %s\n", reason);
+ }
+}
+
+uint16_t
+dump_rx_pkts(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
+ uint16_t nb_pkts, __rte_unused uint16_t max_pkts,
+ __rte_unused void *user_param)
+{
+ dump_pkt_burst(port_id, queue, pkts, nb_pkts, 1);
+ return nb_pkts;
+}
+
+uint16_t
+dump_tx_pkts(uint16_t port_id, uint16_t queue, struct rte_mbuf *pkts[],
+ uint16_t nb_pkts, __rte_unused void *user_param)
+{
+ dump_pkt_burst(port_id, queue, pkts, nb_pkts, 0);
+ return nb_pkts;
+}
+
+uint16_t
+tx_pkt_set_md(uint16_t port_id, __rte_unused uint16_t queue,
+ struct rte_mbuf *pkts[], uint16_t nb_pkts,
+ __rte_unused void *user_param)
+{
+ uint16_t i = 0;
+
+ /*
+ * Add metadata value to every Tx packet,
+ * and set ol_flags accordingly.
+ */
+ if (rte_flow_dynf_metadata_avail())
+ for (i = 0; i < nb_pkts; i++) {
+ *RTE_FLOW_DYNF_METADATA(pkts[i]) =
+ ports[port_id].tx_metadata;
+ pkts[i]->ol_flags |= PKT_TX_DYNF_METADATA;
+ }
+ return nb_pkts;
+}
+
+void
+add_tx_md_callback(portid_t portid)
+{
+ struct rte_eth_dev_info dev_info;
+ uint16_t queue;
+ int ret;
+
+ if (port_id_is_invalid(portid, ENABLED_WARN))
+ return;
+
+ ret = eth_dev_info_get_print_err(portid, &dev_info);
+ if (ret != 0)
+ return;
+
+ for (queue = 0; queue < dev_info.nb_tx_queues; queue++)
+ if (!ports[portid].tx_set_md_cb[queue])
+ ports[portid].tx_set_md_cb[queue] =
+ rte_eth_add_tx_callback(portid, queue,
+ tx_pkt_set_md, NULL);
+}
+
+void
+remove_tx_md_callback(portid_t portid)
+{
+ struct rte_eth_dev_info dev_info;
+ uint16_t queue;
+ int ret;
+
+ if (port_id_is_invalid(portid, ENABLED_WARN))
+ return;
+
+ ret = eth_dev_info_get_print_err(portid, &dev_info);
+ if (ret != 0)
+ return;
+
+ for (queue = 0; queue < dev_info.nb_tx_queues; queue++)
+ if (ports[portid].tx_set_md_cb[queue]) {
+ rte_eth_remove_tx_callback(portid, queue,
+ ports[portid].tx_set_md_cb[queue]);
+ ports[portid].tx_set_md_cb[queue] = NULL;
+ }
+}
+
+uint16_t
+tx_pkt_set_dynf(uint16_t port_id, __rte_unused uint16_t queue,
+ struct rte_mbuf *pkts[], uint16_t nb_pkts,
+ __rte_unused void *user_param)
+{
+ uint16_t i = 0;
+
+ if (ports[port_id].mbuf_dynf)
+ for (i = 0; i < nb_pkts; i++)
+ pkts[i]->ol_flags |= ports[port_id].mbuf_dynf;
+ return nb_pkts;
+}
+
+void
+add_tx_dynf_callback(portid_t portid)
+{
+ struct rte_eth_dev_info dev_info;
+ uint16_t queue;
+ int ret;
+
+ if (port_id_is_invalid(portid, ENABLED_WARN))
+ return;
+
+ ret = eth_dev_info_get_print_err(portid, &dev_info);
+ if (ret != 0)
+ return;
+
+ for (queue = 0; queue < dev_info.nb_tx_queues; queue++)
+ if (!ports[portid].tx_set_dynf_cb[queue])
+ ports[portid].tx_set_dynf_cb[queue] =
+ rte_eth_add_tx_callback(portid, queue,
+ tx_pkt_set_dynf, NULL);
+}
+
+void
+remove_tx_dynf_callback(portid_t portid)
+{
+ struct rte_eth_dev_info dev_info;
+ uint16_t queue;
+ int ret;
+
+ if (port_id_is_invalid(portid, ENABLED_WARN))
+ return;
+
+ ret = eth_dev_info_get_print_err(portid, &dev_info);
+ if (ret != 0)
+ return;
+
+ for (queue = 0; queue < dev_info.nb_tx_queues; queue++)
+ if (ports[portid].tx_set_dynf_cb[queue]) {
+ rte_eth_remove_tx_callback(portid, queue,
+ ports[portid].tx_set_dynf_cb[queue]);
+ ports[portid].tx_set_dynf_cb[queue] = NULL;
+ }
+}
+
+int
+eth_dev_info_get_print_err(uint16_t port_id,
+ struct rte_eth_dev_info *dev_info)
+{
+ int ret;
+
+ ret = rte_eth_dev_info_get(port_id, dev_info);
+ if (ret != 0)
+ printf("Error during getting device (port %u) info: %s\n",
+ port_id, strerror(-ret));
+
+ return ret;
+}
+
+void
+eth_set_promisc_mode(uint16_t port, int enable)
+{
+ int ret;
+
+ if (enable)
+ ret = rte_eth_promiscuous_enable(port);
+ else
+ ret = rte_eth_promiscuous_disable(port);
+
+ if (ret != 0)
+ printf("Error during %s promiscuous mode for port %u: %s\n",
+ enable ? "enabling" : "disabling",
+ port, rte_strerror(-ret));
+}
+
+void
+eth_set_allmulticast_mode(uint16_t port, int enable)
+{
+ int ret;
+
+ if (enable)
+ ret = rte_eth_allmulticast_enable(port);
+ else
+ ret = rte_eth_allmulticast_disable(port);
+
+ if (ret != 0)
+ printf("Error during %s all-multicast mode for port %u: %s\n",
+ enable ? "enabling" : "disabling",
+ port, rte_strerror(-ret));
+}
+
+int
+eth_link_get_nowait_print_err(uint16_t port_id, struct rte_eth_link *link)
+{
+ int ret;
+
+ ret = rte_eth_link_get_nowait(port_id, link);
+ if (ret < 0)
+ printf("Device (port %u) link get (without wait) failed: %s\n",
+ port_id, rte_strerror(-ret));
+
+ return ret;
+}
+
+int
+eth_macaddr_get_print_err(uint16_t port_id, struct rte_ether_addr *mac_addr)
+{
+ int ret;
+
+ ret = rte_eth_macaddr_get(port_id, mac_addr);
+ if (ret != 0)
+ printf("Error getting device (port %u) mac address: %s\n",
+ port_id, rte_strerror(-ret));
+
+ return ret;
+}