From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by dpdk.org (Postfix) with ESMTP id 5B139996A for ; Thu, 17 Aug 2017 11:06:07 +0200 (CEST) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 17 Aug 2017 02:06:07 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.41,387,1498546800"; d="scan'208";a="124663415" Received: from dpdk15.sh.intel.com ([10.67.111.77]) by orsmga002.jf.intel.com with ESMTP; 17 Aug 2017 02:06:04 -0700 From: Jiayu Hu To: dev@dpdk.org Cc: ferruh.yigit@intel.com, konstantin.ananyev@intel.com, jianfeng.tan@intel.com, thomas@monjalon.net, jingjing.wu@intel.com, lei.a.yao@intel.com, Jiayu Hu Date: Thu, 17 Aug 2017 17:08:11 +0800 Message-Id: <1502960892-112960-2-git-send-email-jiayu.hu@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1502960892-112960-1-git-send-email-jiayu.hu@intel.com> References: <1502333448-75976-1-git-send-email-jiayu.hu@intel.com> <1502960892-112960-1-git-send-email-jiayu.hu@intel.com> Subject: [dpdk-dev] [PATCH v2 1/2] app/testpmd: support the heavywight mode GRO X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 17 Aug 2017 09:06:08 -0000 The GRO library provides two reassembly modes: lightweight mode and heavyweight mode. This patch is to support the heavyweight mode in csum forwarding engine. With the command "set port gro (heavymode|lightmode) (on|off)", users can select the lightweight mode or the heavyweight mode to use. With the command "set gro flush interval ", users can set the interval of flushing GROed packets from reassembly tables for the heavyweight mode. With the command "show port gro", users can display GRO configuration. Signed-off-by: Jiayu Hu --- app/test-pmd/cmdline.c | 181 ++++++++++++++++++++++++++++++++++++++++++------ app/test-pmd/config.c | 72 +++++++++++++++---- app/test-pmd/csumonly.c | 29 ++++++-- app/test-pmd/testpmd.c | 18 ++++- app/test-pmd/testpmd.h | 13 +++- 5 files changed, 270 insertions(+), 43 deletions(-) diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index cd8c358..9876604 100644 --- a/app/test-pmd/cmdline.c +++ b/app/test-pmd/cmdline.c @@ -423,14 +423,22 @@ static void cmd_help_long_parsed(void *parsed_result, "tso show (portid)" " Display the status of TCP Segmentation Offload.\n\n" - "gro (on|off) (port_id)" + "set port (port_id) gro (heavymode|lightmode) " + "(on|off)\n" " Enable or disable Generic Receive Offload in" " csum forwarding engine.\n\n" + "show port (port_id) gro\n" + " Display GRO configuration.\n\n" + "gro set (max_flow_num) (max_item_num_per_flow) (port_id)\n" " Set max flow number and max packet number per-flow" " for GRO.\n\n" + "set gro flush interval (num)\n" + " Set the interval of flushing GROed packets from" + " reassembly tables.\n\n" + "set fwd (%s)\n" " Set packet forwarding mode.\n\n" @@ -3850,41 +3858,168 @@ cmdline_parse_inst_t cmd_tunnel_tso_show = { }; /* *** SET GRO FOR A PORT *** */ -struct cmd_gro_result { +struct cmd_gro_enable_result { + cmdline_fixed_string_t cmd_set; + cmdline_fixed_string_t cmd_port; cmdline_fixed_string_t cmd_keyword; - cmdline_fixed_string_t mode; - uint8_t port_id; + cmdline_fixed_string_t cmd_mode; + cmdline_fixed_string_t cmd_onoff; + uint8_t cmd_pid; +}; + +static void +cmd_gro_enable_parsed(void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_gro_enable_result *res; + + res = parsed_result; + setup_gro(res->cmd_mode, res->cmd_onoff, res->cmd_pid); +} + +cmdline_parse_token_string_t cmd_gro_enable_set = + TOKEN_STRING_INITIALIZER(struct cmd_gro_enable_result, + cmd_set, "set"); +cmdline_parse_token_string_t cmd_gro_enable_port = + TOKEN_STRING_INITIALIZER(struct cmd_gro_enable_result, + cmd_keyword, "port"); +cmdline_parse_token_num_t cmd_gro_enable_pid = + TOKEN_NUM_INITIALIZER(struct cmd_gro_enable_result, + cmd_pid, UINT8); +cmdline_parse_token_string_t cmd_gro_enable_keyword = + TOKEN_STRING_INITIALIZER(struct cmd_gro_enable_result, + cmd_keyword, "gro"); +cmdline_parse_token_string_t cmd_gro_enable_mode = + TOKEN_STRING_INITIALIZER(struct cmd_gro_enable_result, + cmd_mode, "heavymode#lightmode"); +cmdline_parse_token_string_t cmd_gro_enable_onoff = + TOKEN_STRING_INITIALIZER(struct cmd_gro_enable_result, + cmd_onoff, "on#off"); + +cmdline_parse_inst_t cmd_gro_enable = { + .f = cmd_gro_enable_parsed, + .data = NULL, + .help_str = "set port gro (heavymode|lightmode) (on|off)", + .tokens = { + (void *)&cmd_gro_enable_set, + (void *)&cmd_gro_enable_port, + (void *)&cmd_gro_enable_pid, + (void *)&cmd_gro_enable_keyword, + (void *)&cmd_gro_enable_mode, + (void *)&cmd_gro_enable_onoff, + NULL, + }, +}; + +/* *** DISPLAY GRO CONFIGURATION *** */ +struct cmd_gro_show_result { + cmdline_fixed_string_t cmd_show; + cmdline_fixed_string_t cmd_port; + cmdline_fixed_string_t cmd_keyword; + uint8_t cmd_pid; +}; + +static void +cmd_gro_show_parsed(void *parsed_result, + __attribute__((unused)) struct cmdline *cl, + __attribute__((unused)) void *data) +{ + struct cmd_gro_show_result *res; + + res = parsed_result; + if (!strcmp(res->cmd_keyword, "gro")) + show_gro(res->cmd_pid); +} + +cmdline_parse_token_string_t cmd_gro_show_show = + TOKEN_STRING_INITIALIZER(struct cmd_gro_show_result, + cmd_show, "show"); +cmdline_parse_token_string_t cmd_gro_show_port = + TOKEN_STRING_INITIALIZER(struct cmd_gro_show_result, + cmd_port, "port"); +cmdline_parse_token_num_t cmd_gro_show_pid = + TOKEN_NUM_INITIALIZER(struct cmd_gro_show_result, + cmd_pid, UINT8); +cmdline_parse_token_string_t cmd_gro_show_keyword = + TOKEN_STRING_INITIALIZER(struct cmd_gro_show_result, + cmd_keyword, "gro"); + +cmdline_parse_inst_t cmd_gro_show = { + .f = cmd_gro_show_parsed, + .data = NULL, + .help_str = "show port gro", + .tokens = { + (void *)&cmd_gro_show_show, + (void *)&cmd_gro_show_port, + (void *)&cmd_gro_show_pid, + (void *)&cmd_gro_show_keyword, + NULL, + }, +}; + +/* *** SET FLUSH INTERVAL FOR THE HEAVYWEIGHT MODE GRO *** */ +struct cmd_gro_flush_result { + cmdline_fixed_string_t cmd_set; + cmdline_fixed_string_t cmd_keyword; + cmdline_fixed_string_t cmd_flush; + cmdline_fixed_string_t cmd_interval; + uint32_t cmd_num; }; static void -cmd_enable_gro_parsed(void *parsed_result, +cmd_gro_flush_parsed(void *parsed_result, __attribute__((unused)) struct cmdline *cl, __attribute__((unused)) void *data) { - struct cmd_gro_result *res; + struct cmd_gro_flush_result *res; res = parsed_result; - setup_gro(res->mode, res->port_id); + if (test_done == 0) { + printf("Before set flushing interval for heavyweight" + " mode GRO, please stop forwarding first\n"); + return; + } + + if (!strcmp(res->cmd_interval, "interval")) { + if (res->cmd_num > GRO_MAX_FLUSH_INTERVAL) { + printf("The interval value should be in the range" + " of 0 to %u. Revert to the default" + " value %u\n", + GRO_MAX_FLUSH_INTERVAL, + GRO_DEFAULT_FLUSH_INTERVAL); + gro_flush_interval = GRO_DEFAULT_FLUSH_INTERVAL; + } else + gro_flush_interval = res->cmd_num; + } } -cmdline_parse_token_string_t cmd_gro_keyword = - TOKEN_STRING_INITIALIZER(struct cmd_gro_result, +cmdline_parse_token_string_t cmd_gro_flush_set = + TOKEN_STRING_INITIALIZER(struct cmd_gro_flush_result, + cmd_set, "set"); +cmdline_parse_token_string_t cmd_gro_flush_keyword = + TOKEN_STRING_INITIALIZER(struct cmd_gro_flush_result, cmd_keyword, "gro"); -cmdline_parse_token_string_t cmd_gro_mode = - TOKEN_STRING_INITIALIZER(struct cmd_gro_result, - mode, "on#off"); -cmdline_parse_token_num_t cmd_gro_pid = - TOKEN_NUM_INITIALIZER(struct cmd_gro_result, - port_id, UINT8); +cmdline_parse_token_string_t cmd_gro_flush_flush = + TOKEN_STRING_INITIALIZER(struct cmd_gro_flush_result, + cmd_flush, "flush"); +cmdline_parse_token_string_t cmd_gro_flush_interval = + TOKEN_STRING_INITIALIZER(struct cmd_gro_flush_result, + cmd_interval, "interval"); +cmdline_parse_token_num_t cmd_gro_flush_num = + TOKEN_NUM_INITIALIZER(struct cmd_gro_flush_result, + cmd_num, UINT32); -cmdline_parse_inst_t cmd_enable_gro = { - .f = cmd_enable_gro_parsed, +cmdline_parse_inst_t cmd_gro_flush = { + .f = cmd_gro_flush_parsed, .data = NULL, - .help_str = "gro (on|off) (port_id)", + .help_str = "set gro flush interval ", .tokens = { - (void *)&cmd_gro_keyword, - (void *)&cmd_gro_mode, - (void *)&cmd_gro_pid, + (void *)&cmd_gro_flush_set, + (void *)&cmd_gro_flush_keyword, + (void *)&cmd_gro_flush_flush, + (void *)&cmd_gro_flush_interval, + (void *)&cmd_gro_flush_num, NULL, }, }; @@ -14249,8 +14384,10 @@ cmdline_parse_ctx_t main_ctx[] = { (cmdline_parse_inst_t *)&cmd_tso_show, (cmdline_parse_inst_t *)&cmd_tunnel_tso_set, (cmdline_parse_inst_t *)&cmd_tunnel_tso_show, - (cmdline_parse_inst_t *)&cmd_enable_gro, + (cmdline_parse_inst_t *)&cmd_gro_enable, + (cmdline_parse_inst_t *)&cmd_gro_show, (cmdline_parse_inst_t *)&cmd_gro_set, + (cmdline_parse_inst_t *)&cmd_gro_flush, (cmdline_parse_inst_t *)&cmd_link_flow_control_set, (cmdline_parse_inst_t *)&cmd_link_flow_control_set_rx, (cmdline_parse_inst_t *)&cmd_link_flow_control_set_tx, diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index 3ae3e1c..9ee4e59 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -2420,7 +2420,7 @@ set_tx_pkt_segments(unsigned *seg_lengths, unsigned nb_segs) } void -setup_gro(const char *mode, uint8_t port_id) +setup_gro(const char *mode, const char *onoff, uint8_t port_id) { if (!rte_eth_dev_is_valid_port(port_id)) { printf("invalid port id %u\n", port_id); @@ -2431,29 +2431,73 @@ setup_gro(const char *mode, uint8_t port_id) " please stop forwarding first\n"); return; } - if (strcmp(mode, "on") == 0) { - if (gro_ports[port_id].enable) { - printf("port %u has enabled GRO\n", port_id); + if (strcmp(onoff, "on") == 0) { + if (gro_ports[port_id].enable != 0) { + printf("Port %u has enabled GRO. Please" + " disable GRO first\n", port_id); return; } - gro_ports[port_id].enable = 1; - gro_ports[port_id].param.gro_types = RTE_GRO_TCP_IPV4; - - if (gro_ports[port_id].param.max_flow_num == 0) - gro_ports[port_id].param.max_flow_num = - GRO_DEFAULT_FLOW_NUM; - if (gro_ports[port_id].param.max_item_per_flow == 0) - gro_ports[port_id].param.max_item_per_flow = - GRO_DEFAULT_ITEM_NUM_PER_FLOW; + if (strcmp(mode, "heavymode") == 0) + gro_ports[port_id].enable = GRO_HEAVYMODE; + else { + gro_ports[port_id].enable = GRO_LIGHTMODE; + gro_ports[port_id].param.gro_types = RTE_GRO_TCP_IPV4; + + if (gro_ports[port_id].param.max_flow_num == 0) { + gro_ports[port_id].param.max_flow_num = + GRO_DEFAULT_FLOW_NUM; + } + if (gro_ports[port_id].param.max_item_per_flow == 0) { + gro_ports[port_id].param.max_item_per_flow = + GRO_DEFAULT_ITEM_NUM_PER_FLOW; + } + } } else { if (gro_ports[port_id].enable == 0) { - printf("port %u has disabled GRO\n", port_id); + printf("Port %u has disabled GRO\n", port_id); return; } gro_ports[port_id].enable = 0; } } +void +show_gro(uint8_t port_id) +{ + struct rte_gro_param *param; + + param = &gro_ports[port_id].param; + + if (!rte_eth_dev_is_valid_port(port_id)) { + printf("Invalid port id %u\n", port_id); + return; + } + switch (gro_ports[port_id].enable) { + case GRO_HEAVYMODE: + printf("GRO mode: heavyweight\n" + "Flushing interval: %u\n" + "GRO type: TCP/IPv4\n" + "Max flow number (fixed): %u\n" + "Max item per flow (fixed): %u\n", + gro_flush_interval, + GRO_MAX_FLUSH_INTERVAL, + MAX_PKT_BURST); + break; + case GRO_LIGHTMODE: + printf("GRO mode: lightweight\n" + "Flushing interval: N/A\n" + "GRO type: TCP/IPv4\n" + "Max flow number: %u\n" + "Max item per flow: %u\n", + param->max_flow_num, + param->max_item_per_flow); + break; + case 0: + printf("Port %u doesn't enable GRO\n", port_id); + break; + } +} + char* list_pkt_forwarding_modes(void) { diff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c index 90c8119..6e98938 100644 --- a/app/test-pmd/csumonly.c +++ b/app/test-pmd/csumonly.c @@ -631,6 +631,9 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) struct rte_mbuf *m, *p; struct ether_hdr *eth_hdr; void *l3_hdr = NULL, *outer_l3_hdr = NULL; /* can be IPv4 or IPv6 */ + void *gro_ctx; + uint16_t gro_pkts_num; + uint8_t gro_enable; uint16_t nb_rx; uint16_t nb_tx; uint16_t nb_prep; @@ -657,17 +660,13 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) nb_pkt_per_burst); if (unlikely(nb_rx == 0)) return; - if (unlikely(gro_ports[fs->rx_port].enable)) - nb_rx = rte_gro_reassemble_burst(pkts_burst, - nb_rx, - &(gro_ports[fs->rx_port].param)); - #ifdef RTE_TEST_PMD_RECORD_BURST_STATS fs->rx_burst_stats.pkt_burst_spread[nb_rx]++; #endif fs->rx_packets += nb_rx; rx_bad_ip_csum = 0; rx_bad_l4_csum = 0; + gro_enable = gro_ports[fs->rx_port].enable; txp = &ports[fs->tx_port]; testpmd_ol_flags = txp->tx_ol_flags; @@ -851,6 +850,26 @@ pkt_burst_checksum_forward(struct fwd_stream *fs) } } + if (unlikely(gro_enable == GRO_HEAVYMODE)) { + gro_ctx = current_fwd_lcore()->gro_ctx; + nb_rx = rte_gro_reassemble(pkts_burst, nb_rx, gro_ctx); + + if (fs->gro_times++ >= gro_flush_interval) { + gro_pkts_num = rte_gro_get_pkt_count(gro_ctx); + if (gro_pkts_num > MAX_PKT_BURST - nb_rx) + gro_pkts_num = MAX_PKT_BURST - nb_rx; + + nb_rx += rte_gro_timeout_flush(gro_ctx, 0, + RTE_GRO_TCP_IPV4, + &pkts_burst[nb_rx], + gro_pkts_num); + fs->gro_times = 0; + } + } else if (unlikely(gro_enable == GRO_LIGHTMODE)) { + nb_rx = rte_gro_reassemble_burst(pkts_burst, nb_rx, + &(gro_ports[fs->rx_port].param)); + } + nb_prep = rte_eth_tx_prepare(fs->tx_port, fs->tx_queue, pkts_burst, nb_rx); if (nb_prep != nb_rx) diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index 7d40139..3946a45 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -90,7 +90,6 @@ #ifdef RTE_LIBRTE_LATENCY_STATS #include #endif -#include #include "testpmd.h" @@ -386,6 +385,7 @@ uint8_t bitrate_enabled; #endif struct gro_status gro_ports[RTE_MAX_ETHPORTS]; +uint32_t gro_flush_interval = GRO_DEFAULT_FLUSH_INTERVAL; /* Forward function declarations */ static void map_port_queue_stats_mapping_registers(uint8_t pi, struct rte_port *port); @@ -570,6 +570,7 @@ init_config(void) unsigned int nb_mbuf_per_pool; lcoreid_t lc_id; uint8_t port_per_socket[RTE_MAX_NUMA_NODES]; + struct rte_gro_param gro_param; memset(port_per_socket,0,RTE_MAX_NUMA_NODES); @@ -671,6 +672,20 @@ init_config(void) rte_exit(EXIT_FAILURE, "FAIL from init_fwd_streams()\n"); fwd_config_setup(); + + /* create a gro context for each lcore */ + gro_param.gro_types = RTE_GRO_TCP_IPV4; + gro_param.max_flow_num = GRO_MAX_FLUSH_INTERVAL; + gro_param.max_item_per_flow = MAX_PKT_BURST; + for (lc_id = 0; lc_id < nb_lcores; lc_id++) { + gro_param.socket_id = rte_lcore_to_socket_id( + fwd_lcores_cpuids[lc_id]); + fwd_lcores[lc_id]->gro_ctx = rte_gro_ctx_create(&gro_param); + if (fwd_lcores[lc_id]->gro_ctx == NULL) { + rte_exit(EXIT_FAILURE, + "rte_gro_ctx_create() failed\n"); + } + } } @@ -1165,6 +1180,7 @@ start_packet_forwarding(int with_tx_first) fwd_streams[sm_id]->fwd_dropped = 0; fwd_streams[sm_id]->rx_bad_ip_csum = 0; fwd_streams[sm_id]->rx_bad_l4_csum = 0; + fwd_streams[sm_id]->gro_times = 0; #ifdef RTE_TEST_PMD_RECORD_BURST_STATS memset(&fwd_streams[sm_id]->rx_burst_stats, 0, diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index c9d7739..8b71a1f 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -120,6 +120,7 @@ struct fwd_stream { unsigned int fwd_dropped; /**< received packets not forwarded */ unsigned int rx_bad_ip_csum ; /**< received packets has bad ip checksum */ unsigned int rx_bad_l4_csum ; /**< received packets has bad l4 checksum */ + unsigned int gro_times; /**< reassembly times in heavyweight mode */ #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES uint64_t core_cycles; /**< used for RX and TX processing */ #endif @@ -206,6 +207,7 @@ struct rte_port { */ struct fwd_lcore { struct rte_mempool *mbp; /**< The mbuf pool to use by this core */ + void *gro_ctx; /**< GRO context */ streamid_t stream_idx; /**< index of 1st stream in "fwd_streams" */ streamid_t stream_nb; /**< number of streams in "fwd_streams" */ lcoreid_t cpuid_idx; /**< index of logical core in CPU id table */ @@ -434,13 +436,21 @@ extern struct ether_addr peer_eth_addrs[RTE_MAX_ETHPORTS]; extern uint32_t burst_tx_delay_time; /**< Burst tx delay time(us) for mac-retry. */ extern uint32_t burst_tx_retry_num; /**< Burst tx retry number for mac-retry. */ +#define GRO_HEAVYMODE 0x1 +#define GRO_LIGHTMODE 0x2 + #define GRO_DEFAULT_FLOW_NUM 4 #define GRO_DEFAULT_ITEM_NUM_PER_FLOW DEF_PKT_BURST + +#define GRO_DEFAULT_FLUSH_INTERVAL 2 +#define GRO_MAX_FLUSH_INTERVAL 4 + struct gro_status { struct rte_gro_param param; uint8_t enable; }; extern struct gro_status gro_ports[RTE_MAX_ETHPORTS]; +extern uint32_t gro_flush_interval; static inline unsigned int lcore_num(void) @@ -640,7 +650,8 @@ void get_2tuple_filter(uint8_t port_id, uint16_t index); void get_5tuple_filter(uint8_t port_id, uint16_t index); int rx_queue_id_is_invalid(queueid_t rxq_id); int tx_queue_id_is_invalid(queueid_t txq_id); -void setup_gro(const char *mode, uint8_t port_id); +void setup_gro(const char *mode, const char *onoff, uint8_t port_id); +void show_gro(uint8_t port_id); /* Functions to manage the set of filtered Multicast MAC addresses */ void mcast_addr_add(uint8_t port_id, struct ether_addr *mc_addr); -- 2.7.4