diff options
author | Christian Ehrhardt <christian.ehrhardt@canonical.com> | 2017-05-16 14:51:32 +0200 |
---|---|---|
committer | Christian Ehrhardt <christian.ehrhardt@canonical.com> | 2017-05-16 16:20:45 +0200 |
commit | 7595afa4d30097c1177b69257118d8ad89a539be (patch) | |
tree | 4bfeadc905c977e45e54a90c42330553b8942e4e /app/test-pmd | |
parent | ce3d555e43e3795b5d9507fcfc76b7a0a92fd0d6 (diff) |
Imported Upstream version 17.05
Change-Id: Id1e419c5a214e4a18739663b91f0f9a549f1fdc6
Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Diffstat (limited to 'app/test-pmd')
-rw-r--r-- | app/test-pmd/Makefile | 22 | ||||
-rw-r--r-- | app/test-pmd/cmdline.c | 2732 | ||||
-rw-r--r-- | app/test-pmd/cmdline_flow.c | 2812 | ||||
-rw-r--r-- | app/test-pmd/config.c | 815 | ||||
-rw-r--r-- | app/test-pmd/csumonly.c | 53 | ||||
-rw-r--r-- | app/test-pmd/flowgen.c | 1 | ||||
-rw-r--r-- | app/test-pmd/icmpecho.c | 5 | ||||
-rw-r--r-- | app/test-pmd/ieee1588fwd.c | 1 | ||||
-rw-r--r-- | app/test-pmd/iofwd.c | 1 | ||||
-rw-r--r-- | app/test-pmd/macfwd.c | 3 | ||||
-rw-r--r-- | app/test-pmd/macswap.c | 3 | ||||
-rw-r--r-- | app/test-pmd/parameters.c | 158 | ||||
-rw-r--r-- | app/test-pmd/rxonly.c | 6 | ||||
-rw-r--r-- | app/test-pmd/testpmd.c | 389 | ||||
-rw-r--r-- | app/test-pmd/testpmd.h | 67 | ||||
-rw-r--r-- | app/test-pmd/txonly.c | 3 |
16 files changed, 6584 insertions, 487 deletions
diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile index 92c0c1b0..35ecee9f 100644 --- a/app/test-pmd/Makefile +++ b/app/test-pmd/Makefile @@ -47,6 +47,7 @@ CFLAGS += $(WERROR_FLAGS) SRCS-y := testpmd.c SRCS-y += parameters.c SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline.c +SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_flow.c SRCS-y += config.c SRCS-y += iofwd.c SRCS-y += macfwd.c @@ -59,13 +60,26 @@ SRCS-y += icmpecho.c SRCS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ieee1588fwd.c ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y) -_LDLIBS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += -lrte_pmd_ixgbe + +ifeq ($(CONFIG_RTE_LIBRTE_PMD_BOND),y) +LDLIBS += -lrte_pmd_bond endif -CFLAGS_cmdline.o := -D_GNU_SOURCE +ifeq ($(CONFIG_RTE_LIBRTE_IXGBE_PMD),y) +LDLIBS += -lrte_pmd_ixgbe +endif + +ifeq ($(CONFIG_RTE_LIBRTE_I40E_PMD),y) +LDLIBS += -lrte_pmd_i40e +endif -# this application needs libraries first -DEPDIRS-y += lib drivers +ifeq ($(CONFIG_RTE_LIBRTE_PMD_XENVIRT),y) +LDLIBS += -lrte_pmd_xenvirt +endif + +endif + +CFLAGS_cmdline.o := -D_GNU_SOURCE include $(RTE_SDK)/mk/rte.app.mk diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index 315a252e..0afac68c 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -75,6 +75,7 @@ #include <rte_string_fns.h> #include <rte_devargs.h> #include <rte_eth_ctrl.h> +#include <rte_flow.h> #include <cmdline_rdline.h> #include <cmdline_parse.h> @@ -90,6 +91,9 @@ #ifdef RTE_LIBRTE_IXGBE_PMD #include <rte_pmd_ixgbe.h> #endif +#ifdef RTE_LIBRTE_I40E_PMD +#include <rte_pmd_i40e.h> +#endif #include "testpmd.h" static struct cmdline *testpmd_cl; @@ -127,7 +131,7 @@ cmdline_parse_token_string_t cmd_help_brief_help = cmdline_parse_inst_t cmd_help_brief = { .f = cmd_help_brief_parsed, .data = NULL, - .help_str = "show help", + .help_str = "help: Show help", .tokens = { (void *)&cmd_help_brief_help, NULL, @@ -182,7 +186,7 @@ static void cmd_help_long_parsed(void *parsed_result, "Display:\n" "--------\n\n" - "show port (info|stats|xstats|fdir|stat_qmap|dcb_tc) (port_id|all)\n" + "show port (info|stats|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" @@ -210,6 +214,15 @@ static void cmd_help_long_parsed(void *parsed_result, "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" + + "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" ); } @@ -262,27 +275,43 @@ static void cmd_help_long_parsed(void *parsed_result, "set portlist (x[,y]*)\n" " Set the list of forwarding ports.\n\n" -#ifdef RTE_LIBRTE_IXGBE_PMD "set tx loopback (port_id) (on|off)\n" " Enable or disable tx loopback.\n\n" +#ifdef RTE_LIBRTE_IXGBE_PMD "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" +#endif "set vf mac antispoof (port_id) (vf_id) (on|off).\n" " Set MAC antispoof for a VF from the PF.\n\n" + +#ifdef RTE_LIBRTE_IXGBE_PMD + "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" #endif + "set vf broadcast (port_id) (vf_id) (on|off)\n" + " Set VF broadcast for a VF from the PF.\n\n" + "vlan set strip (on|off) (port_id)\n" " Set the VLAN strip on a port.\n\n" "vlan set stripq (on|off) (port_id,queue_id)\n" " Set the VLAN strip for a queue on a port.\n\n" -#ifdef RTE_LIBRTE_IXGBE_PMD "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" @@ -291,7 +320,24 @@ static void cmd_help_long_parsed(void *parsed_result, "set vf vlan antispoof (port_id) (vf_id) (on|off)\n" " Set VLAN antispoof for a VF from the PF.\n\n" -#endif + + "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 filter (on|off) (port_id)\n" " Set the VLAN filter on a port.\n\n" @@ -383,13 +429,14 @@ static void cmd_help_long_parsed(void *parsed_result, "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" -#ifdef RTE_LIBRTE_IXGBE_PMD "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" -#endif "set port (port_id) uta (mac_address|all) (on|off)\n" " Add/Remove a or all unicast hash filter(s)" @@ -401,6 +448,12 @@ static void cmd_help_long_parsed(void *parsed_result, "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" @@ -549,6 +602,21 @@ static void cmd_help_long_parsed(void *parsed_result, "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)\n" + " Load a profile package on 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" + , list_pkt_forwarding_modes() ); } @@ -809,6 +877,33 @@ static void cmd_help_long_parsed(void *parsed_result, "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" ); } } @@ -824,7 +919,8 @@ cmdline_parse_token_string_t cmd_help_long_section = cmdline_parse_inst_t cmd_help_long = { .f = cmd_help_long_parsed, .data = NULL, - .help_str = "show help", + .help_str = "help all|control|display|config|ports|register|filters: " + "Show help", .tokens = { (void *)&cmd_help_long_help, (void *)&cmd_help_long_section, @@ -868,7 +964,7 @@ cmdline_parse_token_string_t cmd_operate_port_all_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 all ports", + .help_str = "port start|stop|close all: Start/Stop/Close all ports", .tokens = { (void *)&cmd_operate_port_all_cmd, (void *)&cmd_operate_port_all_port, @@ -913,7 +1009,7 @@ cmdline_parse_token_num_t cmd_operate_specific_port_id = cmdline_parse_inst_t cmd_operate_specific_port = { .f = cmd_operate_specific_port_parsed, .data = NULL, - .help_str = "port start|stop|close X: start/stop/close port X", + .help_str = "port start|stop|close <port_id>: Start/Stop/Close port_id", .tokens = { (void *)&cmd_operate_specific_port_cmd, (void *)&cmd_operate_specific_port_port, @@ -954,8 +1050,8 @@ cmdline_parse_token_string_t cmd_operate_attach_port_identifier = 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", + .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, @@ -996,7 +1092,7 @@ cmdline_parse_token_num_t cmd_operate_detach_port_port_id = cmdline_parse_inst_t cmd_operate_detach_port = { .f = cmd_operate_detach_port_parsed, .data = NULL, - .help_str = "port detach port_id", + .help_str = "port detach <port_id>", .tokens = { (void *)&cmd_operate_detach_port_port, (void *)&cmd_operate_detach_port_keyword, @@ -1085,7 +1181,7 @@ cmd_config_speed_all_parsed(void *parsed_result, &link_speed) < 0) return; - FOREACH_PORT(pid, ports) { + RTE_ETH_FOREACH_DEV(pid) { ports[pid].dev_conf.link_speeds = link_speed; } @@ -1189,7 +1285,7 @@ cmdline_parse_token_string_t cmd_config_speed_specific_value2 = cmdline_parse_inst_t cmd_config_speed_specific = { .f = cmd_config_speed_specific_parsed, .data = NULL, - .help_str = "port config X speed " + .help_str = "port config <port_id> speed " "10|100|1000|10000|25000|40000|50000|100000|auto duplex " "half|full|auto", .tokens = { @@ -1279,7 +1375,7 @@ cmdline_parse_token_num_t cmd_config_rx_tx_value = 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", + .help_str = "port config all rxq|txq|rxd|txd <value>", .tokens = { (void *)&cmd_config_rx_tx_port, (void *)&cmd_config_rx_tx_keyword, @@ -1354,7 +1450,7 @@ cmdline_parse_token_num_t cmd_config_max_pkt_len_value = 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", + .help_str = "port config all max-pkt-len <value>", .tokens = { (void *)&cmd_config_max_pkt_len_port, (void *)&cmd_config_max_pkt_len_keyword, @@ -1405,7 +1501,7 @@ cmdline_parse_token_num_t cmd_config_mtu_value = cmdline_parse_inst_t cmd_config_mtu = { .f = cmd_config_mtu_parsed, .data = NULL, - .help_str = "port config mtu port_id value", + .help_str = "port config mtu <port_id> <value>", .tokens = { (void *)&cmd_config_mtu_port, (void *)&cmd_config_mtu_keyword, @@ -1625,7 +1721,8 @@ cmdline_parse_token_string_t cmd_config_rss_value = cmdline_parse_inst_t cmd_config_rss = { .f = cmd_config_rss_parsed, .data = NULL, - .help_str = "port config all rss all|ip|tcp|udp|sctp|ether|port|vxlan|geneve|nvgre|none", + .help_str = "port config all rss " + "all|ip|tcp|udp|sctp|ether|port|vxlan|geneve|nvgre|none", .tokens = { (void *)&cmd_config_rss_port, (void *)&cmd_config_rss_keyword, @@ -1738,12 +1835,11 @@ cmdline_parse_token_string_t cmd_config_rss_hash_key_value = cmdline_parse_inst_t cmd_config_rss_hash_key = { .f = cmd_config_rss_hash_key_parsed, .data = NULL, - .help_str = - "port config X 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 " - "<string of hexa digits (variable length, NIC dependent)>\n", + .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 " + "<string of hex digits (variable length, NIC dependent)>", .tokens = { (void *)&cmd_config_rss_hash_key_port, (void *)&cmd_config_rss_hash_key_config, @@ -1838,7 +1934,7 @@ cmdline_parse_token_string_t cmd_config_rxtx_queue_opname = cmdline_parse_inst_t cmd_config_rxtx_queue = { .f = cmd_config_rxtx_queue_parsed, .data = NULL, - .help_str = "port X rxq|txq ID start|stop", + .help_str = "port <port_id> rxq|txq <queue_id> start|stop", .tokens = { (void *)&cmd_config_speed_all_port, (void *)&cmd_config_rxtx_queue_portid, @@ -1973,7 +2069,7 @@ cmdline_parse_token_string_t cmd_config_rss_reta_list_of_items = cmdline_parse_inst_t cmd_config_rss_reta = { .f = cmd_set_rss_reta_parsed, .data = NULL, - .help_str = "port config X rss reta (hash,queue)[,(hash,queue)]", + .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, @@ -2006,7 +2102,9 @@ showport_parse_reta_config(struct rte_eth_rss_reta_entry64 *conf, char s[256]; char *end; char *str_fld[8]; - uint16_t i, num = nb_entries / RTE_RETA_GROUP_SIZE; + uint16_t i; + uint16_t num = (nb_entries + RTE_RETA_GROUP_SIZE - 1) / + RTE_RETA_GROUP_SIZE; int ret; p = strchr(p0, '('); @@ -2080,7 +2178,7 @@ cmdline_parse_token_string_t cmd_showport_reta_list_of_items = cmdline_parse_inst_t cmd_showport_reta = { .f = cmd_showport_reta_parsed, .data = NULL, - .help_str = "show port X rss reta (size) (mask0,mask1,...)", + .help_str = "show port <port_id> rss reta <size> <mask0[,mask1]*>", .tokens = { (void *)&cmd_showport_reta_show, (void *)&cmd_showport_reta_port, @@ -2134,11 +2232,10 @@ cmdline_parse_token_string_t cmd_showport_rss_hash_rss_key = cmdline_parse_inst_t cmd_showport_rss_hash = { .f = cmd_showport_rss_hash_parsed, .data = NULL, - .help_str = - "show port X rss-hash 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 (X = port number)\n", + .help_str = "show port <port_id> rss-hash " + "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", .tokens = { (void *)&cmd_showport_rss_hash_show, (void *)&cmd_showport_rss_hash_port, @@ -2152,11 +2249,10 @@ cmdline_parse_inst_t cmd_showport_rss_hash = { cmdline_parse_inst_t cmd_showport_rss_hash_key = { .f = cmd_showport_rss_hash_parsed, .data = (void *)1, - .help_str = - "show port X rss-hash 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 key (X = port number)\n", + .help_str = "show port <port_id> rss-hash " + "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 key", .tokens = { (void *)&cmd_showport_rss_hash_show, (void *)&cmd_showport_rss_hash_port, @@ -2253,10 +2349,10 @@ 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 nb-tcs pfc on|off", - .tokens = { + .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, @@ -2321,7 +2417,7 @@ cmdline_parse_token_num_t cmd_config_burst_value = cmdline_parse_inst_t cmd_config_burst = { .f = cmd_config_burst_parsed, .data = NULL, - .help_str = "port config all burst value", + .help_str = "port config all burst <value>", .tokens = { (void *)&cmd_config_burst_port, (void *)&cmd_config_burst_keyword, @@ -2390,7 +2486,7 @@ cmdline_parse_token_num_t cmd_config_thresh_value = 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", + .help_str = "port config all txpt|txht|txwt|rxpt|rxht|rxwt <value>", .tokens = { (void *)&cmd_config_thresh_port, (void *)&cmd_config_thresh_keyword, @@ -2454,7 +2550,7 @@ cmdline_parse_token_num_t cmd_config_threshold_value = cmdline_parse_inst_t cmd_config_threshold = { .f = cmd_config_threshold_parsed, .data = NULL, - .help_str = "port config all txfreet|txrst|rxfreet value", + .help_str = "port config all txfreet|txrst|rxfreet <value>", .tokens = { (void *)&cmd_config_threshold_port, (void *)&cmd_config_threshold_keyword, @@ -2483,7 +2579,7 @@ cmdline_parse_token_string_t cmd_stop_stop = cmdline_parse_inst_t cmd_stop = { .f = cmd_stop_parsed, .data = NULL, - .help_str = "stop - stop packet forwarding", + .help_str = "stop: Stop packet forwarding", .tokens = { (void *)&cmd_stop_stop, NULL, @@ -2613,7 +2709,7 @@ cmdline_parse_token_string_t cmd_set_list_of_items = cmdline_parse_inst_t cmd_set_fwd_list = { .f = cmd_set_list_parsed, .data = NULL, - .help_str = "set corelist|portlist x[,y]*", + .help_str = "set corelist|portlist <list0[,list1]*>", .tokens = { (void *)&cmd_set_list_keyword, (void *)&cmd_set_list_name, @@ -2660,7 +2756,7 @@ cmdline_parse_token_num_t cmd_setmask_value = cmdline_parse_inst_t cmd_set_fwd_mask = { .f = cmd_set_mask_parsed, .data = NULL, - .help_str = "set coremask|portmask hexadecimal value", + .help_str = "set coremask|portmask <hexadecimal value>", .tokens = { (void *)&cmd_setmask_set, (void *)&cmd_setmask_mask, @@ -2706,7 +2802,7 @@ cmdline_parse_token_num_t cmd_set_value = cmdline_parse_inst_t cmd_set_numbers = { .f = cmd_set_parsed, .data = NULL, - .help_str = "set nbport|nbcore|burst|verbose value", + .help_str = "set nbport|nbcore|burst|verbose <value>", .tokens = { (void *)&cmd_set_set, (void *)&cmd_set_what, @@ -2752,7 +2848,7 @@ cmdline_parse_token_string_t cmd_set_txpkts_lengths = cmdline_parse_inst_t cmd_set_txpkts = { .f = cmd_set_txpkts_parsed, .data = NULL, - .help_str = "set txpkts x[,y]*", + .help_str = "set txpkts <len0[,len1]*>", .tokens = { (void *)&cmd_set_txpkts_keyword, (void *)&cmd_set_txpkts_name, @@ -2859,7 +2955,7 @@ cmdline_parse_token_num_t cmd_config_txqflags_value = cmdline_parse_inst_t cmd_config_txqflags = { .f = cmd_config_txqflags_parsed, .data = NULL, - .help_str = "port config all txqflags value", + .help_str = "port config all txqflags <value>", .tokens = { (void *)&cmd_config_txqflags_port, (void *)&cmd_config_txqflags_config, @@ -2907,8 +3003,9 @@ cmdline_parse_token_num_t cmd_rx_vlan_filter_all_portid = cmdline_parse_inst_t cmd_rx_vlan_filter_all = { .f = cmd_rx_vlan_filter_all_parsed, .data = NULL, - .help_str = "add/remove all identifiers to/from the set of VLAN " - "Identifiers filtered by a port", + .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, @@ -3007,8 +3104,9 @@ cmdline_parse_token_string_t cmd_vlan_offload_portid = cmdline_parse_inst_t cmd_vlan_offload = { .f = cmd_vlan_offload_parsed, .data = NULL, - .help_str = "set strip|filter|qinq|stripq on|off port_id[,queue_id], filter/strip for rx side" - " qinq(extended) for both rx/tx sides ", + .help_str = "vlan set strip|filter|qinq|stripq on|off " + "<port_id[,queue_id]>: " + "Filter/Strip for rx side qinq(extended) for both rx/tx sides", .tokens = { (void *)&cmd_vlan_offload_vlan, (void *)&cmd_vlan_offload_set, @@ -3070,8 +3168,8 @@ cmdline_parse_token_num_t cmd_vlan_tpid_portid = cmdline_parse_inst_t cmd_vlan_tpid = { .f = cmd_vlan_tpid_parsed, .data = NULL, - .help_str = "set inner|outer tpid tp_id port_id, set the VLAN " - "Ether type", + .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, @@ -3120,8 +3218,9 @@ cmdline_parse_token_num_t cmd_rx_vlan_filter_portid = cmdline_parse_inst_t cmd_rx_vlan_filter = { .f = cmd_rx_vlan_filter_parsed, .data = NULL, - .help_str = "add/remove a VLAN identifier to/from the set of VLAN " - "Identifiers filtered by a port", + .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, @@ -3165,7 +3264,8 @@ cmdline_parse_token_num_t cmd_tx_vlan_set_vlanid = cmdline_parse_inst_t cmd_tx_vlan_set = { .f = cmd_tx_vlan_set_parsed, .data = NULL, - .help_str = "enable hardware insertion of a single VLAN header " + .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, @@ -3214,7 +3314,8 @@ cmdline_parse_token_num_t cmd_tx_vlan_set_qinq_vlanid_outer = cmdline_parse_inst_t cmd_tx_vlan_set_qinq = { .f = cmd_tx_vlan_set_qinq_parsed, .data = NULL, - .help_str = "enable hardware insertion of double VLAN header " + .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, @@ -3271,7 +3372,7 @@ cmdline_parse_token_string_t cmd_tx_vlan_set_pvid_mode = 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)", + .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, @@ -3313,8 +3414,8 @@ cmdline_parse_token_num_t cmd_tx_vlan_reset_portid = cmdline_parse_inst_t cmd_tx_vlan_reset = { .f = cmd_tx_vlan_reset_parsed, .data = NULL, - .help_str = "disable hardware insertion of a VLAN header in packets " - "sent on a port", + .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, @@ -3440,8 +3541,9 @@ cmdline_parse_token_num_t cmd_csum_portid = cmdline_parse_inst_t cmd_csum_set = { .f = cmd_csum_parsed, .data = NULL, - .help_str = "enable/disable hardware calculation of L3/L4 checksum when " - "using csum forward engine: csum set ip|tcp|udp|sctp|outer-ip hw|sw <port>", + .help_str = "csum set ip|tcp|udp|sctp|outer-ip 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, @@ -3459,7 +3561,7 @@ cmdline_parse_token_string_t cmd_csum_mode_show = cmdline_parse_inst_t cmd_csum_show = { .f = cmd_csum_parsed, .data = NULL, - .help_str = "show checksum offload configuration: csum show <port>", + .help_str = "csum show <port_id>: Show checksum offload configuration", .tokens = { (void *)&cmd_csum_csum, (void *)&cmd_csum_mode_show, @@ -3512,8 +3614,8 @@ cmdline_parse_token_num_t cmd_csum_tunnel_portid = cmdline_parse_inst_t cmd_csum_tunnel = { .f = cmd_csum_tunnel_parsed, .data = NULL, - .help_str = "enable/disable parsing of tunnels for csum engine: " - "csum parse_tunnel on|off <tx-port>", + .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, @@ -3576,8 +3678,9 @@ cmdline_parse_token_num_t cmd_tso_set_portid = cmdline_parse_inst_t cmd_tso_set = { .f = cmd_tso_set_parsed, .data = NULL, - .help_str = "Set TSO segment size of non-tunneled packets " - "for csum engine (0 to disable): tso set <tso_segsz> <port>", + .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, @@ -3595,8 +3698,8 @@ cmdline_parse_token_string_t cmd_tso_show_mode = cmdline_parse_inst_t cmd_tso_show = { .f = cmd_tso_set_parsed, .data = NULL, - .help_str = "Show TSO segment size of non-tunneled packets " - "for csum engine: tso show <port>", + .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, @@ -3692,8 +3795,9 @@ cmdline_parse_token_num_t cmd_tunnel_tso_set_portid = cmdline_parse_inst_t cmd_tunnel_tso_set = { .f = cmd_tunnel_tso_set_parsed, .data = NULL, - .help_str = "Set TSO segment size of tunneled packets for csum engine " - "(0 to disable): tunnel_tso set <tso_segsz> <port>", + .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, @@ -3711,8 +3815,8 @@ cmdline_parse_token_string_t cmd_tunnel_tso_show_mode = cmdline_parse_inst_t cmd_tunnel_tso_show = { .f = cmd_tunnel_tso_set_parsed, .data = NULL, - .help_str = "Show TSO segment size of tunneled packets " - "for csum engine: tunnel_tso show <port>", + .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, @@ -3750,7 +3854,7 @@ cmdline_parse_token_string_t cmd_setflushrx_mode = 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", + .help_str = "set flush_rx on|off: Enable/Disable flush on rx streams", .data = NULL, .tokens = { (void *)&cmd_setflushrx_set, @@ -3789,7 +3893,7 @@ cmdline_parse_token_string_t cmd_setlinkcheck_mode = 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 " + .help_str = "set link_check on|off: Enable/Disable link status check " "when starting/stopping a port", .data = NULL, .tokens = { @@ -3850,7 +3954,7 @@ cmdline_parse_token_num_t cmd_setbypass_mode_port = cmdline_parse_inst_t cmd_set_bypass_mode = { .f = cmd_set_bypass_mode_parsed, - .help_str = "set bypass mode (normal|bypass|isolate) (port_id): " + .help_str = "set bypass mode normal|bypass|isolate <port_id>: " "Set the NIC bypass mode for port_id", .data = NULL, .tokens = { @@ -3950,9 +4054,9 @@ cmdline_parse_token_num_t cmd_setbypass_event_port = cmdline_parse_inst_t cmd_set_bypass_event = { .f = cmd_set_bypass_event_parsed, - .help_str = "set bypass event (timeout|os_on|os_off|power_on|power_off) " - "mode (normal|bypass|isolate) (port_id): " - "Set the NIC bypass event mode for port_id", + .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, @@ -4015,8 +4119,8 @@ cmdline_parse_token_string_t cmd_setbypass_timeout_value = 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) seconds: " - "Set the NIC bypass watchdog timeout", + .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, @@ -4109,7 +4213,7 @@ cmdline_parse_token_num_t cmd_showbypass_config_port = cmdline_parse_inst_t cmd_show_bypass_config = { .f = cmd_show_bypass_config_parsed, - .help_str = "show bypass config (port_id): " + .help_str = "show bypass config <port_id>: " "Show the NIC bypass config for port_id", .data = NULL, .tokens = { @@ -4162,7 +4266,8 @@ TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_mode_result, 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", + .help_str = "set bonding mode <mode_value> <port_id>: " + "Set the bonding mode for port_id", .data = NULL, .tokens = { (void *) &cmd_setbonding_mode_set, @@ -4227,7 +4332,9 @@ TOKEN_STRING_INITIALIZER(struct cmd_set_bonding_balance_xmit_policy_result, 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) (policy_value): Set the bonding balance_xmit_policy for port_id", + .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, @@ -4353,7 +4460,8 @@ TOKEN_NUM_INITIALIZER(struct cmd_show_bonding_config_result, 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", + .help_str = "show bonding config <port_id>: " + "Show the bonding config for port_id", .data = NULL, .tokens = { (void *)&cmd_showbonding_config_show, @@ -4408,7 +4516,8 @@ TOKEN_NUM_INITIALIZER(struct cmd_set_bonding_primary_result, 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", + .help_str = "set bonding primary <slave_id> <port_id>: " + "Set the primary slave for port_id", .data = NULL, .tokens = { (void *)&cmd_setbonding_primary_set, @@ -4465,7 +4574,8 @@ TOKEN_NUM_INITIALIZER(struct cmd_add_bonding_slave_result, 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", + .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, @@ -4522,7 +4632,8 @@ cmdline_parse_token_num_t cmd_removebonding_slave_port = 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", + .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, @@ -4574,7 +4685,6 @@ static void cmd_create_bonded_device_parsed(void *parsed_result, nb_ports = rte_eth_dev_count(); reconfig(port_id, res->socket); rte_eth_promiscuous_enable(port_id); - ports[port_id].enabled = 1; } } @@ -4597,7 +4707,8 @@ cmdline_parse_token_num_t cmd_createbonded_device_socket = 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", + .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, @@ -4651,7 +4762,7 @@ cmdline_parse_token_etheraddr_t cmd_set_bond_mac_addr_addr = 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) (address): ", + .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, @@ -4710,7 +4821,7 @@ cmdline_parse_token_num_t cmd_set_bond_mon_period_period_ms = 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): ", + .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, @@ -4768,8 +4879,8 @@ static void cmd_set_fwd_mode_init(void) cmdline_parse_token_string_t *token_struct; modes = list_pkt_forwarding_modes(); - snprintf(help, sizeof help, "set fwd %s - " - "set packet forwarding mode", modes); + snprintf(help, sizeof(help), "set fwd %s: " + "Set packet forwarding mode", modes); cmd_set_fwd_mode.help_str = help; /* string token separator is # */ @@ -4835,8 +4946,8 @@ static void cmd_set_fwd_retry_mode_init(void) 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); + 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 # */ @@ -4895,7 +5006,7 @@ cmdline_parse_token_num_t cmd_set_burst_tx_retry_retry_num = cmdline_parse_inst_t cmd_set_burst_tx_retry = { .f = cmd_set_burst_tx_retry_parsed, - .help_str = "set burst tx delay (time_by_useconds) retry (retry_num)", + .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, @@ -4932,7 +5043,7 @@ static void cmd_set_promisc_mode_parsed(void *parsed_result, /* all ports */ if (allports) { - FOREACH_PORT(i, ports) { + RTE_ETH_FOREACH_DEV(i) { if (enable) rte_eth_promiscuous_enable(i); else @@ -4965,7 +5076,7 @@ cmdline_parse_token_string_t cmd_setpromisc_mode = 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", + .help_str = "set promisc all on|off: Set promisc mode for all ports", .tokens = { (void *)&cmd_setpromisc_set, (void *)&cmd_setpromisc_promisc, @@ -4978,7 +5089,7 @@ cmdline_parse_inst_t cmd_set_promisc_mode_all = { cmdline_parse_inst_t cmd_set_promisc_mode_one = { .f = cmd_set_promisc_mode_parsed, .data = (void *)0, - .help_str = "set promisc X on|off: set promisc mode on port X", + .help_str = "set promisc <port_id> on|off: Set promisc mode on port_id", .tokens = { (void *)&cmd_setpromisc_set, (void *)&cmd_setpromisc_promisc, @@ -5012,7 +5123,7 @@ static void cmd_set_allmulti_mode_parsed(void *parsed_result, /* all ports */ if (allports) { - FOREACH_PORT(i, ports) { + RTE_ETH_FOREACH_DEV(i) { if (enable) rte_eth_allmulticast_enable(i); else @@ -5045,7 +5156,7 @@ cmdline_parse_token_string_t cmd_setallmulti_mode = 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", + .help_str = "set allmulti all on|off: Set allmulti mode for all ports", .tokens = { (void *)&cmd_setallmulti_set, (void *)&cmd_setallmulti_allmulti, @@ -5058,7 +5169,8 @@ cmdline_parse_inst_t cmd_set_allmulti_mode_all = { cmdline_parse_inst_t cmd_set_allmulti_mode_one = { .f = cmd_set_allmulti_mode_parsed, .data = (void *)0, - .help_str = "set allmulti X on|off: set allmulti mode on port X", + .help_str = "set allmulti <port_id> on|off: " + "Set allmulti mode on port_id", .tokens = { (void *)&cmd_setallmulti_set, (void *)&cmd_setallmulti_allmulti, @@ -5157,9 +5269,9 @@ cmd_link_flow_ctrl_set_parsed(void *parsed_result, struct cmdline *cl, cmdline_parse_inst_t cmd_link_flow_control_set = { .f = cmd_link_flow_ctrl_set_parsed, .data = NULL, - .help_str = "Configure the Ethernet flow control: 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", + .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, @@ -5183,8 +5295,8 @@ autoneg on|off port_id", 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 = "Change rx flow control parameter: set flow_ctrl " - "rx on|off port_id", + .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, @@ -5198,8 +5310,8 @@ cmdline_parse_inst_t cmd_link_flow_control_set_rx = { 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 = "Change tx flow control parameter: set flow_ctrl " - "tx on|off port_id", + .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, @@ -5213,8 +5325,8 @@ cmdline_parse_inst_t cmd_link_flow_control_set_tx = { 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 = "Change high water flow control parameter: set flow_ctrl " - "high_water value port_id", + .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, @@ -5228,8 +5340,8 @@ cmdline_parse_inst_t cmd_link_flow_control_set_hw = { 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 = "Change low water flow control parameter: set flow_ctrl " - "low_water value port_id", + .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, @@ -5243,8 +5355,8 @@ cmdline_parse_inst_t cmd_link_flow_control_set_lw = { 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 = "Change pause time flow control parameter: set flow_ctrl " - "pause_time value port_id", + .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, @@ -5258,8 +5370,8 @@ cmdline_parse_inst_t cmd_link_flow_control_set_pt = { 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 = "Change send_xon flow control parameter: set flow_ctrl " - "send_xon value port_id", + .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, @@ -5273,8 +5385,8 @@ cmdline_parse_inst_t cmd_link_flow_control_set_xon = { 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 = "Change mac ctrl fwd flow control parameter: set flow_ctrl " - "mac_ctrl_frame_fwd on|off port_id", + .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, @@ -5288,8 +5400,8 @@ cmdline_parse_inst_t cmd_link_flow_control_set_macfwd = { 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 = "Change autoneg flow control parameter: set flow_ctrl " - "autoneg on|off port_id", + .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, @@ -5374,7 +5486,7 @@ cmd_link_flow_ctrl_set_parsed(void *parsed_result, printf("bad flow contrl parameter, return code = %d \n", ret); } -/* *** SETUP ETHERNET PIRORITY FLOW CONTROL *** */ +/* *** SETUP ETHERNET PRIORITY FLOW CONTROL *** */ struct cmd_priority_flow_ctrl_set_result { cmdline_fixed_string_t set; cmdline_fixed_string_t pfc_ctrl; @@ -5459,8 +5571,9 @@ cmdline_parse_token_num_t cmd_pfc_set_portid = cmdline_parse_inst_t cmd_priority_flow_control_set = { .f = cmd_priority_flow_ctrl_set_parsed, .data = NULL, - .help_str = "Configure the Ethernet priority flow control: set pfc_ctrl rx on|off\n\ - tx on|off high_water low_water pause_time priority port_id", + .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, @@ -5500,7 +5613,7 @@ cmdline_parse_token_string_t cmd_reset_def = cmdline_parse_inst_t cmd_reset = { .f = cmd_reset_parsed, .data = NULL, - .help_str = "set default: reset default forwarding configuration", + .help_str = "set default: Reset default forwarding configuration", .tokens = { (void *)&cmd_reset_set, (void *)&cmd_reset_def, @@ -5526,7 +5639,7 @@ static void cmd_start_parsed(__attribute__((unused)) void *parsed_result, cmdline_parse_inst_t cmd_start = { .f = cmd_start_parsed, .data = NULL, - .help_str = "start packet forwarding", + .help_str = "start: Start packet forwarding", .tokens = { (void *)&cmd_start_start, NULL, @@ -5557,7 +5670,8 @@ cmdline_parse_token_string_t cmd_start_tx_first_tx_first = cmdline_parse_inst_t cmd_start_tx_first = { .f = cmd_start_tx_first_parsed, .data = NULL, - .help_str = "start packet forwarding, after sending 1 burst of packets", + .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, @@ -5595,8 +5709,8 @@ cmdline_parse_token_num_t cmd_start_tx_first_n_tx_num = cmdline_parse_inst_t cmd_start_tx_first_n = { .f = cmd_start_tx_first_n_parsed, .data = NULL, - .help_str = "start packet forwarding, after sending <num> " - "bursts of packets", + .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, @@ -5634,7 +5748,7 @@ static void cmd_set_link_up_parsed(__attribute__((unused)) void *parsed_result, cmdline_parse_inst_t cmd_set_link_up = { .f = cmd_set_link_up_parsed, .data = NULL, - .help_str = "set link-up port (port id)", + .help_str = "set link-up port <port id>", .tokens = { (void *)&cmd_set_link_up_set, (void *)&cmd_set_link_up_link_up, @@ -5674,7 +5788,7 @@ static void cmd_set_link_down_parsed( cmdline_parse_inst_t cmd_set_link_down = { .f = cmd_set_link_down_parsed, .data = NULL, - .help_str = "set link-down port (port id)", + .help_str = "set link-down port <port id>", .tokens = { (void *)&cmd_set_link_down_set, (void *)&cmd_set_link_down_link_down, @@ -5743,29 +5857,32 @@ static void cmd_showportall_parsed(void *parsed_result, struct cmd_showportall_result *res = parsed_result; if (!strcmp(res->show, "clear")) { if (!strcmp(res->what, "stats")) - FOREACH_PORT(i, ports) + RTE_ETH_FOREACH_DEV(i) nic_stats_clear(i); else if (!strcmp(res->what, "xstats")) - FOREACH_PORT(i, ports) + RTE_ETH_FOREACH_DEV(i) nic_xstats_clear(i); } else if (!strcmp(res->what, "info")) - FOREACH_PORT(i, ports) + RTE_ETH_FOREACH_DEV(i) port_infos_display(i); else if (!strcmp(res->what, "stats")) - FOREACH_PORT(i, ports) + RTE_ETH_FOREACH_DEV(i) nic_stats_display(i); else if (!strcmp(res->what, "xstats")) - FOREACH_PORT(i, ports) + RTE_ETH_FOREACH_DEV(i) nic_xstats_display(i); else if (!strcmp(res->what, "fdir")) - FOREACH_PORT(i, ports) + RTE_ETH_FOREACH_DEV(i) fdir_get_infos(i); else if (!strcmp(res->what, "stat_qmap")) - FOREACH_PORT(i, ports) + RTE_ETH_FOREACH_DEV(i) nic_stats_mapping_display(i); else if (!strcmp(res->what, "dcb_tc")) - FOREACH_PORT(i, ports) + 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 = @@ -5775,13 +5892,14 @@ 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#stats#xstats#fdir#stat_qmap#dcb_tc"); + "info#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|stats|xstats|fdir|stat_qmap|dcb_tc all", + .help_str = "show|clear port " + "info|stats|xstats|fdir|stat_qmap|dcb_tc|cap all", .tokens = { (void *)&cmd_showportall_show, (void *)&cmd_showportall_port, @@ -5821,6 +5939,8 @@ static void cmd_showport_parsed(void *parsed_result, 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 = @@ -5830,14 +5950,16 @@ 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#stats#xstats#fdir#stat_qmap#dcb_tc"); + "info#stats#xstats#fdir#stat_qmap#dcb_tc#cap"); cmdline_parse_token_num_t cmd_showport_portnum = TOKEN_NUM_INITIALIZER(struct cmd_showport_result, portnum, UINT8); cmdline_parse_inst_t cmd_showport = { .f = cmd_showport_parsed, .data = NULL, - .help_str = "show|clear port info|stats|xstats|fdir|stat_qmap|dcb_tc X (X = port number)", + .help_str = "show|clear port " + "info|stats|xstats|fdir|stat_qmap|dcb_tc|cap " + "<port_id>", .tokens = { (void *)&cmd_showport_show, (void *)&cmd_showport_port, @@ -5883,7 +6005,7 @@ cmdline_parse_token_num_t cmd_showqueue_queuenum = cmdline_parse_inst_t cmd_showqueue = { .f = cmd_showqueue_parsed, .data = NULL, - .help_str = "show rxq|txq info <port number> <queue_number>", + .help_str = "show rxq|txq info <port_id> <queue_id>", .tokens = { (void *)&cmd_showqueue_show, (void *)&cmd_showqueue_type, @@ -5923,7 +6045,7 @@ cmdline_parse_token_num_t cmd_read_reg_reg_off = cmdline_parse_inst_t cmd_read_reg = { .f = cmd_read_reg_parsed, .data = NULL, - .help_str = "read reg port_id reg_off", + .help_str = "read reg <port_id> <reg_off>", .tokens = { (void *)&cmd_read_reg_read, (void *)&cmd_read_reg_reg, @@ -5975,8 +6097,8 @@ cmdline_parse_token_num_t cmd_read_reg_bit_field_bit2_pos = 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)", + .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, @@ -6021,7 +6143,7 @@ cmdline_parse_token_num_t cmd_read_reg_bit_bit_pos = 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)", + .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, @@ -6064,7 +6186,7 @@ cmdline_parse_token_num_t cmd_write_reg_value = cmdline_parse_inst_t cmd_write_reg = { .f = cmd_write_reg_parsed, .data = NULL, - .help_str = "write reg port_id reg_off reg_value", + .help_str = "write reg <port_id> <reg_off> <reg_value>", .tokens = { (void *)&cmd_write_reg_write, (void *)&cmd_write_reg_reg, @@ -6121,8 +6243,9 @@ cmdline_parse_token_num_t cmd_write_reg_bit_field_value = 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)", + .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, @@ -6172,7 +6295,8 @@ cmdline_parse_token_num_t cmd_write_reg_bit_value = 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)", + .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, @@ -6221,7 +6345,7 @@ cmdline_parse_token_num_t cmd_read_rxd_txd_desc_id = 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 rxd_id", + .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, @@ -6251,7 +6375,7 @@ cmdline_parse_token_string_t cmd_quit_quit = cmdline_parse_inst_t cmd_quit = { .f = cmd_quit_parsed, .data = NULL, - .help_str = "exit application", + .help_str = "quit: Exit application", .tokens = { (void *)&cmd_quit_quit, NULL, @@ -6275,6 +6399,9 @@ static void cmd_mac_addr_parsed(void *parsed_result, 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); @@ -6289,7 +6416,7 @@ cmdline_parse_token_string_t cmd_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"); + "add#remove#set"); cmdline_parse_token_num_t cmd_mac_addr_portnum = TOKEN_NUM_INITIALIZER(struct cmd_mac_addr_result, port_num, UINT8); cmdline_parse_token_etheraddr_t cmd_mac_addr_addr = @@ -6298,8 +6425,8 @@ cmdline_parse_token_etheraddr_t cmd_mac_addr_addr = cmdline_parse_inst_t cmd_mac_addr = { .f = cmd_mac_addr_parsed, .data = (void *)0, - .help_str = "mac_addr add|remove X <address>: " - "add/remove MAC address on port X", + .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, @@ -6353,7 +6480,8 @@ cmdline_parse_token_num_t cmd_setqmap_mapvalue = cmdline_parse_inst_t cmd_set_qmap = { .f = cmd_set_qmap_parsed, .data = NULL, - .help_str = "Set statistics mapping value on tx|rx queue_id of port_id", + .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, @@ -6415,7 +6543,7 @@ cmdline_parse_token_string_t cmd_set_uc_hash_mode = cmdline_parse_inst_t cmd_set_uc_hash_filter = { .f = cmd_set_uc_hash_parsed, .data = NULL, - .help_str = "set port X uta Y on|off(X = port number,Y = MAC address)", + .help_str = "set port <port_id> uta <mac_addr> on|off)", .tokens = { (void *)&cmd_set_uc_hash_set, (void *)&cmd_set_uc_hash_port, @@ -6476,7 +6604,7 @@ cmdline_parse_token_string_t cmd_set_uc_all_hash_mode = cmdline_parse_inst_t cmd_set_uc_all_hash_filter = { .f = cmd_set_uc_all_hash_parsed, .data = NULL, - .help_str = "set port X uta all on|off (X = port number)", + .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, @@ -6575,12 +6703,10 @@ cmdline_parse_token_string_t cmd_set_vf_macvlan_mode = cmdline_parse_inst_t cmd_set_vf_macvlan_filter = { .f = cmd_set_vf_macvlan_parsed, .data = NULL, - .help_str = "set port (portid) vf (vfid) (mac-addr) " - "(exact-mac|exact-mac-vlan|hashmac|hashmac-vlan) " - "on|off\n" - "exact match rule:exact match of MAC or MAC and VLAN; " - "hash match rule: hash match of MAC and exact match " - "of VLAN", + .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, @@ -6594,6 +6720,7 @@ cmdline_parse_inst_t cmd_set_vf_macvlan_filter = { }, }; +#ifdef RTE_LIBRTE_IXGBE_PMD /* *** CONFIGURE VF TRAFFIC CONTROL *** */ struct cmd_set_vf_traffic { cmdline_fixed_string_t set; @@ -6642,8 +6769,7 @@ cmdline_parse_token_string_t cmd_setvf_traffic_mode = cmdline_parse_inst_t cmd_set_vf_traffic = { .f = cmd_set_vf_traffic_parsed, .data = NULL, - .help_str = "set port X vf Y rx|tx on|off" - "(X = port number,Y = vf id)", + .help_str = "set port <port_id> vf <vf_id> rx|tx on|off", .tokens = { (void *)&cmd_setvf_traffic_set, (void *)&cmd_setvf_traffic_port, @@ -6689,7 +6815,7 @@ cmd_set_vf_rxmode_parsed(void *parsed_result, rx_mode |= ETH_VMDQ_ACCEPT_MULTICAST; } - ret = rte_eth_dev_set_vf_rxmode(res->port_id,res->vf_id,rx_mode,(uint8_t)is_on); + ret = rte_pmd_ixgbe_set_vf_rxmode(res->port_id, res->vf_id, rx_mode, (uint8_t)is_on); if (ret < 0) printf("bad VF receive mode parameter, return code = %d \n", ret); @@ -6723,7 +6849,8 @@ cmdline_parse_token_string_t cmd_set_vf_rxmode_on = cmdline_parse_inst_t cmd_set_vf_rxmode = { .f = cmd_set_vf_rxmode_parsed, .data = NULL, - .help_str = "set port X vf Y rxmode AUPE|ROPE|BAM|MPE on|off", + .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, @@ -6736,6 +6863,7 @@ cmdline_parse_inst_t cmd_set_vf_rxmode = { NULL, }, }; +#endif /* *** ADD MAC ADDRESS FILTER FOR A VF OF A PORT *** */ struct cmd_vf_mac_addr_result { @@ -6788,8 +6916,8 @@ cmdline_parse_token_etheraddr_t cmd_vf_mac_addr_addr = cmdline_parse_inst_t cmd_vf_mac_addr_filter = { .f = cmd_vf_mac_addr_parsed, .data = (void *)0, - .help_str = "mac_addr add port X vf Y ethaddr:(X = port number," - "Y = VF number)add MAC address filtering for a VF on port X", + .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, @@ -6819,11 +6947,37 @@ cmd_vf_rx_vlan_filter_parsed(void *parsed_result, __attribute__((unused)) void *data) { struct cmd_vf_rx_vlan_filter *res = parsed_result; + int ret = -ENOTSUP; - if (!strcmp(res->what, "add")) - set_vf_rx_vlan(res->port_id, res->vlan_id,res->vf_mask, 1); - else - set_vf_rx_vlan(res->port_id, res->vlan_id,res->vf_mask, 0); + __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 + + 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 = @@ -6851,8 +7005,8 @@ cmdline_parse_token_num_t cmd_vf_rx_vlan_filter_vf_mask = cmdline_parse_inst_t cmd_vf_rxvlan_filter = { .f = cmd_vf_rx_vlan_filter_parsed, .data = NULL, - .help_str = "rx_vlan add|rm X port Y vf Z (X = VLAN ID," - "Y = port number,Z = hexadecimal VF mask)", + .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, @@ -6918,8 +7072,8 @@ cmdline_parse_token_num_t cmd_queue_rate_limit_ratenum = cmdline_parse_inst_t cmd_queue_rate_limit = { .f = cmd_queue_rate_limit_parsed, .data = (void *)0, - .help_str = "set port X queue Y rate Z:(X = port number," - "Y = queue number,Z = rate number)set rate limit for a queue on port X", + .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, @@ -6932,6 +7086,7 @@ cmdline_parse_inst_t cmd_queue_rate_limit = { }, }; +#ifdef RTE_LIBRTE_IXGBE_PMD /* *** SET RATE LIMIT FOR A VF OF A PORT *** */ struct cmd_vf_rate_limit_result { cmdline_fixed_string_t set; @@ -6994,9 +7149,9 @@ cmdline_parse_token_num_t cmd_vf_rate_limit_q_msk_val = cmdline_parse_inst_t cmd_vf_rate_limit = { .f = cmd_vf_rate_limit_parsed, .data = (void *)0, - .help_str = "set port X vf Y rate Z queue_mask V:(X = port number," - "Y = VF number,Z = rate number, V = queue mask value)set rate limit " - "for queues of VF on port X", + .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, @@ -7010,6 +7165,7 @@ cmdline_parse_inst_t cmd_vf_rate_limit = { NULL, }, }; +#endif /* *** ADD TUNNEL FILTER OF A PORT *** */ struct cmd_tunnel_filter_result { @@ -7140,12 +7296,10 @@ cmdline_parse_token_num_t cmd_tunnel_filter_queue_num = cmdline_parse_inst_t cmd_tunnel_filter = { .f = cmd_tunnel_filter_parsed, .data = (void *)0, - .help_str = "add/rm tunnel filter of a port: " - "tunnel_filter add port_id outer_mac inner_mac ip " - "inner_vlan tunnel_type(vxlan|nvgre|ipingre) filter_type " - "(oip|iip|imac-ivlan|imac-ivlan-tenid|imac-tenid|" - "imac|omac-imac-tenid) " - "tenant_id queue_num", + .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, @@ -7211,8 +7365,8 @@ cmdline_parse_token_num_t cmd_tunnel_udp_config_port_id = cmdline_parse_inst_t cmd_tunnel_udp_config = { .f = cmd_tunnel_udp_config_parsed, .data = (void *)0, - .help_str = "add/rm an tunneling UDP port filter: " - "rx_vxlan_port add udp_port port_id", + .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, @@ -7263,7 +7417,7 @@ cmdline_parse_token_num_t cmd_global_config_gre_key_len = cmdline_parse_inst_t cmd_global_config = { .f = cmd_global_config_parsed, .data = (void *)NULL, - .help_str = "global_config <port_id> gre-key-len <number>", + .help_str = "global_config <port_id> gre-key-len <key_len>", .tokens = { (void *)&cmd_global_config_cmd, (void *)&cmd_global_config_port_id, @@ -7371,8 +7525,9 @@ cmd_set_mirror_mask_parsed(void *parsed_result, cmdline_parse_inst_t cmd_set_mirror_mask = { .f = cmd_set_mirror_mask_parsed, .data = NULL, - .help_str = "set port X mirror-rule Y pool-mirror-up|pool-mirror-down|vlan-mirror" - " pool_mask|vlan_id[,vlan_id]* dst-pool Z on|off", + .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, @@ -7388,7 +7543,7 @@ cmdline_parse_inst_t cmd_set_mirror_mask = { }, }; -/* *** CONFIGURE VM MIRROR UDLINK/DOWNLINK RULE *** */ +/* *** CONFIGURE VM MIRROR UPLINK/DOWNLINK RULE *** */ struct cmd_set_mirror_link_result { cmdline_fixed_string_t set; cmdline_fixed_string_t port; @@ -7462,8 +7617,8 @@ cmd_set_mirror_link_parsed(void *parsed_result, cmdline_parse_inst_t cmd_set_mirror_link = { .f = cmd_set_mirror_link_parsed, .data = NULL, - .help_str = "set port X mirror-rule Y uplink-mirror|" - "downlink-mirror dst-pool Z on|off", + .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, @@ -7519,7 +7674,7 @@ cmd_reset_mirror_rule_parsed(void *parsed_result, cmdline_parse_inst_t cmd_reset_mirror_rule = { .f = cmd_reset_mirror_rule_parsed, .data = NULL, - .help_str = "reset port X mirror-rule Y", + .help_str = "reset port <port_id> mirror-rule <rule_id>", .tokens = { (void *)&cmd_rm_mirror_rule_reset, (void *)&cmd_rm_mirror_rule_port, @@ -7564,6 +7719,8 @@ static void cmd_dump_parsed(void *parsed_result, rte_mempool_list_dump(stdout); else if (!strcmp(res->dump, "dump_devargs")) rte_eal_devargs_dump(stdout); + else if (!strcmp(res->dump, "dump_log_types")) + rte_log_dump(stdout); } cmdline_parse_token_string_t cmd_dump_dump = @@ -7573,12 +7730,13 @@ cmdline_parse_token_string_t cmd_dump_dump = "dump_struct_sizes#" "dump_ring#" "dump_mempool#" - "dump_devargs"); + "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", + .help_str = "Dump status", .tokens = { /* token list, NULL terminated */ (void *)&cmd_dump_dump, NULL, @@ -7626,7 +7784,7 @@ cmdline_parse_token_string_t cmd_dump_one_name = cmdline_parse_inst_t cmd_dump_one = { .f = cmd_dump_one_parsed, /* function to call */ .data = NULL, /* 2nd arg of func */ - .help_str = "dump one ring/mempool: dump_ring|dump_mempool <name>", + .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, @@ -7711,7 +7869,8 @@ cmdline_parse_token_num_t cmd_syn_filter_queue_id = cmdline_parse_inst_t cmd_syn_filter = { .f = cmd_syn_filter_parsed, .data = NULL, - .help_str = "add/delete syn filter", + .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, @@ -7850,7 +8009,9 @@ cmdline_parse_token_num_t cmd_2tuple_filter_queue_id = cmdline_parse_inst_t cmd_2tuple_filter = { .f = cmd_2tuple_filter_parsed, .data = NULL, - .help_str = "add a 2tuple filter", + .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, @@ -8045,7 +8206,10 @@ cmdline_parse_token_num_t cmd_5tuple_filter_queue_id = cmdline_parse_inst_t cmd_5tuple_filter = { .f = cmd_5tuple_filter_parsed, .data = NULL, - .help_str = "add/del a 5tuple filter", + .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, @@ -8240,7 +8404,9 @@ cmdline_parse_token_num_t cmd_flex_filter_queue_id = cmdline_parse_inst_t cmd_flex_filter = { .f = cmd_flex_filter_parsed, .data = NULL, - .help_str = "add/del a flex filter", + .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, @@ -8352,7 +8518,9 @@ cmd_ethertype_filter_parsed(void *parsed_result, cmdline_parse_inst_t cmd_ethertype_filter = { .f = cmd_ethertype_filter_parsed, .data = NULL, - .help_str = "add or delete an ethertype filter entry", + .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, @@ -8573,6 +8741,7 @@ cmd_flow_director_filter_parsed(void *parsed_result, 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, @@ -8605,6 +8774,7 @@ cmd_flow_director_filter_parsed(void *parsed_result, 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, @@ -8840,7 +9010,14 @@ cmdline_parse_token_num_t cmd_flow_director_tunnel_id_value = cmdline_parse_inst_t cmd_add_del_ip_flow_director = { .f = cmd_flow_director_filter_parsed, .data = NULL, - .help_str = "add or delete an ip flow director entry on NIC", + .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_vaues> 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, @@ -8876,7 +9053,8 @@ cmdline_parse_inst_t cmd_add_del_ip_flow_director = { cmdline_parse_inst_t cmd_add_del_udp_flow_director = { .f = cmd_flow_director_filter_parsed, .data = NULL, - .help_str = "add or delete an udp/tcp flow director entry on NIC", + .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, @@ -8912,7 +9090,8 @@ cmdline_parse_inst_t cmd_add_del_udp_flow_director = { cmdline_parse_inst_t cmd_add_del_sctp_flow_director = { .f = cmd_flow_director_filter_parsed, .data = NULL, - .help_str = "add or delete a sctp flow director entry on NIC", + .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, @@ -8950,7 +9129,8 @@ cmdline_parse_inst_t cmd_add_del_sctp_flow_director = { cmdline_parse_inst_t cmd_add_del_l2_flow_director = { .f = cmd_flow_director_filter_parsed, .data = NULL, - .help_str = "add or delete a L2 flow director entry on NIC", + .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, @@ -8976,7 +9156,8 @@ cmdline_parse_inst_t cmd_add_del_l2_flow_director = { cmdline_parse_inst_t cmd_add_del_mac_vlan_flow_director = { .f = cmd_flow_director_filter_parsed, .data = NULL, - .help_str = "add or delete a MAC VLAN flow director entry on NIC", + .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, @@ -9001,7 +9182,8 @@ cmdline_parse_inst_t cmd_add_del_mac_vlan_flow_director = { cmdline_parse_inst_t cmd_add_del_tunnel_flow_director = { .f = cmd_flow_director_filter_parsed, .data = NULL, - .help_str = "add or delete a tunnel flow director entry on NIC", + .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, @@ -9064,7 +9246,8 @@ cmd_flush_flow_director_parsed(void *parsed_result, cmdline_parse_inst_t cmd_flush_flow_director = { .f = cmd_flush_flow_director_parsed, .data = NULL, - .help_str = "flush all flow director entries of a device on NIC", + .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, @@ -9225,7 +9408,8 @@ cmdline_parse_token_num_t cmd_flow_director_mask_tunnel_id_value = cmdline_parse_inst_t cmd_set_flow_director_ip_mask = { .f = cmd_flow_director_mask_parsed, .data = NULL, - .help_str = "set IP mode flow director's mask on NIC", + .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, @@ -9248,7 +9432,8 @@ cmdline_parse_inst_t cmd_set_flow_director_ip_mask = { cmdline_parse_inst_t cmd_set_flow_director_mac_vlan_mask = { .f = cmd_flow_director_mask_parsed, .data = NULL, - .help_str = "set MAC VLAN mode flow director's mask on NIC", + .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, @@ -9263,7 +9448,8 @@ cmdline_parse_inst_t cmd_set_flow_director_mac_vlan_mask = { cmdline_parse_inst_t cmd_set_flow_director_tunnel_mask = { .f = cmd_flow_director_mask_parsed, .data = NULL, - .help_str = "set tunnel mode flow director's mask on NIC", + .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, @@ -9391,7 +9577,8 @@ cmdline_parse_token_string_t cmd_flow_director_flexmask_mask = cmdline_parse_inst_t cmd_set_flow_director_flex_mask = { .f = cmd_flow_director_flex_mask_parsed, .data = NULL, - .help_str = "set flow director's flex mask on NIC", + .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, @@ -9509,7 +9696,8 @@ cmdline_parse_token_string_t cmd_flow_director_flexpayload_payload_cfg = cmdline_parse_inst_t cmd_set_flow_director_flex_payload = { .f = cmd_flow_director_flxpld_parsed, .data = NULL, - .help_str = "set flow director's flex payload on NIC", + .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, @@ -9519,6 +9707,9 @@ cmdline_parse_inst_t cmd_set_flow_director_flex_payload = { }, }; +/* 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 { @@ -9567,7 +9758,7 @@ cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_port_port_id = 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", + .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, @@ -9626,7 +9817,7 @@ cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_enable = 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", + .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, @@ -9744,7 +9935,7 @@ cmdline_parse_token_num_t cmd_get_hash_global_config_port_id = 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", + .help_str = "get_hash_global_config <port_id>", .tokens = { (void *)&cmd_get_hash_global_config_all, (void *)&cmd_get_hash_global_config_port_id, @@ -9827,11 +10018,11 @@ cmdline_parse_token_string_t cmd_set_hash_global_config_enable = 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 " + .help_str = "set_hash_global_config <port_id> " "toeplitz|simple_xor|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", + "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, @@ -10082,7 +10273,8 @@ cmdline_parse_token_etheraddr_t cmd_mcast_addr_addr = cmdline_parse_inst_t cmd_mcast_addr = { .f = cmd_mcast_addr_parsed, .data = (void *)0, - .help_str = "mcast_addr add|remove X <mcast_addr>: add/remove multicast MAC address on port X", + .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, @@ -10174,7 +10366,7 @@ cmd_config_l2_tunnel_eth_type_all_parsed entry.l2_tunnel_type = str2fdir_l2_tunnel_type(res->l2_tunnel_type); entry.ether_type = res->eth_type_val; - FOREACH_PORT(pid, ports) { + RTE_ETH_FOREACH_DEV(pid) { rte_eth_dev_l2_tunnel_eth_type_conf(pid, &entry); } } @@ -10182,7 +10374,7 @@ cmd_config_l2_tunnel_eth_type_all_parsed 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 ether-type", + .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, @@ -10218,7 +10410,7 @@ cmd_config_l2_tunnel_eth_type_specific_parsed( 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 l2-tunnel ether-type", + .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, @@ -10290,7 +10482,7 @@ cmd_config_l2_tunnel_en_dis_all_parsed( else en = 0; - FOREACH_PORT(pid, ports) { + RTE_ETH_FOREACH_DEV(pid) { rte_eth_dev_l2_tunnel_offload_set(pid, &entry, ETH_L2_TUNNEL_ENABLE_MASK, @@ -10301,7 +10493,7 @@ cmd_config_l2_tunnel_en_dis_all_parsed( 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 enable/disable", + .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, @@ -10344,7 +10536,7 @@ cmd_config_l2_tunnel_en_dis_specific_parsed( 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 l2-tunnel enable/disable", + .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, @@ -10517,7 +10709,7 @@ cmd_config_e_tag_insertion_dis_parsed( cmdline_parse_inst_t cmd_config_e_tag_insertion_en = { .f = cmd_config_e_tag_insertion_en_parsed, .data = NULL, - .help_str = "E-tag insertion enable", + .help_str = "E-tag ... : E-tag insertion enable", .tokens = { (void *)&cmd_config_e_tag_e_tag, (void *)&cmd_config_e_tag_set, @@ -10536,7 +10728,7 @@ cmdline_parse_inst_t cmd_config_e_tag_insertion_en = { cmdline_parse_inst_t cmd_config_e_tag_insertion_dis = { .f = cmd_config_e_tag_insertion_dis_parsed, .data = NULL, - .help_str = "E-tag insertion disable", + .help_str = "E-tag ... : E-tag insertion disable", .tokens = { (void *)&cmd_config_e_tag_e_tag, (void *)&cmd_config_e_tag_set, @@ -10583,7 +10775,7 @@ cmd_config_e_tag_stripping_parsed( cmdline_parse_inst_t cmd_config_e_tag_stripping_en_dis = { .f = cmd_config_e_tag_stripping_parsed, .data = NULL, - .help_str = "E-tag stripping enable/disable", + .help_str = "E-tag ... : E-tag stripping enable/disable", .tokens = { (void *)&cmd_config_e_tag_e_tag, (void *)&cmd_config_e_tag_set, @@ -10627,7 +10819,7 @@ cmd_config_e_tag_forwarding_parsed( cmdline_parse_inst_t cmd_config_e_tag_forwarding_en_dis = { .f = cmd_config_e_tag_forwarding_parsed, .data = NULL, - .help_str = "E-tag forwarding enable/disable", + .help_str = "E-tag ... : E-tag forwarding enable/disable", .tokens = { (void *)&cmd_config_e_tag_e_tag, (void *)&cmd_config_e_tag_set, @@ -10682,7 +10874,7 @@ cmd_config_e_tag_filter_add_parsed( cmdline_parse_inst_t cmd_config_e_tag_filter_add = { .f = cmd_config_e_tag_filter_add_parsed, .data = NULL, - .help_str = "E-tag filter add", + .help_str = "E-tag ... : E-tag filter add", .tokens = { (void *)&cmd_config_e_tag_e_tag, (void *)&cmd_config_e_tag_set, @@ -10739,7 +10931,7 @@ cmd_config_e_tag_filter_del_parsed( cmdline_parse_inst_t cmd_config_e_tag_filter_del = { .f = cmd_config_e_tag_filter_del_parsed, .data = NULL, - .help_str = "E-tag filter delete", + .help_str = "E-tag ... : E-tag filter delete", .tokens = { (void *)&cmd_config_e_tag_e_tag, (void *)&cmd_config_e_tag_set, @@ -10752,7 +10944,6 @@ cmdline_parse_inst_t cmd_config_e_tag_filter_del = { NULL, }, }; -#ifdef RTE_LIBRTE_IXGBE_PMD /* vf vlan anti spoof configuration */ @@ -10804,14 +10995,24 @@ cmd_set_vf_vlan_anti_spoof_parsed( __attribute__((unused)) void *data) { struct cmd_vf_vlan_anti_spoof_result *res = parsed_result; - int ret = 0; - int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0; + 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; - ret = rte_pmd_ixgbe_set_vf_vlan_anti_spoof(res->port_id, res->vf_id, - is_on); +#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 + switch (ret) { case 0: break; @@ -10821,6 +11022,9 @@ cmd_set_vf_vlan_anti_spoof_parsed( 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)); } @@ -10829,7 +11033,7 @@ cmd_set_vf_vlan_anti_spoof_parsed( 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", + .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, @@ -10892,14 +11096,24 @@ cmd_set_vf_mac_anti_spoof_parsed( __attribute__((unused)) void *data) { struct cmd_vf_mac_anti_spoof_result *res = parsed_result; - int ret; - int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0; + 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; - ret = rte_pmd_ixgbe_set_vf_mac_anti_spoof(res->port_id, res->vf_id, - is_on); +#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 + switch (ret) { case 0: break; @@ -10909,6 +11123,9 @@ cmd_set_vf_mac_anti_spoof_parsed( 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)); } @@ -10917,7 +11134,7 @@ cmd_set_vf_mac_anti_spoof_parsed( 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", + .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, @@ -10980,13 +11197,24 @@ cmd_set_vf_vlan_stripq_parsed( __attribute__((unused)) void *data) { struct cmd_vf_vlan_stripq_result *res = parsed_result; - int ret = 0; - int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0; + 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; - ret = rte_pmd_ixgbe_set_vf_vlan_stripq(res->port_id, res->vf_id, is_on); +#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 + switch (ret) { case 0: break; @@ -10996,6 +11224,9 @@ cmd_set_vf_vlan_stripq_parsed( 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)); } @@ -11004,7 +11235,7 @@ cmd_set_vf_vlan_stripq_parsed( 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", + .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, @@ -11067,12 +11298,22 @@ cmd_set_vf_vlan_insert_parsed( __attribute__((unused)) void *data) { struct cmd_vf_vlan_insert_result *res = parsed_result; - int ret; + int ret = -ENOTSUP; if (port_id_is_invalid(res->port_id, ENABLED_WARN)) return; - ret = rte_pmd_ixgbe_set_vf_vlan_insert(res->port_id, res->vf_id, res->vlan_id); +#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 + switch (ret) { case 0: break; @@ -11082,6 +11323,9 @@ cmd_set_vf_vlan_insert_parsed( 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)); } @@ -11090,7 +11334,7 @@ cmd_set_vf_vlan_insert_parsed( 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", + .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, @@ -11143,13 +11387,22 @@ cmd_set_tx_loopback_parsed( __attribute__((unused)) void *data) { struct cmd_tx_loopback_result *res = parsed_result; - int ret; - int is_on = (strcmp(res->on_off, "on") == 0) ? 1 : 0; + 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; - ret = rte_pmd_ixgbe_set_tx_loopback(res->port_id, is_on); +#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 + switch (ret) { case 0: break; @@ -11159,6 +11412,9 @@ cmd_set_tx_loopback_parsed( 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)); } @@ -11167,7 +11423,7 @@ cmd_set_tx_loopback_parsed( 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", + .help_str = "set tx loopback <port_id> on|off", .tokens = { (void *)&cmd_tx_loopback_set, (void *)&cmd_tx_loopback_tx, @@ -11178,6 +11434,7 @@ cmdline_parse_inst_t cmd_set_tx_loopback = { }, }; +#ifdef RTE_LIBRTE_IXGBE_PMD /* all queues drop enable configuration */ /* Common result structure for all queues drop enable */ @@ -11239,6 +11496,9 @@ cmd_set_all_queues_drop_en_parsed( 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)); } @@ -11247,7 +11507,7 @@ cmd_set_all_queues_drop_en_parsed( 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", + .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, @@ -11334,7 +11594,7 @@ cmd_set_vf_split_drop_en_parsed( 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", + .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, @@ -11346,6 +11606,7 @@ cmdline_parse_inst_t cmd_set_vf_split_drop_en = { NULL, }, }; +#endif /* vf mac address configuration */ @@ -11397,13 +11658,22 @@ cmd_set_vf_mac_addr_parsed( __attribute__((unused)) void *data) { struct cmd_set_vf_mac_addr_result *res = parsed_result; - int ret; + int ret = -ENOTSUP; if (port_id_is_invalid(res->port_id, ENABLED_WARN)) return; - ret = rte_pmd_ixgbe_set_vf_mac_addr(res->port_id, res->vf_id, - &res->mac_addr); +#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 + switch (ret) { case 0: break; @@ -11413,6 +11683,9 @@ cmd_set_vf_mac_addr_parsed( 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)); } @@ -11421,7 +11694,7 @@ cmd_set_vf_mac_addr_parsed( 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 xx:xx:xx:xx:xx:xx", + .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, @@ -11433,8 +11706,1865 @@ cmdline_parse_inst_t cmd_set_vf_mac_addr = { NULL, }, }; + +#ifdef RTE_LIBRTE_IXGBE_PMD +/* 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; + uint8_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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_macsec_offload_on_result *res = parsed_result; + int ret; + 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; + + if (port_id_is_invalid(port_id, ENABLED_WARN)) + return; + + ports[port_id].tx_ol_flags |= TESTPMD_TX_OFFLOAD_MACSEC; + ret = rte_pmd_ixgbe_macsec_enable(port_id, en, rp); + + switch (ret) { + case 0: + break; + case -ENODEV: + printf("invalid port_id %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; + uint8_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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_macsec_offload_off_result *res = parsed_result; + int ret; + portid_t port_id = res->port_id; + + if (port_id_is_invalid(port_id, ENABLED_WARN)) + return; + + ports[port_id].tx_ol_flags &= ~TESTPMD_TX_OFFLOAD_MACSEC; + ret = rte_pmd_ixgbe_macsec_disable(port_id); + + switch (ret) { + case 0: + break; + case -ENODEV: + printf("invalid port_id %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; + uint8_t port_id; + struct 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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_macsec_sc_result *res = parsed_result; + int ret; + int is_tx = (strcmp(res->tx_rx, "tx") == 0) ? 1 : 0; + + 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); + switch (ret) { + case 0: + break; + case -ENODEV: + printf("invalid port_id %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; + uint8_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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_macsec_sa_result *res = parsed_result; + int ret; + 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); + } + + 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); + 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; + 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, + }, +}; +#endif + +/* 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; + uint8_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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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; + uint8_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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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; + uint8_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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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; + uint8_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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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; + uint8_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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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, + }, +}; + +/* Strict link priority scheduling mode setting */ +static void +cmd_strict_link_prio_parsed( + void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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; + uint8_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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_ddp_add_result *res = parsed_result; + uint8_t *buff; + uint32_t size; + int ret = -ENOTSUP; + + if (res->port_id > nb_ports) { + printf("Invalid port, range is [0, %d]\n", nb_ports - 1); + return; + } + + if (!all_ports_stopped()) { + printf("Please stop all ports first\n"); + return; + } + + buff = open_ddp_package_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_ADD); +#endif + + if (ret < 0) + printf("Failed to load profile.\n"); + else if (ret > 0) + printf("Profile has already existed.\n"); + + close_ddp_package_file(buff); +} + +cmdline_parse_inst_t cmd_ddp_add = { + .f = cmd_ddp_add_parsed, + .data = NULL, + .help_str = "ddp add <port_id> <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, + }, +}; + +/* 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; + uint8_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, UINT8); + +static void +cmd_ddp_get_list_parsed( + void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_ddp_get_list_result *res = parsed_result; +#ifdef RTE_LIBRTE_I40E_PMD + 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; + + if (res->port_id > nb_ports) { + printf("Invalid port, range is [0, %d]\n", nb_ports - 1); + return; + } + +#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__); + + 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, + }, +}; + +/* 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; + uint8_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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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 + ret = rte_pmd_i40e_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; + uint8_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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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 + ret = rte_pmd_i40e_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, + }, +}; + +/* 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; + uint8_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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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; + uint8_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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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; + uint8_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, UINT8); + +static void +cmd_ptype_mapping_reset_parsed( + void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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; + uint8_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, UINT8); +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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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, + __attribute__((unused)) struct cmdline *cl, + __attribute__((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, + }, +}; + /* ******************************************************************************** */ /* list of instructions */ @@ -11442,6 +13572,7 @@ 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, @@ -11537,15 +13668,11 @@ cmdline_parse_ctx_t main_ctx[] = { (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_vf_rxmode, (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_set_vf_traffic, - (cmdline_parse_inst_t *)&cmd_vf_rxvlan_filter, (cmdline_parse_inst_t *)&cmd_queue_rate_limit, - (cmdline_parse_inst_t *)&cmd_vf_rate_limit, (cmdline_parse_inst_t *)&cmd_tunnel_filter, (cmdline_parse_inst_t *)&cmd_tunnel_udp_config, (cmdline_parse_inst_t *)&cmd_global_config, @@ -11580,6 +13707,7 @@ cmdline_parse_ctx_t main_ctx[] = { (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_mcast_addr, (cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_all, (cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_specific, @@ -11591,19 +13719,65 @@ cmdline_parse_ctx_t main_ctx[] = { (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, -#ifdef RTE_LIBRTE_IXGBE_PMD (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, +#ifdef RTE_LIBRTE_IXGBE_PMD (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_vf_mac_addr, + (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_rxmode, + (cmdline_parse_inst_t *)&cmd_set_vf_traffic, + (cmdline_parse_inst_t *)&cmd_vf_rate_limit, #endif + (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, + (cmdline_parse_inst_t *)&cmd_ddp_add, + (cmdline_parse_inst_t *)&cmd_ddp_get_list, + (cmdline_parse_inst_t *)&cmd_show_vf_stats, + (cmdline_parse_inst_t *)&cmd_clear_vf_stats, + (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, 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) @@ -11632,7 +13806,7 @@ cmd_reconfig_device_queue(portid_t id, uint8_t dev, uint8_t queue) if (id == (portid_t)RTE_PORT_ALL) { portid_t pid; - FOREACH_PORT(pid, ports) { + 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; diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c new file mode 100644 index 00000000..0fd69f90 --- /dev/null +++ b/app/test-pmd/cmdline_flow.c @@ -0,0 +1,2812 @@ +/*- + * BSD LICENSE + * + * Copyright 2016 6WIND S.A. + * Copyright 2016 Mellanox. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of 6WIND S.A. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <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_common.h> +#include <rte_ethdev.h> +#include <rte_byteorder.h> +#include <cmdline_parse.h> +#include <cmdline_parse_etheraddr.h> +#include <rte_flow.h> + +#include "testpmd.h" + +/** Parser token indices. */ +enum index { + /* Special tokens. */ + ZERO = 0, + END, + + /* Common tokens. */ + INTEGER, + UNSIGNED, + PREFIX, + BOOLEAN, + STRING, + MAC_ADDR, + IPV4_ADDR, + IPV6_ADDR, + RULE_ID, + PORT_ID, + GROUP_ID, + PRIORITY_LEVEL, + + /* Top-level command. */ + FLOW, + + /* Sub-level commands. */ + VALIDATE, + CREATE, + DESTROY, + FLUSH, + QUERY, + LIST, + + /* Destroy arguments. */ + DESTROY_RULE, + + /* Query arguments. */ + QUERY_ACTION, + + /* List arguments. */ + LIST_GROUP, + + /* Validate/create arguments. */ + GROUP, + PRIORITY, + INGRESS, + EGRESS, + + /* 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_PORT, + ITEM_PORT_INDEX, + 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_TPID, + ITEM_VLAN_TCI, + ITEM_VLAN_PCP, + ITEM_VLAN_DEI, + ITEM_VLAN_VID, + 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_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_GRE, + ITEM_GRE_PROTO, + + /* Validate/create actions. */ + ACTIONS, + ACTION_NEXT, + ACTION_END, + ACTION_VOID, + ACTION_PASSTHRU, + ACTION_MARK, + ACTION_MARK_ID, + ACTION_FLAG, + ACTION_QUEUE, + ACTION_QUEUE_INDEX, + ACTION_DROP, + ACTION_COUNT, + ACTION_DUP, + ACTION_DUP_INDEX, + ACTION_RSS, + ACTION_RSS_QUEUES, + ACTION_RSS_QUEUE, + ACTION_PF, + ACTION_VF, + ACTION_VF_ORIGINAL, + ACTION_VF_ID, +}; + +/** Size of pattern[] field in struct rte_flow_item_raw. */ +#define ITEM_RAW_PATTERN_SIZE 36 + +/** Storage size for struct rte_flow_item_raw including pattern. */ +#define ITEM_RAW_SIZE \ + (offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE) + +/** Number of queue[] entries in struct rte_flow_action_rss. */ +#define ACTION_RSS_NUM 32 + +/** Storage size for struct rte_flow_action_rss including queues. */ +#define ACTION_RSS_SIZE \ + (offsetof(struct rte_flow_action_rss, queue) + \ + sizeof(*((struct rte_flow_action_rss *)0)->queue) * ACTION_RSS_NUM) + +/** 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 reparse:1; /**< Start over from the beginning. */ + uint32_t eol:1; /**< EOL has been detected. */ + uint32_t last:1; /**< No more arguments. */ + uint16_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 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 size. */ +#define ARGS_ENTRY_USZ(s, f, sz) \ + (&(const struct arg){ \ + .offset = offsetof(s, f), \ + .size = (sz), \ + }) + +/** 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), \ + }) + +/** Parser output buffer layout expected by cmd_flow_parsed(). */ +struct buffer { + enum index command; /**< Flow command. */ + uint16_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 { + uint32_t rule; + enum rte_flow_action_type action; + } query; /**< Query arguments. */ + struct { + uint32_t *group; + uint32_t group_n; + } list; /**< List 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, + PATTERN, + ZERO, +}; + +static const enum index next_destroy_attr[] = { + DESTROY_RULE, + END, + ZERO, +}; + +static const enum index next_list_attr[] = { + LIST_GROUP, + 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_PORT, + 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, + 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_port[] = { + ITEM_PORT_INDEX, + 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_TPID, + ITEM_VLAN_TCI, + ITEM_VLAN_PCP, + ITEM_VLAN_DEI, + ITEM_VLAN_VID, + 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_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_NEXT, + ZERO, +}; + +static const enum index item_gre[] = { + ITEM_GRE_PROTO, + ITEM_NEXT, + ZERO, +}; + +static const enum index next_action[] = { + ACTION_END, + ACTION_VOID, + ACTION_PASSTHRU, + ACTION_MARK, + ACTION_FLAG, + ACTION_QUEUE, + ACTION_DROP, + ACTION_COUNT, + ACTION_DUP, + ACTION_RSS, + ACTION_PF, + ACTION_VF, + 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_dup[] = { + ACTION_DUP_INDEX, + ACTION_NEXT, + ZERO, +}; + +static const enum index action_rss[] = { + ACTION_RSS_QUEUES, + ACTION_NEXT, + ZERO, +}; + +static const enum index action_vf[] = { + ACTION_VF_ORIGINAL, + ACTION_VF_ID, + ACTION_NEXT, + ZERO, +}; + +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_queue(struct context *, const struct token *, + const char *, unsigned int, void *, + unsigned int); +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_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_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_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_queue(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", + }, + /* 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, + }, + [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, + LIST, + QUERY)), + .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, + }, + [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), + 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, + }, + /* 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, + }, + /* 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, + }, + /* 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 packets addressed to the physical function", + .priv = PRIV_ITEM(PF, 0), + .next = NEXT(NEXT_ENTRY(ITEM_NEXT)), + .call = parse_vc, + }, + [ITEM_VF] = { + .name = "vf", + .help = "match packets addressed 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 = "destination VF ID", + .next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_vf, id)), + }, + [ITEM_PORT] = { + .name = "port", + .help = "device-specific physical port index to use", + .priv = PRIV_ITEM(PORT, sizeof(struct rte_flow_item_port)), + .next = NEXT(item_port), + .call = parse_vc, + }, + [ITEM_PORT_INDEX] = { + .name = "index", + .help = "physical port index", + .next = NEXT(item_port, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port, index)), + }, + [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, length), + ARGS_ENTRY_USZ(struct rte_flow_item_raw, + pattern, + 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_TPID] = { + .name = "tpid", + .help = "tag protocol identifier", + .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tpid)), + }, + [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_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_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_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)), + }, + /* 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_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, 0), + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc, + }, + [ACTION_DUP] = { + .name = "dup", + .help = "duplicate packets to a given queue index", + .priv = PRIV_ACTION(DUP, sizeof(struct rte_flow_action_dup)), + .next = NEXT(action_dup), + .call = parse_vc, + }, + [ACTION_DUP_INDEX] = { + .name = "index", + .help = "queue index to duplicate packets to", + .next = NEXT(action_dup, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_dup, index)), + .call = parse_vc_conf, + }, + [ACTION_RSS] = { + .name = "rss", + .help = "spread packets among several queues", + .priv = PRIV_ACTION(RSS, ACTION_RSS_SIZE), + .next = NEXT(action_rss), + .call = parse_vc, + }, + [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 = "redirect packets to physical device function", + .priv = PRIV_ACTION(PF, 0), + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc, + }, + [ACTION_VF] = { + .name = "vf", + .help = "redirect packets to virtual device function", + .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 to redirect packets to", + .next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)), + .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; +} + +/** + * 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 (strncmp(str, token->name, 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 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, + }; + ++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; + struct rte_flow_action *action; + + (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; + 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; + /* Update configuration pointer. */ + action->conf = ctx->object; + 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); + int ret; + int i; + + (void)token; + (void)buf; + (void)size; + if (ctx->curr != ACTION_RSS_QUEUE) + return -1; + i = ctx->objdata >> 16; + if (!strncmp(str, "end", len)) { + ctx->objdata &= 0xffff; + return len; + } + if (i >= ACTION_RSS_NUM) + return -1; + if (push_args(ctx, ARGS_ENTRY(struct rte_flow_action_rss, queue[i]))) + 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; + if (!ctx->object) + return len; + ((struct rte_flow_action_rss *)ctx->object)->num = i; + 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 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 (strncmp(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 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 (!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; +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. + * + * Two arguments (ctx->args) are retrieved from the stack to store data and + * its length (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); + 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; + } + 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, 0x55, size - len); + if (ctx->objmask) + memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len); + return len; +error: + push_args(ctx, arg_len); + 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 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", + 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 (!strncmp(str, boolean_name[i], 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; +} + +/** 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 snprintf(buf, size, "%s", boolean_name[i]); + 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 snprintf(buf, size, "%s", + token_list[next_action[i]].name); + 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 == (uint16_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 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) +{ + static const char *const str[] = { "", "end", NULL }; + unsigned int i; + + (void)ctx; + (void)token; + for (i = 0; str[i] != NULL; ++i) + if (buf && i == ent) + return snprintf(buf, size, "%s", str[i]); + if (buf) + return -1; + return i; +} + +/** Internal context. */ +static struct context cmd_flow_context; + +/** Global parser instance (cmdline API). */ +cmdline_parse_inst_t cmd_flow; + +/** 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->reparse = 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; + /* Restart as requested. */ + if (ctx->reparse) + cmd_flow_context_init(ctx); + 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; + /* Tell cmd_flow_parse() that context must be reinitialized. */ + ctx->reparse = 1; + /* 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; + /* Tell cmd_flow_parse() that context must be reinitialized. */ + ctx->reparse = 1; + /* 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]]; + snprintf(dst, size, "%s", token->name); + /* 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; + /* Tell cmd_flow_parse() that context must be reinitialized. */ + ctx->reparse = 1; + 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_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 *(*hdrs)[]) +{ + struct context *ctx = &cmd_flow_context; + + /* Always reinitialize context before requesting the first token. */ + if (!(hdr - *hdrs)) + 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 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; + 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(). */ +}; diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index 36c47ab5..4d873cdd 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -92,6 +92,11 @@ #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 #include "testpmd.h" @@ -169,7 +174,7 @@ nic_stats_display(portid_t port_id) if (port_id_is_invalid(port_id, ENABLED_WARN)) { printf("Valid port range is [0"); - FOREACH_PORT(pid, ports) + RTE_ETH_FOREACH_DEV(pid) printf(", %d", pid); printf("]\n"); return; @@ -247,7 +252,7 @@ nic_stats_clear(portid_t port_id) if (port_id_is_invalid(port_id, ENABLED_WARN)) { printf("Valid port range is [0"); - FOREACH_PORT(pid, ports) + RTE_ETH_FOREACH_DEV(pid) printf(", %d", pid); printf("]\n"); return; @@ -329,7 +334,7 @@ nic_stats_mapping_display(portid_t port_id) if (port_id_is_invalid(port_id, ENABLED_WARN)) { printf("Valid port range is [0"); - FOREACH_PORT(pid, ports) + RTE_ETH_FOREACH_DEV(pid) printf(", %d", pid); printf("]\n"); return; @@ -444,20 +449,24 @@ port_infos_display(portid_t port_id) struct rte_mempool * mp; static const char *info_border = "*********************"; portid_t pid; + uint16_t mtu; if (port_id_is_invalid(port_id, ENABLED_WARN)) { printf("Valid port range is [0"); - FOREACH_PORT(pid, ports) + RTE_ETH_FOREACH_DEV(pid) printf(", %d", pid); printf("]\n"); return; } port = &ports[port_id]; rte_eth_link_get_nowait(port_id, &link); + memset(&dev_info, 0, sizeof(dev_info)); + rte_eth_dev_info_get(port_id, &dev_info); printf("\n%s Infos for port %-2d %s\n", info_border, port_id, info_border); rte_eth_macaddr_get(port_id, &mac_addr); print_ethaddr("MAC address: ", &mac_addr); + printf("\nDriver name: %s", dev_info.driver_name); printf("\nConnect to socket: %u", port->socket_id); if (port_numa[port_id] != NUMA_NO_CONFIG) { @@ -472,6 +481,10 @@ port_infos_display(portid_t port_id) 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", @@ -500,8 +513,6 @@ port_infos_display(portid_t port_id) printf(" qinq(extend) off \n"); } - memset(&dev_info, 0, sizeof(dev_info)); - rte_eth_dev_info_get(port_id, &dev_info); 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) @@ -537,13 +548,189 @@ port_infos_display(portid_t port_id) printf("TXDs number alignment: %hu\n", dev_info.tx_desc_lim.nb_align); } +void +port_offload_cap_display(portid_t port_id) +{ + struct rte_eth_dev *dev; + struct rte_eth_dev_info dev_info; + static const char *info_border = "************"; + + if (port_id_is_invalid(port_id, ENABLED_WARN)) + return; + + dev = &rte_eth_devices[port_id]; + rte_eth_dev_info_get(port_id, &dev_info); + + 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 (dev->data->dev_conf.rxmode.hw_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 (dev->data->dev_conf.rxmode.hw_vlan_extend) + printf("on\n"); + else + printf("off\n"); + } + + if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_IPV4_CKSUM) { + printf("RX IPv4 checksum: "); + if (dev->data->dev_conf.rxmode.hw_ip_checksum) + printf("on\n"); + else + printf("off\n"); + } + + if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_UDP_CKSUM) { + printf("RX UDP checksum: "); + if (dev->data->dev_conf.rxmode.hw_ip_checksum) + printf("on\n"); + else + printf("off\n"); + } + + if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_TCP_CKSUM) { + printf("RX TCP checksum: "); + if (dev->data->dev_conf.rxmode.hw_ip_checksum) + printf("on\n"); + else + printf("off\n"); + } + + if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM) + printf("RX Outer IPv4 checksum: on"); + + if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_TCP_LRO) { + printf("Large receive offload: "); + if (dev->data->dev_conf.rxmode.enable_lro) + 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].tx_ol_flags & + TESTPMD_TX_OFFLOAD_INSERT_VLAN) + 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].tx_ol_flags & + TESTPMD_TX_OFFLOAD_INSERT_QINQ) + 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].tx_ol_flags & TESTPMD_TX_OFFLOAD_IP_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].tx_ol_flags & TESTPMD_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].tx_ol_flags & TESTPMD_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].tx_ol_flags & TESTPMD_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].tx_ol_flags & + TESTPMD_TX_OFFLOAD_OUTER_IP_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].tso_segsz != 0) + 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].tso_segsz != 0) + 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].tunnel_tso_segsz) + 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].tunnel_tso_segsz) + 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].tunnel_tso_segsz) + 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].tunnel_tso_segsz) + printf("on\n"); + else + printf("off\n"); + } + +} + int port_id_is_invalid(portid_t port_id, enum print_warning warning) { if (port_id == (portid_t)RTE_PORT_ALL) return 0; - if (port_id < RTE_MAX_ETHPORTS && ports[port_id].enabled) + if (rte_eth_dev_is_valid_port(port_id)) return 0; if (warning == ENABLED_WARN) @@ -750,6 +937,504 @@ port_mtu_set(portid_t port_id, uint16_t mtu) printf("Set MTU failed. diag=%d\n", diag); } +/* Generic flow management functions. */ + +/** Generate flow_item[] entry. */ +#define MK_FLOW_ITEM(t, s) \ + [RTE_FLOW_ITEM_TYPE_ ## t] = { \ + .name = # t, \ + .size = s, \ + } + +/** Information about known flow pattern items. */ +static const struct { + const char *name; + size_t size; +} flow_item[] = { + MK_FLOW_ITEM(END, 0), + MK_FLOW_ITEM(VOID, 0), + MK_FLOW_ITEM(INVERT, 0), + MK_FLOW_ITEM(ANY, sizeof(struct rte_flow_item_any)), + MK_FLOW_ITEM(PF, 0), + MK_FLOW_ITEM(VF, sizeof(struct rte_flow_item_vf)), + MK_FLOW_ITEM(PORT, sizeof(struct rte_flow_item_port)), + MK_FLOW_ITEM(RAW, sizeof(struct rte_flow_item_raw)), /* +pattern[] */ + MK_FLOW_ITEM(ETH, sizeof(struct rte_flow_item_eth)), + MK_FLOW_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)), + MK_FLOW_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)), + MK_FLOW_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)), + MK_FLOW_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)), + MK_FLOW_ITEM(UDP, sizeof(struct rte_flow_item_udp)), + MK_FLOW_ITEM(TCP, sizeof(struct rte_flow_item_tcp)), + MK_FLOW_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)), + MK_FLOW_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)), + MK_FLOW_ITEM(MPLS, sizeof(struct rte_flow_item_mpls)), + MK_FLOW_ITEM(GRE, sizeof(struct rte_flow_item_gre)), +}; + +/** Compute storage space needed by item specification. */ +static void +flow_item_spec_size(const struct rte_flow_item *item, + size_t *size, size_t *pad) +{ + if (!item->spec) + goto empty; + switch (item->type) { + union { + const struct rte_flow_item_raw *raw; + } spec; + + case RTE_FLOW_ITEM_TYPE_RAW: + spec.raw = item->spec; + *size = offsetof(struct rte_flow_item_raw, pattern) + + spec.raw->length * sizeof(*spec.raw->pattern); + break; + default: +empty: + *size = 0; + break; + } + *pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size; +} + +/** Generate flow_action[] entry. */ +#define MK_FLOW_ACTION(t, s) \ + [RTE_FLOW_ACTION_TYPE_ ## t] = { \ + .name = # t, \ + .size = s, \ + } + +/** Information about known flow actions. */ +static const struct { + const char *name; + size_t size; +} flow_action[] = { + MK_FLOW_ACTION(END, 0), + MK_FLOW_ACTION(VOID, 0), + MK_FLOW_ACTION(PASSTHRU, 0), + MK_FLOW_ACTION(MARK, sizeof(struct rte_flow_action_mark)), + MK_FLOW_ACTION(FLAG, 0), + MK_FLOW_ACTION(QUEUE, sizeof(struct rte_flow_action_queue)), + MK_FLOW_ACTION(DROP, 0), + MK_FLOW_ACTION(COUNT, 0), + MK_FLOW_ACTION(DUP, sizeof(struct rte_flow_action_dup)), + MK_FLOW_ACTION(RSS, sizeof(struct rte_flow_action_rss)), /* +queue[] */ + MK_FLOW_ACTION(PF, 0), + MK_FLOW_ACTION(VF, sizeof(struct rte_flow_action_vf)), +}; + +/** Compute storage space needed by action configuration. */ +static void +flow_action_conf_size(const struct rte_flow_action *action, + size_t *size, size_t *pad) +{ + if (!action->conf) + goto empty; + switch (action->type) { + union { + const struct rte_flow_action_rss *rss; + } conf; + + case RTE_FLOW_ACTION_TYPE_RSS: + conf.rss = action->conf; + *size = offsetof(struct rte_flow_action_rss, queue) + + conf.rss->num * sizeof(*conf.rss->queue); + break; + default: +empty: + *size = 0; + break; + } + *pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size; +} + +/** 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) +{ + const struct rte_flow_item *item; + const struct rte_flow_action *action; + struct port_flow *pf = NULL; + size_t tmp; + size_t pad; + size_t off1 = 0; + size_t off2 = 0; + int err = ENOTSUP; + +store: + item = pattern; + if (pf) + pf->pattern = (void *)&pf->data[off1]; + do { + struct rte_flow_item *dst = NULL; + + if ((unsigned int)item->type >= RTE_DIM(flow_item) || + !flow_item[item->type].name) + goto notsup; + if (pf) + dst = memcpy(pf->data + off1, item, sizeof(*item)); + off1 += sizeof(*item); + flow_item_spec_size(item, &tmp, &pad); + if (item->spec) { + if (pf) + dst->spec = memcpy(pf->data + off2, + item->spec, tmp); + off2 += tmp + pad; + } + if (item->last) { + if (pf) + dst->last = memcpy(pf->data + off2, + item->last, tmp); + off2 += tmp + pad; + } + if (item->mask) { + if (pf) + dst->mask = memcpy(pf->data + off2, + item->mask, tmp); + off2 += tmp + pad; + } + off2 = RTE_ALIGN_CEIL(off2, sizeof(double)); + } while ((item++)->type != RTE_FLOW_ITEM_TYPE_END); + off1 = RTE_ALIGN_CEIL(off1, sizeof(double)); + action = actions; + if (pf) + pf->actions = (void *)&pf->data[off1]; + do { + struct rte_flow_action *dst = NULL; + + if ((unsigned int)action->type >= RTE_DIM(flow_action) || + !flow_action[action->type].name) + goto notsup; + if (pf) + dst = memcpy(pf->data + off1, action, sizeof(*action)); + off1 += sizeof(*action); + flow_action_conf_size(action, &tmp, &pad); + if (action->conf) { + if (pf) + dst->conf = memcpy(pf->data + off2, + action->conf, tmp); + off2 += tmp + pad; + } + off2 = RTE_ALIGN_CEIL(off2, sizeof(double)); + } while ((action++)->type != RTE_FLOW_ACTION_TYPE_END); + if (pf != NULL) + return pf; + off1 = RTE_ALIGN_CEIL(off1, sizeof(double)); + tmp = RTE_ALIGN_CEIL(offsetof(struct port_flow, data), sizeof(double)); + pf = calloc(1, tmp + off1 + off2); + if (pf == NULL) + err = errno; + else { + *pf = (const struct port_flow){ + .size = tmp + off1 + off2, + .attr = *attr, + }; + tmp -= offsetof(struct port_flow, data); + off2 = tmp + off1; + off1 = tmp; + goto store; + } +notsup: + rte_errno = err; + 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] = "attributes structure", + [RTE_FLOW_ERROR_TYPE_ITEM_NUM] = "pattern length", + [RTE_FLOW_ERROR_TYPE_ITEM] = "specific pattern item", + [RTE_FLOW_ERROR_TYPE_ACTION_NUM] = "number of actions", + [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("Caught error type %d (%s): %s%s\n", + error->type, errstr, + error->cause ? (snprintf(buf, sizeof(buf), "cause: %p, ", + error->cause), buf) : "", + error->message ? error->message : "(no stated reason)"); + 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; +} + +/** 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; + struct rte_flow_error error; + + /* 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) + return port_flow_complain(&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"); + rte_flow_destroy(port_id, flow, NULL); + return -ENOMEM; + } + id = port->flow_list->id + 1; + } else + id = 0; + pf = port_flow_new(attr, pattern, actions); + if (!pf) { + int err = rte_errno; + + printf("Cannot allocate flow: %s\n", rte_strerror(err)); + rte_flow_destroy(port_id, flow, NULL); + return -err; + } + 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; +} + +/** Query a flow rule. */ +int +port_flow_query(portid_t port_id, uint32_t rule, + enum rte_flow_action_type 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; + + 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; + } + if ((unsigned int)action >= RTE_DIM(flow_action) || + !flow_action[action].name) + name = "unknown"; + else + name = flow_action[action].name; + switch (action) { + case RTE_FLOW_ACTION_TYPE_COUNT: + break; + default: + printf("Cannot query action type %d (%s)\n", action, 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) { + 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, name); + break; + } + return 0; +} + +/** 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; + + if (n) { + /* Filter out unwanted groups. */ + for (i = 0; i != n; ++i) + if (pf->attr.group == group[i]) + break; + if (i == n) + continue; + } + tmp = &list; + while (*tmp && + (pf->attr.group > (*tmp)->attr.group || + (pf->attr.group == (*tmp)->attr.group && + pf->attr.priority > (*tmp)->attr.priority) || + (pf->attr.group == (*tmp)->attr.group && + pf->attr.priority == (*tmp)->attr.priority && + pf->id > (*tmp)->id))) + tmp = &(*tmp)->tmp; + 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->pattern; + const struct rte_flow_action *action = pf->actions; + + printf("%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 "\t%c%c\t", + pf->id, + pf->attr.group, + pf->attr.priority, + pf->attr.ingress ? 'i' : '-', + pf->attr.egress ? 'e' : '-'); + while (item->type != RTE_FLOW_ITEM_TYPE_END) { + if (item->type != RTE_FLOW_ITEM_TYPE_VOID) + printf("%s ", flow_item[item->type].name); + ++item; + } + printf("=>"); + while (action->type != RTE_FLOW_ACTION_TYPE_END) { + if (action->type != RTE_FLOW_ACTION_TYPE_VOID) + printf(" %s", flow_action[action->type].name); + ++action; + } + printf("\n"); + } +} + /* * RX/TX ring descriptors display functions. */ @@ -1601,7 +2286,7 @@ set_fwd_ports_mask(uint64_t portmask) return; } nb_pt = 0; - for (i = 0; i < (unsigned)RTE_MIN(64, RTE_MAX_ETHPORTS); i++) { + RTE_ETH_FOREACH_DEV(i) { if (! ((uint64_t)(1ULL << i) & portmask)) continue; portlist[nb_pt++] = i; @@ -2323,43 +3008,28 @@ fdir_set_flex_payload(portid_t port_id, struct rte_eth_flex_payload_cfg *cfg) } +#ifdef RTE_LIBRTE_IXGBE_PMD void set_vf_traffic(portid_t port_id, uint8_t is_rx, uint16_t vf, uint8_t on) { int diag; - if (port_id_is_invalid(port_id, ENABLED_WARN)) - return; if (is_rx) - diag = rte_eth_dev_set_vf_rx(port_id,vf,on); + diag = rte_pmd_ixgbe_set_vf_rx(port_id, vf, on); else - diag = rte_eth_dev_set_vf_tx(port_id,vf,on); + diag = rte_pmd_ixgbe_set_vf_tx(port_id, vf, on); + if (diag == 0) return; if(is_rx) - printf("rte_eth_dev_set_vf_rx for port_id=%d failed " + printf("rte_pmd_ixgbe_set_vf_rx for port_id=%d failed " "diag=%d\n", port_id, diag); else - printf("rte_eth_dev_set_vf_tx for port_id=%d failed " + printf("rte_pmd_ixgbe_set_vf_tx for port_id=%d failed " "diag=%d\n", port_id, diag); } - -void -set_vf_rx_vlan(portid_t port_id, uint16_t vlan_id, uint64_t vf_mask, uint8_t on) -{ - int diag; - - if (port_id_is_invalid(port_id, ENABLED_WARN)) - return; - if (vlan_id_is_invalid(vlan_id)) - return; - diag = rte_eth_dev_set_vf_vlan_filter(port_id, vlan_id, vf_mask, on); - if (diag == 0) - return; - printf("rte_eth_dev_set_vf_vlan_filter for port_id=%d failed " - "diag=%d\n", port_id, diag); -} +#endif int set_queue_rate_limit(portid_t port_id, uint16_t queue_idx, uint16_t rate) @@ -2383,30 +3053,20 @@ set_queue_rate_limit(portid_t port_id, uint16_t queue_idx, uint16_t rate) return diag; } +#ifdef RTE_LIBRTE_IXGBE_PMD int set_vf_rate_limit(portid_t port_id, uint16_t vf, uint16_t rate, uint64_t q_msk) { int diag; - struct rte_eth_link link; - - if (q_msk == 0) - return 0; - if (port_id_is_invalid(port_id, ENABLED_WARN)) - return 1; - rte_eth_link_get_nowait(port_id, &link); - 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_vf_rate_limit(port_id, vf, rate, q_msk); + diag = rte_pmd_ixgbe_set_vf_rate_limit(port_id, vf, rate, q_msk); if (diag == 0) return diag; - printf("rte_eth_set_vf_rate_limit for port_id=%d failed diag=%d\n", + printf("rte_pmd_ixgbe_set_vf_rate_limit for port_id=%d failed diag=%d\n", port_id, diag); return diag; } +#endif /* * Functions to manage the set of filtered Multicast MAC addresses. @@ -2592,3 +3252,70 @@ port_dcb_info_display(uint8_t port_id) printf("\t%4d", dcb_info.tc_queue.tc_txq[0][i].nb_queue); printf("\n"); } + +uint8_t * +open_ddp_package_file(const char *file_path, uint32_t *size) +{ + FILE *fh = fopen(file_path, "rb"); + uint32_t pkg_size; + uint8_t *buf = NULL; + int ret = 0; + + if (size) + *size = 0; + + if (fh == NULL) { + printf("%s: Failed to open %s\n", __func__, file_path); + return buf; + } + + ret = fseek(fh, 0, SEEK_END); + if (ret < 0) { + fclose(fh); + printf("%s: File operations failed\n", __func__); + return buf; + } + + pkg_size = ftell(fh); + + buf = (uint8_t *)malloc(pkg_size); + if (!buf) { + fclose(fh); + printf("%s: Failed to malloc memory\n", __func__); + return buf; + } + + ret = fseek(fh, 0, SEEK_SET); + if (ret < 0) { + fclose(fh); + printf("%s: File seek operation failed\n", __func__); + close_ddp_package_file(buf); + return NULL; + } + + ret = fread(buf, 1, pkg_size, fh); + if (ret < 0) { + fclose(fh); + printf("%s: File read operation failed\n", __func__); + close_ddp_package_file(buf); + return NULL; + } + + if (size) + *size = pkg_size; + + fclose(fh); + + return buf; +} + +int +close_ddp_package_file(uint8_t *buf) +{ + if (buf) { + free((void *)buf); + return 0; + } + + return -1; +} diff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c index 57e6ae27..66fc9a00 100644 --- a/app/test-pmd/csumonly.c +++ b/app/test-pmd/csumonly.c @@ -70,6 +70,7 @@ #include <rte_sctp.h> #include <rte_prefetch.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h" #define IP_DEFTTL 64 /* from RFC 1340. */ @@ -112,15 +113,6 @@ struct simple_gre_hdr { } __attribute__((__packed__)); static uint16_t -get_psd_sum(void *l3_hdr, uint16_t ethertype, uint64_t ol_flags) -{ - if (ethertype == _htons(ETHER_TYPE_IPv4)) - return rte_ipv4_phdr_cksum(l3_hdr, ol_flags); - else /* assume ethertype == ETHER_TYPE_IPv6 */ - return rte_ipv6_phdr_cksum(l3_hdr, ol_flags); -} - -static uint16_t get_udptcp_checksum(void *l3_hdr, void *l4_hdr, uint16_t ethertype) { if (ethertype == _htons(ETHER_TYPE_IPv4)) @@ -370,11 +362,9 @@ process_inner_cksums(void *l3_hdr, const struct testpmd_offload_info *info, /* do not recalculate udp cksum if it was 0 */ if (udp_hdr->dgram_cksum != 0) { udp_hdr->dgram_cksum = 0; - if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_UDP_CKSUM) { + if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_UDP_CKSUM) ol_flags |= PKT_TX_UDP_CKSUM; - udp_hdr->dgram_cksum = get_psd_sum(l3_hdr, - info->ethertype, ol_flags); - } else { + else { udp_hdr->dgram_cksum = get_udptcp_checksum(l3_hdr, udp_hdr, info->ethertype); @@ -383,15 +373,11 @@ process_inner_cksums(void *l3_hdr, const struct testpmd_offload_info *info, } else if (info->l4_proto == IPPROTO_TCP) { tcp_hdr = (struct tcp_hdr *)((char *)l3_hdr + info->l3_len); tcp_hdr->cksum = 0; - if (tso_segsz) { + if (tso_segsz) ol_flags |= PKT_TX_TCP_SEG; - tcp_hdr->cksum = get_psd_sum(l3_hdr, info->ethertype, - ol_flags); - } else if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_TCP_CKSUM) { + else if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_TCP_CKSUM) ol_flags |= PKT_TX_TCP_CKSUM; - tcp_hdr->cksum = get_psd_sum(l3_hdr, info->ethertype, - ol_flags); - } else { + else { tcp_hdr->cksum = get_udptcp_checksum(l3_hdr, tcp_hdr, info->ethertype); @@ -431,7 +417,7 @@ process_outer_cksums(void *outer_l3_hdr, struct testpmd_offload_info *info, ol_flags |= PKT_TX_OUTER_IP_CKSUM; else ipv4_hdr->hdr_checksum = rte_ipv4_cksum(ipv4_hdr); - } else if (testpmd_ol_flags & TESTPMD_TX_OFFLOAD_OUTER_IP_CKSUM) + } else ol_flags |= PKT_TX_OUTER_IPV6; if (info->outer_l4_proto != IPPROTO_UDP) @@ -597,7 +583,7 @@ pkt_copy_split(const struct rte_mbuf *pkt) rc = mbuf_copy_split(pkt, md, seglen, nb_seg); if (rc < 0) RTE_LOG(ERR, USER1, - "mbuf_copy_split for %p(len=%u, nb_seg=%hhu) " + "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); @@ -648,6 +634,7 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) void *l3_hdr = NULL, *outer_l3_hdr = NULL; /* can be IPv4 or IPv6 */ uint16_t nb_rx; uint16_t nb_tx; + uint16_t nb_prep; uint16_t i; uint64_t rx_ol_flags, tx_ol_flags; uint16_t testpmd_ol_flags; @@ -769,7 +756,9 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) if (info.is_tunnel == 1) { if (info.tunnel_tso_segsz || - testpmd_ol_flags & TESTPMD_TX_OFFLOAD_OUTER_IP_CKSUM) { + (testpmd_ol_flags & + TESTPMD_TX_OFFLOAD_OUTER_IP_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; @@ -814,7 +803,7 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) char buf[256]; printf("-----------------\n"); - printf("port=%u, mbuf=%p, pkt_len=%u, nb_segs=%hhu:\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)); @@ -839,8 +828,9 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) "m->l4_len=%d\n", m->l2_len, m->l3_len, m->l4_len); if (info.is_tunnel == 1) { - if (testpmd_ol_flags & - TESTPMD_TX_OFFLOAD_OUTER_IP_CKSUM) + if ((testpmd_ol_flags & + TESTPMD_TX_OFFLOAD_OUTER_IP_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, @@ -857,7 +847,16 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) printf("\n"); } } - nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_rx); + + nb_prep = rte_eth_tx_prepare(fs->tx_port, fs->tx_queue, + 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, pkts_burst, + nb_prep); + /* * Retry if necessary */ diff --git a/app/test-pmd/flowgen.c b/app/test-pmd/flowgen.c index b13ff89a..13b4f900 100644 --- a/app/test-pmd/flowgen.c +++ b/app/test-pmd/flowgen.c @@ -68,6 +68,7 @@ #include <rte_tcp.h> #include <rte_udp.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h" diff --git a/app/test-pmd/icmpecho.c b/app/test-pmd/icmpecho.c index 6a4e750f..d4b4c9eb 100644 --- a/app/test-pmd/icmpecho.c +++ b/app/test-pmd/icmpecho.c @@ -61,6 +61,7 @@ #include <rte_ip.h> #include <rte_icmp.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h" @@ -199,7 +200,7 @@ ip_proto_name(uint16_t ip_proto) "OSPFIGP", /**< OSPFIGP */ "SRPC", /**< Strite RPC protocol */ - "LARP", /**< Locus Address Resoloution */ + "LARP", /**< Locus Address Resolution */ "MTP", /**< Multicast Transport */ "AX25", /**< AX.25 Frames */ "4IN4", /**< IP encapsulated in IP */ @@ -296,7 +297,7 @@ ipv4_hdr_cksum(struct ipv4_hdr *ip_h) (((rte_be_to_cpu_32((ipv4_addr)) >> 24) & 0x000000FF) == 0xE0) /* - * Receive a burst of packets, lookup for ICMP echo requets, and, if any, + * Receive a burst of packets, lookup for ICMP echo requests, and, if any, * send back ICMP echo replies. */ static void diff --git a/app/test-pmd/ieee1588fwd.c b/app/test-pmd/ieee1588fwd.c index 0d3b37a7..51170ee3 100644 --- a/app/test-pmd/ieee1588fwd.c +++ b/app/test-pmd/ieee1588fwd.c @@ -34,6 +34,7 @@ #include <rte_cycles.h> #include <rte_ethdev.h> +#include <rte_flow.h> #include "testpmd.h" diff --git a/app/test-pmd/iofwd.c b/app/test-pmd/iofwd.c index 26936b7b..15cb4a20 100644 --- a/app/test-pmd/iofwd.c +++ b/app/test-pmd/iofwd.c @@ -64,6 +64,7 @@ #include <rte_ether.h> #include <rte_ethdev.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h" diff --git a/app/test-pmd/macfwd.c b/app/test-pmd/macfwd.c index 86e01dea..cf7eab12 100644 --- a/app/test-pmd/macfwd.c +++ b/app/test-pmd/macfwd.c @@ -65,6 +65,7 @@ #include <rte_ethdev.h> #include <rte_ip.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h" @@ -112,6 +113,8 @@ pkt_burst_mac_forward(struct fwd_stream *fs) ol_flags = PKT_TX_VLAN_PKT; if (txp->tx_ol_flags & TESTPMD_TX_OFFLOAD_INSERT_QINQ) ol_flags |= PKT_TX_QINQ_PKT; + if (txp->tx_ol_flags & TESTPMD_TX_OFFLOAD_MACSEC) + 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], diff --git a/app/test-pmd/macswap.c b/app/test-pmd/macswap.c index 36e139f6..3a093512 100644 --- a/app/test-pmd/macswap.c +++ b/app/test-pmd/macswap.c @@ -65,6 +65,7 @@ #include <rte_ethdev.h> #include <rte_ip.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h" @@ -112,6 +113,8 @@ pkt_burst_mac_swap(struct fwd_stream *fs) ol_flags = PKT_TX_VLAN_PKT; if (txp->tx_ol_flags & TESTPMD_TX_OFFLOAD_INSERT_QINQ) ol_flags |= PKT_TX_QINQ_PKT; + if (txp->tx_ol_flags & TESTPMD_TX_OFFLOAD_MACSEC) + 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], diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c index 08e5a76f..fbe6284c 100644 --- a/app/test-pmd/parameters.c +++ b/app/test-pmd/parameters.c @@ -1,7 +1,7 @@ /*- * BSD LICENSE * - * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * Copyright(c) 2010-2017 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -76,6 +76,7 @@ #ifdef RTE_LIBRTE_PMD_BOND #include <rte_eth_bond.h> #endif +#include <rte_flow.h> #include "testpmd.h" @@ -85,6 +86,7 @@ usage(char* progname) printf("usage: %s " #ifdef RTE_LIBRTE_CMDLINE "[--interactive|-i] " + "[--cmdline-file=FILENAME] " #endif "[--help|-h] | [--auto-start|-a] | [" "--coremask=COREMASK --portmask=PORTMASK --numa " @@ -102,6 +104,7 @@ usage(char* progname) 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"); @@ -148,7 +151,11 @@ usage(char* progname) "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"); - printf(" --crc-strip: enable CRC stripping by hardware.\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(" --disable-hw-vlan: disable hardware vlan.\n"); @@ -195,6 +202,14 @@ usage(char* progname) " or total packet length.\n"); printf(" --disable-link-check: disable check on link status when " "starting/stopping ports.\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|all>: " + "enable print of designated event or all of them."); + printf(" --mask-event <unknown|intr_lsc|queue_state|intr_reset|vf_mbox|macsec|intr_rmv|all>: " + "disable print of designated event or all of them."); } #ifdef RTE_LIBRTE_CMDLINE @@ -354,6 +369,18 @@ parse_queue_stats_mapping_config(const char *q_arg, int is_rx) 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) { @@ -393,15 +420,14 @@ parse_portnuma_config(const char *q_arg) port_id = (uint8_t)int_fld[FLD_PORT]; if (port_id_is_invalid(port_id, ENABLED_WARN)) { printf("Valid port range is [0"); - FOREACH_PORT(pid, ports) + RTE_ETH_FOREACH_DEV(pid) printf(", %d", pid); printf("]\n"); return -1; } socket_id = (uint8_t)int_fld[FLD_SOCKET]; - if(socket_id >= max_socket) { - printf("Invalid socket id, range is [0, %d]\n", - max_socket - 1); + if (new_socket_id(socket_id)) { + print_invalid_socket_id_error(); return -1; } port_numa[port_id] = socket_id; @@ -453,15 +479,14 @@ parse_ringnuma_config(const char *q_arg) port_id = (uint8_t)int_fld[FLD_PORT]; if (port_id_is_invalid(port_id, ENABLED_WARN)) { printf("Valid port range is [0"); - FOREACH_PORT(pid, ports) + RTE_ETH_FOREACH_DEV(pid) printf(", %d", pid); printf("]\n"); return -1; } socket_id = (uint8_t)int_fld[FLD_SOCKET]; - if (socket_id >= max_socket) { - printf("Invalid socket id, range is [0, %d]\n", - max_socket - 1); + if (new_socket_id(socket_id)) { + print_invalid_socket_id_error(); return -1; } ring_flag = (uint8_t)int_fld[FLD_FLAG]; @@ -492,6 +517,38 @@ parse_ringnuma_config(const char *q_arg) 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, "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, "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) { @@ -504,6 +561,7 @@ launch_args_parse(int argc, char** argv) { "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 }, @@ -514,6 +572,7 @@ launch_args_parse(int argc, char** argv) { "coremask", 1, 0, 0 }, { "portmask", 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 }, @@ -525,7 +584,13 @@ launch_args_parse(int argc, char** argv) { "pkt-filter-report-hash", 1, 0, 0 }, { "pkt-filter-size", 1, 0, 0 }, { "pkt-filter-drop-queue", 1, 0, 0 }, - { "crc-strip", 0, 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-scatter", 0, 0, 0 }, @@ -560,6 +625,10 @@ launch_args_parse(int argc, char** argv) { "no-flush-rx", 0, 0, 0 }, { "txpkts", 1, 0, 0 }, { "disable-link-check", 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 }, { 0, 0, 0, 0 }, }; @@ -594,6 +663,13 @@ launch_args_parse(int argc, char** argv) 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); + snprintf(cmdline_filename, + sizeof(cmdline_filename), "%s", + optarg); + } if (!strcmp(lgopts[opt_idx].name, "auto-start")) { printf("Auto-start selected\n"); auto_start = 1; @@ -650,12 +726,10 @@ launch_args_parse(int argc, char** argv) parse_fwd_coremask(optarg); if (!strcmp(lgopts[opt_idx].name, "portmask")) parse_fwd_portmask(optarg); - if (!strcmp(lgopts[opt_idx].name, "numa")) { + if (!strcmp(lgopts[opt_idx].name, "no-numa")) + numa_support = 0; + if (!strcmp(lgopts[opt_idx].name, "numa")) numa_support = 1; - 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); - } if (!strcmp(lgopts[opt_idx].name, "mp-anon")) { mp_anon = 1; } @@ -670,12 +744,13 @@ launch_args_parse(int argc, char** argv) "invalid ring-numa configuration\n"); if (!strcmp(lgopts[opt_idx].name, "socket-num")) { n = atoi(optarg); - if((uint8_t)n < max_socket) + if (!new_socket_id((uint8_t)n)) { socket_num = (uint8_t)n; - else + } else { + print_invalid_socket_id_error(); rte_exit(EXIT_FAILURE, - "The socket number should be < %d\n", - max_socket); + "Invalid socket id"); + } } if (!strcmp(lgopts[opt_idx].name, "mbuf-size")) { n = atoi(optarg); @@ -765,8 +840,33 @@ launch_args_parse(int argc, char** argv) "drop queue %d invalid - must" "be >= 0 \n", n); } - if (!strcmp(lgopts[opt_idx].name, "crc-strip")) - rx_mode.hw_strip_crc = 1; +#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_mode.hw_strip_crc = 0; if (!strcmp(lgopts[opt_idx].name, "enable-lro")) rx_mode.enable_lro = 1; if (!strcmp(lgopts[opt_idx].name, "enable-scatter")) @@ -977,6 +1077,20 @@ launch_args_parse(int argc, char** argv) no_flush_rx = 1; if (!strcmp(lgopts[opt_idx].name, "disable-link-check")) no_link_check = 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, "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"); + } break; case 'h': diff --git a/app/test-pmd/rxonly.c b/app/test-pmd/rxonly.c index fff815c6..dcd1d85c 100644 --- a/app/test-pmd/rxonly.c +++ b/app/test-pmd/rxonly.c @@ -67,6 +67,7 @@ #include <rte_ip.h> #include <rte_udp.h> #include <rte_net.h> +#include <rte_flow.h> #include "testpmd.h" @@ -100,9 +101,7 @@ pkt_burst_receive(struct fwd_stream *fs) 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 @@ -147,7 +146,8 @@ pkt_burst_receive(struct fwd_stream *fs) if (ol_flags & PKT_RX_RSS_HASH) { printf(" - RSS hash=0x%x", (unsigned) mb->hash.rss); printf(" - RSS queue=0x%x",(unsigned) fs->rx_queue); - } else if (ol_flags & PKT_RX_FDIR) { + } + if (ol_flags & PKT_RX_FDIR) { printf(" - FDIR matched "); if (ol_flags & PKT_RX_FDIR_ID) printf("ID=0x%x", diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index a0332c26..d1041afa 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -1,7 +1,7 @@ /*- * BSD LICENSE * - * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * Copyright(c) 2010-2017 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -59,6 +59,7 @@ #include <rte_memzone.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> @@ -78,6 +79,14 @@ #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" @@ -86,6 +95,7 @@ uint16_t verbose_level = 0; /**< Silent by default. */ /* use master core for command line ? */ uint8_t interactive = 0; uint8_t auto_start = 0; +char cmdline_filename[PATH_MAX] = {0}; /* * NUMA support configuration. @@ -94,7 +104,7 @@ uint8_t auto_start = 0; * probed ports among the CPU sockets 0 and 1. * Otherwise, all memory is allocated from CPU socket 0. */ -uint8_t numa_support = 0; /**< No numa support by default */ +uint8_t numa_support = 1; /**< numa enabled by default */ /* * In UMA mode,all memory is allocated from socket 0 if --socket-num is @@ -110,7 +120,7 @@ uint8_t mp_anon = 0; /* * Record the Ethernet address of peer target ports to which packets are * forwarded. - * Must be instanciated with the ethernet addresses of peer traffic generator + * Must be instantiated with the ethernet addresses of peer traffic generator * ports. */ struct ether_addr peer_eth_addrs[RTE_MAX_ETHPORTS]; @@ -262,6 +272,27 @@ uint8_t no_flush_rx = 0; /* flush by default */ uint8_t no_link_check = 0; /* check by default */ /* + * 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 */ + +/* + * 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_MACSEC) | + (UINT32_C(1) << RTE_ETH_EVENT_INTR_RMV); + +/* * NIC bypass mode configuration options. */ #ifdef RTE_NIC_BYPASS @@ -271,6 +302,20 @@ uint32_t bypass_timeout = RTE_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. */ @@ -283,7 +328,7 @@ struct rte_eth_rxmode rx_mode = { .hw_vlan_strip = 1, /**< VLAN strip enabled. */ .hw_vlan_extend = 0, /**< Extended VLAN disabled. */ .jumbo_frame = 0, /**< Jumbo Frame Support disabled. */ - .hw_strip_crc = 0, /**< CRC stripping by hardware disabled. */ + .hw_strip_crc = 1, /**< CRC stripping by hardware enabled. */ }; struct rte_fdir_conf fdir_conf = { @@ -320,11 +365,22 @@ struct queue_stats_mappings *rx_queue_stats_mappings = rx_queue_stats_mappings_a uint16_t nb_tx_queue_stats_mappings = 0; uint16_t nb_rx_queue_stats_mappings = 0; -unsigned max_socket = 0; +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 /* Forward function declarations */ static void map_port_queue_stats_mapping_registers(uint8_t pi, struct rte_port *port); static void check_all_ports_link_status(uint32_t port_mask); +static void eth_event_callback(uint8_t port_id, + enum rte_eth_event_type type, + void *param); /* * Check if all the ports are started. @@ -333,17 +389,19 @@ static void check_all_ports_link_status(uint32_t port_mask); static int all_ports_started(void); /* - * Find next enabled port + * Helper function to check if socket is allready discovered. + * If yes, return positive value. If not, return zero. */ -portid_t -find_next_port(portid_t p, struct rte_port *ports, int size) +int +new_socket_id(unsigned int socket_id) { - if (ports == NULL) - rte_exit(-EINVAL, "failed to find a next port id\n"); + unsigned int i; - while ((p < size) && (ports[p].enabled == 0)) - p++; - return p; + for (i = 0; i < num_sockets; i++) { + if (socket_ids[i] == socket_id) + return 0; + } + return 1; } /* @@ -358,11 +416,14 @@ set_default_fwd_lcores_config(void) nb_lc = 0; for (i = 0; i < RTE_MAX_LCORE; i++) { - sock_num = rte_lcore_to_socket_id(i) + 1; - if (sock_num > max_socket) { - if (sock_num > RTE_MAX_NUMA_NODES) - rte_exit(EXIT_FAILURE, "Total sockets greater than %u\n", RTE_MAX_NUMA_NODES); - max_socket = sock_num; + 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 (!rte_lcore_is_enabled(i)) continue; @@ -476,7 +537,7 @@ check_socket_id(const unsigned int socket_id) { static int warning_once = 0; - if (socket_id >= max_socket) { + if (new_socket_id(socket_id)) { if (!warning_once && numa_support) printf("Warning: NUMA should be configured manually by" " using --port-numa-config and" @@ -499,6 +560,13 @@ init_config(void) uint8_t port_per_socket[RTE_MAX_NUMA_NODES]; memset(port_per_socket,0,RTE_MAX_NUMA_NODES); + + if (numa_support) { + 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); + } + /* Configuration of logical cores. */ fwd_lcores = rte_zmalloc("testpmd: fwd_lcores", sizeof(struct fwd_lcore *) * nb_lcores, @@ -518,35 +586,7 @@ init_config(void) fwd_lcores[lc_id]->cpuid_idx = lc_id; } - /* - * 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; - - if (!numa_support) - nb_mbuf_per_pool = - (nb_mbuf_per_pool * RTE_MAX_ETHPORTS); - } - - if (!numa_support) { - if (socket_num == UMA_NO_CONFIG) - mbuf_pool_create(mbuf_data_size, nb_mbuf_per_pool, 0); - else - mbuf_pool_create(mbuf_data_size, nb_mbuf_per_pool, - socket_num); - } - - FOREACH_PORT(pid, ports) { + RTE_ETH_FOREACH_DEV(pid) { port = &ports[pid]; rte_eth_dev_info_get(pid, &port->dev_info); @@ -568,20 +608,38 @@ init_config(void) port->need_reconfig_queues = 1; } + /* + * 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; - unsigned int nb_mbuf; - - if (param_total_num_mbufs) - nb_mbuf_per_pool = nb_mbuf_per_pool/nb_ports; - for (i = 0; i < max_socket; i++) { - nb_mbuf = (nb_mbuf_per_pool * RTE_MAX_ETHPORTS); - if (nb_mbuf) - mbuf_pool_create(mbuf_data_size, - nb_mbuf,i); - } + for (i = 0; i < num_sockets; i++) + mbuf_pool_create(mbuf_data_size, nb_mbuf_per_pool, + socket_ids[i]); + } else { + if (socket_num == UMA_NO_CONFIG) + mbuf_pool_create(mbuf_data_size, nb_mbuf_per_pool, 0); + else + mbuf_pool_create(mbuf_data_size, nb_mbuf_per_pool, + socket_num); } + init_port_config(); /* @@ -631,7 +689,7 @@ init_fwd_streams(void) queueid_t q; /* set socket id according to numa or not */ - FOREACH_PORT(pid, ports) { + 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 " @@ -921,12 +979,42 @@ 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; + uint8_t idx_port, cnt_ports; + + cnt_ports = rte_eth_dev_count(); + 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 (idx_port = 0; + idx_port < cnt_ports; + idx_port++) + rte_stats_bitrate_calc(bitrate_data, + idx_port); + 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); } @@ -1252,7 +1340,7 @@ all_ports_started(void) portid_t pi; struct rte_port *port; - FOREACH_PORT(pi, ports) { + 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) && @@ -1270,7 +1358,7 @@ all_ports_stopped(void) portid_t pi; struct rte_port *port; - FOREACH_PORT(pi, ports) { + RTE_ETH_FOREACH_DEV(pi) { port = &ports[pi]; if ((port->port_status != RTE_PORT_STOPPED) && (port->slave_flag == 0)) @@ -1312,13 +1400,14 @@ start_port(portid_t pid) queueid_t qi; struct rte_port *port; struct ether_addr mac_addr; + enum rte_eth_event_type event_type; if (port_id_is_invalid(pid, ENABLED_WARN)) return 0; if(dcb_config) dcb_test = 1; - FOREACH_PORT(pi, ports) { + RTE_ETH_FOREACH_DEV(pi) { if (pid != pi && pid != (portid_t)RTE_PORT_ALL) continue; @@ -1423,6 +1512,21 @@ start_port(portid_t pid) return -1; } } + + for (event_type = RTE_ETH_EVENT_UNKNOWN; + event_type < RTE_ETH_EVENT_MAX; + event_type++) { + diag = rte_eth_dev_callback_register(pi, + event_type, + eth_event_callback, + NULL); + if (diag) { + printf("Failed to setup even callback for event %d\n", + event_type); + return -1; + } + } + /* start port */ if (rte_eth_dev_start(pi) < 0) { printf("Fail to start port %d\n", pi); @@ -1475,7 +1579,7 @@ stop_port(portid_t pid) printf("Stopping ports...\n"); - FOREACH_PORT(pi, ports) { + RTE_ETH_FOREACH_DEV(pi) { if (pid != pi && pid != (portid_t)RTE_PORT_ALL) continue; @@ -1518,7 +1622,7 @@ close_port(portid_t pid) printf("Closing ports...\n"); - FOREACH_PORT(pi, ports) { + RTE_ETH_FOREACH_DEV(pi) { if (pid != pi && pid != (portid_t)RTE_PORT_ALL) continue; @@ -1545,6 +1649,8 @@ close_port(portid_t pid) continue; } + if (port->flow_list) + port_flow_flush(pi); rte_eth_dev_close(pi); if (rte_atomic16_cmpset(&(port->port_status), @@ -1571,7 +1677,6 @@ attach_port(char *identifier) if (rte_eth_dev_attach(identifier, &pi)) return; - ports[pi].enabled = 1; socket_id = (unsigned)rte_eth_dev_socket_id(pi); /* if socket_id is invalid, set to 0 */ if (check_socket_id(socket_id) < 0) @@ -1599,10 +1704,12 @@ detach_port(uint8_t port_id) return; } + if (ports[port_id].flow_list) + port_flow_flush(port_id); + if (rte_eth_dev_detach(port_id, name)) return; - ports[port_id].enabled = 0; nb_ports = rte_eth_dev_count(); printf("Port '%s' is detached. Now total ports is %d\n", @@ -1621,7 +1728,7 @@ pmd_test_exit(void) if (ports != NULL) { no_link_check = 1; - FOREACH_PORT(pt_id, ports) { + RTE_ETH_FOREACH_DEV(pt_id) { printf("\nShutting down port %d...\n", pt_id); fflush(stdout); stop_port(pt_id); @@ -1652,7 +1759,7 @@ check_all_ports_link_status(uint32_t port_mask) fflush(stdout); for (count = 0; count <= MAX_CHECK_TIME; count++) { all_ports_up = 1; - FOREACH_PORT(portid, ports) { + RTE_ETH_FOREACH_DEV(portid) { if ((port_mask & (1 << portid)) == 0) continue; memset(&link, 0, sizeof(link)); @@ -1689,6 +1796,70 @@ check_all_ports_link_status(uint32_t port_mask) if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { print_flag = 1; } + + if (lsc_interrupt) + break; + } +} + +static void +rmv_event_callback(void *arg) +{ + struct rte_eth_dev *dev; + struct rte_devargs *da; + char name[32] = ""; + uint8_t port_id = (intptr_t)arg; + + RTE_ETH_VALID_PORTID_OR_RET(port_id); + dev = &rte_eth_devices[port_id]; + da = dev->device->devargs; + + stop_port(port_id); + close_port(port_id); + if (da->type == RTE_DEVTYPE_VIRTUAL) + snprintf(name, sizeof(name), "%s", da->virt.drv_name); + else if (da->type == RTE_DEVTYPE_WHITELISTED_PCI) + rte_pci_device_name(&da->pci.addr, name, sizeof(name)); + printf("removing device %s\n", name); + rte_eal_dev_detach(name); + dev->state = RTE_ETH_DEV_UNUSED; +} + +/* This function is used by the interrupt thread */ +static void +eth_event_callback(uint8_t port_id, enum rte_eth_event_type type, void *param) +{ + static const char * const event_desc[] = { + [RTE_ETH_EVENT_UNKNOWN] = "Unknown", + [RTE_ETH_EVENT_INTR_LSC] = "LSC", + [RTE_ETH_EVENT_QUEUE_STATE] = "Queue state", + [RTE_ETH_EVENT_INTR_RESET] = "Interrupt reset", + [RTE_ETH_EVENT_VF_MBOX] = "VF Mbox", + [RTE_ETH_EVENT_MACSEC] = "MACsec", + [RTE_ETH_EVENT_INTR_RMV] = "device removal", + [RTE_ETH_EVENT_MAX] = NULL, + }; + + RTE_SET_USED(param); + + if (type >= RTE_ETH_EVENT_MAX) { + fprintf(stderr, "\nPort %" PRIu8 ": %s called upon invalid event %d\n", + port_id, __func__, type); + fflush(stderr); + } else if (event_print_mask & (UINT32_C(1) << type)) { + printf("\nPort %" PRIu8 ": %s event\n", port_id, + event_desc[type]); + fflush(stdout); + } + + switch (type) { + case RTE_ETH_EVENT_INTR_RMV: + if (rte_eal_alarm_set(100000, + rmv_event_callback, (void *)(intptr_t)port_id)) + fprintf(stderr, "Could not set up deferred device removal\n"); + break; + default: + break; } } @@ -1817,7 +1988,7 @@ init_port_config(void) portid_t pid; struct rte_port *port; - FOREACH_PORT(pid, ports) { + RTE_ETH_FOREACH_DEV(pid) { port = &ports[pid]; port->dev_conf.rxmode = rx_mode; port->dev_conf.fdir_conf = fdir_conf; @@ -1829,24 +2000,13 @@ init_port_config(void) port->dev_conf.rx_adv_conf.rss_conf.rss_hf = 0; } - if (port->dcb_flag == 0 && port->dev_info.max_vfs == 0) { + if (port->dcb_flag == 0) { if( port->dev_conf.rx_adv_conf.rss_conf.rss_hf != 0) port->dev_conf.rxmode.mq_mode = ETH_MQ_RX_RSS; else port->dev_conf.rxmode.mq_mode = ETH_MQ_RX_NONE; } - if (port->dev_info.max_vfs != 0) { - if (port->dev_conf.rx_adv_conf.rss_conf.rss_hf != 0) - port->dev_conf.rxmode.mq_mode = - ETH_MQ_RX_VMDQ_RSS; - else - port->dev_conf.rxmode.mq_mode = - ETH_MQ_RX_NONE; - - port->dev_conf.txmode.mq_mode = ETH_MQ_TX_NONE; - } - rxtx_port_config(port); rte_eth_macaddr_get(pid, &port->eth_addr); @@ -1855,6 +2015,15 @@ init_port_config(void) #ifdef RTE_NIC_BYPASS rte_eth_dev_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; } } @@ -1907,7 +2076,7 @@ get_eth_dcb_conf(struct rte_eth_conf *eth_conf, struct rte_eth_vmdq_dcb_tx_conf *vmdq_tx_conf = ð_conf->tx_adv_conf.vmdq_dcb_tx_conf; - /* VMDQ+DCB RX and TX configrations */ + /* 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 = @@ -1938,9 +2107,9 @@ get_eth_dcb_conf(struct rte_eth_conf *eth_conf, rx_conf->nb_tcs = num_tcs; tx_conf->nb_tcs = num_tcs; - for (i = 0; i < num_tcs; i++) { - rx_conf->dcb_tc[i] = i; - tx_conf->dcb_tc[i] = i; + 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 = ETH_MQ_RX_DCB_RSS; eth_conf->rx_adv_conf.rss_conf.rss_hf = rss_hf; @@ -2041,8 +2210,6 @@ init_port_dcb_config(portid_t pid, static void init_port(void) { - portid_t pid; - /* Configuration of Ethernet ports. */ ports = rte_zmalloc("testpmd: ports", sizeof(struct rte_port) * RTE_MAX_ETHPORTS, @@ -2052,10 +2219,6 @@ init_port(void) "rte_zmalloc(%d struct rte_port) failed\n", RTE_MAX_ETHPORTS); } - - /* enabled allocated ports */ - for (pid = 0; pid < nb_ports; pid++) - ports[pid].enabled = 1; } static void @@ -2075,6 +2238,9 @@ signal_handler(int signum) /* uninitialize packet capture framework */ rte_pdump_uninit(); #endif +#ifdef RTE_LIBRTE_LATENCY_STATS + rte_latencystats_uninit(); +#endif force_quit(); /* exit with the expected status */ signal(signum, SIG_DFL); @@ -2112,6 +2278,14 @@ main(int argc, char** argv) rte_panic("Empty set of forwarding logical cores - check the " "core mask supplied in the command parameters\n"); + /* Bitrate/latency stats disabled by default */ +#ifdef RTE_LIBRTE_BITRATE + bitrate_enabled = 0; +#endif +#ifdef RTE_LIBRTE_LATENCY_STATS + latencystats_enabled = 0; +#endif + argc -= diag; argv += diag; if (argc > 1) @@ -2130,16 +2304,45 @@ main(int argc, char** argv) rte_exit(EXIT_FAILURE, "Start ports failed\n"); /* set all ports to promiscuous mode by default */ - FOREACH_PORT(port_id, ports) + RTE_ETH_FOREACH_DEV(port_id) rte_eth_promiscuous_enable(port_id); + /* 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 { diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 9c1e7039..e6c43ba0 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -1,7 +1,7 @@ /*- * BSD LICENSE * - * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * Copyright(c) 2010-2017 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -143,12 +143,26 @@ struct fwd_stream { #define TESTPMD_TX_OFFLOAD_INSERT_VLAN 0x0040 /** Insert double VLAN header in forward engine */ #define TESTPMD_TX_OFFLOAD_INSERT_QINQ 0x0080 +/** Offload MACsec in forward engine */ +#define TESTPMD_TX_OFFLOAD_MACSEC 0x0100 + +/** Descriptor for a single flow. */ +struct port_flow { + size_t size; /**< Allocated space including data[]. */ + 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_attr attr; /**< Attributes. */ + struct rte_flow_item *pattern; /**< Pattern. */ + struct rte_flow_action *actions; /**< Actions. */ + uint8_t data[]; /**< Storage for pattern/actions. */ +}; /** * The data structure associated with each port. */ struct rte_port { - uint8_t enabled; /**< Port enabled or not */ struct rte_eth_dev_info dev_info; /**< PCI info + driver name */ struct rte_eth_conf dev_conf; /**< Port configuration. */ struct ether_addr eth_addr; /**< Port ethernet address */ @@ -177,16 +191,9 @@ struct rte_port { struct 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. */ }; -extern portid_t __rte_unused -find_next_port(portid_t p, struct rte_port *ports, int size); - -#define FOREACH_PORT(p, ports) \ - for (p = find_next_port(0, ports, RTE_MAX_ETHPORTS); \ - p < RTE_MAX_ETHPORTS; \ - p = find_next_port(p + 1, ports, RTE_MAX_ETHPORTS)) - /** * The data structure associated with each forwarding logical core. * The logical cores are internally numbered by a core index from 0 to @@ -292,12 +299,17 @@ extern uint16_t nb_rx_queue_stats_mappings; extern uint16_t verbose_level; /**< Drives messages being displayed, if any. */ extern uint8_t interactive; extern uint8_t auto_start; +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 mp_anon; /**< set by "--mp-anon" parameter */ extern uint8_t no_link_check; /**<set by "--disable-link-check" 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 */ #ifdef RTE_NIC_BYPASS extern uint32_t bypass_timeout; /**< Store the NIC bypass watchdog timeout */ @@ -331,7 +343,8 @@ 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 max_socket; +extern unsigned int num_sockets; +extern unsigned int socket_ids[RTE_MAX_NUMA_NODES]; /* * Configuration of Ethernet ports: @@ -365,6 +378,17 @@ extern enum dcb_queue_mapping_mode dcb_q_mapping; extern uint16_t mbuf_data_size; /**< Mbuf data space size. */ extern uint32_t param_total_num_mbufs; + +#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; /* @@ -476,6 +500,7 @@ 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); @@ -484,6 +509,7 @@ 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 port_infos_display(portid_t port_id); +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); @@ -504,6 +530,19 @@ 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); +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_query(portid_t port_id, uint32_t rule, + enum rte_flow_action_type action); +void port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group); 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); @@ -571,8 +610,6 @@ void port_rss_reta_info(portid_t port_id, uint16_t nb_entries); void set_vf_traffic(portid_t port_id, uint8_t is_rx, uint16_t vf, uint8_t on); -void set_vf_rx_vlan(portid_t port_id, uint16_t vlan_id, - uint64_t vf_mask, 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, @@ -594,11 +631,15 @@ void mcast_addr_add(uint8_t port_id, struct ether_addr *mc_addr); void mcast_addr_remove(uint8_t port_id, struct ether_addr *mc_addr); void port_dcb_info_display(uint8_t port_id); +uint8_t *open_ddp_package_file(const char *file_path, uint32_t *size); +int close_ddp_package_file(uint8_t *buf); + enum print_warning { ENABLED_WARN = 0, DISABLED_WARN }; int port_id_is_invalid(portid_t port_id, enum print_warning warning); +int new_socket_id(unsigned int socket_id); /* * Work-around of a compilation error with ICC on invocations of the diff --git a/app/test-pmd/txonly.c b/app/test-pmd/txonly.c index 8513a062..8b1a2afc 100644 --- a/app/test-pmd/txonly.c +++ b/app/test-pmd/txonly.c @@ -68,6 +68,7 @@ #include <rte_tcp.h> #include <rte_udp.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h" @@ -214,6 +215,8 @@ pkt_burst_transmit(struct fwd_stream *fs) ol_flags = PKT_TX_VLAN_PKT; if (txp->tx_ol_flags & TESTPMD_TX_OFFLOAD_INSERT_QINQ) ol_flags |= PKT_TX_QINQ_PKT; + if (txp->tx_ol_flags & TESTPMD_TX_OFFLOAD_MACSEC) + 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 == NULL) { |