app/testpmd: reduce txonly multi-flow src_port range
PATCH 1/1 app/testpmd: reduce txonly multi-flow src_port range
Reduce the UDP source port OR-mask from 0xC0 to 0xF0, lowering unique high-byte values from 64 to 16 (16 unique ports per lcore).
Modern SmartNICs rarely need more than 16 queues to saturate RX, and excessive unique ports can exhaust hardware flow caching, degrading performance.
Unique source ports by lcore count:
1: 16, 2: 32, 4: 64, 8: 128, 16: 256
--- app/test-pmd/txonly.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
app/test-pmd/txonly.c +4 -5
@@ -229,12 +229,11 @@ pkt_burst_prepare(struct rte_mbuf *pkt, struct rte_mempool *mbp,* packet generator for developer's quick performance * regression test. * -* Only ports in the range 49152 (0xC000) and 65535 (0xFFFF) -* will be used, with the least significant byte representing -* the lcore ID. As such, the most significant byte will cycle -* through 0xC0 and 0xFF. +* Generate ports in the IANA ephemeral range (49152+). +* The OR-mask (0xF0) produces 16 unique port values +* per lcore for good RSS distribution. */ - src_port = ((src_var++ |0xC0 ) <<8 ) +rte_lcore_id (); + src_port = ((src_var++ |0xF0 ) <<8 ) +rte_lcore_id (); udp_hdr->src_port =rte_cpu_to_be_16 (src_port);RTE_PER_LCORE (_src_port_var) = src_var; }
Signature · 1 line
2.43.0
Quoted 7 lines · On Thu, 26 Feb 2026 11:16:25 -0800 Long Li <[email protected]> wrote:
Reduce the UDP source port OR-mask from
0xC0to0xF0, lowering unique high-byte values from 64 to 16 (16 unique ports per lcore).Modern SmartNICs rarely need more than 16 queues to saturate RX, and excessive unique ports can exhaust hardware flow caching, degrading performance.
Quoted 5 lines
Unique source ports by lcore count:
1: 16, 2: 32, 4: 64, 8: 128, 16: 256Signed-off-by Long Li <[email protected]>---
Make sense to make this less spread out.
I wonder if this should be a parameter to allow for testing different spreads?
RFC 1/1 app/testpmd: add configurable flow count for txonly multi-flow
In reply to Long LiStarted with Long's patch to change port and added a parameter. This is suggestion only *DO NOT MERGE*
Not sure what good name for parameter is, this is just a quick hack.
The txonly multi-flow mode generates 64 unique UDP source ports per lcore by cycling the high byte from 0xC0 to 0xFF. On SmartNICs with limited hardware flow table caching, this fixed count can exhaust the flow cache and degrade receive-side performance.
Add --txonly-nb-flows=N command line parameter and 'set txonly-nb-flows' runtime command to limit the number of unique source ports per lcore to between 1 and 64. The default remains 64 to preserve existing behavior.
The source port encoding is unchanged: the low byte carries the lcore ID (avoiding atomics) and the high byte cycles through N values starting at 0xC0. Total unique flows = txonly_nb_flows * active_lcores.
---
app/test-pmd/cmdline.c | 49 +++++++++++++++++++++ app/test-pmd/parameters.c | 13 ++++++ app/test-pmd/testpmd.c | 3 ++ app/test-pmd/testpmd.h | 1 + app/test-pmd/txonly.c | 24 +++++----- doc/guides/testpmd_app_ug/run_app.rst | 8 ++++ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 16 +++++++ 7 files changed, 104 insertions(+), 10 deletions(-)
app/test-pmd/cmdline.c +49 -0
@@ -384,6 +384,10 @@ static void cmd_help_long_parsed(void *parsed_result," Set the scheduling on timestamps" " timings for the TXONLY mode\n\n" +"set txonly-nb-flows (N)\n" +" Set the number of flows per lcore in" +" txonly multi-flow mode (1-64)\n\n" +"set corelist (x[,y]*)\n" " Set the list of forwarding cores.\n\n"
@@ -4612,6 +4616,50 @@ static cmdline_parse_inst_t cmd_set_txtimes = { }, }; +/* *** SET NUMBER OF FLOWS IN TXONLY MULTI-FLOW MODE *** */ + +struct cmd_set_txonly_nb_flows_result { +cmdline_fixed_string_t cmd_keyword; +cmdline_fixed_string_t name; +uint16_t value; +}; + +static void +cmd_set_txonly_nb_flows_parsed (void *parsed_result, + __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ +struct cmd_set_txonly_nb_flows_result *res = parsed_result; + +if (res->value <1 || res->value >64 ) { +fprintf (stderr,"txonly-nb-flows must be >= 1 and <= 64\n" ); +return ; + } + txonly_nb_flows = res->value; +} + +static cmdline_parse_token_string_t cmd_set_txonly_nb_flows_keyword = + TOKEN_STRING_INITIALIZER(struct cmd_set_txonly_nb_flows_result, + cmd_keyword,"set" ); +static cmdline_parse_token_string_t cmd_set_txonly_nb_flows_name = + TOKEN_STRING_INITIALIZER(struct cmd_set_txonly_nb_flows_result, + name,"txonly-nb-flows" ); +static cmdline_parse_token_num_t cmd_set_txonly_nb_flows_value = + TOKEN_NUM_INITIALIZER(struct cmd_set_txonly_nb_flows_result, + value,RTE_UINT16 ); + +static cmdline_parse_inst_t cmd_set_txonly_nb_flows = { + .f = cmd_set_txonly_nb_flows_parsed, + .data =NULL , + .help_str ="set txonly-nb-flows <N>" , + .tokens = { + (void *)&cmd_set_txonly_nb_flows_keyword, + (void *)&cmd_set_txonly_nb_flows_name, + (void *)&cmd_set_txonly_nb_flows_value, +NULL , + }, +}; +/* *** ADD/REMOVE ALL VLAN IDENTIFIERS TO/FROM A PORT VLAN RX FILTER *** */ struct cmd_rx_vlan_filter_all_result {cmdline_fixed_string_t rx_vlan;
@@ -14102,6 +14150,7 @@ static cmdline_parse_ctx_t builtin_ctx[] = { &cmd_set_txpkts, &cmd_set_txsplit, &cmd_set_txtimes, + &cmd_set_txonly_nb_flows, &cmd_set_fwd_list, &cmd_set_fwd_mask, &cmd_set_fwd_mode,
app/test-pmd/parameters.c +13 -0
@@ -193,6 +193,8 @@ enum {TESTPMD_OPT_MULTI_RX_MEMPOOL_NUM , #define TESTPMD_OPT_TXONLY_MULTI_FLOW "txonly-multi-flow"TESTPMD_OPT_TXONLY_MULTI_FLOW_NUM , +#define TESTPMD_OPT_TXONLY_NB_FLOWS "txonly-nb-flows" +TESTPMD_OPT_TXONLY_NB_FLOWS_NUM , #define TESTPMD_OPT_RXQ_SHARE "rxq-share"TESTPMD_OPT_RXQ_SHARE_NUM , #define TESTPMD_OPT_ETH_LINK_SPEED "eth-link-speed"
@@ -348,6 +350,7 @@ static const struct option long_options[] = {REQUIRED_ARG (TESTPMD_OPT_TXPKTS ),NO_ARG (TESTPMD_OPT_MULTI_RX_MEMPOOL ),NO_ARG (TESTPMD_OPT_TXONLY_MULTI_FLOW ), +REQUIRED_ARG (TESTPMD_OPT_TXONLY_NB_FLOWS ),OPTIONAL_ARG (TESTPMD_OPT_RXQ_SHARE ),REQUIRED_ARG (TESTPMD_OPT_ETH_LINK_SPEED ), NO_ARG(TESTPMD_OPT_DISABLE_LINK_CHECK),
@@ -499,6 +502,8 @@ usage(char* progname) " or total packet length.\n");printf (" --multi-rx-mempool: enable multi-rx-mempool support\n" );printf (" --txonly-multi-flow: generate multiple flows in txonly mode\n" ); +printf (" --txonly-nb-flows=N: number of flows per lcore in txonly" +" multi-flow mode (1-64, default 64)\n" );printf (" --tx-ip=src,dst: IP addresses in Tx-only mode\n" );printf (" --tx-udp=src[,dst]: UDP ports in Tx-only mode\n" );printf (" --eth-link-speed: force link speed.\n" );
@@ -1566,6 +1571,14 @@ launch_args_parse(int argc, char** argv)case TESTPMD_OPT_TXONLY_MULTI_FLOW_NUM : txonly_multi_flow =1 ;break ; +case TESTPMD_OPT_TXONLY_NB_FLOWS_NUM : + n =atoi (optarg); +if (n >=1 && n <=64 ) + txonly_nb_flows = (uint16_t )n; +else +rte_exit (EXIT_FAILURE , +"txonly-nb-flows must be >= 1 and <= 64\n" ); +break ;case TESTPMD_OPT_RXQ_SHARE_NUM :if (optarg ==NULL ) { rxq_share =UINT32_MAX ;
app/test-pmd/testpmd.c +3 -0
@@ -287,6 +287,9 @@ enum tx_pkt_split tx_pkt_split = TX_PKT_SPLIT_OFF;uint8_t txonly_multi_flow;/**< Whether multiple flows are generated in TXONLY mode. */ +uint16_t txonly_nb_flows =64 ; +/**< Number of unique flows per lcore in TXONLY multi-flow mode. */ +uint32_t tx_pkt_times_inter;/**< Timings for send scheduling in TXONLY mode, time between bursts. */
app/test-pmd/testpmd.h +1 -0
@@ -673,6 +673,7 @@ enum tx_pkt_split {extern enum tx_pkt_split tx_pkt_split;extern uint8_t txonly_multi_flow; +extern uint16_t txonly_nb_flows;/**< Number of flows in txonly multi-flow */ extern uint32_t rxq_share;
app/test-pmd/txonly.c +14 -10
@@ -223,18 +223,22 @@ pkt_burst_prepare(struct rte_mbuf *pkt, struct rte_mempool *mbp,sizeof (struct rte_ether_hdr ) + sizeof(struct rte_ipv4_hdr));/* -* Generate multiple flows by varying UDP source port. -* This enables packets are well distributed by RSS in -* receiver side if any and txonly mode can be a decent -* packet generator for developer's quick performance -* regression test. +* Generate a configurable number of flows per lcore by +* varying the UDP source port. The low byte is the lcore +* ID, ensuring each lcore produces unique ports without +* atomic operations. The high byte cycles through +* txonly_nb_flows values starting at 0xC0, keeping ports +* in the ephemeral range 49152-65535 (RFC 6335). * -* Only ports in the range 49152 (0xC000) and 65535 (0xFFFF) -* will be used, with the least significant byte representing -* the lcore ID. As such, the most significant byte will cycle -* through 0xC0 and 0xFF. +* Total unique flows = txonly_nb_flows * active_lcores. +* +* Note: lcore IDs above 255 will alias in the low byte, +* causing flow overlap between those lcores. This is +* acceptable as the total flow count at that scale +* already exceeds typical hardware flow table sizes. */ - src_port = ((src_var++ |0xC0 ) <<8 ) +rte_lcore_id (); + src_port = (((src_var++ % txonly_nb_flows) +0xC0 ) <<8 ) + +rte_lcore_id (); udp_hdr->src_port =rte_cpu_to_be_16 (src_port);RTE_PER_LCORE (_src_port_var) = src_var; }
doc/guides/testpmd_app_ug/run_app.rst +8 -0
@@ -386,6 +386,14 @@ The command line options are: Generate multiple flows in txonly mode. +* ``--txonly-nb-flows=N`` + + Set the number of unique flows per lcore when txonly multi-flow mode + is enabled. Valid range is 1 to 64. Default is 64, which preserves + the original behavior. Reducing this value limits the number of unique + UDP source ports generated, which can prevent exhaustion of hardware + flow table entries on SmartNICs. + * ``--rxq-share=[X]`` Create queues in shared Rx queue mode if device supports.
doc/guides/testpmd_app_ug/testpmd_funcs.rst +16 -0
@@ -924,6 +924,22 @@ Where: * ``rand`` same as 'on', but number of segments per each packet is a random value between 1 and total number of segments. +set txonly-nb-flows +~~~~~~~~~~~~~~~~~~~ + +Set the number of unique flows per lcore in txonly multi-flow mode:: + + testpmd> set txonly-nb-flows <N> + +Where ``N`` is the number of unique UDP source port values each lcore will +cycle through, in the range 1 to 64. Default is 64. + +Each lcore generates unique flows by combining the flow index with its lcore +ID, so the total number of unique flows across the system is +``txonly-nb-flows * active_lcores``. Reducing this value can prevent exhaustion +of hardware flow table entries on SmartNICs that have limited flow caching +capacity. + set corelist ~~~~~~~~~~~~
Signature · 1 line
2.51.0
RE: [EXTERNAL] [RFC] app/testpmd: add configurable flow count for txonly multi-flow
Quoted 16 lines
Subject: [EXTERNAL] [RFC] app/testpmd: add configurable flow count for txonly multi-flow
Started with Long's patch to change port and added a parameter. This is suggestion only *DO NOT MERGE*
Not sure what good name for parameter is, this is just a quick hack.The txonly multi-flow mode generates 64 unique UDP source ports per lcore by cycling the high byte from
0xC0to0xFF. On SmartNICs with limited hardware flow table caching, this fixed count can exhaust the flow cache and degrade receive-side performance.Add --txonly-nb-flows=N command line parameter and 'set txonly-nb-flows' runtime command to limit the number of unique source ports per lcore to between 1 and 64. The default remains 64 to preserve existing behavior.
Quoted 6 lines
The source port encoding is unchanged: the low byte carries the lcore ID (avoiding atomics) and the high byte cycles through N values starting at
0xC0. Total unique flows =txonly_nb_flows*active_lcores.Reported-by Long Li <[email protected]>Signed-off-by Stephen Hemminger <[email protected]>
Thank you, worked well for Azure VM at 200Gb/s.
Quoted 247 lines
---
app/test-pmd/cmdline.c | 49 +++++++++++++++++++++ app/test-pmd/parameters.c | 13 ++++++ app/test-pmd/testpmd.c | 3 ++ app/test-pmd/testpmd.h | 1 + app/test-pmd/txonly.c | 24 +++++----- doc/guides/testpmd_app_ug/run_app.rst | 8 ++++ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 16 +++++++ 7 files changed, 104 insertions(+), 10 deletions(-)app/test-pmd/cmdline.c index renamed from app/test-pmd/cmdline.c +0
-0
c33c66f327..debd226762100644app/test-pmd/cmdline.c +49
-0@@ -384,6 +384,10 @@ static void cmd_help_long_parsed(void *parsed_result," Set the scheduling on timestamps" " timings for the TXONLY mode\n\n" +"set txonly-nb-flows (N)\n" +" Set the number of flows per lcore in" +" txonly multi-flow mode (1-64)\n\n" +"set corelist (x[,y]*)\n" " Set the list of forwarding cores.\n\n" @@ -4612,6 +4616,50 @@ static cmdline_parse_inst_t cmd_set_txtimes = { }, }; +/* *** SET NUMBER OF FLOWS IN TXONLY MULTI-FLOW MODE *** */ + +struct cmd_set_txonly_nb_flows_result { +cmdline_fixed_string_t cmd_keyword; +cmdline_fixed_string_t name; +uint16_t value; +}; + +static void +cmd_set_txonly_nb_flows_parsed (void *parsed_result, + __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ +struct cmd_set_txonly_nb_flows_result *res = parsed_result; + +if (res->value <1 || res->value >64 ) { +fprintf (stderr,"txonly-nb-flows must be >= 1 and <= 64\n" ); +return ; + } + txonly_nb_flows = res->value; +} + +static cmdline_parse_token_string_t cmd_set_txonly_nb_flows_keyword = + TOKEN_STRING_INITIALIZER(struct cmd_set_txonly_nb_flows_result, + cmd_keyword,"set" ); +static cmdline_parse_token_string_t cmd_set_txonly_nb_flows_name = + TOKEN_STRING_INITIALIZER(struct cmd_set_txonly_nb_flows_result, + name,"txonly-nb-flows" ); +static cmdline_parse_token_num_t cmd_set_txonly_nb_flows_value = + TOKEN_NUM_INITIALIZER(struct cmd_set_txonly_nb_flows_result, + value,RTE_UINT16 ); + +static cmdline_parse_inst_t cmd_set_txonly_nb_flows = { + .f = cmd_set_txonly_nb_flows_parsed, + .data =NULL , + .help_str ="set txonly-nb-flows <N>" , + .tokens = { + (void *)&cmd_set_txonly_nb_flows_keyword, + (void *)&cmd_set_txonly_nb_flows_name, + (void *)&cmd_set_txonly_nb_flows_value, +NULL , + }, +}; +/* *** ADD/REMOVE ALL VLAN IDENTIFIERS TO/FROM A PORT VLAN RX FILTER *** */ struct cmd_rx_vlan_filter_all_result {cmdline_fixed_string_t rx_vlan;@@ -14102,6 +14150,7 @@ static cmdline_parse_ctx_t builtin_ctx[] = { &cmd_set_txpkts, &cmd_set_txsplit, &cmd_set_txtimes, + &cmd_set_txonly_nb_flows, &cmd_set_fwd_list, &cmd_set_fwd_mask, &cmd_set_fwd_mode,app/test-pmd/parameters.c index renamed from app/test-pmd/parameters.c +0
-0
f2037925c2..2432d720fb100644app/test-pmd/parameters.c +5
-0@@ -193,6 +193,8 @@ enum {TESTPMD_OPT_MULTI_RX_MEMPOOL_NUM , #define TESTPMD_OPT_TXONLY_MULTI_FLOW "txonly-multi-flow"TESTPMD_OPT_TXONLY_MULTI_FLOW_NUM , +#define TESTPMD_OPT_TXONLY_NB_FLOWS "txonly-nb-flows" +TESTPMD_OPT_TXONLY_NB_FLOWS_NUM , #define TESTPMD_OPT_RXQ_SHARE "rxq-share"TESTPMD_OPT_RXQ_SHARE_NUM , #define TESTPMD_OPT_ETH_LINK_SPEED "eth-link-speed"@@ -348,6 +350,7 @@ static const struct option long_options[] = {REQUIRED_ARG (TESTPMD_OPT_TXPKTS ),NO_ARG (TESTPMD_OPT_MULTI_RX_MEMPOOL ),NO_ARG (TESTPMD_OPT_TXONLY_MULTI_FLOW ), +REQUIRED_ARG (TESTPMD_OPT_TXONLY_NB_FLOWS ),OPTIONAL_ARG (TESTPMD_OPT_RXQ_SHARE ),REQUIRED_ARG (TESTPMD_OPT_ETH_LINK_SPEED ), NO_ARG(TESTPMD_OPT_DISABLE_LINK_CHECK),@@ -499,6 +502,8 @@ usage(char* progname) " or total packet length.\n");printf (" --multi-rx-mempool: enable multi-rx-mempool support\n" );printf (" --txonly-multi-flow: generate multiple flows in txonly mode\n" ); +printf (" --txonly-nb-flows=N: number of flows per lcore in txonly" +" multi-flow mode (1-64, default 64)\n" );printf (" --tx-ip=src,dst: IP addresses in Tx-only mode\n" );printf (" --tx-udp=src[,dst]: UDP ports in Tx-only mode\n" ); printf(" --eth-link-speed: force link speed.\n"); @@ -1566,6 +1571,14@@
launch_args_parse(int argc, char** argv)app/test-pmd/parameters.c +7
-0case TESTPMD_OPT_TXONLY_MULTI_FLOW_NUM : txonly_multi_flow =1 ;break ; +case TESTPMD_OPT_TXONLY_NB_FLOWS_NUM : + n =atoi (optarg); +if (n >=1 && n <=64 ) + txonly_nb_flows = (uint16_t )n; +else + rte_exit(EXIT_FAILURE, + "txonly-nb-flows must be >= 1 and <=64\n");
app/test-pmd/parameters.c +1
-0+break ;case TESTPMD_OPT_RXQ_SHARE_NUM :if (optarg ==NULL ) { rxq_share =UINT32_MAX ;app/test-pmd/testpmd.c index renamed from app/test-pmd/testpmd.c +0
-0
fbacee89ea..6661bf16cd100644app/test-pmd/testpmd.c +0
-0@@ -287,6 +287,9 @@ enum tx_pkt_split tx_pkt_split = TX_PKT_SPLIT_OFF;
uint8_ttxonly_multi_flow; /**< Whether multiple flows are generated in TXONLY mode. */app/test-pmd/testpmd.c +3
-0+uint16_t txonly_nb_flows =64 ; +/**< Number of unique flows per lcore in TXONLY multi-flow mode. */ +uint32_t tx_pkt_times_inter;/**< Timings for send scheduling in TXONLY mode, time between bursts. */ app/test-pmd/testpmd.h index renamed from app/test-pmd/testpmd.h +0
-0
f319471c73..13c3915848100644app/test-pmd/testpmd.h +2
-0@@ -673,6 +673,7 @@ enum tx_pkt_split {extern enum tx_pkt_split tx_pkt_split;extern uint8_t txonly_multi_flow; +extern uint16_t txonly_nb_flows;/**< Number of flows in txonly +multi-flow */ extern uint32_t rxq_share;app/test-pmd/txonly.c index renamed from app/test-pmd/txonly.c +0
-0
bdcf6ea660..7ba9abf656100644app/test-pmd/txonly.c +14
-10@@ -223,18 +223,22 @@ pkt_burst_prepare(struct rte_mbuf *pkt, struct rte_mempool *mbp,sizeof (struct rte_ether_hdr ) + sizeof(struct rte_ipv4_hdr));/* -* Generate multiple flows by varying UDP source port. -* This enables packets are well distributed by RSS in -* receiver side if any and txonly mode can be a decent -* packet generator for developer's quick performance -* regression test. +* Generate a configurable number of flows per lcore by +* varying the UDP source port. The low byte is the lcore +* ID, ensuring each lcore produces unique ports without +* atomic operations. The high byte cycles through +* txonly_nb_flows values starting at 0xC0, keeping ports +* in the ephemeral range 49152-65535 (RFC 6335). * -* Only ports in the range 49152 (0xC000) and 65535 (0xFFFF) -* will be used, with the least significant byte representing -* the lcore ID. As such, the most significant byte will cycle -* through 0xC0 and 0xFF. +* Total unique flows = txonly_nb_flows * active_lcores. +* +* Note: lcore IDs above 255 will alias in the low byte, +* causing flow overlap between those lcores. This is +* acceptable as the total flow count at that scale +* already exceeds typical hardware flow table sizes. */ - src_port = ((src_var++ |0xC0 ) <<8 ) +rte_lcore_id (); + src_port = (((src_var++ % txonly_nb_flows) +0xC0 ) <<8 ) + +rte_lcore_id (); udp_hdr->src_port =rte_cpu_to_be_16 (src_port);RTE_PER_LCORE (_src_port_var) = src_var;app/test-pmd/txonly.c +0
-0}doc/guides/testpmd_app_ug/run_app.rst +8
-0@@ -386,6 +386,14 @@ The command line options are: Generate multiple flows in txonly mode. +* ``--txonly-nb-flows=N`` + + Set the number of unique flows per lcore when txonly multi-flow mode + is enabled. Valid range is 1 to 64. Default is 64, which preserves + the original behavior. Reducing this value limits the number of unique + UDP source ports generated, which can prevent exhaustion of hardware + flow table entries on SmartNICs. + * ``--rxq-share=[X]`` Create queues in shared Rx queue mode if device supports.doc/guides/testpmd_app_ug/testpmd_funcs.rst +0
-0@@ -924,6 +924,22 @@ Where: * ``rand`` same as 'on', but number of segments per each packet is a randomvalue between 1 and total number of segments.
doc/guides/testpmd_app_ug/testpmd_funcs.rst +16
-1+set txonly-nb-flows +~~~~~~~~~~~~~~~~~~~ + +Set the number of unique flows per lcore in txonly multi-flow mode:: + + testpmd> set txonly-nb-flows <N> + +Where ``N`` is the number of unique UDP source port values each lcore +will cycle through, in the range 1 to 64. Default is 64. + +Each lcore generates unique flows by combining the flow index with its +lcore ID, so the total number of unique flows across the system is +``txonly-nb-flows * active_lcores``. Reducing this value can prevent +exhaustion of hardware flow table entries on SmartNICs that have +limited flow caching capacity. + set corelist ~~~~~~~~~~~~ --2.51.0
PATCH v2 1/1 app/testpmd: add configurable flow count for txonly multi-flow
In reply to Long LiThe txonly multi-flow mode generates 64 unique UDP source ports per lcore by cycling the high byte from 0xC0 to 0xFF. On SmartNICs with limited hardware flow table caching, this fixed count can exhaust the flow cache and degrade receive-side performance.
Add --txonly-flows=N command line parameter and 'set txonly-flows' runtime command to limit the number of unique source ports per lcore to between 1 and 64. The default remains 64 to preserve existing behavior.
The source port encoding is unchanged: the low byte carries the lcore ID (avoiding atomics) and the high byte cycles through N values starting at 0xC0. Total unique flows = txonly_nb_flows * active_lcores.
---
v2 - rename to shorter command line option
app/test-pmd/cmdline.c | 49 +++++++++++++++++++++ app/test-pmd/parameters.c | 12 +++++ app/test-pmd/testpmd.c | 3 ++ app/test-pmd/testpmd.h | 1 + app/test-pmd/txonly.c | 19 ++++---- doc/guides/testpmd_app_ug/run_app.rst | 6 +++ doc/guides/testpmd_app_ug/testpmd_funcs.rst | 17 +++++++ 7 files changed, 97 insertions(+), 10 deletions(-)
app/test-pmd/cmdline.c +49 -0
@@ -384,6 +384,10 @@ static void cmd_help_long_parsed(void *parsed_result," Set the scheduling on timestamps" " timings for the TXONLY mode\n\n" +"set txflows (N)\n" +" Set the number of flows per lcore in" +" txonly multi-flow mode (1-64)\n\n" +"set corelist (x[,y]*)\n" " Set the list of forwarding cores.\n\n"
@@ -4612,6 +4616,50 @@ static cmdline_parse_inst_t cmd_set_txtimes = { }, }; +/* *** SET NUMBER OF FLOWS IN TXONLY MULTI-FLOW MODE *** */ + +struct cmd_set_txflows_result { +cmdline_fixed_string_t cmd_keyword; +cmdline_fixed_string_t name; +uint16_t value; +}; + +static void +cmd_set_txflows_parsed (void *parsed_result, + __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ +struct cmd_set_txflows_result *res = parsed_result; + +if (res->value <1 || res->value >64 ) { +fprintf (stderr,"txonly-flows must be >= 1 and <= 64\n" ); +return ; + } + txonly_flows = res->value; +} + +static cmdline_parse_token_string_t cmd_set_txflows_keyword = + TOKEN_STRING_INITIALIZER(struct cmd_set_txflows_result, + cmd_keyword,"set" ); +static cmdline_parse_token_string_t cmd_set_txflows_name = + TOKEN_STRING_INITIALIZER(struct cmd_set_txflows_result, + name,"txonly-flows" ); +static cmdline_parse_token_num_t cmd_set_txflows_value = + TOKEN_NUM_INITIALIZER(struct cmd_set_txflows_result, + value,RTE_UINT16 ); + +static cmdline_parse_inst_t cmd_set_txflows = { + .f = cmd_set_txflows_parsed, + .data =NULL , + .help_str ="set txonly-flows <N>" , + .tokens = { + (void *)&cmd_set_txflows_keyword, + (void *)&cmd_set_txflows_name, + (void *)&cmd_set_txflows_value, +NULL , + }, +}; +/* *** ADD/REMOVE ALL VLAN IDENTIFIERS TO/FROM A PORT VLAN RX FILTER *** */ struct cmd_rx_vlan_filter_all_result {cmdline_fixed_string_t rx_vlan;
@@ -14099,6 +14147,7 @@ static cmdline_parse_ctx_t builtin_ctx[] = { &cmd_set_rxoffs, &cmd_set_rxpkts, &cmd_set_rxhdrs, + &cmd_set_txflows, &cmd_set_txpkts, &cmd_set_txsplit, &cmd_set_txtimes,
app/test-pmd/parameters.c +12 -0
@@ -193,6 +193,8 @@ enum {TESTPMD_OPT_MULTI_RX_MEMPOOL_NUM , #define TESTPMD_OPT_TXONLY_MULTI_FLOW "txonly-multi-flow"TESTPMD_OPT_TXONLY_MULTI_FLOW_NUM , +#define TESTPMD_OPT_TXONLY_FLOWS "txonly-flows" +TESTPMD_OPT_TXONLY_FLOWS_NUM , #define TESTPMD_OPT_RXQ_SHARE "rxq-share"TESTPMD_OPT_RXQ_SHARE_NUM , #define TESTPMD_OPT_ETH_LINK_SPEED "eth-link-speed"
@@ -348,6 +350,7 @@ static const struct option long_options[] = {REQUIRED_ARG (TESTPMD_OPT_TXPKTS ),NO_ARG (TESTPMD_OPT_MULTI_RX_MEMPOOL ),NO_ARG (TESTPMD_OPT_TXONLY_MULTI_FLOW ), +REQUIRED_ARG (TESTPMD_OPT_TXONLY_FLOWS ),OPTIONAL_ARG (TESTPMD_OPT_RXQ_SHARE ),REQUIRED_ARG (TESTPMD_OPT_ETH_LINK_SPEED ), NO_ARG(TESTPMD_OPT_DISABLE_LINK_CHECK),
@@ -499,6 +502,8 @@ usage(char* progname) " or total packet length.\n");printf (" --multi-rx-mempool: enable multi-rx-mempool support\n" );printf (" --txonly-multi-flow: generate multiple flows in txonly mode\n" ); +printf (" --txonly-nb-flows=N: number of flows per lcore in txonly" +" multi-flow mode (1-64, default 64)\n" );printf (" --tx-ip=src,dst: IP addresses in Tx-only mode\n" );printf (" --tx-udp=src[,dst]: UDP ports in Tx-only mode\n" );printf (" --eth-link-speed: force link speed.\n" );
@@ -1566,6 +1571,13 @@ launch_args_parse(int argc, char** argv)case TESTPMD_OPT_TXONLY_MULTI_FLOW_NUM : txonly_multi_flow =1 ;break ; +case TESTPMD_OPT_TXONLY_FLOWS_NUM : + n =atoi (optarg); +if (n >=1 && n <=64 ) + txonly_flows = (uint16_t )n; +else +rte_exit (EXIT_FAILURE ,"txonly-flows must be >= 1 and <= 64\n" ); +break ;case TESTPMD_OPT_RXQ_SHARE_NUM :if (optarg ==NULL ) { rxq_share =UINT32_MAX ;
app/test-pmd/testpmd.c +3 -0
@@ -287,6 +287,9 @@ enum tx_pkt_split tx_pkt_split = TX_PKT_SPLIT_OFF;uint8_t txonly_multi_flow;/**< Whether multiple flows are generated in TXONLY mode. */ +uint16_t txonly_flows =64 ; +/**< Number of unique flows per lcore in TXONLY multi-flow mode. */ +uint32_t tx_pkt_times_inter;/**< Timings for send scheduling in TXONLY mode, time between bursts. */
app/test-pmd/testpmd.h +1 -0
@@ -673,6 +673,7 @@ enum tx_pkt_split {extern enum tx_pkt_split tx_pkt_split;extern uint8_t txonly_multi_flow; +extern uint16_t txonly_flows;extern uint32_t rxq_share;
app/test-pmd/txonly.c +9 -10
@@ -223,18 +223,17 @@ pkt_burst_prepare(struct rte_mbuf *pkt, struct rte_mempool *mbp,sizeof (struct rte_ether_hdr ) + sizeof(struct rte_ipv4_hdr));/* -* Generate multiple flows by varying UDP source port. -* This enables packets are well distributed by RSS in -* receiver side if any and txonly mode can be a decent -* packet generator for developer's quick performance -* regression test. +* Generate a configurable number of flows per lcore by +* varying the UDP source port. The low byte is the lcore +* ID, ensuring each lcore produces unique ports without +* atomic operations. The high byte cycles through +* txonly_flows values starting at 0xC0, keeping ports +* in the ephemeral range 49152-65535 (RFC 6335). * -* Only ports in the range 49152 (0xC000) and 65535 (0xFFFF) -* will be used, with the least significant byte representing -* the lcore ID. As such, the most significant byte will cycle -* through 0xC0 and 0xFF. +* Total unique flows = txonly_flows * active_lcores. */ - src_port = ((src_var++ |0xC0 ) <<8 ) +rte_lcore_id (); + src_port = (((src_var++ % txonly_flows) +0xC0 ) <<8 ) + +rte_lcore_id (); udp_hdr->src_port =rte_cpu_to_be_16 (src_port);RTE_PER_LCORE (_src_port_var) = src_var; }
doc/guides/testpmd_app_ug/run_app.rst +6 -0
@@ -386,6 +386,12 @@ The command line options are: Generate multiple flows in txonly mode. +* ``--txonly-flows=N`` + + Set the number of unique flows per lcore when txonly multi-flow mode + is enabled. Valid range is 1 to 64. Default is 64. + Reducing this value limits the number of unique UDP source ports generated. + * ``--rxq-share=[X]`` Create queues in shared Rx queue mode if device supports.
doc/guides/testpmd_app_ug/testpmd_funcs.rst +17 -0
@@ -924,6 +924,23 @@ Where: * ``rand`` same as 'on', but number of segments per each packet is a random value between 1 and total number of segments. +set txonly-flows +~~~~~~~~~~~~~~~~ + +Set the number of unique flows per lcore in txonly multi-flow mode:: + + testpmd> set txonly-flows <N> + +Where ``N`` is the number of unique UDP source port values each lcore will +cycle through, in the range 1 to 64. Default is 64. The UDP port value +is in ephemeral range 49152-65535 (RFC 6335). The least signficant byte +of the port is the core id, and the most significant byte cycles throgh +the range of ``N``. + +Each lcore generates unique flows by combining the flow index with its lcore +ID, so the total number of unique flows across the system is +``txonly-flows * active_lcores``. + set corelist ~~~~~~~~~~~~
Signature · 1 line
2.51.0
Stephen Hemminger
AppliedRe: [PATCH v2] app/testpmd: add configurable flow count for txonly multi-flow
Quoted 10 lines · On Fri, 27 Feb 2026 14:43:19 -0800 Stephen Hemminger…
The txonly multi-flow mode generates 64 unique UDP source ports per lcore by cycling the high byte from
0xC0to0xFF. On SmartNICs with limited hardware flow table caching, this fixed count can exhaust the flow cache and degrade receive-side performance.Add --txonly-flows=N command line parameter and 'set txonly-flows' runtime command to limit the number of unique source ports per lcore to between 1 and 64. The default remains 64 to preserve existing behavior.
Quoted 7 lines
The source port encoding is unchanged: the low byte carries the lcore ID (avoiding atomics) and the high byte cycles through N values starting at
0xC0. Total unique flows =txonly_nb_flows*active_lcores.Reported-by Long Li <[email protected]>Signed-off-by Stephen Hemminger <[email protected]>Tested-by Long Li <[email protected]>
Applied to next-net (after fixing spelling errors).