testpmd: add hairpin-map parameter
PATCH 1/1 testpmd: add hairpin-map parameter
Testpmd hairpin implementation always sets the next valid port to complete hairpin binding. That limits hairpin configuration options.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The new hairpin-map parameter is provided with 5 parameters, separated by :
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number
Testpmd operator can provide several hairpin-map parameters for different hairpin maps.
Example:
dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]
Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.
The new hairpin-map parameter is optional. If omitted, testpmd will create "default" hairpin maps.
--- app/test-pmd/parameters.c | 63 ++++++++ app/test-pmd/testpmd.c | 212 ++++++++++++++++++-------- app/test-pmd/testpmd.h | 18 +++ doc/guides/testpmd_app_ug/run_app.rst | 3 + 4 files changed, 230 insertions(+), 66 deletions(-)
app/test-pmd/parameters.c +63 -0
@@ -206,6 +206,12 @@ usage(char* progname)printf (" --hairpin-mode=0xXX: bitmask set the hairpin port mode.\n" " 0x10 - explicit Tx rule, 0x02 - hairpin ports paired\n" " 0x01 - hairpin ports loop, 0x00 - hairpin port self\n" ); +printf (" --hairpin-map=rxpi:rxq:txpi:txq:n: hairpin map.\n" +" rxpi - Rx port index.\n" +" rxq - Rx queue.\n" +" txpi - Tx port index.\n" +" txq - Tx queue.\n" +" n - hairpin queues number.\n" ); }#ifdef RTE_LIB_CMDLINE
@@ -588,6 +594,55 @@ parse_link_speed(int n)return speed; } +static __rte_always_inline +char *parse_hairpin_map_entry(char *input, char **next) +{ +char *tail =strchr (input,':' ); + +if (!tail) +return NULL ; + tail[0 ] ='\0' ; + *next = tail +1 ; +return input; +} + +static int +parse_hairpin_map (char *hpmap) +{ +/* +* Testpmd hairpin map format: +* <Rx port id:First Rx queue:Tx port id:First Tx queue:queues number> +*/ +char *head, *next = hpmap; +struct hairpin_map *map =calloc (1 ,sizeof (*map)); + +if (!map) +return -ENOMEM ; + + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->rx_port =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->rxq_head =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->tx_port =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->txq_head =atoi (head); + map->qnum =atoi (next); +hairpin_add_multiport_map (map); +return 0 ; +err: +free (map); +return -EINVAL ; +} +void launch_args_parse (int argc,char ** argv) {
@@ -663,6 +718,7 @@ launch_args_parse(int argc, char** argv) { "txd", 1, 0, 0 }, { "hairpinq", 1, 0, 0 }, { "hairpin-mode", 1, 0, 0 }, + { "hairpin-map", 1, 0, 0 }, { "burst", 1, 0, 0 }, { "flowgen-clones", 1, 0, 0 }, { "flowgen-flows", 1, 0, 0 },
@@ -1111,6 +1167,13 @@ launch_args_parse(int argc, char** argv)else hairpin_mode = (uint32_t )n; } +if (!strcmp (lgopts[opt_idx].name,"hairpin-map" )) { + hairpin_multiport_mode = true; + ret =parse_hairpin_map (optarg); +if (ret) +rte_exit (EXIT_FAILURE ,"invalid hairpin map\n" ); + + }if (!strcmp (lgopts[opt_idx].name,"burst" )) { n =atoi (optarg);if (n ==0 ) {
app/test-pmd/testpmd.c +146 -66
259 lines not on this page · raw message
app/test-pmd/testpmd.h +18 -0
@@ -125,6 +125,24 @@ enum noisy_fwd_mode { NOISY_FWD_MODE_MAX, }; +struct hairpin_map { +LIST_ENTRY (hairpin_map) entry;/**< List entry. */ +portid_t rx_port;/**< Hairpin Rx port ID. */ +portid_t tx_port;/**< Hairpin Tx port ID. */ +uint16_t rxq_head;/**< Hairpin Rx queue head. */ +uint16_t txq_head;/**< Hairpin Tx queue head. */ +uint16_t qnum;/**< Hairpin queues number. */ +}; + +/** +* Command line arguments parser sets `hairpin_multiport_mode` to True +* if explicit hairpin map configuration mode was used. +*/ +extern bool hairpin_multiport_mode; + +/** Hairpin maps list. */ +extern void hairpin_add_multiport_map (struct hairpin_map *map); +/** * The data structure associated with RX and TX packet burst statistics * that are recorded for each forwarding stream.
doc/guides/testpmd_app_ug/run_app.rst +3 -0
@@ -566,6 +566,9 @@ The command line options are: The default value is 0. Hairpin will use single port mode and implicit Tx flow mode. +* ``--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number`` + + Set explicit hairpin configuration. Testpmd Multi-Process Command-line Options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Signature · 1 line
2.39.2
PATCH v2 1/1 testpmd: add hairpin-map parameter
Testpmd hairpin implementation always sets the next valid port to complete hairpin binding. That limits hairpin configuration options.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The new hairpin-map parameter is provided with 5 parameters, separated by :
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number
Testpmd operator can provide several hairpin-map parameters for different hairpin maps.
Example:
dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]
Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.
The new hairpin-map parameter is optional. If omitted, testpmd will create "default" hairpin maps.
---
v2: fix Windows Server 2019 compilation failure.
--- app/test-pmd/parameters.c | 63 ++++++++ app/test-pmd/testpmd.c | 212 ++++++++++++++++++-------- app/test-pmd/testpmd.h | 18 +++ doc/guides/testpmd_app_ug/run_app.rst | 3 + 4 files changed, 230 insertions(+), 66 deletions(-)
app/test-pmd/parameters.c +63 -0
@@ -206,6 +206,12 @@ usage(char* progname)printf (" --hairpin-mode=0xXX: bitmask set the hairpin port mode.\n" " 0x10 - explicit Tx rule, 0x02 - hairpin ports paired\n" " 0x01 - hairpin ports loop, 0x00 - hairpin port self\n" ); +printf (" --hairpin-map=rxpi:rxq:txpi:txq:n: hairpin map.\n" +" rxpi - Rx port index.\n" +" rxq - Rx queue.\n" +" txpi - Tx port index.\n" +" txq - Tx queue.\n" +" n - hairpin queues number.\n" ); }#ifdef RTE_LIB_CMDLINE
@@ -588,6 +594,55 @@ parse_link_speed(int n)return speed; } +static __rte_always_inline +char *parse_hairpin_map_entry(char *input, char **next) +{ +char *tail =strchr (input,':' ); + +if (!tail) +return NULL ; + tail[0 ] ='\0' ; + *next = tail +1 ; +return input; +} + +static int +parse_hairpin_map (const char *hpmap) +{ +/* +* Testpmd hairpin map format: +* <Rx port id:First Rx queue:Tx port id:First Tx queue:queues number> +*/ +char *head, *next = (char *)(uintptr_t )hpmap; +struct hairpin_map *map =calloc (1 ,sizeof (*map)); + +if (!map) +return -ENOMEM ; + + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->rx_port =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->rxq_head =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->tx_port =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->txq_head =atoi (head); + map->qnum =atoi (next); +hairpin_add_multiport_map (map); +return 0 ; +err: +free (map); +return -EINVAL ; +} +void launch_args_parse (int argc,char ** argv) {
@@ -663,6 +718,7 @@ launch_args_parse(int argc, char** argv) { "txd", 1, 0, 0 }, { "hairpinq", 1, 0, 0 }, { "hairpin-mode", 1, 0, 0 }, + { "hairpin-map", 1, 0, 0 }, { "burst", 1, 0, 0 }, { "flowgen-clones", 1, 0, 0 }, { "flowgen-flows", 1, 0, 0 },
@@ -1111,6 +1167,13 @@ launch_args_parse(int argc, char** argv)else hairpin_mode = (uint32_t )n; } +if (!strcmp (lgopts[opt_idx].name,"hairpin-map" )) { + hairpin_multiport_mode = true; + ret =parse_hairpin_map (optarg); +if (ret) +rte_exit (EXIT_FAILURE ,"invalid hairpin map\n" ); + + }if (!strcmp (lgopts[opt_idx].name,"burst" )) { n =atoi (optarg);if (n ==0 ) {
app/test-pmd/testpmd.c +146 -66
259 lines not on this page · raw message
app/test-pmd/testpmd.h +18 -0
@@ -125,6 +125,24 @@ enum noisy_fwd_mode { NOISY_FWD_MODE_MAX, }; +struct hairpin_map { +LIST_ENTRY (hairpin_map) entry;/**< List entry. */ +portid_t rx_port;/**< Hairpin Rx port ID. */ +portid_t tx_port;/**< Hairpin Tx port ID. */ +uint16_t rxq_head;/**< Hairpin Rx queue head. */ +uint16_t txq_head;/**< Hairpin Tx queue head. */ +uint16_t qnum;/**< Hairpin queues number. */ +}; + +/** +* Command line arguments parser sets `hairpin_multiport_mode` to True +* if explicit hairpin map configuration mode was used. +*/ +extern bool hairpin_multiport_mode; + +/** Hairpin maps list. */ +extern void hairpin_add_multiport_map (struct hairpin_map *map); +/** * The data structure associated with RX and TX packet burst statistics * that are recorded for each forwarding stream.
doc/guides/testpmd_app_ug/run_app.rst +3 -0
@@ -566,6 +566,9 @@ The command line options are: The default value is 0. Hairpin will use single port mode and implicit Tx flow mode. +* ``--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number`` + + Set explicit hairpin configuration. Testpmd Multi-Process Command-line Options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Signature · 1 line
2.39.2
PATCH v3 1/1 testpmd: add hairpin-map parameter
In reply to Gregory EtelsonHairpin offloads packet forwarding between ports. Packet is expected on Rx port <rp>, Rx queue <rq> and is delivered to Tx port <tp> Tx queue <tq>.
Testpmd implements a static hairpin configuration scheme. The scheme implicitly matches next valid port for given <rp> or <tp>. That approach can be used in a single or double port setups only.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The new hairpin-map parameter is provided with 5 parameters, separated by :
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number
Testpmd operator can provide several hairpin-map parameters for different hairpin maps.
Example:
dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]
Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.
The new hairpin-map parameter is optional. If omitted, testpmd will create "default" hairpin maps.
---
v2: Fix Windows Server 2019 compilation failure.
v3: Update the patch comment.
Fix typo.
--- app/test-pmd/parameters.c | 63 ++++++++ app/test-pmd/testpmd.c | 212 ++++++++++++++++++-------- app/test-pmd/testpmd.h | 18 +++ doc/guides/testpmd_app_ug/run_app.rst | 3 + 4 files changed, 230 insertions(+), 66 deletions(-)
app/test-pmd/parameters.c +63 -0
@@ -206,6 +206,12 @@ usage(char* progname)printf (" --hairpin-mode=0xXX: bitmask set the hairpin port mode.\n" " 0x10 - explicit Tx rule, 0x02 - hairpin ports paired\n" " 0x01 - hairpin ports loop, 0x00 - hairpin port self\n" ); +printf (" --hairpin-map=rxpi:rxq:txpi:txq:n: hairpin map.\n" +" rxpi - Rx port index.\n" +" rxq - Rx queue.\n" +" txpi - Tx port index.\n" +" txq - Tx queue.\n" +" n - hairpin queues number.\n" ); }#ifdef RTE_LIB_CMDLINE
@@ -588,6 +594,55 @@ parse_link_speed(int n)return speed; } +static __rte_always_inline +char *parse_hairpin_map_entry(char *input, char **next) +{ +char *tail =strchr (input,':' ); + +if (!tail) +return NULL ; + tail[0 ] ='\0' ; + *next = tail +1 ; +return input; +} + +static int +parse_hairpin_map (const char *hpmap) +{ +/* +* Testpmd hairpin map format: +* <Rx port id:First Rx queue:Tx port id:First Tx queue:queues number> +*/ +char *head, *next = (char *)(uintptr_t )hpmap; +struct hairpin_map *map =calloc (1 ,sizeof (*map)); + +if (!map) +return -ENOMEM ; + + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->rx_port =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->rxq_head =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->tx_port =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->txq_head =atoi (head); + map->qnum =atoi (next); +hairpin_add_multiport_map (map); +return 0 ; +err: +free (map); +return -EINVAL ; +} +void launch_args_parse (int argc,char ** argv) {
@@ -663,6 +718,7 @@ launch_args_parse(int argc, char** argv) { "txd", 1, 0, 0 }, { "hairpinq", 1, 0, 0 }, { "hairpin-mode", 1, 0, 0 }, + { "hairpin-map", 1, 0, 0 }, { "burst", 1, 0, 0 }, { "flowgen-clones", 1, 0, 0 }, { "flowgen-flows", 1, 0, 0 },
@@ -1111,6 +1167,13 @@ launch_args_parse(int argc, char** argv)else hairpin_mode = (uint32_t )n; } +if (!strcmp (lgopts[opt_idx].name,"hairpin-map" )) { + hairpin_multiport_mode = true; + ret =parse_hairpin_map (optarg); +if (ret) +rte_exit (EXIT_FAILURE ,"invalid hairpin map\n" ); + + }if (!strcmp (lgopts[opt_idx].name,"burst" )) { n =atoi (optarg);if (n ==0 ) {
app/test-pmd/testpmd.c +146 -66
259 lines not on this page · raw message
app/test-pmd/testpmd.h +18 -0
@@ -125,6 +125,24 @@ enum noisy_fwd_mode { NOISY_FWD_MODE_MAX, }; +struct hairpin_map { +LIST_ENTRY (hairpin_map) entry;/**< List entry. */ +portid_t rx_port;/**< Hairpin Rx port ID. */ +portid_t tx_port;/**< Hairpin Tx port ID. */ +uint16_t rxq_head;/**< Hairpin Rx queue head. */ +uint16_t txq_head;/**< Hairpin Tx queue head. */ +uint16_t qnum;/**< Hairpin queues number. */ +}; + +/** +* Command line arguments parser sets `hairpin_multiport_mode` to True +* if explicit hairpin map configuration mode was used. +*/ +extern bool hairpin_multiport_mode; + +/** Hairpin maps list. */ +extern void hairpin_add_multiport_map (struct hairpin_map *map); +/** * The data structure associated with RX and TX packet burst statistics * that are recorded for each forwarding stream.
doc/guides/testpmd_app_ug/run_app.rst +3 -0
@@ -566,6 +566,9 @@ The command line options are: The default value is 0. Hairpin will use single port mode and implicit Tx flow mode. +* ``--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number`` + + Set explicit hairpin configuration. Testpmd Multi-Process Command-line Options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Signature · 1 line
2.39.2
Quoted 33 lines
Subject: [PATCH v3] testpmd: add hairpin-map parameter
Hairpin offloads packet forwarding between ports.
Packet is expected on Rx port <rp>, Rx queue <rq> and is delivered to Tx port <tp> Tx queue <tq>.Testpmd implements a static hairpin configuration scheme. The scheme implicitly matches next valid port for given <rp> or <tp>. That approach can be used in a single or double port setups only.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The newhairpin-mapparameter is provided with 5 parameters, separated by:
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues numberTestpmd operator can provide several
hairpin-mapparameters for different hairpin maps.
Example:dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.
Quoted 4 lines
The new
hairpin-mapparameter is optional. If omitted, testpmd will create "default" hairpin maps.Signed-off-by Gregory Etelson <[email protected]>
Best regards,
Dariusz Sosnowski
Quoted 25 lines · Gregory Etelson
Hairpin offloads packet forwarding between ports. Packet is expected on Rx port <rp>, Rx queue <rq> and is delivered to Tx port <tp> Tx queue <tq>.
Testpmd implements a static hairpin configuration scheme. The scheme implicitly matches next valid port for given <rp> or <tp>. That approach can be used in a single or double port setups only.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The newhairpin-mapparameter is provided with 5 parameters, separated by:
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues numberTestpmd operator can provide several
hairpin-mapparameters for different hairpin maps.
Example:dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]
Quoted 9 lines
Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.The new
hairpin-mapparameter is optional. If omitted, testpmd will create "default" hairpin maps.
Hi Gregory,
This patch is waiting for a while in the patchwork, not because there is a problem with the implementation, but I have a feeling that it is bloating the testpmd code with the hairpin feature which is not commonly supported, and I don't know what to do.
Also there was no review on the code ...
As a brainstorm, what do you think move hairpin related code to its own file, and have a kind of register logic to the commands, argument parsing and usage() functions etc.
@David did something similar to move PMD specific testpmd code to the drivers [1].
This can be initial steps for the more modular testpmd design and we can introduce more features with this approach in the future, I think hairpin support is a good instance to start this work, because of its limited impact to users.
[1]
Commit 592ab76f9f0f ("app/testpmd: register driver specific commands") Commit 94b3c1a72507 ("net/i40e: move testpmd commands")
Quoted 17 lines
Signed-off-by Gregory Etelson <[email protected]>---
v2: Fix Windows Server 2019 compilation failure.
v3: Update the patch comment.
Fix typo.--- app/test-pmd/parameters.c | 63 ++++++++ app/test-pmd/testpmd.c | 212 ++++++++++++++++++-------- app/test-pmd/testpmd.h | 18 +++ doc/guides/testpmd_app_ug/run_app.rst | 3 + 4 files changed, 230 insertions(+), 66 deletions(-)app/test-pmd/parameters.c +0
-0
app/test-pmd/parameters.c usage(char* progname) · line 215
Quoted 10 lines
app/test-pmd/parameters.c +6
-0@@ -206,6 +206,12 @@ usage(char* progname)printf (" --hairpin-mode=0xXX: bitmask set the hairpin port mode.\n" " 0x10 - explicit Tx rule, 0x02 - hairpin ports paired\n" " 0x01 - hairpin ports loop, 0x00 - hairpin port self\n" ); +printf (" --hairpin-map=rxpi:rxq:txpi:txq:n: hairpin map.\n" +" rxpi - Rx port index.\n" +" rxq - Rx queue.\n" +" txpi - Tx port index.\n" +" txq - Tx queue.\n" +" n - hairpin queues number.\n" );
'rxpi' or 'port index' are not common usage in DPDK, what about 'rx_port' & 'Rx port id' or similar?
app/test-pmd/parameters.c parse_link_speed(int n) · line 600
Quoted 11 lines
app/test-pmd/parameters.c +0
-0}#ifdef
RTE_LIB_CMDLINEapp/test-pmd/parameters.c +3
-0@@ -588,6 +594,55 @@ parse_link_speed(int n)return speed; } +static __rte_always_inline +char *parse_hairpin_map_entry(char *input, char **next) +{
Why forcing this function to be inline, can make it static and left decision to compiler.
<...>
doc/guides/testpmd_app_ug/run_app.rst The command line options are: · line 572
Quoted 12 lines
doc/guides/testpmd_app_ug/run_app.rst +3
-0@@ -566,6 +566,9 @@ The command line options are: The default value is 0. Hairpin will use single port mode and implicit Tx flow mode. +* ``--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number`` + + Set explicit hairpin configuration.
What 'queues number' does is not intuitive, sample in the commit log makes it easier to understand.
Can you please either explain or provide sample to clarify what "queues number" is for?
Hello Ferruh,
As a brainstorm, what do you think move hairpin related code to its own file, and have a kind of register logic to the commands, argument parsing and usage() functions etc.
Please consider an option for the testpmd to dynamically add supported commands. Testpmd can still provide some build-in core functionality, but custom test commands can be added and removed on demand.
In addition, the custom command code does not have to be part of the testpmd. That will reduce maintanance.
Regards,
Gregory
________________________________
From: Ferruh Yigit <[email protected]>
Sent: Friday, March 1, 2024 20:54
To: Gregory Etelson <[email protected]>; [email protected] <[email protected]>
Cc: Maayan Kashani <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Aman Singh <[email protected]>; Yuying Zhang <[email protected]>; David Marchand <[email protected]>
Subject: Re: [PATCH v3] testpmd: add hairpin-map parameter
External email: Use caution opening links or attachments
Quoted 25 lines · Gregory Etelson
Hairpin offloads packet forwarding between ports. Packet is expected on Rx port <rp>, Rx queue <rq> and is delivered to Tx port <tp> Tx queue <tq>.
Testpmd implements a static hairpin configuration scheme. The scheme implicitly matches next valid port for given <rp> or <tp>. That approach can be used in a single or double port setups only.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The newhairpin-mapparameter is provided with 5 parameters, separated by:
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues numberTestpmd operator can provide several
hairpin-mapparameters for different hairpin maps.
Example:dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]
Quoted 9 lines
Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.The new
hairpin-mapparameter is optional. If omitted, testpmd will create "default" hairpin maps.
Hi Gregory,
This patch is waiting for a while in the patchwork, not because there is a problem with the implementation, but I have a feeling that it is bloating the testpmd code with the hairpin feature which is not commonly supported, and I don't know what to do.
Also there was no review on the code ...
As a brainstorm, what do you think move hairpin related code to its own file, and have a kind of register logic to the commands, argument parsing and usage() functions etc.
@David did something similar to move PMD specific testpmd code to the drivers [1].
This can be initial steps for the more modular testpmd design and we can introduce more features with this approach in the future, I think hairpin support is a good instance to start this work, because of its limited impact to users.
[1]
Commit 592ab76f9f0f ("app/testpmd: register driver specific commands") Commit 94b3c1a72507 ("net/i40e: move testpmd commands")
Quoted 17 lines
Signed-off-by Gregory Etelson <[email protected]>---
v2: Fix Windows Server 2019 compilation failure.
v3: Update the patch comment.
Fix typo.--- app/test-pmd/parameters.c | 63 ++++++++ app/test-pmd/testpmd.c | 212 ++++++++++++++++++-------- app/test-pmd/testpmd.h | 18 +++ doc/guides/testpmd_app_ug/run_app.rst | 3 + 4 files changed, 230 insertions(+), 66 deletions(-)app/test-pmd/parameters.c +0
-0
app/test-pmd/parameters.c usage(char* progname) · line 215
Quoted 10 lines
app/test-pmd/parameters.c +6
-0@@ -206,6 +206,12 @@ usage(char* progname)printf (" --hairpin-mode=0xXX: bitmask set the hairpin port mode.\n" " 0x10 - explicit Tx rule, 0x02 - hairpin ports paired\n" " 0x01 - hairpin ports loop, 0x00 - hairpin port self\n" ); +printf (" --hairpin-map=rxpi:rxq:txpi:txq:n: hairpin map.\n" +" rxpi - Rx port index.\n" +" rxq - Rx queue.\n" +" txpi - Tx port index.\n" +" txq - Tx queue.\n" +" n - hairpin queues number.\n" );
'rxpi' or 'port index' are not common usage in DPDK, what about 'rx_port' & 'Rx port id' or similar?
app/test-pmd/parameters.c parse_link_speed(int n) · line 600
Quoted 11 lines
app/test-pmd/parameters.c +0
-0}#ifdef
RTE_LIB_CMDLINEapp/test-pmd/parameters.c +3
-0@@ -588,6 +594,55 @@ parse_link_speed(int n)return speed; } +static __rte_always_inline +char *parse_hairpin_map_entry(char *input, char **next) +{
Why forcing this function to be inline, can make it static and left decision to compiler.
<...>
doc/guides/testpmd_app_ug/run_app.rst The command line options are: · line 572
Quoted 12 lines
doc/guides/testpmd_app_ug/run_app.rst +3
-0@@ -566,6 +566,9 @@ The command line options are: The default value is 0. Hairpin will use single port mode and implicit Tx flow mode. +* ``--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number`` + + Set explicit hairpin configuration.
What 'queues number' does is not intuitive, sample in the commit log makes it easier to understand.
Can you please either explain or provide sample to clarify what "queues number" is for?
PATCH v5 1/1 testpmd: add hairpin-map parameter
In reply to Ferruh YigitHairpin offloads packet forwarding between ports. Packet is expected on Rx port <rp>, Rx queue <rq> and is forwarded to Tx port <tp> Tx queue <tq>.
Testpmd implements a static hairpin configuration scheme.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The new hairpin-map parameter is provided with 5 parameters, separated by :
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number
Testpmd operator can provide several hairpin-map parameters for different hairpin maps.
Example:
dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]
Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.
The new hairpin-map parameter is optional. If omitted, testpmd will create "default" hairpin maps.
--- app/test-pmd/hairpin.c | 386 ++++++++++++++++++++++++++ app/test-pmd/meson.build | 1 + app/test-pmd/parameters.c | 10 + app/test-pmd/testpmd.c | 217 +-------------- app/test-pmd/testpmd.h | 14 + doc/guides/testpmd_app_ug/run_app.rst | 3 + 6 files changed, 417 insertions(+), 214 deletions(-) create mode 100644 app/test-pmd/hairpin.c
app/test-pmd/hairpin.c new file +386 -0
@@ -0,0 +1,386 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright (c) 2022 NVIDIA Corporation & Affiliates +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <stdint.h> + +#include <sys/queue.h> + +#include "testpmd.h" + +/* Hairpin ports configuration mode. */ +uint32_t hairpin_mode; + +bool hairpin_multiport_mode = false; + +queueid_t nb_hairpinq;/**< Number of hairpin queues per port. */ + +static LIST_HEAD(, hairpin_map) hairpin_map_head = LIST_HEAD_INITIALIZER(); + +struct hairpin_map { +LIST_ENTRY (hairpin_map) entry;/**< List entry. */ +portid_t rx_port;/**< Hairpin Rx port ID. */ +portid_t tx_port;/**< Hairpin Tx port ID. */ +uint16_t rxq_head;/**< Hairpin Rx queue head. */ +uint16_t txq_head;/**< Hairpin Tx queue head. */ +uint16_t qnum;/**< Hairpin queues number. */ +}; + +void +hairpin_add_multiport_map (struct hairpin_map *map) +{ +LIST_INSERT_HEAD (&hairpin_map_head, map, entry); +} + +/* +* Get the allowed maximum number of hairpin queues. +* *pid return the port id which has minimal value of +* max_hairpin_queues in all ports. +*/ +queueid_t +get_allowed_max_nb_hairpinq (portid_t *pid) +{ +queueid_t allowed_max_hairpinq =RTE_MAX_QUEUES_PER_PORT ; +portid_t pi; +struct rte_eth_hairpin_cap cap; + +RTE_ETH_FOREACH_DEV (pi) { +if (rte_eth_dev_hairpin_capability_get (pi, &cap) !=0 ) { + *pid = pi; +return 0 ; + } +if (cap.max_nb_queues < allowed_max_hairpinq) { + allowed_max_hairpinq = cap.max_nb_queues; + *pid = pi; + } + } +return allowed_max_hairpinq; +} + +/* +* Check input hairpin is valid or not. +* If input hairpin is not greater than any of maximum number +* of hairpin queues of all ports, it is valid. +* if valid, return 0, else return -1 +*/ +int +check_nb_hairpinq (queueid_t hairpinq) +{ +queueid_t allowed_max_hairpinq; +portid_t pid =0 ; + + allowed_max_hairpinq =get_allowed_max_nb_hairpinq (&pid); +if (hairpinq > allowed_max_hairpinq) { +fprintf (stderr, +"Fail: input hairpin (%u) can't be greater than max_hairpin_queues (%u) of port %u\n" , + hairpinq, allowed_max_hairpinq, pid); +return -1 ; + } +return 0 ; +} + +#define HAIRPIN_MODE_RX_FORCE_MEMORY RTE_BIT32(8) +#define HAIRPIN_MODE_TX_FORCE_MEMORY RTE_BIT32(9) + +#define HAIRPIN_MODE_RX_LOCKED_MEMORY RTE_BIT32(12) +#define HAIRPIN_MODE_RX_RTE_MEMORY RTE_BIT32(13) + +#define HAIRPIN_MODE_TX_LOCKED_MEMORY RTE_BIT32(16) +#define HAIRPIN_MODE_TX_RTE_MEMORY RTE_BIT32(17) + +static int +port_config_hairpin_rxq (portid_t pi,uint16_t peer_tx_port, +queueid_t rxq_head,queueid_t txq_head, +uint16_t qcount,uint32_t manual_bind) +{ +int diag; +queueid_t i, qi; +uint32_t tx_explicit = !!(hairpin_mode &0x10 ); +uint32_t force_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_FORCE_MEMORY ); +uint32_t locked_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_LOCKED_MEMORY ); +uint32_t rte_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_RTE_MEMORY ); +struct rte_port *port = &ports[pi]; +struct rte_eth_hairpin_conf hairpin_conf = { + .peer_count =1 , + }; + +for (qi = rxq_head, i =0 ; qi < rxq_head + qcount; qi++) { + hairpin_conf.peers[0 ].port = peer_tx_port; + hairpin_conf.peers[0 ].queue = i + txq_head; + hairpin_conf.manual_bind = manual_bind; + hairpin_conf.tx_explicit = tx_explicit; + hairpin_conf.force_memory = force_mem; + hairpin_conf.use_locked_device_memory = locked_mem; + hairpin_conf.use_rte_memory = rte_mem; + diag =rte_eth_rx_hairpin_queue_setup + (pi, qi, nb_rxd, &hairpin_conf); + i++; +if (diag ==0 ) +continue ; + +/* Fail to setup rx queue, return */ +if (port->port_status ==RTE_PORT_HANDLING ) + port->port_status =RTE_PORT_STOPPED ; +else +fprintf (stderr, +"Port %d can not be set back to stopped\n" , pi); +fprintf (stderr, +"Port %d failed to configure hairpin on rxq %u.\n" +"Peer port: %u peer txq: %u\n" , + pi, qi, peer_tx_port, i); +/* try to reconfigure queues next time */ + port->need_reconfig_queues =1 ; +return -1 ; + } +return 0 ; +} + +static int +port_config_hairpin_txq (portid_t pi,uint16_t peer_rx_port, +queueid_t rxq_head,queueid_t txq_head, +uint16_t qcount,uint32_t manual_bind) +{ +int diag; +queueid_t i, qi; +uint32_t tx_explicit = !!(hairpin_mode &0x10 ); +uint32_t force_mem = !!(hairpin_mode &HAIRPIN_MODE_TX_FORCE_MEMORY ); +uint32_t locked_mem = !!(hairpin_mode &HAIRPIN_MODE_TX_LOCKED_MEMORY ); +uint32_t rte_mem = !!(hairpin_mode &HAIRPIN_MODE_TX_RTE_MEMORY ); +struct rte_port *port = &ports[pi]; +struct rte_eth_hairpin_conf hairpin_conf = { + .peer_count =1 , + }; + +for (qi = txq_head, i =0 ; qi < txq_head + qcount; qi++) { + hairpin_conf.peers[0 ].port = peer_rx_port; + hairpin_conf.peers[0 ].queue = i + rxq_head; + hairpin_conf.manual_bind = manual_bind; + hairpin_conf.tx_explicit = tx_explicit; + hairpin_conf.force_memory = force_mem; + hairpin_conf.use_locked_device_memory = locked_mem; + hairpin_conf.use_rte_memory = rte_mem; + diag =rte_eth_tx_hairpin_queue_setup + (pi, qi, nb_txd, &hairpin_conf); + i++; +if (diag ==0 ) +continue ; + +/* Fail to setup rx queue, return */ +if (port->port_status ==RTE_PORT_HANDLING ) + port->port_status =RTE_PORT_STOPPED ; +else +fprintf (stderr, +"Port %d can not be set back to stopped\n" , pi); +fprintf (stderr, +"Port %d failed to configure hairpin on txq %u.\n" +"Peer port: %u peer rxq: %u\n" , + pi, qi, peer_rx_port, i); +/* try to reconfigure queues next time */ + port->need_reconfig_queues =1 ; +return -1 ; + } +return 0 ; +} + +static int +setup_legacy_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t cnt_pi) +{ +int diag; +uint16_t peer_rx_port = pi; +uint16_t peer_tx_port = pi; +uint32_t manual =1 ; + +if (!(hairpin_mode &0xf )) { + peer_rx_port = pi; + peer_tx_port = pi; + manual =0 ; + }else if (hairpin_mode &0x1 ) { + peer_tx_port =rte_eth_find_next_owned_by (pi +1 , +RTE_ETH_DEV_NO_OWNER ); +if (peer_tx_port >=RTE_MAX_ETHPORTS ) + peer_tx_port =rte_eth_find_next_owned_by (0 , +RTE_ETH_DEV_NO_OWNER ); +if (p_pi !=RTE_MAX_ETHPORTS ) { + peer_rx_port = p_pi; + }else { +uint16_t next_pi; + +/* Last port will be the peer RX port of the first. */ +RTE_ETH_FOREACH_DEV (next_pi) + peer_rx_port = next_pi; + } + manual =1 ; + }else if (hairpin_mode &0x2 ) { +if (cnt_pi &0x1 ) { + peer_rx_port = p_pi; + }else { + peer_rx_port =rte_eth_find_next_owned_by (pi +1 , +RTE_ETH_DEV_NO_OWNER ); +if (peer_rx_port >=RTE_MAX_ETHPORTS ) + peer_rx_port = pi; + } + peer_tx_port = peer_rx_port; + manual =1 ; + } + diag =port_config_hairpin_txq (pi, peer_rx_port, nb_rxq, nb_txq, + nb_hairpinq, manual); +if (diag) +return diag; + diag =port_config_hairpin_rxq (pi, peer_tx_port, nb_rxq, nb_txq, + nb_hairpinq, manual); +if (diag) +return diag; +return 0 ; +} + +static int +setup_mapped_harpin_queues (portid_t pi) +{ +int ret =0 ; +struct hairpin_map *map; + + LIST_FOREACH(map, &hairpin_map_head, entry) { +if (map->rx_port == pi) { + ret =port_config_hairpin_rxq (pi, map->tx_port, + map->rxq_head, + map->txq_head, + map->qnum, true); +if (ret) +return ret; + } +if (map->tx_port == pi) { + ret =port_config_hairpin_txq (pi, map->rx_port, + map->rxq_head, + map->txq_head, + map->qnum, true); +if (ret) +return ret; + } + } +return 0 ; +} + +/* Configure the Rx and Tx hairpin queues for the selected port. */ +int +setup_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t cnt_pi) +{ +return !hairpin_multiport_mode ? +setup_legacy_hairpin_queues (pi, p_pi, cnt_pi) : +setup_mapped_harpin_queues (pi); +} + +int +hairpin_bind (uint16_t cfg_pi,portid_t *pl,portid_t *peer_pl) +{ +uint16_t i; +portid_t pi; +int peer_pi; +int diag; +int j; + +/* bind all started hairpin ports */ +for (i =0 ; i < cfg_pi; i++) { + pi = pl[i]; +/* bind current Tx to all peer Rx */ + peer_pi =rte_eth_hairpin_get_peer_ports (pi, peer_pl, +RTE_MAX_ETHPORTS ,1 ); +if (peer_pi <0 ) +return peer_pi; +for (j =0 ; j < peer_pi; j++) { +if (!port_is_started (peer_pl[j])) +continue ; + diag =rte_eth_hairpin_bind (pi, peer_pl[j]); +if (diag <0 ) { +fprintf (stderr, +"Error during binding hairpin Tx port %u to %u: %s\n" , + pi, peer_pl[j], +rte_strerror (-diag)); +return -1 ; + } + } +/* bind all peer Tx to current Rx */ + peer_pi =rte_eth_hairpin_get_peer_ports (pi, peer_pl, +RTE_MAX_ETHPORTS ,0 ); +if (peer_pi <0 ) +return peer_pi; +for (j =0 ; j < peer_pi; j++) { +if (!port_is_started (peer_pl[j])) +continue ; + diag =rte_eth_hairpin_bind (peer_pl[j], pi); +if (diag <0 ) { +fprintf (stderr, +"Error during binding hairpin Tx port %u to %u: %s\n" , + peer_pl[j], pi, +rte_strerror (-diag)); +return -1 ; + } + } + } +return 0 ; +} + +void +hairpin_map_usage (void ) +{ +printf (" --hairpin-map=rxpi:rxq:txpi:txq:n: hairpin map.\n" +" rxpi - Rx port index.\n" +" rxq - Rx queue.\n" +" txpi - Tx port index.\n" +" txq - Tx queue.\n" +" n - hairpin queues number.\n" ); +} + +static char +*parse_hairpin_map_entry (char *input,char **next) +{ +char *tail =strchr (input,':' ); + +if (!tail) +return NULL ; + tail[0 ] ='\0' ; + *next = tail +1 ; +return input; +} + +int +parse_hairpin_map (const char *hpmap) +{ +/* +* Testpmd hairpin map format: +* <Rx port id:First Rx queue:Tx port id:First Tx queue:queues number> +*/ +char *head, *next = (char *)(uintptr_t )hpmap; +struct hairpin_map *map =calloc (1 ,sizeof (*map)); + +if (!map) +return -ENOMEM ; + + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->rx_port =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->rxq_head =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->tx_port =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->txq_head =atoi (head); + map->qnum =atoi (next); +hairpin_add_multiport_map (map); +return 0 ; +err: +free (map); +return -EINVAL ; +} + +
app/test-pmd/meson.build +1 -0
@@ -15,6 +15,7 @@ sources = files( 'config.c', 'csumonly.c', 'flowgen.c', + 'hairpin.c', 'icmpecho.c', 'ieee1588fwd.c', 'iofwd.c',
app/test-pmd/parameters.c +10 -0
@@ -143,6 +143,8 @@ enum {TESTPMD_OPT_HAIRPINQ_NUM , #define TESTPMD_OPT_HAIRPIN_MODE "hairpin-mode"TESTPMD_OPT_HAIRPIN_MODE_NUM , +#define TESTPMD_OPT_HAIRPIN_MAP "hairpin-map" +TESTPMD_OPT_HAIRPIN_MAP_NUM , #define TESTPMD_OPT_BURST "burst"TESTPMD_OPT_BURST_NUM , #define TESTPMD_OPT_FLOWGEN_CLONES "flowgen-clones"
@@ -317,6 +319,7 @@ static const struct option long_options[] = {REQUIRED_ARG (TESTPMD_OPT_TXD ),REQUIRED_ARG (TESTPMD_OPT_HAIRPINQ ),REQUIRED_ARG (TESTPMD_OPT_HAIRPIN_MODE ), +REQUIRED_ARG (TESTPMD_OPT_HAIRPIN_MAP ),REQUIRED_ARG (TESTPMD_OPT_BURST ),REQUIRED_ARG (TESTPMD_OPT_FLOWGEN_CLONES ), REQUIRED_ARG(TESTPMD_OPT_FLOWGEN_FLOWS),
@@ -542,6 +545,7 @@ usage(char* progname)printf (" --hairpin-mode=0xXX: bitmask set the hairpin port mode.\n" " 0x10 - explicit Tx rule, 0x02 - hairpin ports paired\n" " 0x01 - hairpin ports loop, 0x00 - hairpin port self\n" ); +hairpin_map_usage (); } static int
@@ -1317,6 +1321,12 @@ launch_args_parse(int argc, char** argv) hairpin_mode = (uint32_t )n;break ; } +case TESTPMD_OPT_HAIRPIN_MAP_NUM : + hairpin_multiport_mode = true; + ret =parse_hairpin_map (optarg); +if (ret) +rte_exit (EXIT_FAILURE ,"invalid hairpin map\n" ); +break ;case TESTPMD_OPT_BURST_NUM : n =atoi (optarg);if (n ==0 ) {
app/test-pmd/testpmd.c +3 -214
253 lines not on this page · raw message
app/test-pmd/testpmd.h +14 -0
@@ -126,6 +126,16 @@ enum noisy_fwd_mode { NOISY_FWD_MODE_MAX, }; +/** +* Command line arguments parser sets `hairpin_multiport_mode` to True +* if explicit hairpin map configuration mode was used. +*/ +extern bool hairpin_multiport_mode; + +/** Hairpin maps list. */ +struct hairpin_map ; +extern void hairpin_add_multiport_map (struct hairpin_map *map); +/** * The data structure associated with RX and TX packet burst statistics * that are recorded for each forwarding stream.
@@ -1252,6 +1262,10 @@ extern int flow_parse(const char *src, void *result, unsigned int size,struct rte_flow_attr **attr, struct rte_flow_item **pattern, struct rte_flow_action **actions); +int setup_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t cnt_pi); +int hairpin_bind (uint16_t cfg_pi,portid_t *pl,portid_t *peer_pl); +void hairpin_map_usage (void ); +int parse_hairpin_map (const char *hpmap);uint64_t str_to_rsstypes (const char *str);const char *rsstypes_to_str (uint64_t rss_type);
doc/guides/testpmd_app_ug/run_app.rst +3 -0
@@ -571,6 +571,9 @@ The command line options are: The default value is 0. Hairpin will use single port mode and implicit Tx flow mode. +* ``--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number`` + + Set explicit hairpin configuration. Testpmd Multi-Process Command-line Options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Signature · 1 line
2.43.0
Quoted 29 lines · Gregory Etelson
Hairpin offloads packet forwarding between ports. Packet is expected on Rx port <rp>, Rx queue <rq> and is forwarded to Tx port <tp> Tx queue <tq>.
Testpmd implements a static hairpin configuration scheme.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The newhairpin-mapparameter is provided with 5 parameters, separated by:
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues numberTestpmd operator can provide several
hairpin-mapparameters for different hairpin maps.
Example:dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.
Quoted 6 lines
The new
hairpin-mapparameter is optional. If omitted, testpmd will create "default" hairpin maps.Signed-off-by Gregory Etelson <[email protected]>
Hi Aman, reminder of this patch.
PATCH v5 1/1 testpmd: add hairpin-map parameter
In reply to Gregory EtelsonHello,
Is this patch scheduled to be merged into DPDK-24.11 ? What can I do to speed up it's integration ?
Regards,
Gregory
Quoted 29 lines · Gregory Etelson
Hairpin offloads packet forwarding between ports. Packet is expected on Rx port <rp>, Rx queue <rq> and is forwarded to Tx port <tp> Tx queue <tq>.
Testpmd implements a static hairpin configuration scheme.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The newhairpin-mapparameter is provided with 5 parameters, separated by:
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues numberTestpmd operator can provide several
hairpin-mapparameters for different hairpin maps.
Example:dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.
Quoted 6 lines
The new
hairpin-mapparameter is optional. If omitted, testpmd will create "default" hairpin maps.Signed-off-by Gregory Etelson <[email protected]>
+Praveen
cpfl is only other driver that implements hairpin, @Praveen can you please help reviewing this patch, and confirm change works fine with your changes.
@Stephen, if you have any free cycles, can you please help on this patch too?
Thanks,
ferruh
Quoted 42 lines · On Tue, 29 Oct 2024 21:51:40 +0000 Ferruh Yigit <[email protected]> wrote:
Quoted 29 lines · Gregory Etelson
Hairpin offloads packet forwarding between ports. Packet is expected on Rx port <rp>, Rx queue <rq> and is forwarded to Tx port <tp> Tx queue <tq>.
Testpmd implements a static hairpin configuration scheme.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The newhairpin-mapparameter is provided with 5 parameters, separated by:
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues numberTestpmd operator can provide several
hairpin-mapparameters for different hairpin maps.
Example:dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.Quoted 6 lines
The new
hairpin-mapparameter is optional. If omitted, testpmd will create "default" hairpin maps.Signed-off-by Gregory Etelson <[email protected]>+Praveen
cpfl is only other driver that implements hairpin, @Praveen can you please help reviewing this patch, and confirm change works fine with your changes.
Quoted 5 lines
@Stephen, if you have any free cycles, can you please help on this patch too?
Thanks,
ferruh
Ok, can do semantic review but do not have any working HW with hairpin capability.
PATCH v6 1/1 testpmd: add hairpin map parameter
In reply to Gregory EtelsonHairpin offloads packet forwarding between ports. Packet is expected on Rx port <rp>, Rx queue <rq> and is forwarded to Tx port <tp> Tx queue <tq>.
Testpmd implements a static hairpin configuration scheme.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The new hairpin-map parameter is provided with 5 parameters, separated by :
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number
Testpmd operator can provide several hairpin-map parameters for different hairpin maps.
Example:
dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]
Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.
The new hairpin-map parameter is optional. If omitted, testpmd will create "default" hairpin maps.
--- app/test-pmd/hairpin.c | 360 ++++++++++++++++++++++++++ app/test-pmd/meson.build | 1 + app/test-pmd/parameters.c | 10 + app/test-pmd/testpmd.c | 217 +--------------- app/test-pmd/testpmd.h | 14 + doc/guides/testpmd_app_ug/run_app.rst | 3 + 6 files changed, 391 insertions(+), 214 deletions(-) create mode 100644 app/test-pmd/hairpin.c
app/test-pmd/hairpin.c new file +360 -0
@@ -0,0 +1,360 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright (c) 2022 NVIDIA Corporation & Affiliates +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <stdint.h> + +#include <sys/queue.h> + +#include "testpmd.h" + +/* Hairpin ports configuration mode. */ +uint32_t hairpin_mode; + +bool hairpin_multiport_mode = false; + +queueid_t nb_hairpinq;/**< Number of hairpin queues per port. */ + +static LIST_HEAD(, hairpin_map) hairpin_map_head = LIST_HEAD_INITIALIZER(); + +struct hairpin_map { +LIST_ENTRY (hairpin_map) entry;/**< List entry. */ +portid_t rx_port;/**< Hairpin Rx port ID. */ +portid_t tx_port;/**< Hairpin Tx port ID. */ +uint16_t rxq_head;/**< Hairpin Rx queue head. */ +uint16_t txq_head;/**< Hairpin Tx queue head. */ +uint16_t qnum;/**< Hairpin queues number. */ +}; + +void +hairpin_add_multiport_map (struct hairpin_map *map) +{ +LIST_INSERT_HEAD (&hairpin_map_head, map, entry); +} + +/* +* Get the allowed maximum number of hairpin queues. +* *pid return the port id which has minimal value of +* max_hairpin_queues in all ports. +*/ +queueid_t +get_allowed_max_nb_hairpinq (portid_t *pid) +{ +queueid_t allowed_max_hairpinq =RTE_MAX_QUEUES_PER_PORT ; +portid_t pi; +struct rte_eth_hairpin_cap cap; + +RTE_ETH_FOREACH_DEV (pi) { +if (rte_eth_dev_hairpin_capability_get (pi, &cap) !=0 ) { + *pid = pi; +return 0 ; + } +if (cap.max_nb_queues < allowed_max_hairpinq) { + allowed_max_hairpinq = cap.max_nb_queues; + *pid = pi; + } + } +return allowed_max_hairpinq; +} + +/* +* Check input hairpin is valid or not. +* If input hairpin is not greater than any of maximum number +* of hairpin queues of all ports, it is valid. +* if valid, return 0, else return -1 +*/ +int +check_nb_hairpinq (queueid_t hairpinq) +{ +queueid_t allowed_max_hairpinq; +portid_t pid =0 ; + + allowed_max_hairpinq =get_allowed_max_nb_hairpinq (&pid); +if (hairpinq > allowed_max_hairpinq) { +fprintf (stderr, +"Fail: input hairpin (%u) can't be greater than max_hairpin_queues (%u) of port %u\n" , + hairpinq, allowed_max_hairpinq, pid); +return -1 ; + } +return 0 ; +} + +#define HAIRPIN_MODE_RX_FORCE_MEMORY RTE_BIT32(8) +#define HAIRPIN_MODE_TX_FORCE_MEMORY RTE_BIT32(9) + +#define HAIRPIN_MODE_RX_LOCKED_MEMORY RTE_BIT32(12) +#define HAIRPIN_MODE_RX_RTE_MEMORY RTE_BIT32(13) + +#define HAIRPIN_MODE_TX_LOCKED_MEMORY RTE_BIT32(16) +#define HAIRPIN_MODE_TX_RTE_MEMORY RTE_BIT32(17) + +static int +port_config_hairpin_rxq (portid_t pi,uint16_t peer_tx_port, +queueid_t rxq_head,queueid_t txq_head, +uint16_t qcount,uint32_t manual_bind) +{ +int diag; +queueid_t i, qi; +uint32_t tx_explicit = !!(hairpin_mode &0x10 ); +uint32_t force_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_FORCE_MEMORY ); +uint32_t locked_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_LOCKED_MEMORY ); +uint32_t rte_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_RTE_MEMORY ); +struct rte_port *port = &ports[pi]; +struct rte_eth_hairpin_conf hairpin_conf = { + .peer_count =1 , + }; + +for (qi = rxq_head, i =0 ; qi < rxq_head + qcount; qi++) { + hairpin_conf.peers[0 ].port = peer_tx_port; + hairpin_conf.peers[0 ].queue = i + txq_head; + hairpin_conf.manual_bind = manual_bind; + hairpin_conf.tx_explicit = tx_explicit; + hairpin_conf.force_memory = force_mem; + hairpin_conf.use_locked_device_memory = locked_mem; + hairpin_conf.use_rte_memory = rte_mem; + diag =rte_eth_rx_hairpin_queue_setup + (pi, qi, nb_rxd, &hairpin_conf); + i++; +if (diag ==0 ) +continue ; + +/* Fail to setup rx queue, return */ +if (port->port_status ==RTE_PORT_HANDLING ) + port->port_status =RTE_PORT_STOPPED ; +else +fprintf (stderr, +"Port %d can not be set back to stopped\n" , pi); +fprintf (stderr, +"Port %u failed to configure hairpin on rxq %u.\n" +"Peer port: %u peer txq: %u\n" , + pi, qi, peer_tx_port, i); +/* try to reconfigure queues next time */ + port->need_reconfig_queues =1 ; +return -1 ; + } +return 0 ; +} + +static int +port_config_hairpin_txq (portid_t pi,uint16_t peer_rx_port, +queueid_t rxq_head,queueid_t txq_head, +uint16_t qcount,uint32_t manual_bind) +{ +int diag; +queueid_t i, qi; +uint32_t tx_explicit = !!(hairpin_mode &0x10 ); +uint32_t force_mem = !!(hairpin_mode &HAIRPIN_MODE_TX_FORCE_MEMORY ); +uint32_t locked_mem = !!(hairpin_mode &HAIRPIN_MODE_TX_LOCKED_MEMORY ); +uint32_t rte_mem = !!(hairpin_mode &HAIRPIN_MODE_TX_RTE_MEMORY ); +struct rte_port *port = &ports[pi]; +struct rte_eth_hairpin_conf hairpin_conf = { + .peer_count =1 , + }; + +for (qi = txq_head, i =0 ; qi < txq_head + qcount; qi++) { + hairpin_conf.peers[0 ].port = peer_rx_port; + hairpin_conf.peers[0 ].queue = i + rxq_head; + hairpin_conf.manual_bind = manual_bind; + hairpin_conf.tx_explicit = tx_explicit; + hairpin_conf.force_memory = force_mem; + hairpin_conf.use_locked_device_memory = locked_mem; + hairpin_conf.use_rte_memory = rte_mem; + diag =rte_eth_tx_hairpin_queue_setup + (pi, qi, nb_txd, &hairpin_conf); + i++; +if (diag ==0 ) +continue ; + +/* Fail to setup rx queue, return */ +if (port->port_status ==RTE_PORT_HANDLING ) + port->port_status =RTE_PORT_STOPPED ; +else +fprintf (stderr, +"Port %d can not be set back to stopped\n" , pi); +fprintf (stderr, +"Port %d failed to configure hairpin on txq %u.\n" +"Peer port: %u peer rxq: %u\n" , + pi, qi, peer_rx_port, i); +/* try to reconfigure queues next time */ + port->need_reconfig_queues =1 ; +return -1 ; + } +return 0 ; +} + +static int +setup_legacy_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t cnt_pi) +{ +int diag; +uint16_t peer_rx_port = pi; +uint16_t peer_tx_port = pi; +uint32_t manual =1 ; + +if (!(hairpin_mode &0xf )) { + peer_rx_port = pi; + peer_tx_port = pi; + manual =0 ; + }else if (hairpin_mode &0x1 ) { + peer_tx_port =rte_eth_find_next_owned_by (pi +1 , +RTE_ETH_DEV_NO_OWNER ); +if (peer_tx_port >=RTE_MAX_ETHPORTS ) + peer_tx_port =rte_eth_find_next_owned_by (0 , +RTE_ETH_DEV_NO_OWNER ); +if (p_pi !=RTE_MAX_ETHPORTS ) { + peer_rx_port = p_pi; + }else { +uint16_t next_pi; + +/* Last port will be the peer RX port of the first. */ +RTE_ETH_FOREACH_DEV (next_pi) + peer_rx_port = next_pi; + } + manual =1 ; + }else if (hairpin_mode &0x2 ) { +if (cnt_pi &0x1 ) { + peer_rx_port = p_pi; + }else { + peer_rx_port =rte_eth_find_next_owned_by (pi +1 , +RTE_ETH_DEV_NO_OWNER ); +if (peer_rx_port >=RTE_MAX_ETHPORTS ) + peer_rx_port = pi; + } + peer_tx_port = peer_rx_port; + manual =1 ; + } + diag =port_config_hairpin_txq (pi, peer_rx_port, nb_rxq, nb_txq, + nb_hairpinq, manual); +if (diag) +return diag; + diag =port_config_hairpin_rxq (pi, peer_tx_port, nb_rxq, nb_txq, + nb_hairpinq, manual); +if (diag) +return diag; +return 0 ; +} + +static int +setup_mapped_harpin_queues (portid_t pi) +{ +int ret =0 ; +struct hairpin_map *map; + + LIST_FOREACH(map, &hairpin_map_head, entry) { +if (map->rx_port == pi) { + ret =port_config_hairpin_rxq (pi, map->tx_port, + map->rxq_head, + map->txq_head, + map->qnum, true); +if (ret) +return ret; + } +if (map->tx_port == pi) { + ret =port_config_hairpin_txq (pi, map->rx_port, + map->rxq_head, + map->txq_head, + map->qnum, true); +if (ret) +return ret; + } + } +return 0 ; +} + +/* Configure the Rx and Tx hairpin queues for the selected port. */ +int +setup_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t cnt_pi) +{ +if (hairpin_multiport_mode) +return setup_mapped_harpin_queues (pi); + +return setup_legacy_hairpin_queues (pi, p_pi, cnt_pi); +} + +int +hairpin_bind (uint16_t cfg_pi,portid_t *pl,portid_t *peer_pl) +{ +uint16_t i; +portid_t pi; +int peer_pi; +int diag; +int j; + +/* bind all started hairpin ports */ +for (i =0 ; i < cfg_pi; i++) { + pi = pl[i]; +/* bind current Tx to all peer Rx */ + peer_pi =rte_eth_hairpin_get_peer_ports (pi, peer_pl, +RTE_MAX_ETHPORTS ,1 ); +if (peer_pi <0 ) +return peer_pi; +for (j =0 ; j < peer_pi; j++) { +if (!port_is_started (peer_pl[j])) +continue ; + diag =rte_eth_hairpin_bind (pi, peer_pl[j]); +if (diag <0 ) { +fprintf (stderr, +"Error during binding hairpin Tx port %u to %u: %s\n" , + pi, peer_pl[j], +rte_strerror (-diag)); +return -1 ; + } + } +/* bind all peer Tx to current Rx */ + peer_pi =rte_eth_hairpin_get_peer_ports (pi, peer_pl, +RTE_MAX_ETHPORTS ,0 ); +if (peer_pi <0 ) +return peer_pi; +for (j =0 ; j < peer_pi; j++) { +if (!port_is_started (peer_pl[j])) +continue ; + diag =rte_eth_hairpin_bind (peer_pl[j], pi); +if (diag <0 ) { +fprintf (stderr, +"Error during binding hairpin Tx port %u to %u: %s\n" , + peer_pl[j], pi, +rte_strerror (-diag)); +return -1 ; + } + } + } +return 0 ; +} + +void +hairpin_map_usage (void ) +{ +printf (" --hairpin-map=rxpi:rxq:txpi:txq:n: hairpin map.\n" +" rxpi - Rx port index.\n" +" rxq - Rx queue.\n" +" txpi - Tx port index.\n" +" txq - Tx queue.\n" +" n - hairpin queues number.\n" ); +} + +int +parse_hairpin_map (const char *hpmap) +{ +/* +* Testpmd hairpin map format: +* <Rx port id:First Rx queue:Tx port id:First Tx queue:queues number> +*/ +int ret; +struct hairpin_map *map =calloc (1 ,sizeof (*map)); + +if (!map) +return -ENOMEM ; + + ret =sscanf (hpmap,"%hu:%hu:%hu:%hu:%hu" , + &map->rx_port, &map->rxq_head, + &map->tx_port, &map->txq_head, &map->qnum); +if (ret !=5 ) { +free (map); +return -EINVAL ; + } +hairpin_add_multiport_map (map); +return 0 ; +}
app/test-pmd/meson.build +1 -0
@@ -15,6 +15,7 @@ sources = files( 'config.c', 'csumonly.c', 'flowgen.c', + 'hairpin.c', 'icmpecho.c', 'ieee1588fwd.c', 'iofwd.c',
app/test-pmd/parameters.c +10 -0
@@ -143,6 +143,8 @@ enum {TESTPMD_OPT_HAIRPINQ_NUM , #define TESTPMD_OPT_HAIRPIN_MODE "hairpin-mode"TESTPMD_OPT_HAIRPIN_MODE_NUM , +#define TESTPMD_OPT_HAIRPIN_MAP "hairpin-map" +TESTPMD_OPT_HAIRPIN_MAP_NUM , #define TESTPMD_OPT_BURST "burst"TESTPMD_OPT_BURST_NUM , #define TESTPMD_OPT_FLOWGEN_CLONES "flowgen-clones"
@@ -317,6 +319,7 @@ static const struct option long_options[] = {REQUIRED_ARG (TESTPMD_OPT_TXD ),REQUIRED_ARG (TESTPMD_OPT_HAIRPINQ ),REQUIRED_ARG (TESTPMD_OPT_HAIRPIN_MODE ), +REQUIRED_ARG (TESTPMD_OPT_HAIRPIN_MAP ),REQUIRED_ARG (TESTPMD_OPT_BURST ),REQUIRED_ARG (TESTPMD_OPT_FLOWGEN_CLONES ), REQUIRED_ARG(TESTPMD_OPT_FLOWGEN_FLOWS),
@@ -542,6 +545,7 @@ usage(char* progname)printf (" --hairpin-mode=0xXX: bitmask set the hairpin port mode.\n" " 0x10 - explicit Tx rule, 0x02 - hairpin ports paired\n" " 0x01 - hairpin ports loop, 0x00 - hairpin port self\n" ); +hairpin_map_usage (); } static int
@@ -1317,6 +1321,12 @@ launch_args_parse(int argc, char** argv) hairpin_mode = (uint32_t )n;break ; } +case TESTPMD_OPT_HAIRPIN_MAP_NUM : + hairpin_multiport_mode = true; + ret =parse_hairpin_map (optarg); +if (ret) +rte_exit (EXIT_FAILURE ,"invalid hairpin map\n" ); +break ;case TESTPMD_OPT_BURST_NUM : n =atoi (optarg);if (n ==0 ) {
app/test-pmd/testpmd.c +3 -214
253 lines not on this page · raw message
app/test-pmd/testpmd.h +14 -0
@@ -126,6 +126,16 @@ enum noisy_fwd_mode { NOISY_FWD_MODE_MAX, }; +/** +* Command line arguments parser sets `hairpin_multiport_mode` to True +* if explicit hairpin map configuration mode was used. +*/ +extern bool hairpin_multiport_mode; + +/** Hairpin maps list. */ +struct hairpin_map ; +extern void hairpin_add_multiport_map (struct hairpin_map *map); +/** * The data structure associated with RX and TX packet burst statistics * that are recorded for each forwarding stream.
@@ -1255,6 +1265,10 @@ extern int flow_parse(const char *src, void *result, unsigned int size,struct rte_flow_attr **attr, struct rte_flow_item **pattern, struct rte_flow_action **actions); +int setup_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t cnt_pi); +int hairpin_bind (uint16_t cfg_pi,portid_t *pl,portid_t *peer_pl); +void hairpin_map_usage (void ); +int parse_hairpin_map (const char *hpmap);uint64_t str_to_rsstypes (const char *str);const char *rsstypes_to_str (uint64_t rss_type);
doc/guides/testpmd_app_ug/run_app.rst +3 -0
@@ -571,6 +571,9 @@ The command line options are: The default value is 0. Hairpin will use single port mode and implicit Tx flow mode. +* ``--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number`` + + Set explicit hairpin configuration. Testpmd Multi-Process Command-line Options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Signature · 1 line
2.43.0
Re: [PATCH v6] testpmd: add hairpin map parameter
Quoted 14 lines · On Wed, 30 Oct 2024 09:37:24 +0200 Gregory Etelson <[email protected]> wrote:
app/test-pmd/hairpin.c new file +14
-0+static int +port_config_hairpin_rxq (portid_t pi,uint16_t peer_tx_port, +queueid_t rxq_head,queueid_t txq_head, +uint16_t qcount,uint32_t manual_bind) +{ +int diag; +queueid_t i, qi; +uint32_t tx_explicit = !!(hairpin_mode &0x10 ); +uint32_t force_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_FORCE_MEMORY ); +uint32_t locked_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_LOCKED_MEMORY ); +uint32_t rte_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_RTE_MEMORY ); +struct rte_port *port = &ports[pi]; +struct rte_eth_hairpin_conf hairpin_conf = { + .peer_count =1 ,
app/test-pmd/hairpin.c line 118
Quoted 10 lines
app/test-pmd/hairpin.c new file +10
-0+ }; + +for (qi = rxq_head, i =0 ; qi < rxq_head + qcount; qi++) { + hairpin_conf.peers[0 ].port = peer_tx_port; + hairpin_conf.peers[0 ].queue = i + txq_head; + hairpin_conf.manual_bind = manual_bind; + hairpin_conf.tx_explicit = tx_explicit; + hairpin_conf.force_memory = force_mem; + hairpin_conf.use_locked_device_memory = locked_mem; + hairpin_conf.use_rte_memory = rte_mem;
Did you consider that most of the hairpin_conf values could just be set directly, avoiding intermediate variables.
app/test-pmd/hairpin.c line 120
Quoted 2 lines
app/test-pmd/hairpin.c new file +2
-0+ diag =rte_eth_rx_hairpin_queue_setup + (pi, qi, nb_rxd, &hairpin_conf);
Unnecessary line break.
Suggestion:
static int
port_config_hairpin_rxq(portid_t pi, uint16_t peer_tx_port,
queueid_t rxq_head, queueid_t txq_head, uint16_t qcount, uint32_t manual_bind)
{
int diag;
queueid_t i, qi;
struct rte_port *port = &ports[pi];
struct rte_eth_hairpin_conf hairpin_conf = {
.peer_count = 1,
.manual_bind = manual_bind,
.tx_explicit = !!(hairpin_mode & 0x10),
.force_memory = !!(hairpin_mode & HAIRPIN_MODE_RX_FORCE_MEMORY),
.use_locked_device_memory = !!(hairpin_mode & HAIRPIN_MODE_RX_LOCKED_MEMORY),
.use_rte_memory = !!(hairpin_mode & HAIRPIN_MODE_RX_RTE_MEMORY),
};
for (qi = rxq_head, i = 0; qi < rxq_head + qcount; qi++) {
hairpin_conf.peers[0].port = peer_tx_port;
hairpin_conf.peers[0].queue = i + txq_head;
diag = rte_eth_rx_hairpin_queue_setup(pi, qi, nb_rxd, &hairpin_conf);
i++;
if (diag == 0)
continue;Re: [PATCH v6] testpmd: add hairpin map parameter
Hello Stephen,
Quoted 4 lines
Did you consider that most of the
hairpin_confvalues could just be set directly, avoiding intermediate variables.
fixed.
Quoted 4 lines
app/test-pmd/hairpin.c line 120
Quoted 3 lines
app/test-pmd/hairpin.c new file +2
-0+ diag =rte_eth_rx_hairpin_queue_setup + (pi, qi, nb_rxd, &hairpin_conf);
fixed.
PATCH v7 1/1 testpmd: add hairpin map parameter
In reply to Gregory EtelsonHairpin offloads packet forwarding between ports. Packet is expected on Rx port <rp>, Rx queue <rq> and is forwarded to Tx port <tp> Tx queue <tq>.
Testpmd implements a static hairpin configuration scheme.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The new hairpin-map parameter is provided with 5 parameters, separated by :
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number
Testpmd operator can provide several hairpin-map parameters for different hairpin maps.
Example:
dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]
Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.
The new hairpin-map parameter is optional. If omitted, testpmd will create "default" hairpin maps.
--- app/test-pmd/hairpin.c | 350 ++++++++++++++++++++++++++ app/test-pmd/meson.build | 1 + app/test-pmd/parameters.c | 10 + app/test-pmd/testpmd.c | 217 +--------------- app/test-pmd/testpmd.h | 14 ++ doc/guides/testpmd_app_ug/run_app.rst | 3 + 6 files changed, 381 insertions(+), 214 deletions(-) create mode 100644 app/test-pmd/hairpin.c
app/test-pmd/hairpin.c new file +350 -0
@@ -0,0 +1,350 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright (c) 2022 NVIDIA Corporation & Affiliates +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <stdint.h> + +#include <sys/queue.h> + +#include "testpmd.h" + +/* Hairpin ports configuration mode. */ +uint32_t hairpin_mode; + +bool hairpin_multiport_mode = false; + +queueid_t nb_hairpinq;/**< Number of hairpin queues per port. */ + +static LIST_HEAD(, hairpin_map) hairpin_map_head = LIST_HEAD_INITIALIZER(); + +struct hairpin_map { +LIST_ENTRY (hairpin_map) entry;/**< List entry. */ +portid_t rx_port;/**< Hairpin Rx port ID. */ +portid_t tx_port;/**< Hairpin Tx port ID. */ +uint16_t rxq_head;/**< Hairpin Rx queue head. */ +uint16_t txq_head;/**< Hairpin Tx queue head. */ +uint16_t qnum;/**< Hairpin queues number. */ +}; + +void +hairpin_add_multiport_map (struct hairpin_map *map) +{ +LIST_INSERT_HEAD (&hairpin_map_head, map, entry); +} + +/* +* Get the allowed maximum number of hairpin queues. +* *pid return the port id which has minimal value of +* max_hairpin_queues in all ports. +*/ +queueid_t +get_allowed_max_nb_hairpinq (portid_t *pid) +{ +queueid_t allowed_max_hairpinq =RTE_MAX_QUEUES_PER_PORT ; +portid_t pi; +struct rte_eth_hairpin_cap cap; + +RTE_ETH_FOREACH_DEV (pi) { +if (rte_eth_dev_hairpin_capability_get (pi, &cap) !=0 ) { + *pid = pi; +return 0 ; + } +if (cap.max_nb_queues < allowed_max_hairpinq) { + allowed_max_hairpinq = cap.max_nb_queues; + *pid = pi; + } + } +return allowed_max_hairpinq; +} + +/* +* Check input hairpin is valid or not. +* If input hairpin is not greater than any of maximum number +* of hairpin queues of all ports, it is valid. +* if valid, return 0, else return -1 +*/ +int +check_nb_hairpinq (queueid_t hairpinq) +{ +queueid_t allowed_max_hairpinq; +portid_t pid =0 ; + + allowed_max_hairpinq =get_allowed_max_nb_hairpinq (&pid); +if (hairpinq > allowed_max_hairpinq) { +fprintf (stderr, +"Fail: input hairpin (%u) can't be greater than max_hairpin_queues (%u) of port %u\n" , + hairpinq, allowed_max_hairpinq, pid); +return -1 ; + } +return 0 ; +} + +#define HAIRPIN_MODE_RX_FORCE_MEMORY RTE_BIT32(8) +#define HAIRPIN_MODE_TX_FORCE_MEMORY RTE_BIT32(9) + +#define HAIRPIN_MODE_RX_LOCKED_MEMORY RTE_BIT32(12) +#define HAIRPIN_MODE_RX_RTE_MEMORY RTE_BIT32(13) + +#define HAIRPIN_MODE_TX_LOCKED_MEMORY RTE_BIT32(16) +#define HAIRPIN_MODE_TX_RTE_MEMORY RTE_BIT32(17) + +static int +port_config_hairpin_rxq (portid_t pi,uint16_t peer_tx_port, +queueid_t rxq_head,queueid_t txq_head, +uint16_t qcount,uint32_t manual_bind) +{ +int diag; +queueid_t i, qi; +struct rte_port *port = &ports[pi]; +struct rte_eth_hairpin_conf hairpin_conf = { + .peer_count =1 , + .peers[0 ].port = peer_tx_port, + .manual_bind = manual_bind, + .tx_explicit = !!(hairpin_mode &0x10 ), + .force_memory = !!(hairpin_mode &HAIRPIN_MODE_RX_FORCE_MEMORY ), + .use_locked_device_memory = + !!(hairpin_mode &HAIRPIN_MODE_RX_LOCKED_MEMORY ), + .use_rte_memory = !!(hairpin_mode &HAIRPIN_MODE_RX_RTE_MEMORY ), + }; + +for (qi = rxq_head, i =0 ; qi < rxq_head + qcount; qi++, i++) { + hairpin_conf.peers[0 ].queue = i + txq_head; + diag =rte_eth_rx_hairpin_queue_setup (pi, qi, nb_rxd, &hairpin_conf); +if (diag ==0 ) +continue ; + +/* Fail to setup rx queue, return */ +if (port->port_status ==RTE_PORT_HANDLING ) + port->port_status =RTE_PORT_STOPPED ; +else +fprintf (stderr, +"Port %d can not be set back to stopped\n" , pi); +fprintf (stderr, +"Port %u failed to configure hairpin on rxq %u.\n" +"Peer port: %u peer txq: %u\n" , + pi, qi, peer_tx_port, i); +/* try to reconfigure queues next time */ + port->need_reconfig_queues =1 ; +return -1 ; + } +return 0 ; +} + +static int +port_config_hairpin_txq (portid_t pi,uint16_t peer_rx_port, +queueid_t rxq_head,queueid_t txq_head, +uint16_t qcount,uint32_t manual_bind) +{ +int diag; +queueid_t i, qi; +struct rte_port *port = &ports[pi]; +struct rte_eth_hairpin_conf hairpin_conf = { + .peer_count =1 , + .peers[0 ].port = peer_rx_port, + .manual_bind = manual_bind, + .tx_explicit = !!(hairpin_mode &0x10 ), + .force_memory = !!(hairpin_mode &HAIRPIN_MODE_TX_FORCE_MEMORY ), + .use_locked_device_memory = + !!(hairpin_mode &HAIRPIN_MODE_TX_LOCKED_MEMORY ), + .use_rte_memory = !!(hairpin_mode &HAIRPIN_MODE_TX_RTE_MEMORY ), + }; + +for (qi = txq_head, i =0 ; qi < txq_head + qcount; qi++, i++) { + hairpin_conf.peers[0 ].queue = i + rxq_head; + diag =rte_eth_tx_hairpin_queue_setup (pi, qi, nb_txd, &hairpin_conf); +if (diag ==0 ) +continue ; + +/* Fail to setup rx queue, return */ +if (port->port_status ==RTE_PORT_HANDLING ) + port->port_status =RTE_PORT_STOPPED ; +else +fprintf (stderr, +"Port %d can not be set back to stopped\n" , pi); +fprintf (stderr, +"Port %d failed to configure hairpin on txq %u.\n" +"Peer port: %u peer rxq: %u\n" , + pi, qi, peer_rx_port, i); +/* try to reconfigure queues next time */ + port->need_reconfig_queues =1 ; +return -1 ; + } +return 0 ; +} + +static int +setup_legacy_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t cnt_pi) +{ +int diag; +uint16_t peer_rx_port = pi; +uint16_t peer_tx_port = pi; +uint32_t manual =1 ; + +if (!(hairpin_mode &0xf )) { + peer_rx_port = pi; + peer_tx_port = pi; + manual =0 ; + }else if (hairpin_mode &0x1 ) { + peer_tx_port =rte_eth_find_next_owned_by (pi +1 , +RTE_ETH_DEV_NO_OWNER ); +if (peer_tx_port >=RTE_MAX_ETHPORTS ) + peer_tx_port =rte_eth_find_next_owned_by (0 , +RTE_ETH_DEV_NO_OWNER ); +if (p_pi !=RTE_MAX_ETHPORTS ) { + peer_rx_port = p_pi; + }else { +uint16_t next_pi; + +/* Last port will be the peer RX port of the first. */ +RTE_ETH_FOREACH_DEV (next_pi) + peer_rx_port = next_pi; + } + manual =1 ; + }else if (hairpin_mode &0x2 ) { +if (cnt_pi &0x1 ) { + peer_rx_port = p_pi; + }else { + peer_rx_port =rte_eth_find_next_owned_by (pi +1 , +RTE_ETH_DEV_NO_OWNER ); +if (peer_rx_port >=RTE_MAX_ETHPORTS ) + peer_rx_port = pi; + } + peer_tx_port = peer_rx_port; + manual =1 ; + } + diag =port_config_hairpin_txq (pi, peer_rx_port, nb_rxq, nb_txq, + nb_hairpinq, manual); +if (diag) +return diag; + diag =port_config_hairpin_rxq (pi, peer_tx_port, nb_rxq, nb_txq, + nb_hairpinq, manual); +if (diag) +return diag; +return 0 ; +} + +static int +setup_mapped_harpin_queues (portid_t pi) +{ +int ret =0 ; +struct hairpin_map *map; + + LIST_FOREACH(map, &hairpin_map_head, entry) { +if (map->rx_port == pi) { + ret =port_config_hairpin_rxq (pi, map->tx_port, + map->rxq_head, + map->txq_head, + map->qnum, true); +if (ret) +return ret; + } +if (map->tx_port == pi) { + ret =port_config_hairpin_txq (pi, map->rx_port, + map->rxq_head, + map->txq_head, + map->qnum, true); +if (ret) +return ret; + } + } +return 0 ; +} + +/* Configure the Rx and Tx hairpin queues for the selected port. */ +int +setup_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t cnt_pi) +{ +if (hairpin_multiport_mode) +return setup_mapped_harpin_queues (pi); + +return setup_legacy_hairpin_queues (pi, p_pi, cnt_pi); +} + +int +hairpin_bind (uint16_t cfg_pi,portid_t *pl,portid_t *peer_pl) +{ +uint16_t i; +portid_t pi; +int peer_pi; +int diag; +int j; + +/* bind all started hairpin ports */ +for (i =0 ; i < cfg_pi; i++) { + pi = pl[i]; +/* bind current Tx to all peer Rx */ + peer_pi =rte_eth_hairpin_get_peer_ports (pi, peer_pl, +RTE_MAX_ETHPORTS ,1 ); +if (peer_pi <0 ) +return peer_pi; +for (j =0 ; j < peer_pi; j++) { +if (!port_is_started (peer_pl[j])) +continue ; + diag =rte_eth_hairpin_bind (pi, peer_pl[j]); +if (diag <0 ) { +fprintf (stderr, +"Error during binding hairpin Tx port %u to %u: %s\n" , + pi, peer_pl[j], +rte_strerror (-diag)); +return -1 ; + } + } +/* bind all peer Tx to current Rx */ + peer_pi =rte_eth_hairpin_get_peer_ports (pi, peer_pl, +RTE_MAX_ETHPORTS ,0 ); +if (peer_pi <0 ) +return peer_pi; +for (j =0 ; j < peer_pi; j++) { +if (!port_is_started (peer_pl[j])) +continue ; + diag =rte_eth_hairpin_bind (peer_pl[j], pi); +if (diag <0 ) { +fprintf (stderr, +"Error during binding hairpin Tx port %u to %u: %s\n" , + peer_pl[j], pi, +rte_strerror (-diag)); +return -1 ; + } + } + } +return 0 ; +} + +void +hairpin_map_usage (void ) +{ +printf (" --hairpin-map=rxpi:rxq:txpi:txq:n: hairpin map.\n" +" rxpi - Rx port index.\n" +" rxq - Rx queue.\n" +" txpi - Tx port index.\n" +" txq - Tx queue.\n" +" n - hairpin queues number.\n" ); +} + +int +parse_hairpin_map (const char *hpmap) +{ +/* +* Testpmd hairpin map format: +* <Rx port id:First Rx queue:Tx port id:First Tx queue:queues number> +*/ +int ret; +struct hairpin_map *map =calloc (1 ,sizeof (*map)); + +if (!map) +return -ENOMEM ; + + ret =sscanf (hpmap,"%hu:%hu:%hu:%hu:%hu" , + &map->rx_port, &map->rxq_head, + &map->tx_port, &map->txq_head, &map->qnum); +if (ret !=5 ) { +free (map); +return -EINVAL ; + } +hairpin_add_multiport_map (map); +return 0 ; +}
app/test-pmd/meson.build +1 -0
@@ -15,6 +15,7 @@ sources = files( 'config.c', 'csumonly.c', 'flowgen.c', + 'hairpin.c', 'icmpecho.c', 'ieee1588fwd.c', 'iofwd.c',
app/test-pmd/parameters.c +10 -0
@@ -143,6 +143,8 @@ enum {TESTPMD_OPT_HAIRPINQ_NUM , #define TESTPMD_OPT_HAIRPIN_MODE "hairpin-mode"TESTPMD_OPT_HAIRPIN_MODE_NUM , +#define TESTPMD_OPT_HAIRPIN_MAP "hairpin-map" +TESTPMD_OPT_HAIRPIN_MAP_NUM , #define TESTPMD_OPT_BURST "burst"TESTPMD_OPT_BURST_NUM , #define TESTPMD_OPT_FLOWGEN_CLONES "flowgen-clones"
@@ -317,6 +319,7 @@ static const struct option long_options[] = {REQUIRED_ARG (TESTPMD_OPT_TXD ),REQUIRED_ARG (TESTPMD_OPT_HAIRPINQ ),REQUIRED_ARG (TESTPMD_OPT_HAIRPIN_MODE ), +REQUIRED_ARG (TESTPMD_OPT_HAIRPIN_MAP ),REQUIRED_ARG (TESTPMD_OPT_BURST ),REQUIRED_ARG (TESTPMD_OPT_FLOWGEN_CLONES ), REQUIRED_ARG(TESTPMD_OPT_FLOWGEN_FLOWS),
@@ -542,6 +545,7 @@ usage(char* progname)printf (" --hairpin-mode=0xXX: bitmask set the hairpin port mode.\n" " 0x10 - explicit Tx rule, 0x02 - hairpin ports paired\n" " 0x01 - hairpin ports loop, 0x00 - hairpin port self\n" ); +hairpin_map_usage (); } static int
@@ -1317,6 +1321,12 @@ launch_args_parse(int argc, char** argv) hairpin_mode = (uint32_t )n;break ; } +case TESTPMD_OPT_HAIRPIN_MAP_NUM : + hairpin_multiport_mode = true; + ret =parse_hairpin_map (optarg); +if (ret) +rte_exit (EXIT_FAILURE ,"invalid hairpin map\n" ); +break ;case TESTPMD_OPT_BURST_NUM : n =atoi (optarg);if (n ==0 ) {
app/test-pmd/testpmd.c +3 -214
253 lines not on this page · raw message
app/test-pmd/testpmd.h +14 -0
@@ -126,6 +126,16 @@ enum noisy_fwd_mode { NOISY_FWD_MODE_MAX, }; +/** +* Command line arguments parser sets `hairpin_multiport_mode` to True +* if explicit hairpin map configuration mode was used. +*/ +extern bool hairpin_multiport_mode; + +/** Hairpin maps list. */ +struct hairpin_map ; +extern void hairpin_add_multiport_map (struct hairpin_map *map); +/** * The data structure associated with RX and TX packet burst statistics * that are recorded for each forwarding stream.
@@ -1255,6 +1265,10 @@ extern int flow_parse(const char *src, void *result, unsigned int size,struct rte_flow_attr **attr, struct rte_flow_item **pattern, struct rte_flow_action **actions); +int setup_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t cnt_pi); +int hairpin_bind (uint16_t cfg_pi,portid_t *pl,portid_t *peer_pl); +void hairpin_map_usage (void ); +int parse_hairpin_map (const char *hpmap);uint64_t str_to_rsstypes (const char *str);const char *rsstypes_to_str (uint64_t rss_type);
doc/guides/testpmd_app_ug/run_app.rst +3 -0
@@ -571,6 +571,9 @@ The command line options are: The default value is 0. Hairpin will use single port mode and implicit Tx flow mode. +* ``--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number`` + + Set explicit hairpin configuration. Testpmd Multi-Process Command-line Options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Signature · 1 line
2.43.0
Re: [PATCH v7] testpmd: add hairpin map parameter
Quoted 29 lines · On Thu, 31 Oct 2024 06:58:17 +0200 Gregory Etelson <[email protected]> wrote:
Hairpin offloads packet forwarding between ports. Packet is expected on Rx port <rp>, Rx queue <rq> and is forwarded to Tx port <tp> Tx queue <tq>.
Testpmd implements a static hairpin configuration scheme.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The newhairpin-mapparameter is provided with 5 parameters, separated by:
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues numberTestpmd operator can provide several
hairpin-mapparameters for different hairpin maps.
Example:dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.
Quoted 5 lines
The new
hairpin-mapparameter is optional. If omitted, testpmd will create "default" hairpin maps.Signed-off-by Gregory Etelson <[email protected]>
Ferruh Yigit
AppliedRe: [PATCH v7] testpmd: add hairpin map parameter
Quoted 32 lines · Stephen Hemminger
Quoted 29 lines · On Thu, 31 Oct 2024 06:58:17 +0200 Gregory Etelson <[email protected]> wrote:
Hairpin offloads packet forwarding between ports. Packet is expected on Rx port <rp>, Rx queue <rq> and is forwarded to Tx port <tp> Tx queue <tq>.
Testpmd implements a static hairpin configuration scheme.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The newhairpin-mapparameter is provided with 5 parameters, separated by:
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues numberTestpmd operator can provide several
hairpin-mapparameters for different hairpin maps.
Example:dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.
Quoted 8 lines
Quoted 5 lines
The new
hairpin-mapparameter is optional. If omitted, testpmd will create "default" hairpin maps.Signed-off-by Gregory Etelson <[email protected]>
Applied to dpdk-next-net/main, thanks.
PATCH v4 1/1 testpmd: add hairpin-map parameter
In reply to Gregory EtelsonHairpin offloads packet forwarding between ports. Packet is expected on Rx port <rp>, Rx queue <rq> and is forwarded to Tx port <tp> Tx queue <tq>.
Testpmd implements a static hairpin configuration scheme.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration.
The new hairpin-map parameter is provided with 5 parameters, separated by :
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number
Testpmd operator can provide several hairpin-map parameters for different hairpin maps.
Example:
dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]
Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.
The new hairpin-map parameter is optional. If omitted, testpmd will create "default" hairpin maps.
--- app/test-pmd/hairpin.c | 385 ++++++++++++++++++++++++++ app/test-pmd/meson.build | 1 + app/test-pmd/parameters.c | 10 + app/test-pmd/testpmd.c | 217 +-------------- app/test-pmd/testpmd.h | 14 + doc/guides/testpmd_app_ug/run_app.rst | 3 + 6 files changed, 416 insertions(+), 214 deletions(-) create mode 100644 app/test-pmd/hairpin.c
app/test-pmd/hairpin.c new file +385 -0
@@ -0,0 +1,385 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright (c) 2022 NVIDIA Corporation & Affiliates +*/ + +#include <stdio.h> +#include <string.h> +#include <stdbool.h> +#include <stdint.h> + +#include <sys/queue.h> + +#include "testpmd.h" + +/* Hairpin ports configuration mode. */ +uint32_t hairpin_mode; + +bool hairpin_multiport_mode = false; + +queueid_t nb_hairpinq;/**< Number of hairpin queues per port. */ + +static LIST_HEAD(, hairpin_map) hairpin_map_head = LIST_HEAD_INITIALIZER(); + +struct hairpin_map { +LIST_ENTRY (hairpin_map) entry;/**< List entry. */ +portid_t rx_port;/**< Hairpin Rx port ID. */ +portid_t tx_port;/**< Hairpin Tx port ID. */ +uint16_t rxq_head;/**< Hairpin Rx queue head. */ +uint16_t txq_head;/**< Hairpin Tx queue head. */ +uint16_t qnum;/**< Hairpin queues number. */ +}; + +void +hairpin_add_multiport_map (struct hairpin_map *map) +{ +LIST_INSERT_HEAD (&hairpin_map_head, map, entry); +} + +/* +* Get the allowed maximum number of hairpin queues. +* *pid return the port id which has minimal value of +* max_hairpin_queues in all ports. +*/ +queueid_t +get_allowed_max_nb_hairpinq (portid_t *pid) +{ +queueid_t allowed_max_hairpinq =RTE_MAX_QUEUES_PER_PORT ; +portid_t pi; +struct rte_eth_hairpin_cap cap; + +RTE_ETH_FOREACH_DEV (pi) { +if (rte_eth_dev_hairpin_capability_get (pi, &cap) !=0 ) { + *pid = pi; +return 0 ; + } +if (cap.max_nb_queues < allowed_max_hairpinq) { + allowed_max_hairpinq = cap.max_nb_queues; + *pid = pi; + } + } +return allowed_max_hairpinq; +} + +/* +* Check input hairpin is valid or not. +* If input hairpin is not greater than any of maximum number +* of hairpin queues of all ports, it is valid. +* if valid, return 0, else return -1 +*/ +int +check_nb_hairpinq (queueid_t hairpinq) +{ +queueid_t allowed_max_hairpinq; +portid_t pid =0 ; + + allowed_max_hairpinq =get_allowed_max_nb_hairpinq (&pid); +if (hairpinq > allowed_max_hairpinq) { +fprintf (stderr, +"Fail: input hairpin (%u) can't be greater than max_hairpin_queues (%u) of port %u\n" , + hairpinq, allowed_max_hairpinq, pid); +return -1 ; + } +return 0 ; +} + +#define HAIRPIN_MODE_RX_FORCE_MEMORY RTE_BIT32(8) +#define HAIRPIN_MODE_TX_FORCE_MEMORY RTE_BIT32(9) + +#define HAIRPIN_MODE_RX_LOCKED_MEMORY RTE_BIT32(12) +#define HAIRPIN_MODE_RX_RTE_MEMORY RTE_BIT32(13) + +#define HAIRPIN_MODE_TX_LOCKED_MEMORY RTE_BIT32(16) +#define HAIRPIN_MODE_TX_RTE_MEMORY RTE_BIT32(17) + +static int +port_config_hairpin_rxq (portid_t pi,uint16_t peer_tx_port, +queueid_t rxq_head,queueid_t txq_head, +uint16_t qcount,uint32_t manual_bind) +{ +int diag; +queueid_t i, qi; +uint32_t tx_explicit = !!(hairpin_mode &0x10 ); +uint32_t force_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_FORCE_MEMORY ); +uint32_t locked_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_LOCKED_MEMORY ); +uint32_t rte_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_RTE_MEMORY ); +struct rte_port *port = &ports[pi]; +struct rte_eth_hairpin_conf hairpin_conf = { + .peer_count =1 , + }; + +for (qi = rxq_head, i =0 ; qi < rxq_head + qcount; qi++) { + hairpin_conf.peers[0 ].port = peer_tx_port; + hairpin_conf.peers[0 ].queue = i + txq_head; + hairpin_conf.manual_bind = manual_bind; + hairpin_conf.tx_explicit = tx_explicit; + hairpin_conf.force_memory = force_mem; + hairpin_conf.use_locked_device_memory = locked_mem; + hairpin_conf.use_rte_memory = rte_mem; + diag =rte_eth_rx_hairpin_queue_setup + (pi, qi, nb_rxd, &hairpin_conf); + i++; +if (diag ==0 ) +continue ; + +/* Fail to setup rx queue, return */ +if (port->port_status ==RTE_PORT_HANDLING ) + port->port_status =RTE_PORT_STOPPED ; +else +fprintf (stderr, +"Port %d can not be set back to stopped\n" , pi); +fprintf (stderr, +"Port %d failed to configure hairpin on rxq %u.\n" +"Peer port: %u peer txq: %u\n" , + pi, qi, peer_tx_port, i); +/* try to reconfigure queues next time */ + port->need_reconfig_queues =1 ; +return -1 ; + } +return 0 ; +} + +static int +port_config_hairpin_txq (portid_t pi,uint16_t peer_rx_port, +queueid_t rxq_head,queueid_t txq_head, +uint16_t qcount,uint32_t manual_bind) +{ +int diag; +queueid_t i, qi; +uint32_t tx_explicit = !!(hairpin_mode &0x10 ); +uint32_t force_mem = !!(hairpin_mode &HAIRPIN_MODE_TX_FORCE_MEMORY ); +uint32_t locked_mem = !!(hairpin_mode &HAIRPIN_MODE_TX_LOCKED_MEMORY ); +uint32_t rte_mem = !!(hairpin_mode &HAIRPIN_MODE_TX_RTE_MEMORY ); +struct rte_port *port = &ports[pi]; +struct rte_eth_hairpin_conf hairpin_conf = { + .peer_count =1 , + }; + +for (qi = txq_head, i =0 ; qi < txq_head + qcount; qi++) { + hairpin_conf.peers[0 ].port = peer_rx_port; + hairpin_conf.peers[0 ].queue = i + rxq_head; + hairpin_conf.manual_bind = manual_bind; + hairpin_conf.tx_explicit = tx_explicit; + hairpin_conf.force_memory = force_mem; + hairpin_conf.use_locked_device_memory = locked_mem; + hairpin_conf.use_rte_memory = rte_mem; + diag =rte_eth_tx_hairpin_queue_setup + (pi, qi, nb_txd, &hairpin_conf); + i++; +if (diag ==0 ) +continue ; + +/* Fail to setup rx queue, return */ +if (port->port_status ==RTE_PORT_HANDLING ) + port->port_status =RTE_PORT_STOPPED ; +else +fprintf (stderr, +"Port %d can not be set back to stopped\n" , pi); +fprintf (stderr, +"Port %d failed to configure hairpin on txq %u.\n" +"Peer port: %u peer rxq: %u\n" , + pi, qi, peer_rx_port, i); +/* try to reconfigure queues next time */ + port->need_reconfig_queues =1 ; +return -1 ; + } +return 0 ; +} + +static int +setup_legacy_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t cnt_pi) +{ +int diag; +uint16_t peer_rx_port = pi; +uint16_t peer_tx_port = pi; +uint32_t manual =1 ; + +if (!(hairpin_mode &0xf )) { + peer_rx_port = pi; + peer_tx_port = pi; + manual =0 ; + }else if (hairpin_mode &0x1 ) { + peer_tx_port =rte_eth_find_next_owned_by (pi +1 , +RTE_ETH_DEV_NO_OWNER ); +if (peer_tx_port >=RTE_MAX_ETHPORTS ) + peer_tx_port =rte_eth_find_next_owned_by (0 , +RTE_ETH_DEV_NO_OWNER ); +if (p_pi !=RTE_MAX_ETHPORTS ) { + peer_rx_port = p_pi; + }else { +uint16_t next_pi; + +/* Last port will be the peer RX port of the first. */ +RTE_ETH_FOREACH_DEV (next_pi) + peer_rx_port = next_pi; + } + manual =1 ; + }else if (hairpin_mode &0x2 ) { +if (cnt_pi &0x1 ) { + peer_rx_port = p_pi; + }else { + peer_rx_port =rte_eth_find_next_owned_by (pi +1 , +RTE_ETH_DEV_NO_OWNER ); +if (peer_rx_port >=RTE_MAX_ETHPORTS ) + peer_rx_port = pi; + } + peer_tx_port = peer_rx_port; + manual =1 ; + } + diag =port_config_hairpin_txq (pi, peer_rx_port, nb_rxq, nb_txq, + nb_hairpinq, manual); +if (diag) +return diag; + diag =port_config_hairpin_rxq (pi, peer_tx_port, nb_rxq, nb_txq, + nb_hairpinq, manual); +if (diag) +return diag; +return 0 ; +} + +static int +setup_mapped_harpin_queues (portid_t pi) +{ +int ret =0 ; +struct hairpin_map *map; + + LIST_FOREACH(map, &hairpin_map_head, entry) { +if (map->rx_port == pi) { + ret =port_config_hairpin_rxq (pi, map->tx_port, + map->rxq_head, + map->txq_head, + map->qnum, true); +if (ret) +return ret; + } +if (map->tx_port == pi) { + ret =port_config_hairpin_txq (pi, map->rx_port, + map->rxq_head, + map->txq_head, + map->qnum, true); +if (ret) +return ret; + } + } +return 0 ; +} + +/* Configure the Rx and Tx hairpin queues for the selected port. */ +int +setup_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t cnt_pi) +{ +return !hairpin_multiport_mode ? +setup_legacy_hairpin_queues (pi, p_pi, cnt_pi) : +setup_mapped_harpin_queues (pi); +} + +int +hairpin_bind (uint16_t cfg_pi,portid_t *pl,portid_t *peer_pl) +{ +uint16_t i; +portid_t pi; +int peer_pi; +int diag; +int j; + +/* bind all started hairpin ports */ +for (i =0 ; i < cfg_pi; i++) { + pi = pl[i]; +/* bind current Tx to all peer Rx */ + peer_pi =rte_eth_hairpin_get_peer_ports (pi, peer_pl, +RTE_MAX_ETHPORTS ,1 ); +if (peer_pi <0 ) +return peer_pi; +for (j =0 ; j < peer_pi; j++) { +if (!port_is_started (peer_pl[j])) +continue ; + diag =rte_eth_hairpin_bind (pi, peer_pl[j]); +if (diag <0 ) { +fprintf (stderr, +"Error during binding hairpin Tx port %u to %u: %s\n" , + pi, peer_pl[j], +rte_strerror (-diag)); +return -1 ; + } + } +/* bind all peer Tx to current Rx */ + peer_pi =rte_eth_hairpin_get_peer_ports (pi, peer_pl, +RTE_MAX_ETHPORTS ,0 ); +if (peer_pi <0 ) +return peer_pi; +for (j =0 ; j < peer_pi; j++) { +if (!port_is_started (peer_pl[j])) +continue ; + diag =rte_eth_hairpin_bind (peer_pl[j], pi); +if (diag <0 ) { +fprintf (stderr, +"Error during binding hairpin Tx port %u to %u: %s\n" , + peer_pl[j], pi, +rte_strerror (-diag)); +return -1 ; + } + } + } +return 0 ; +} + +void +hairpin_map_usage (void ) +{ +printf (" --hairpin-map=rxpi:rxq:txpi:txq:n: hairpin map.\n" +" rxpi - Rx port index.\n" +" rxq - Rx queue.\n" +" txpi - Tx port index.\n" +" txq - Tx queue.\n" +" n - hairpin queues number.\n" ); +} + +static char +*parse_hairpin_map_entry (char *input,char **next) +{ +char *tail =strchr (input,':' ); + +if (!tail) +return NULL ; + tail[0 ] ='\0' ; + *next = tail +1 ; +return input; +} + +int +parse_hairpin_map (const char *hpmap) +{ +/* +* Testpmd hairpin map format: +* <Rx port id:First Rx queue:Tx port id:First Tx queue:queues number> +*/ +char *head, *next = (char *)(uintptr_t )hpmap; +struct hairpin_map *map =calloc (1 ,sizeof (*map)); + +if (!map) +return -ENOMEM ; + + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->rx_port =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->rxq_head =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->tx_port =atoi (head); + head =parse_hairpin_map_entry (next, &next); +if (!head) + goto err; + map->txq_head =atoi (head); + map->qnum =atoi (next); +hairpin_add_multiport_map (map); +return 0 ; +err: +free (map); +return -EINVAL ; +} + +
app/test-pmd/meson.build +1 -0
@@ -15,6 +15,7 @@ sources = files( 'config.c', 'csumonly.c', 'flowgen.c', + 'hairpin.c', 'icmpecho.c', 'ieee1588fwd.c', 'iofwd.c',
app/test-pmd/parameters.c +10 -0
@@ -143,6 +143,8 @@ enum {TESTPMD_OPT_HAIRPINQ_NUM , #define TESTPMD_OPT_HAIRPIN_MODE "hairpin-mode"TESTPMD_OPT_HAIRPIN_MODE_NUM , +#define TESTPMD_OPT_HAIRPIN_MAP "hairpin-map" +TESTPMD_OPT_HAIRPIN_MAP_NUM , #define TESTPMD_OPT_BURST "burst"TESTPMD_OPT_BURST_NUM , #define TESTPMD_OPT_FLOWGEN_CLONES "flowgen-clones"
@@ -317,6 +319,7 @@ static const struct option long_options[] = {REQUIRED_ARG (TESTPMD_OPT_TXD ),REQUIRED_ARG (TESTPMD_OPT_HAIRPINQ ),REQUIRED_ARG (TESTPMD_OPT_HAIRPIN_MODE ), +REQUIRED_ARG (TESTPMD_OPT_HAIRPIN_MAP ),REQUIRED_ARG (TESTPMD_OPT_BURST ),REQUIRED_ARG (TESTPMD_OPT_FLOWGEN_CLONES ), REQUIRED_ARG(TESTPMD_OPT_FLOWGEN_FLOWS),
@@ -542,6 +545,7 @@ usage(char* progname)printf (" --hairpin-mode=0xXX: bitmask set the hairpin port mode.\n" " 0x10 - explicit Tx rule, 0x02 - hairpin ports paired\n" " 0x01 - hairpin ports loop, 0x00 - hairpin port self\n" ); +hairpin_map_usage (); } static int
@@ -1317,6 +1321,12 @@ launch_args_parse(int argc, char** argv) hairpin_mode = (uint32_t )n;break ; } +case TESTPMD_OPT_HAIRPIN_MAP_NUM : + hairpin_multiport_mode = true; + ret =parse_hairpin_map (optarg); +if (ret) +rte_exit (EXIT_FAILURE ,"invalid hairpin map\n" ); +break ;case TESTPMD_OPT_BURST_NUM : n =atoi (optarg);if (n ==0 ) {
app/test-pmd/testpmd.c +3 -214
253 lines not on this page · raw message
app/test-pmd/testpmd.h +14 -0
@@ -126,6 +126,16 @@ enum noisy_fwd_mode { NOISY_FWD_MODE_MAX, }; +/** +* Command line arguments parser sets `hairpin_multiport_mode` to True +* if explicit hairpin map configuration mode was used. +*/ +extern bool hairpin_multiport_mode; + +/** Hairpin maps list. */ +struct hairpin_map ; +extern void hairpin_add_multiport_map (struct hairpin_map *map); +/** * The data structure associated with RX and TX packet burst statistics * that are recorded for each forwarding stream.
@@ -1252,6 +1262,10 @@ extern int flow_parse(const char *src, void *result, unsigned int size,struct rte_flow_attr **attr, struct rte_flow_item **pattern, struct rte_flow_action **actions); +int setup_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t cnt_pi); +int hairpin_bind (uint16_t cfg_pi,portid_t *pl,portid_t *peer_pl); +void hairpin_map_usage (void ); +int parse_hairpin_map (const char *hpmap);uint64_t str_to_rsstypes (const char *str);const char *rsstypes_to_str (uint64_t rss_type);
doc/guides/testpmd_app_ug/run_app.rst +3 -0
@@ -571,6 +571,9 @@ The command line options are: The default value is 0. Hairpin will use single port mode and implicit Tx flow mode. +* ``--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number`` + + Set explicit hairpin configuration. Testpmd Multi-Process Command-line Options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Signature · 1 line
2.43.0
Hi Gregory,
Can you please resolve the compilation issues seen with this patch.
Hairpin offloads packet forwarding between ports.
Packet is expected on Rx port <rp>, Rx queue <rq> and is forwarded to Tx port <tp> Tx queue <tq>.
Testpmd implements a static hairpin configuration scheme.
The new parameter allows explicit selection of Rx and Tx ports and queues in hairpin configuration. The new hairpin-map parameter is provided with 5 parameters, separated by :
--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number
Can we rephrase the parameter "queues number " to something like "total queue pairs"
Testpmd operator can provide several hairpin-map parameters for different hairpin maps. Example:
dpdk-testpmd <EAL params> -- \
<testpmd params> \
--rxq=2 --txq=2 --hairpinq=2 --hairpin-mode=0x12 \
--hairpin-map=0:2:1:2:1 \ # [1]
--hairpin-map=0:3:2:2:3 # [2]
Hairpin map [1] binds Rx port 0, queue 2 with Tx port 1, queue 2. Hairpin map [2] binds
Rx port 0, queue 3 with Tx port 2, queue 2,
Rx port 0, queue 4 with Tx port 2, queue 3,
Rx port 0, queue 5 with Tx port 2, queue 4.
The new hairpin-map parameter is optional. If omitted, testpmd will create "default" hairpin maps.
--- app/test-pmd/hairpin.c | 385 ++++++++++++++++++++++++++ app/test-pmd/meson.build | 1 + app/test-pmd/parameters.c | 10 + app/test-pmd/testpmd.c | 217 +-------------- app/test-pmd/testpmd.h | 14 + doc/guides/testpmd_app_ug/run_app.rst | 3 + 6 files changed, 416 insertions(+), 214 deletions(-) create mode 100644 app/test-pmd/hairpin.c
app/test-pmd/hairpin.c new file +343 -0
@@ -0,0 +1,385 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright (c) 2022 NVIDIA Corporation & Affiliates */ + +#include <stdio.h> +#include <string.h> +#include <stdbool.h> +#include <stdint.h> + +#include <sys/queue.h> + +#include "testpmd.h" + +/* Hairpin ports configuration mode. */ uint32_t hairpin_mode; + +bool hairpin_multiport_mode = false; + +queueid_t nb_hairpinq;/**< Number of hairpin queues per port. */ + +static LIST_HEAD(, hairpin_map) hairpin_map_head = +LIST_HEAD_INITIALIZER (); + +struct hairpin_map { +LIST_ENTRY (hairpin_map) entry;/**< List entry. */ +portid_t rx_port;/**< Hairpin Rx port ID. */ +portid_t tx_port;/**< Hairpin Tx port ID. */ +uint16_t rxq_head;/**< Hairpin Rx queue head. */ +uint16_t txq_head;/**< Hairpin Tx queue head. */ +uint16_t qnum;/**< Hairpin queues number. */ }; + +void +hairpin_add_multiport_map (struct hairpin_map *map) { +LIST_INSERT_HEAD (&hairpin_map_head, map, entry); } + +/* +* Get the allowed maximum number of hairpin queues. +* *pid return the port id which has minimal value of +* max_hairpin_queues in all ports. +*/ +queueid_t +get_allowed_max_nb_hairpinq (portid_t *pid) { +queueid_t allowed_max_hairpinq =RTE_MAX_QUEUES_PER_PORT ; +portid_t pi; +struct rte_eth_hairpin_cap cap; + +RTE_ETH_FOREACH_DEV (pi) { +if (rte_eth_dev_hairpin_capability_get (pi, &cap) !=0 ) { + *pid = pi; +return 0 ; + } +if (cap.max_nb_queues < allowed_max_hairpinq) { + allowed_max_hairpinq = cap.max_nb_queues; + *pid = pi; + } + } +return allowed_max_hairpinq; +} + +/* +* Check input hairpin is valid or not. +* If input hairpin is not greater than any of maximum number +* of hairpin queues of all ports, it is valid. +* if valid, return 0, else return -1 +*/ +int +check_nb_hairpinq (queueid_t hairpinq) +{ +queueid_t allowed_max_hairpinq; +portid_t pid =0 ; + + allowed_max_hairpinq =get_allowed_max_nb_hairpinq (&pid); +if (hairpinq > allowed_max_hairpinq) { +fprintf (stderr, +"Fail: input hairpin (%u) can't be greater than max_hairpin_queues (%u) of port %u\n" , + hairpinq, allowed_max_hairpinq, pid); +return -1 ; + } +return 0 ; +} + +#define HAIRPIN_MODE_RX_FORCE_MEMORY RTE_BIT32(8) #define +HAIRPIN_MODE_TX_FORCE_MEMORY RTE_BIT32(9) + +#define HAIRPIN_MODE_RX_LOCKED_MEMORY RTE_BIT32(12) #define +HAIRPIN_MODE_RX_RTE_MEMORY RTE_BIT32(13) + +#define HAIRPIN_MODE_TX_LOCKED_MEMORY RTE_BIT32(16) #define +HAIRPIN_MODE_TX_RTE_MEMORY RTE_BIT32(17) + +static int +port_config_hairpin_rxq(portid_t pi, uint16_t peer_tx_port, + queueid_t rxq_head, queueid_t txq_head, + uint16_t qcount, uint32_t manual_bind) { + int diag; +queueid_t i, qi; +uint32_t tx_explicit = !!(hairpin_mode &0x10 ); +uint32_t force_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_FORCE_MEMORY ); +uint32_t locked_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_LOCKED_MEMORY ); +uint32_t rte_mem = !!(hairpin_mode &HAIRPIN_MODE_RX_RTE_MEMORY ); +struct rte_port *port = &ports[pi]; +struct rte_eth_hairpin_conf hairpin_conf = { + .peer_count =1 , + }; + + for (qi = rxq_head, i = 0; qi < rxq_head + qcount; qi++) { + hairpin_conf.peers[0 ].port = peer_tx_port; + hairpin_conf.peers[0 ].queue = i + txq_head; + hairpin_conf.manual_bind = manual_bind; + hairpin_conf.tx_explicit = tx_explicit; + hairpin_conf.force_memory = force_mem; + hairpin_conf.use_locked_device_memory = locked_mem; + hairpin_conf.use_rte_memory = rte_mem; + diag =rte_eth_rx_hairpin_queue_setup + (pi, qi, nb_rxd, &hairpin_conf); + i++; +if (diag ==0 ) +continue ; + +/* Fail to setup rx queue, return */ +if (port->port_status ==RTE_PORT_HANDLING ) + port->port_status =RTE_PORT_STOPPED ; +else +fprintf (stderr, +"Port %d can not be set back to stopped\n" , pi); +fprintf (stderr, +"Port %d failed to configure hairpin on rxq %u.\n" +"Peer port: %u peer txq: %u\n" , + pi, qi, peer_tx_port, i); +/* try to reconfigure queues next time */ + port->need_reconfig_queues =1 ; +return -1 ; + } +return 0 ; +} + +static int +port_config_hairpin_txq (portid_t pi,uint16_t peer_rx_port, +queueid_t rxq_head,queueid_t txq_head, +uint16_t qcount,uint32_t manual_bind) { +int diag; +queueid_t i, qi; +uint32_t tx_explicit = !!(hairpin_mode &0x10 ); +uint32_t force_mem = !!(hairpin_mode &HAIRPIN_MODE_TX_FORCE_MEMORY ); +uint32_t locked_mem = !!(hairpin_mode &HAIRPIN_MODE_TX_LOCKED_MEMORY ); +uint32_t rte_mem = !!(hairpin_mode &HAIRPIN_MODE_TX_RTE_MEMORY ); +struct rte_port *port = &ports[pi]; +struct rte_eth_hairpin_conf hairpin_conf = { + .peer_count =1 , + }; + +for (qi = txq_head, i =0 ; qi < txq_head + qcount; qi++) { + hairpin_conf.peers[0 ].port = peer_rx_port; + hairpin_conf.peers[0 ].queue = i + rxq_head; + hairpin_conf.manual_bind = manual_bind; + hairpin_conf.tx_explicit = tx_explicit; + hairpin_conf.force_memory = force_mem; + hairpin_conf.use_locked_device_memory = locked_mem; + hairpin_conf.use_rte_memory = rte_mem; + diag =rte_eth_tx_hairpin_queue_setup + (pi, qi, nb_txd, &hairpin_conf); + i++; +if (diag ==0 ) +continue ; + +/* Fail to setup rx queue, return */ +if (port->port_status ==RTE_PORT_HANDLING ) + port->port_status =RTE_PORT_STOPPED ; +else +fprintf (stderr, +"Port %d can not be set back to stopped\n" , pi); +fprintf (stderr, +"Port %d failed to configure hairpin on txq %u.\n" +"Peer port: %u peer rxq: %u\n" , + pi, qi, peer_rx_port, i); +/* try to reconfigure queues next time */ + port->need_reconfig_queues =1 ; +return -1 ; + } +return 0 ; +} + +static int +setup_legacy_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t +cnt_pi) { +int diag; +uint16_t peer_rx_port = pi; +uint16_t peer_tx_port = pi; +uint32_t manual =1 ; + +if (!(hairpin_mode &0xf )) { + peer_rx_port = pi; + peer_tx_port = pi; + manual =0 ; + }else if (hairpin_mode &0x1 ) { + peer_tx_port =rte_eth_find_next_owned_by (pi +1 , +RTE_ETH_DEV_NO_OWNER ); +if (peer_tx_port >=RTE_MAX_ETHPORTS ) + peer_tx_port =rte_eth_find_next_owned_by (0 , +RTE_ETH_DEV_NO_OWNER ); +if (p_pi !=RTE_MAX_ETHPORTS ) { + peer_rx_port = p_pi; + }else { +uint16_t next_pi; + +/* Last port will be the peer RX port of the first. */ +RTE_ETH_FOREACH_DEV (next_pi) + peer_rx_port = next_pi; + } + manual =1 ; + }else if (hairpin_mode &0x2 ) { +if (cnt_pi &0x1 ) { + peer_rx_port = p_pi; + }else { + peer_rx_port =rte_eth_find_next_owned_by (pi +1 , +RTE_ETH_DEV_NO_OWNER ); +if (peer_rx_port >=RTE_MAX_ETHPORTS ) + peer_rx_port = pi; + } + peer_tx_port = peer_rx_port; + manual =1 ; + } + diag =port_config_hairpin_txq (pi, peer_rx_port, nb_rxq, nb_txq, + nb_hairpinq, manual); +if (diag) +return diag; + diag =port_config_hairpin_rxq (pi, peer_tx_port, nb_rxq, nb_txq, + nb_hairpinq, manual); +if (diag) +return diag; +return 0 ; +} + +static int +setup_mapped_harpin_queues (portid_t pi) { +int ret =0 ; +struct hairpin_map *map; + + LIST_FOREACH(map, &hairpin_map_head, entry) { +if (map->rx_port == pi) { + ret =port_config_hairpin_rxq (pi, map->tx_port, + map->rxq_head, + map->txq_head, + map->qnum, true); +if (ret) +return ret; + } +if (map->tx_port == pi) { + ret =port_config_hairpin_txq (pi, map->rx_port, + map->rxq_head, + map->txq_head, + map->qnum, true); +if (ret) +return ret; + } + } +return 0 ; +} + +/* Configure the Rx and Tx hairpin queues for the selected port. */ int +setup_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t cnt_pi) { +return !hairpin_multiport_mode ? +setup_legacy_hairpin_queues (pi, p_pi, cnt_pi) : +setup_mapped_harpin_queues (pi); } + +int +hairpin_bind (uint16_t cfg_pi,portid_t *pl,portid_t *peer_pl) { +uint16_t i; +portid_t pi; +int peer_pi; +int diag; +int j; + +/* bind all started hairpin ports */ +for (i =0 ; i < cfg_pi; i++) { + pi = pl[i]; +/* bind current Tx to all peer Rx */ + peer_pi =rte_eth_hairpin_get_peer_ports (pi, peer_pl, +RTE_MAX_ETHPORTS ,1 ); +if (peer_pi <0 ) +return peer_pi; +for (j =0 ; j < peer_pi; j++) { +if (!port_is_started (peer_pl[j])) +continue ; + diag =rte_eth_hairpin_bind (pi, peer_pl[j]); +if (diag <0 ) { +fprintf (stderr, +"Error during binding hairpin Tx port %u to %u: %s\n" , + pi, peer_pl[j], +rte_strerror (-diag)); +return -1 ; + } + } +/* bind all peer Tx to current Rx */ + peer_pi =rte_eth_hairpin_get_peer_ports (pi, peer_pl, +RTE_MAX_ETHPORTS ,0 ); +if (peer_pi <0 ) +return peer_pi; +for (j =0 ; j < peer_pi; j++) { +if (!port_is_started (peer_pl[j])) +continue ; + diag =rte_eth_hairpin_bind (peer_pl[j], pi); +if (diag <0 ) { +fprintf (stderr, +"Error during binding hairpin Tx port %u to %u: %s\n" , + peer_pl[j], pi, +rte_strerror (-diag)); +return -1 ; + } + } + } +return 0 ; +} + +void +hairpin_map_usage (void ) +{ +printf (" --hairpin-map=rxpi:rxq:txpi:txq:n: hairpin map.\n" +" rxpi - Rx port index.\n" +" rxq - Rx queue.\n" +" txpi - Tx port index.\n" +" txq - Tx queue.\n" +" n - hairpin queues number.\n" ); +} + +static char +*parse_hairpin_map_entry (char *input,char **next) { +char *tail =strchr (input,':' ); + +if (!tail) +return NULL ; + tail[0 ] ='\0' ; + *next = tail +1 ; +return input; +} + +int +parse_hairpin_map (const char *hpmap) +{ +/* +* Testpmd hairpin map format: +* <Rx port id:First Rx queue:Tx port id:First Tx queue:queues number> +*/ +char *head, *next = (char *)(uintptr_t )hpmap; +struct hairpin_map *map =calloc (1 ,sizeof (*map));
Can use rte_calloc() here.
+
+ if (!map)
+ return -ENOMEM;
+
+ head = parse_hairpin_map_entry(next, &next);
+ if (!head)
+ goto err;
+ map->rx_port = atoi(head);
+ head = parse_hairpin_map_entry(next, &next);
+ if (!head)
+ goto err;
+ map->rxq_head = atoi(head);
+ head = parse_hairpin_map_entry(next, &next);
+ if (!head)
+ goto err;
+ map->tx_port = atoi(head);
+ head = parse_hairpin_map_entry(next, &next);
+ if (!head)
+ goto err;
+ map->txq_head = atoi(head);
+ map->qnum = atoi(next);
+ hairpin_add_multiport_map(map);
+ return 0;
+err:
+ free(map);
Can use rte_free()
+ return -EINVAL;
+}
+
+
app/test-pmd/meson.build +1 -0
@@ -15,6 +15,7 @@ sources = files( 'config.c', 'csumonly.c', 'flowgen.c', + 'hairpin.c', 'icmpecho.c', 'ieee1588fwd.c', 'iofwd.c',
app/test-pmd/parameters.c +10 -0
@@ -143,6 +143,8 @@ enum {TESTPMD_OPT_HAIRPINQ_NUM , #define TESTPMD_OPT_HAIRPIN_MODE "hairpin-mode"TESTPMD_OPT_HAIRPIN_MODE_NUM , +#define TESTPMD_OPT_HAIRPIN_MAP "hairpin-map" +TESTPMD_OPT_HAIRPIN_MAP_NUM , #define TESTPMD_OPT_BURST "burst"TESTPMD_OPT_BURST_NUM , #define TESTPMD_OPT_FLOWGEN_CLONES "flowgen-clones"
@@ -317,6 +319,7 @@ static const struct option long_options[] = {REQUIRED_ARG (TESTPMD_OPT_TXD ),REQUIRED_ARG (TESTPMD_OPT_HAIRPINQ ),REQUIRED_ARG (TESTPMD_OPT_HAIRPIN_MODE ), +REQUIRED_ARG (TESTPMD_OPT_HAIRPIN_MAP ),REQUIRED_ARG (TESTPMD_OPT_BURST ),REQUIRED_ARG (TESTPMD_OPT_FLOWGEN_CLONES ), REQUIRED_ARG(TESTPMD_OPT_FLOWGEN_FLOWS),
@@ -542,6 +545,7 @@ usage(char* progname)printf (" --hairpin-mode=0xXX: bitmask set the hairpin port mode.\n" " 0x10 - explicit Tx rule, 0x02 - hairpin ports paired\n" " 0x01 - hairpin ports loop, 0x00 - hairpin port self\n" ); +hairpin_map_usage (); } static int
@@ -1317,6 +1321,12 @@ launch_args_parse(int argc, char** argv) hairpin_mode = (uint32_t )n;break ; } +case TESTPMD_OPT_HAIRPIN_MAP_NUM : + hairpin_multiport_mode = true; + ret =parse_hairpin_map (optarg); +if (ret) +rte_exit (EXIT_FAILURE ,"invalid hairpin map\n" ); +break ;case TESTPMD_OPT_BURST_NUM : n =atoi (optarg);if (n ==0 ) {
app/test-pmd/testpmd.c +0 -50
65 lines not on this page · raw message
}
-#define HAIRPIN_MODE_RX_FORCE_MEMORY RTE_BIT32(8) -#define HAIRPIN_MODE_TX_FORCE_MEMORY RTE_BIT32(9)
-
-#define HAIRPIN_MODE_RX_LOCKED_MEMORY RTE_BIT32(12) -#define HAIRPIN_MODE_RX_RTE_MEMORY RTE_BIT32(13)
-
-#define HAIRPIN_MODE_TX_LOCKED_MEMORY RTE_BIT32(16) -#define HAIRPIN_MODE_TX_RTE_MEMORY RTE_BIT32(17)
-
-
-/* Configure the Rx and Tx hairpin queues for the selected port. */ -static int -setup_hairpin_queues(portid_t pi, portid_t p_pi, uint16_t cnt_pi) -{
- queueid_t qi;
- struct rte_eth_hairpin_conf hairpin_conf = {
- .peer_count = 1,
- };
- int i;
- int diag;
- struct rte_port *port = &ports[pi];
- uint16_t peer_rx_port = pi;
- uint16_t peer_tx_port = pi;
- uint32_t manual = 1;
- uint32_t tx_exp = hairpin_mode & 0x10;
- uint32_t rx_force_memory = hairpin_mode & HAIRPIN_MODE_RX_FORCE_MEMORY;
- uint32_t rx_locked_memory = hairpin_mode & HAIRPIN_MODE_RX_LOCKED_MEMORY;
- uint32_t rx_rte_memory = hairpin_mode & HAIRPIN_MODE_RX_RTE_MEMORY;
- uint32_t tx_force_memory = hairpin_mode & HAIRPIN_MODE_TX_FORCE_MEMORY;
- uint32_t tx_locked_memory = hairpin_mode & HAIRPIN_MODE_TX_LOCKED_MEMORY;
- uint32_t tx_rte_memory = hairpin_mode & HAIRPIN_MODE_TX_RTE_MEMORY;
-
- if (!(hairpin_mode & 0xf)) {
- peer_rx_port = pi;
- peer_tx_port = pi;
- manual = 0;
- } else if (hairpin_mode & 0x1) {
- peer_tx_port = rte_eth_find_next_owned_by(pi + 1,
- RTE_ETH_DEV_NO_OWNER);
- if (peer_tx_port >= RTE_MAX_ETHPORTS)
- peer_tx_port = rte_eth_find_next_owned_by(0,
- RTE_ETH_DEV_NO_OWNER);
- if (p_pi != RTE_MAX_ETHPORTS) {
- peer_rx_port = p_pi;
- } else {
- uint16_t next_pi;
-
- /* Last port will be the peer RX port of the first. */
- RTE_ETH_FOREACH_DEV(next_pi)
- peer_rx_port = next_pi;
- }
- manual = 1;
- } else if (hairpin_mode & 0x2) {
- if (cnt_pi & 0x1) {
- peer_rx_port = p_pi;
- } else {
- peer_rx_port = rte_eth_find_next_owned_by(pi + 1,
- RTE_ETH_DEV_NO_OWNER);
- if (peer_rx_port >= RTE_MAX_ETHPORTS)
- peer_rx_port = pi;
- }
- peer_tx_port = peer_rx_port;
- manual = 1;
- }
-
- for (qi = nb_txq, i = 0; qi < nb_hairpinq + nb_txq; qi++) {
- hairpin_conf.peers[0].port = peer_rx_port;
- hairpin_conf.peers[0].queue = i + nb_rxq;
- hairpin_conf.manual_bind = !!manual;
- hairpin_conf.tx_explicit = !!tx_exp;
- hairpin_conf.force_memory = !!tx_force_memory;
- hairpin_conf.use_locked_device_memory = !!tx_locked_memory;
- hairpin_conf.use_rte_memory = !!tx_rte_memory;
- diag = rte_eth_tx_hairpin_queue_setup
- (pi, qi, nb_txd, &hairpin_conf);
- i++;
- if (diag == 0)
- continue;
-
- /* Fail to setup rx queue, return */
- if (port->port_status == RTE_PORT_HANDLING)
- port->port_status = RTE_PORT_STOPPED;
- else
- fprintf(stderr,
- "Port %d can not be set back to stopped\n", pi);
- fprintf(stderr, "Fail to configure port %d hairpin queues\n",
- pi);
- /* try to reconfigure queues next time */
- port->need_reconfig_queues = 1;
- return -1;
- }
- for (qi = nb_rxq, i = 0; qi < nb_hairpinq + nb_rxq; qi++) {
- hairpin_conf.peers[0].port = peer_tx_port;
- hairpin_conf.peers[0].queue = i + nb_txq;
- hairpin_conf.manual_bind = !!manual;
- hairpin_conf.tx_explicit = !!tx_exp;
- hairpin_conf.force_memory = !!rx_force_memory;
- hairpin_conf.use_locked_device_memory = !!rx_locked_memory;
- hairpin_conf.use_rte_memory = !!rx_rte_memory;
- diag = rte_eth_rx_hairpin_queue_setup
- (pi, qi, nb_rxd, &hairpin_conf);
- i++;
- if (diag == 0)
- continue;
-
- /* Fail to setup rx queue, return */
- if (port->port_status == RTE_PORT_HANDLING)
- port->port_status = RTE_PORT_STOPPED;
- else
- fprintf(stderr,
- "Port %d can not be set back to stopped\n", pi);
- fprintf(stderr, "Fail to configure port %d hairpin queues\n",
- pi);
- /* try to reconfigure queues next time */
- port->need_reconfig_queues = 1;
- return -1;
- }
- return 0;
-}
-
/* Configure the Rx with optional split. */ int rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id, @@ -3043,7 +2871,6 @@ start_port(portid_t pid)
portid_t peer_pl[RTE_MAX_ETHPORTS];
uint16_t cnt_pi = 0;
uint16_t cfg_pi = 0;
- int peer_pi;
queueid_t qi;
struct rte_port *port;
struct rte_eth_hairpin_cap cap;
@@ -3304,47 +3131,9 @@ start_port(portid_t pid)
fprintf(stderr, "Please stop the ports first\n");
if (hairpin_mode & 0xf) {
- uint16_t i;
- int j;
-
- /* bind all started hairpin ports */
- for (i = 0; i < cfg_pi; i++) {
- pi = pl[i];
- /* bind current Tx to all peer Rx */
- peer_pi = rte_eth_hairpin_get_peer_ports(pi, peer_pl,
- RTE_MAX_ETHPORTS, 1);
- if (peer_pi < 0)
- return peer_pi;
- for (j = 0; j < peer_pi; j++) {
- if (!port_is_started(peer_pl[j]))
- continue;
- diag = rte_eth_hairpin_bind(pi, peer_pl[j]);
- if (diag < 0) {
- fprintf(stderr,
- "Error during binding hairpin Tx port %u to %u: %s\n",
- pi, peer_pl[j],
- rte_strerror(-diag));
- return -1;
- }
- }
- /* bind all peer Tx to current Rx */
- peer_pi = rte_eth_hairpin_get_peer_ports(pi, peer_pl,
- RTE_MAX_ETHPORTS, 0);
- if (peer_pi < 0)
- return peer_pi;
- for (j = 0; j < peer_pi; j++) {
- if (!port_is_started(peer_pl[j]))
- continue;
- diag = rte_eth_hairpin_bind(peer_pl[j], pi);
- if (diag < 0) {
- fprintf(stderr,
- "Error during binding hairpin Tx port %u to %u: %s\n",
- peer_pl[j], pi,
- rte_strerror(-diag));
- return -1;
- }
- }
- }
+ diag = hairpin_bind(cfg_pi, pl, peer_pl);
+ if (diag < 0)
+ return -1;
}
fill_xstats_display_info_for_port(pid);
app/test-pmd/testpmd.h +13 -0
@@ -126,6 +126,16 @@ enum noisy_fwd_mode { NOISY_FWD_MODE_MAX, }; +/** +* Command line arguments parser sets `hairpin_multiport_mode` to True +* if explicit hairpin map configuration mode was used. +*/ +extern bool hairpin_multiport_mode; + +/** Hairpin maps list. */ +struct hairpin_map ; +extern void hairpin_add_multiport_map (struct hairpin_map *map); +/** * The data structure associated with RX and TX packet burst statistics * that are recorded for each forwarding stream.
@@ -1252,6 +1262,10 @@ extern int flow_parse(const char *src, void *result, unsigned int size,struct rte_flow_attr **attr, struct rte_flow_item **pattern, struct rte_flow_action **actions); +int setup_hairpin_queues (portid_t pi,portid_t p_pi,uint16_t cnt_pi); +int hairpin_bind (uint16_t cfg_pi,portid_t *pl,portid_t *peer_pl); +void hairpin_map_usage (void );int parse_hairpin_map (const char *hpmap); uint64_t str_to_rsstypes(const char *str); const char *rsstypes_to_str(uint64_t rss_type); diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
index 1a9b812a7f..48717707a7 100644
doc/guides/testpmd_app_ug/run_app.rst +3 -1
@@ -571,6 +571,9 @@ The command line options are: The default value is 0. Hairpin will use single port mode and implicit Tx flow mode. +* ``--hairpin-map=Rx port id:Rx queue:Tx port id:Tx queue:queues number`` + + Set explicit hairpin configuration. Testpmd Multi-Process Command-line Options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --
2.43.0
Quoted 6 lines · Aman Deep
External email: Use caution opening links or attachments
Hi Gregory,
Can you please resolve the compilation issues seen with this patch.
Hello,
I've posted v5.
Regards,
Gregory