* [RFC PATCH] net/dpaa2: fix RSS at inner level for non-tunnelled traffic
@ 2026-06-30 12:38 Maxime Leroy
2026-07-15 17:00 ` Maxime Leroy
` (3 more replies)
0 siblings, 4 replies; 15+ messages in thread
From: Maxime Leroy @ 2026-06-30 12:38 UTC (permalink / raw)
To: dev; +Cc: hemant.agrawal, sachin.saxena, Maxime Leroy
When RTE_ETH_RSS_LEVEL_INNERMOST is requested, the IP key extracts use
the innermost header index (HDR_INDEX_LAST). The hardware only resolves
that index when several IP headers are stacked: for a non-tunnelled
frame, which carries a single IP header, the extraction returns nothing.
The RSS hash is then constant and all such frames are steered to a
single Rx queue.
Always also extract the outer IP (header index 0), which the hardware
resolves for any frame. Non-tunnelled frames are thus hashed on their
only IP header, while tunnelled frames keep being hashed on their inner
IP.
This is a deliberate tradeoff: the ethdev API defines
RTE_ETH_RSS_LEVEL_INNERMOST as hashing the innermost header only, but the
hardware cannot do that without breaking RSS for plain traffic. As a
consequence, two tunnelled flows with the same inner header but
different outer IPs may hash to different queues. This limitation is
documented in the dpaa2 guide.
Alternatives considered (feedback welcome, hence RFC):
- Hash both outer and inner only under RTE_ETH_RSS_LEVEL_PMD_DEFAULT and
keep INNERMOST strictly inner-only. The ethdev API leaves the default
level to the PMD, so this stays API-compliant; it changes the default
hash for tunnelled traffic.
- Add a generic RTE_ETH_RSS_LEVEL_OUTER_INNER value to the ethdev API so
applications can request hashing on both encapsulation levels
explicitly, instead of overloading INNERMOST. This needs an ethdev API
change and agreement from other PMDs.
Fixes: 32f701671d2f ("net/dpaa2: support inner RSS level for tunnelled traffic")
Signed-off-by: Maxime Leroy <maxime@leroys.fr>
---
doc/guides/nics/dpaa2.rst | 6 +++
drivers/net/dpaa2/base/dpaa2_hw_dpni.c | 64 +++++++++++---------------
2 files changed, 33 insertions(+), 37 deletions(-)
diff --git a/doc/guides/nics/dpaa2.rst b/doc/guides/nics/dpaa2.rst
index 2d70bd0ab9..b7b68f0cd5 100644
--- a/doc/guides/nics/dpaa2.rst
+++ b/doc/guides/nics/dpaa2.rst
@@ -558,6 +558,12 @@ Other Limitations
- RSS hash key cannot be modified.
- RSS RETA cannot be configured.
+- Under ``RTE_ETH_RSS_LEVEL_INNERMOST``, the IP hash also covers the
+ outermost IP, not only the innermost one. The hardware extracts no IP
+ at the innermost index for non-tunnelled frames, so the outer IP is
+ added to keep RSS working on plain traffic. As a result, tunnelled
+ flows with the same inner header but different outer IPs may be
+ distributed to different queues.
.. _dptmapi:
diff --git a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c
index 07f4a3d414..b002dba171 100644
--- a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c
+++ b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c
@@ -398,48 +398,38 @@ dpaa2_distset_to_dpkg_profile_cfg(
case RTE_ETH_RSS_IPV6:
case RTE_ETH_RSS_FRAG_IPV6:
case RTE_ETH_RSS_NONFRAG_IPV6_OTHER:
- case RTE_ETH_RSS_IPV6_EX:
+ case RTE_ETH_RSS_IPV6_EX: {
+ static const uint32_t ip_fields[] = {
+ NH_FLD_IP_SRC, NH_FLD_IP_DST,
+ NH_FLD_IP_PROTO };
+ static const uint8_t ip_hdr_index[] = {
+ 0, DPAA2_DIST_HDR_INDEX_LAST };
+ unsigned int n_hdr, f, h;
if (l3_configured)
break;
l3_configured = 1;
- kg_cfg->extracts[i].extract.from_hdr.prot =
- NET_PROT_IP;
- kg_cfg->extracts[i].extract.from_hdr.hdr_index =
- hdr_index;
- kg_cfg->extracts[i].extract.from_hdr.field =
- NH_FLD_IP_SRC;
- kg_cfg->extracts[i].type =
- DPKG_EXTRACT_FROM_HDR;
- kg_cfg->extracts[i].extract.from_hdr.type =
- DPKG_FULL_FIELD;
- i++;
-
- kg_cfg->extracts[i].extract.from_hdr.prot =
- NET_PROT_IP;
- kg_cfg->extracts[i].extract.from_hdr.hdr_index =
- hdr_index;
- kg_cfg->extracts[i].extract.from_hdr.field =
- NH_FLD_IP_DST;
- kg_cfg->extracts[i].type =
- DPKG_EXTRACT_FROM_HDR;
- kg_cfg->extracts[i].extract.from_hdr.type =
- DPKG_FULL_FIELD;
- i++;
-
- kg_cfg->extracts[i].extract.from_hdr.prot =
- NET_PROT_IP;
- kg_cfg->extracts[i].extract.from_hdr.hdr_index =
- hdr_index;
- kg_cfg->extracts[i].extract.from_hdr.field =
- NH_FLD_IP_PROTO;
- kg_cfg->extracts[i].type =
- DPKG_EXTRACT_FROM_HDR;
- kg_cfg->extracts[i].extract.from_hdr.type =
- DPKG_FULL_FIELD;
- i++;
- break;
+ /* outer IP always; inner IP too for INNERMOST */
+ n_hdr = (hdr_index == DPAA2_DIST_HDR_INDEX_LAST) ?
+ 2 : 1;
+
+ for (h = 0; h < n_hdr; h++)
+ for (f = 0; f < RTE_DIM(ip_fields); f++) {
+ kg_cfg->extracts[i].extract.from_hdr.prot =
+ NET_PROT_IP;
+ kg_cfg->extracts[i].extract.from_hdr.hdr_index =
+ ip_hdr_index[h];
+ kg_cfg->extracts[i].extract.from_hdr.field =
+ ip_fields[f];
+ kg_cfg->extracts[i].type =
+ DPKG_EXTRACT_FROM_HDR;
+ kg_cfg->extracts[i].extract.from_hdr.type =
+ DPKG_FULL_FIELD;
+ i++;
+ }
+ break;
+ }
case RTE_ETH_RSS_NONFRAG_IPV4_TCP:
case RTE_ETH_RSS_NONFRAG_IPV6_TCP:
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [RFC PATCH] net/dpaa2: fix RSS at inner level for non-tunnelled traffic 2026-06-30 12:38 [RFC PATCH] net/dpaa2: fix RSS at inner level for non-tunnelled traffic Maxime Leroy @ 2026-07-15 17:00 ` Maxime Leroy 2026-07-16 7:47 ` Hemant Agrawal 2026-07-20 13:34 ` [PATCH v1 0/2] net/dpaa2: fix RSS for plain and tunnelled traffic Maxime Leroy ` (2 subsequent siblings) 3 siblings, 1 reply; 15+ messages in thread From: Maxime Leroy @ 2026-07-15 17:00 UTC (permalink / raw) To: Hemant Agrawal; +Cc: dev Hi Hemant, Do you have any preference between the different approaches proposed below? Regards, Maxime Leroy On Tue, Jun 30, 2026 at 2:39 PM Maxime Leroy <maxime@leroys.fr> wrote: > > When RTE_ETH_RSS_LEVEL_INNERMOST is requested, the IP key extracts use > the innermost header index (HDR_INDEX_LAST). The hardware only resolves > that index when several IP headers are stacked: for a non-tunnelled > frame, which carries a single IP header, the extraction returns nothing. > The RSS hash is then constant and all such frames are steered to a > single Rx queue. > > Always also extract the outer IP (header index 0), which the hardware > resolves for any frame. Non-tunnelled frames are thus hashed on their > only IP header, while tunnelled frames keep being hashed on their inner > IP. > > This is a deliberate tradeoff: the ethdev API defines > RTE_ETH_RSS_LEVEL_INNERMOST as hashing the innermost header only, but the > hardware cannot do that without breaking RSS for plain traffic. As a > consequence, two tunnelled flows with the same inner header but > different outer IPs may hash to different queues. This limitation is > documented in the dpaa2 guide. > > Alternatives considered (feedback welcome, hence RFC): > > - Hash both outer and inner only under RTE_ETH_RSS_LEVEL_PMD_DEFAULT and > keep INNERMOST strictly inner-only. The ethdev API leaves the default > level to the PMD, so this stays API-compliant; it changes the default > hash for tunnelled traffic. > > - Add a generic RTE_ETH_RSS_LEVEL_OUTER_INNER value to the ethdev API so > applications can request hashing on both encapsulation levels > explicitly, instead of overloading INNERMOST. This needs an ethdev API > change and agreement from other PMDs. > > Fixes: 32f701671d2f ("net/dpaa2: support inner RSS level for tunnelled traffic") > Signed-off-by: Maxime Leroy <maxime@leroys.fr> > --- > doc/guides/nics/dpaa2.rst | 6 +++ > drivers/net/dpaa2/base/dpaa2_hw_dpni.c | 64 +++++++++++--------------- > 2 files changed, 33 insertions(+), 37 deletions(-) > > diff --git a/doc/guides/nics/dpaa2.rst b/doc/guides/nics/dpaa2.rst > index 2d70bd0ab9..b7b68f0cd5 100644 > --- a/doc/guides/nics/dpaa2.rst > +++ b/doc/guides/nics/dpaa2.rst > @@ -558,6 +558,12 @@ Other Limitations > > - RSS hash key cannot be modified. > - RSS RETA cannot be configured. > +- Under ``RTE_ETH_RSS_LEVEL_INNERMOST``, the IP hash also covers the > + outermost IP, not only the innermost one. The hardware extracts no IP > + at the innermost index for non-tunnelled frames, so the outer IP is > + added to keep RSS working on plain traffic. As a result, tunnelled > + flows with the same inner header but different outer IPs may be > + distributed to different queues. > > .. _dptmapi: > > diff --git a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c > index 07f4a3d414..b002dba171 100644 > --- a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c > +++ b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c > @@ -398,48 +398,38 @@ dpaa2_distset_to_dpkg_profile_cfg( > case RTE_ETH_RSS_IPV6: > case RTE_ETH_RSS_FRAG_IPV6: > case RTE_ETH_RSS_NONFRAG_IPV6_OTHER: > - case RTE_ETH_RSS_IPV6_EX: > + case RTE_ETH_RSS_IPV6_EX: { > + static const uint32_t ip_fields[] = { > + NH_FLD_IP_SRC, NH_FLD_IP_DST, > + NH_FLD_IP_PROTO }; > + static const uint8_t ip_hdr_index[] = { > + 0, DPAA2_DIST_HDR_INDEX_LAST }; > + unsigned int n_hdr, f, h; > > if (l3_configured) > break; > l3_configured = 1; > > - kg_cfg->extracts[i].extract.from_hdr.prot = > - NET_PROT_IP; > - kg_cfg->extracts[i].extract.from_hdr.hdr_index = > - hdr_index; > - kg_cfg->extracts[i].extract.from_hdr.field = > - NH_FLD_IP_SRC; > - kg_cfg->extracts[i].type = > - DPKG_EXTRACT_FROM_HDR; > - kg_cfg->extracts[i].extract.from_hdr.type = > - DPKG_FULL_FIELD; > - i++; > - > - kg_cfg->extracts[i].extract.from_hdr.prot = > - NET_PROT_IP; > - kg_cfg->extracts[i].extract.from_hdr.hdr_index = > - hdr_index; > - kg_cfg->extracts[i].extract.from_hdr.field = > - NH_FLD_IP_DST; > - kg_cfg->extracts[i].type = > - DPKG_EXTRACT_FROM_HDR; > - kg_cfg->extracts[i].extract.from_hdr.type = > - DPKG_FULL_FIELD; > - i++; > - > - kg_cfg->extracts[i].extract.from_hdr.prot = > - NET_PROT_IP; > - kg_cfg->extracts[i].extract.from_hdr.hdr_index = > - hdr_index; > - kg_cfg->extracts[i].extract.from_hdr.field = > - NH_FLD_IP_PROTO; > - kg_cfg->extracts[i].type = > - DPKG_EXTRACT_FROM_HDR; > - kg_cfg->extracts[i].extract.from_hdr.type = > - DPKG_FULL_FIELD; > - i++; > - break; > + /* outer IP always; inner IP too for INNERMOST */ > + n_hdr = (hdr_index == DPAA2_DIST_HDR_INDEX_LAST) ? > + 2 : 1; > + > + for (h = 0; h < n_hdr; h++) > + for (f = 0; f < RTE_DIM(ip_fields); f++) { > + kg_cfg->extracts[i].extract.from_hdr.prot = > + NET_PROT_IP; > + kg_cfg->extracts[i].extract.from_hdr.hdr_index = > + ip_hdr_index[h]; > + kg_cfg->extracts[i].extract.from_hdr.field = > + ip_fields[f]; > + kg_cfg->extracts[i].type = > + DPKG_EXTRACT_FROM_HDR; > + kg_cfg->extracts[i].extract.from_hdr.type = > + DPKG_FULL_FIELD; > + i++; > + } > + break; > + } > > case RTE_ETH_RSS_NONFRAG_IPV4_TCP: > case RTE_ETH_RSS_NONFRAG_IPV6_TCP: > -- > 2.43.0 > -- ------------------------------- Maxime Leroy maxime@leroys.fr ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC PATCH] net/dpaa2: fix RSS at inner level for non-tunnelled traffic 2026-07-15 17:00 ` Maxime Leroy @ 2026-07-16 7:47 ` Hemant Agrawal 2026-07-16 8:00 ` Maxime Leroy 0 siblings, 1 reply; 15+ messages in thread From: Hemant Agrawal @ 2026-07-16 7:47 UTC (permalink / raw) To: Maxime Leroy, Hemant Agrawal; +Cc: dev, Jun Yang, Gagandeep Singh [-- Attachment #1: Type: text/plain, Size: 2540 bytes --] On 15-07-2026 22:30, Maxime Leroy wrote: > Hi Hemant, > > Do you have any preference between the different approaches proposed below? > > Regards, > > Maxime Leroy > > On Tue, Jun 30, 2026 at 2:39 PM Maxime Leroy<maxime@leroys.fr> wrote: >> When RTE_ETH_RSS_LEVEL_INNERMOST is requested, the IP key extracts use >> the innermost header index (HDR_INDEX_LAST). The hardware only resolves >> that index when several IP headers are stacked: for a non-tunnelled >> frame, which carries a single IP header, the extraction returns nothing. >> The RSS hash is then constant and all such frames are steered to a >> single Rx queue. >> >> Always also extract the outer IP (header index 0), which the hardware >> resolves for any frame. Non-tunnelled frames are thus hashed on their >> only IP header, while tunnelled frames keep being hashed on their inner >> IP. >> >> This is a deliberate tradeoff: the ethdev API defines >> RTE_ETH_RSS_LEVEL_INNERMOST as hashing the innermost header only, but the >> hardware cannot do that without breaking RSS for plain traffic. As a >> consequence, two tunnelled flows with the same inner header but >> different outer IPs may hash to different queues. This limitation is >> documented in the dpaa2 guide. >> >> Alternatives considered (feedback welcome, hence RFC): >> >> - Hash both outer and inner only under RTE_ETH_RSS_LEVEL_PMD_DEFAULT and >> keep INNERMOST strictly inner-only. The ethdev API leaves the default >> level to the PMD, so this stays API-compliant; it changes the default >> hash for tunnelled traffic. >> >> - Add a generic RTE_ETH_RSS_LEVEL_OUTER_INNER value to the ethdev API so >> applications can request hashing on both encapsulation levels >> explicitly, instead of overloading INNERMOST. This needs an ethdev API >> change and agreement from other PMDs. >> >> Fixes: 32f701671d2f ("net/dpaa2: support inner RSS level for tunnelled traffic") >> Signed-off-by: Maxime Leroy<maxime@leroys.fr> Hi Maxime, My preference is to keep |RTE_ETH_RSS_LEVEL_INNERMOST| semantics unchanged and strictly hash on the innermost header. I would rather use the PMD-defined default level to provide the best RSS distribution for both plain and tunnelled traffic. Overloading |INNERMOST| to include the outer IP makes the behavior diverge from the ethdev definition and may surprise applications relying on true inner-header affinity. Longer term, an explicit |OUTER_INNER| RSS level would be the cleanest solution if there is interest from other PMDs. Regards, Hemant [-- Attachment #2: Type: text/html, Size: 3520 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [RFC PATCH] net/dpaa2: fix RSS at inner level for non-tunnelled traffic 2026-07-16 7:47 ` Hemant Agrawal @ 2026-07-16 8:00 ` Maxime Leroy 0 siblings, 0 replies; 15+ messages in thread From: Maxime Leroy @ 2026-07-16 8:00 UTC (permalink / raw) To: Hemant Agrawal; +Cc: dev, Jun Yang, Gagandeep Singh On Thu, Jul 16, 2026 at 9:48 AM Hemant Agrawal <hemant.agrawal@oss.nxp.com> wrote: > > > On 15-07-2026 22:30, Maxime Leroy wrote: > > Hi Hemant, > > Do you have any preference between the different approaches proposed below? > > Regards, > > Maxime Leroy > > On Tue, Jun 30, 2026 at 2:39 PM Maxime Leroy <maxime@leroys.fr> wrote: > > When RTE_ETH_RSS_LEVEL_INNERMOST is requested, the IP key extracts use > the innermost header index (HDR_INDEX_LAST). The hardware only resolves > that index when several IP headers are stacked: for a non-tunnelled > frame, which carries a single IP header, the extraction returns nothing. > The RSS hash is then constant and all such frames are steered to a > single Rx queue. > > Always also extract the outer IP (header index 0), which the hardware > resolves for any frame. Non-tunnelled frames are thus hashed on their > only IP header, while tunnelled frames keep being hashed on their inner > IP. > > This is a deliberate tradeoff: the ethdev API defines > RTE_ETH_RSS_LEVEL_INNERMOST as hashing the innermost header only, but the > hardware cannot do that without breaking RSS for plain traffic. As a > consequence, two tunnelled flows with the same inner header but > different outer IPs may hash to different queues. This limitation is > documented in the dpaa2 guide. > > Alternatives considered (feedback welcome, hence RFC): > > - Hash both outer and inner only under RTE_ETH_RSS_LEVEL_PMD_DEFAULT and > keep INNERMOST strictly inner-only. The ethdev API leaves the default > level to the PMD, so this stays API-compliant; it changes the default > hash for tunnelled traffic. > > - Add a generic RTE_ETH_RSS_LEVEL_OUTER_INNER value to the ethdev API so > applications can request hashing on both encapsulation levels > explicitly, instead of overloading INNERMOST. This needs an ethdev API > change and agreement from other PMDs. > > Fixes: 32f701671d2f ("net/dpaa2: support inner RSS level for tunnelled traffic") > Signed-off-by: Maxime Leroy <maxime@leroys.fr> > > Hi Maxime, > > My preference is to keep RTE_ETH_RSS_LEVEL_INNERMOST semantics unchanged and strictly hash on the innermost header. > > I would rather use the PMD-defined default level to provide the best RSS distribution for both plain and tunnelled traffic. Overloading INNERMOST to include the outer IP makes the behavior diverge from the ethdev definition and may surprise applications relying on true inner-header affinity. > > Longer term, an explicit OUTER_INNER RSS level would be the cleanest solution if there is interest from other PMDs. > > Regards, > > Hemant Thanks for the feedback, but I have a concern with keeping INNERMOST strictly inner-only on dpaa2. The ethdev API defines INNERMOST in terms of the innermost encapsulation level, not the presence of a tunnel. A plain frame has a single level, so its innermost header is its only IP header, and INNERMOST must hash it. Collapsing all non-tunnelled traffic onto one queue is not "strict inner-only", it is broken RSS for the common case. dpaa2 cannot express true innermost-only: we map innermost to HDR_INDEX_LAST, which only resolves when at least two IP headers are stacked. For a single header nothing resolves, hence the constant hash today. The only way to hash a plain frame's IP is to also extract header index 0 (always resolves), which unavoidably folds the outer IP into the hash for tunnelled frames. I can move the outer+inner extraction under PMD_DEFAULT as you suggest. But that leaves only two options for INNERMOST on dpaa2: - drop INNERMOST support entirely (reject the level), or - keep it strictly inner-only and accept it does not respect the API for plain traffic (single queue). Which of the two do you prefer? Regards, Maxime ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v1 0/2] net/dpaa2: fix RSS for plain and tunnelled traffic 2026-06-30 12:38 [RFC PATCH] net/dpaa2: fix RSS at inner level for non-tunnelled traffic Maxime Leroy 2026-07-15 17:00 ` Maxime Leroy @ 2026-07-20 13:34 ` Maxime Leroy 2026-07-23 9:35 ` [PATCH v2] net/dpaa2: hash inner IP for " Maxime Leroy 2026-07-20 13:34 ` [PATCH v1 1/2] net/dpaa2: revert inner RSS level support Maxime Leroy 2026-07-20 13:34 ` [PATCH v1 2/2] net/dpaa2: hash inner IP for tunnelled traffic Maxime Leroy 3 siblings, 1 reply; 15+ messages in thread From: Maxime Leroy @ 2026-07-20 13:34 UTC (permalink / raw) To: dev; +Cc: thomas, david.marchand, hemant.agrawal, Maxime Leroy The RTE_ETH_RSS_LEVEL_INNERMOST support merged in 618a06c53d47 maps the inner level to hdr_index = HDR_INDEX_LAST in the IP key extracts. The hardware only resolves that index when several IP headers are stacked, so a non-tunnelled frame, which carries a single IP header, resolves to nothing: its RSS hash is constant and every such frame lands on a single Rx queue. This breaks RSS for plain traffic, which the ethdev API requires INNERMOST to hash, since a plain frame's innermost header is its only IP header. dpaa2 cannot express strict inner-only hashing and keep plain traffic spread at the same time: the only index that resolves for a single header is the outer one (index 0). This series therefore reverts the INNERMOST support and, rather than exposing the RSS level selector, always extracts both the outer IP (index 0) and the innermost IP (HDR_INDEX_LAST) as the PMD default. Plain frames keep being hashed on their only IP header; tunnelled frames are additionally spread on their inner IP. The tradeoff, documented in the dpaa2 guide, is that two tunnelled flows sharing an inner IP but differing in their outer IP may hash to different queues. A future generic RSS level (for example OUTER_INNER) could expose the distinction explicitly if other PMDs are interested. Note on timing: the reverted INNERMOST support is present only in the 26.07 release candidates (currently rc4) and has never appeared in a DPDK release. This series should be applied before 26.07 is released, so the broken behaviour never ships and no cross-release regression is left behind. Maxime Leroy (2): net/dpaa2: revert inner RSS level support net/dpaa2: hash inner IP for tunnelled traffic doc/guides/nics/dpaa2.rst | 3 + doc/guides/rel_notes/release_26_07.rst | 3 +- drivers/net/dpaa2/base/dpaa2_hw_dpni.c | 82 ++++++++++---------------- drivers/net/dpaa2/dpaa2_ethdev.c | 3 +- 4 files changed, 36 insertions(+), 55 deletions(-) -- 2.43.0 ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2] net/dpaa2: hash inner IP for tunnelled traffic 2026-07-20 13:34 ` [PATCH v1 0/2] net/dpaa2: fix RSS for plain and tunnelled traffic Maxime Leroy @ 2026-07-23 9:35 ` Maxime Leroy 2026-07-26 16:37 ` Stephen Hemminger 2026-08-25 7:42 ` [PATCH v3] " Maxime Leroy 0 siblings, 2 replies; 15+ messages in thread From: Maxime Leroy @ 2026-07-23 9:35 UTC (permalink / raw) To: dev; +Cc: Maxime Leroy, Hemant Agrawal, Sachin Saxena The RSS key only extracted the outer IP header. Tunnelled traffic whose outer headers are fixed then carries no entropy for the hash, so every flow lands on a single Rx queue. Extract both the outer IP (header index 0) and the innermost IP instance (HDR_INDEX_LAST). Plain frames keep being hashed on their only IP header; the inner extract resolves to nothing and adds no entropy. Tunnelled frames are also hashed on their inner IP and spread across the Rx queues. This is the PMD default hash: dpaa2 does not expose the ethdev RSS level selector, so it applies to every RSS request. The hardware cannot hash the inner IP alone, as HDR_INDEX_LAST only resolves when several IP headers are stacked and a plain frame would hash to a constant. Folding the outer IP into the key is therefore unavoidable, and two tunnelled flows that share an inner IP but differ in their outer IP may hash to different queues. This is documented in the dpaa2 guide. Signed-off-by: Maxime Leroy <maxime@leroys.fr> --- v2: * Dropped the first patch (the INNERMOST revert), now applied upstream; this is the remaining standalone patch. * Rebased on main for the 26.11 cycle; moved the release note from release_26_07.rst to release_26_11.rst. v1 (since RFC): * Reworked the approach: rather than overloading INNERMOST to also hash the outer IP, always extract outer+inner as the PMD default, since dpaa2 does not expose the RSS level selector, and revert the INNERMOST support in a separate patch. Dropped the Fixes: tag accordingly. --- doc/guides/nics/dpaa2.rst | 3 ++ doc/guides/rel_notes/release_26_11.rst | 5 ++ drivers/net/dpaa2/base/dpaa2_hw_dpni.c | 63 +++++++++++++------------- 3 files changed, 40 insertions(+), 31 deletions(-) diff --git a/doc/guides/nics/dpaa2.rst b/doc/guides/nics/dpaa2.rst index ae8b32af2c..aaaf5f9713 100644 --- a/doc/guides/nics/dpaa2.rst +++ b/doc/guides/nics/dpaa2.rst @@ -588,6 +588,9 @@ Other Limitations - RSS hash key cannot be modified. - RSS RETA cannot be configured. +- RSS hashes on both the outer and the inner IP header. Tunnelled flows + that share the same inner IP but differ in their outer IP may therefore + be steered to different Rx queues. .. _dpaa2_dptmapi: diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst index 938617ca75..bdfe424f26 100644 --- a/doc/guides/rel_notes/release_26_11.rst +++ b/doc/guides/rel_notes/release_26_11.rst @@ -55,6 +55,11 @@ New Features Also, make sure to start the actual text at the margin. ======================================================= +* **Updated NXP dpaa2 driver.** + + * Added the inner IP header to the RSS hash so tunnelled traffic is + distributed across the Rx queues. + Removed Items ------------- diff --git a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c index 26ad105c73..5bb9ad4591 100644 --- a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c +++ b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c @@ -236,6 +236,9 @@ dpaa2_remove_flow_dist(struct rte_eth_dev *eth_dev, return ret; } +/* hdr_index selecting the innermost IP instance in a dpkg extract */ +#define DPAA2_DIST_HDR_INDEX_LAST 0xff + int dpaa2_distset_to_dpkg_profile_cfg( uint64_t req_dist_set, @@ -381,42 +384,40 @@ dpaa2_distset_to_dpkg_profile_cfg( case RTE_ETH_RSS_IPV6: case RTE_ETH_RSS_FRAG_IPV6: case RTE_ETH_RSS_NONFRAG_IPV6_OTHER: - case RTE_ETH_RSS_IPV6_EX: + case RTE_ETH_RSS_IPV6_EX: { + static const uint32_t ip_fields[] = { + NH_FLD_IP_SRC, NH_FLD_IP_DST, + NH_FLD_IP_PROTO }; + static const uint8_t ip_hdr_index[] = { + 0, DPAA2_DIST_HDR_INDEX_LAST }; + unsigned int f, h; if (l3_configured) break; l3_configured = 1; - kg_cfg->extracts[i].extract.from_hdr.prot = - NET_PROT_IP; - kg_cfg->extracts[i].extract.from_hdr.field = - NH_FLD_IP_SRC; - kg_cfg->extracts[i].type = - DPKG_EXTRACT_FROM_HDR; - kg_cfg->extracts[i].extract.from_hdr.type = - DPKG_FULL_FIELD; - i++; - - kg_cfg->extracts[i].extract.from_hdr.prot = - NET_PROT_IP; - kg_cfg->extracts[i].extract.from_hdr.field = - NH_FLD_IP_DST; - kg_cfg->extracts[i].type = - DPKG_EXTRACT_FROM_HDR; - kg_cfg->extracts[i].extract.from_hdr.type = - DPKG_FULL_FIELD; - i++; - - kg_cfg->extracts[i].extract.from_hdr.prot = - NET_PROT_IP; - kg_cfg->extracts[i].extract.from_hdr.field = - NH_FLD_IP_PROTO; - kg_cfg->extracts[i].type = - DPKG_EXTRACT_FROM_HDR; - kg_cfg->extracts[i].extract.from_hdr.type = - DPKG_FULL_FIELD; - i++; - break; + /* Hash on the outer IP (index 0) and the innermost + * IP instance. A plain frame has a single IP header, + * so only the outer extract resolves; a tunnelled + * frame resolves both and is also spread on its inner + * IP. + */ + for (h = 0; h < RTE_DIM(ip_hdr_index); h++) + for (f = 0; f < RTE_DIM(ip_fields); f++) { + kg_cfg->extracts[i].extract.from_hdr.prot = + NET_PROT_IP; + kg_cfg->extracts[i].extract.from_hdr.hdr_index = + ip_hdr_index[h]; + kg_cfg->extracts[i].extract.from_hdr.field = + ip_fields[f]; + kg_cfg->extracts[i].type = + DPKG_EXTRACT_FROM_HDR; + kg_cfg->extracts[i].extract.from_hdr.type = + DPKG_FULL_FIELD; + i++; + } + break; + } case RTE_ETH_RSS_NONFRAG_IPV4_TCP: case RTE_ETH_RSS_NONFRAG_IPV6_TCP: -- 2.43.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v2] net/dpaa2: hash inner IP for tunnelled traffic 2026-07-23 9:35 ` [PATCH v2] net/dpaa2: hash inner IP for " Maxime Leroy @ 2026-07-26 16:37 ` Stephen Hemminger 2026-07-27 8:04 ` Maxime Leroy 2026-08-25 7:42 ` [PATCH v3] " Maxime Leroy 1 sibling, 1 reply; 15+ messages in thread From: Stephen Hemminger @ 2026-07-26 16:37 UTC (permalink / raw) To: Maxime Leroy; +Cc: dev, Hemant Agrawal, Sachin Saxena On Thu, 23 Jul 2026 11:35:40 +0200 Maxime Leroy <maxime@leroys.fr> wrote: > The RSS key only extracted the outer IP header. Tunnelled traffic whose > outer headers are fixed then carries no entropy for the hash, so every > flow lands on a single Rx queue. > > Extract both the outer IP (header index 0) and the innermost IP > instance (HDR_INDEX_LAST). Plain frames keep being hashed on their only > IP header; the inner extract resolves to nothing and adds no entropy. > Tunnelled frames are also hashed on their inner IP and spread across the > Rx queues. > > This is the PMD default hash: dpaa2 does not expose the ethdev RSS level > selector, so it applies to every RSS request. The hardware cannot hash > the inner IP alone, as HDR_INDEX_LAST only resolves when several IP > headers are stacked and a plain frame would hash to a constant. Folding > the outer IP into the key is therefore unavoidable, and two tunnelled > flows that share an inner IP but differ in their outer IP may hash to > different queues. This is documented in the dpaa2 guide. > > Signed-off-by: Maxime Leroy <maxime@leroys.fr> > --- More detailed AI review Warning: RSS key size likely exceeds the DPNI key limit drivers/net/dpaa2/base/dpaa2_hw_dpni.c Doubling the IP extracts doubles the generated key, not just the extract count. The driver's own accounting treats a NET_PROT_IP full-field address extract as 16 bytes (NH_FLD_IPV6_ADDR_SIZE, see dpaa2_flow_add_ipaddr_extract_rule() in dpaa2_flow.c), so: before: 16 + 16 + 1 = 33 bytes (+4 with L4 = 37) after: 2 * (16 + 16 + 1) = 66 bytes (+4 with L4 = 70) DPNI_MAX_KEY_SIZE is 56, and dpni_attr.fs_key_size is documented as "Size, in bytes, of the flow steering look-up key. Defining a key larger than this when composing the hash + FS key will result in an error." The PMD never reads fs_key_size and there is no size check anywhere on this path, so the first sign of trouble would be dpni_set_rx_hash_dist() failing and rte_eth_dev_configure() returning an error for a plain RTE_ETH_RSS_IP request that works today. Has this been tested on hardware with RTE_ETH_RSS_IP (and IP|TCP|UDP)? If MC accepts it, please say so in the commit message, because the arithmetic says it should not. If the limit is real, the extract set needs to shrink -- dropping NH_FLD_IP_PROTO, or extracting only the inner address pair, would be candidates. Warning: the "inner extract resolves to nothing" claim needs backing Both the commit message and the new comment assert that on a plain frame the HDR_INDEX_LAST extract resolves to nothing and contributes no entropy. The MC header documents hdr_index as "used for protocols that may have more than a single header, 0 indicates an outer header" with NET_PROT_IP taking (0, HDR_INDEX_LAST). The natural reading is that for a single-IP frame the last header *is* the outer one, so index 0 and HDR_INDEX_LAST select the same header and the fields are extracted twice. That is harmless for distribution but it is not what the patch says, and it changes the key size and hash values for every existing non-tunnelled user. Please confirm the actual behaviour with NXP and describe it accurately, one way or the other. This also feeds directly into the key-size question above. Info: duplicate constant +#define DPAA2_DIST_HDR_INDEX_LAST 0xff mc/fsl_net.h already carries LAST_HDR_INDEX (0xFFFFFFFF), truncated to 0xff by the uint8_t hdr_index field. Two differently-named constants for the same hardware encoding in one driver is confusing. Either reuse the existing one with an explicit cast, or add a comment saying this is LAST_HDR_INDEX narrowed to the 8-bit command field. Info: placement The #define sits between two function definitions. Move it up with the other file-scope definitions, or into dpaa2_ethdev.h next to the related driver constants. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] net/dpaa2: hash inner IP for tunnelled traffic 2026-07-26 16:37 ` Stephen Hemminger @ 2026-07-27 8:04 ` Maxime Leroy 0 siblings, 0 replies; 15+ messages in thread From: Maxime Leroy @ 2026-07-27 8:04 UTC (permalink / raw) To: Stephen Hemminger; +Cc: dev, Hemant Agrawal, Sachin Saxena On Sun, Jul 26, 2026 at 6:37 PM Stephen Hemminger <stephen@networkplumber.org> wrote: > > On Thu, 23 Jul 2026 11:35:40 +0200 > Maxime Leroy <maxime@leroys.fr> wrote: > > > The RSS key only extracted the outer IP header. Tunnelled traffic whose > > outer headers are fixed then carries no entropy for the hash, so every > > flow lands on a single Rx queue. > > > > Extract both the outer IP (header index 0) and the innermost IP > > instance (HDR_INDEX_LAST). Plain frames keep being hashed on their only > > IP header; the inner extract resolves to nothing and adds no entropy. > > Tunnelled frames are also hashed on their inner IP and spread across the > > Rx queues. > > > > This is the PMD default hash: dpaa2 does not expose the ethdev RSS level > > selector, so it applies to every RSS request. The hardware cannot hash > > the inner IP alone, as HDR_INDEX_LAST only resolves when several IP > > headers are stacked and a plain frame would hash to a constant. Folding > > the outer IP into the key is therefore unavoidable, and two tunnelled > > flows that share an inner IP but differ in their outer IP may hash to > > different queues. This is documented in the dpaa2 guide. > > > > Signed-off-by: Maxime Leroy <maxime@leroys.fr> > > --- > > More detailed AI review > > Warning: RSS key size likely exceeds the DPNI key limit > > drivers/net/dpaa2/base/dpaa2_hw_dpni.c > > Doubling the IP extracts doubles the generated key, not just the > extract count. The driver's own accounting treats a NET_PROT_IP > full-field address extract as 16 bytes (NH_FLD_IPV6_ADDR_SIZE, see > dpaa2_flow_add_ipaddr_extract_rule() in dpaa2_flow.c), so: > > before: 16 + 16 + 1 = 33 bytes (+4 with L4 = 37) > after: 2 * (16 + 16 + 1) = 66 bytes (+4 with L4 = 70) > > DPNI_MAX_KEY_SIZE is 56, and dpni_attr.fs_key_size is documented as > "Size, in bytes, of the flow steering look-up key. Defining a key > larger than this when composing the hash + FS key will result in an > error." The PMD never reads fs_key_size and there is no size check > anywhere on this path, so the first sign of trouble would be > dpni_set_rx_hash_dist() failing and rte_eth_dev_configure() returning > an error for a plain RTE_ETH_RSS_IP request that works today. > > Has this been tested on hardware with RTE_ETH_RSS_IP (and IP|TCP|UDP)? It has, on LX2160A, and with exactly those two requests. testpmd --rss-ip sets rss_hf to RTE_ETH_RSS_IP and testpmd --rss-udp sets it to RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP, which compose six and eight extracts, that is your 66 bytes and 70 bytes. Our forwarding application goes further, requesting rss_hf = RTE_ETH_RSS_VLAN | RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP which composes nine extracts: one VLAN TCI, six IP (source, destination and protocol, at index 0 and at HDR_INDEX_LAST) and two L4 ports, so 72 bytes with the 16 bytes per address you count, against 39 bytes before the patch. In all three cases dpni_set_rx_hash_dist() accepts the key and rte_eth_dev_configure() succeeds. Distribution was then checked per traffic type: plain IPv4, plain IPv6, VLAN tagged frames and IPv6 tunnelled traffic all spread across the Rx queues, the last one on its inner IP, which is the point of the patch. So 56 does not bound this path. DPNI_MAX_KEY_SIZE and fs_key_size bound the flow steering look-up key, that is the key which is stored in, and compared against, the FS and QoS table entries. Its size is explicit in the API (dpni_rule_cfg carries key_iova, mask_iova and key_size), and it is the size dpaa2_flow.c accounts and checks: that is the path your 16 bytes figure comes from. The hash distribution path installs no table entry and stores no key. dpni_rx_dist_cfg has no key_size field at all, only dist_size and key_cfg_iova, i.e. the key composition; the composed bytes are only fed to the hash function which yields the queue index. The two budgets are not the same. For the extract count, the flib bound is DPKG_MAX_NUM_OF_EXTRACTS = 20, and it is the only limit the driver checks, in dpkg_prepare_key_cfg(). The worst case, requesting every type the PMD advertises (ETH, PPPOE, ESP, AH, VLAN, MPLS, IP and L4), is 16 extracts with this patch. It is 13 without it, and it was 15 in the code that shipped until the June cleanup folded the SCTP ports into the L4 case (4b200f10de27). > If MC accepts it, please say so in the commit message, because the > arithmetic says it should not. If the limit is real, the extract set > needs to shrink -- dropping NH_FLD_IP_PROTO, or extracting only the > inner address pair, would be candidates. > > Warning: the "inner extract resolves to nothing" claim needs backing > > Both the commit message and the new comment assert that on a plain > frame the HDR_INDEX_LAST extract resolves to nothing and contributes no > entropy. The MC header documents hdr_index as "used for protocols that > may have more than a single header, 0 indicates an outer header" with > NET_PROT_IP taking (0, HDR_INDEX_LAST). The natural reading is that > for a single-IP frame the last header *is* the outer one, so index 0 > and HDR_INDEX_LAST select the same header and the fields are extracted > twice. That reading is excluded by measurement on LX2160A, with testpmd. It is in fact the regression patch 1 of this series reverts. The reverted commit programmed the IP extracts *only* at HDR_INDEX_LAST. Had HDR_INDEX_LAST selected the outer header of a frame carrying a single IP header, plain traffic would have kept hashing on that header and there would have been nothing to fix. What we measured instead was every plain frame getting the same hash and landing on one Rx queue, while tunnelled traffic spread correctly on its inner IP. Patch 1 states this and carries Hemant's ack. Reading the driver leads to the same conclusion, though I can only offer it as a reading. fsl_dpkg.h defines hdr_index for VLAN, MPLS and IP only, and for those three the Rx annotation exposes one flag set per header instance: L3_IPV4_1_PRESENT against L3_IPV4_N_PRESENT and so on in base/dpaa2_hw_dpni_annot.h, the matching offset accessor being named IP_N_OR_MIN_ENCAP_OFFSET(). Index 0 would then select the "1" instance and HDR_INDEX_LAST the "N" one, and a frame with a single IP header has no "N" instance for the extract to resolve to. Whatever the key generator places in the key for such an extract, it is the same for every plain frame, which is what the measurement shows: no entropy, and no second extraction of the outer header. > That is harmless for distribution but it is not what the patch > says, and it changes the key size and hash values for every existing > non-tunnelled user. > > Please confirm the actual behaviour with NXP and describe it > accurately, one way or the other. This also feeds directly into the > key-size question above. > > Info: duplicate constant > > +#define DPAA2_DIST_HDR_INDEX_LAST 0xff > > mc/fsl_net.h already carries LAST_HDR_INDEX (0xFFFFFFFF), truncated to > 0xff by the uint8_t hdr_index field. Two differently-named constants > for the same hardware encoding in one driver is confusing. Either > reuse the existing one with an explicit cast, or add a comment saying > this is LAST_HDR_INDEX narrowed to the 8-bit command field. > > Info: placement > > The #define sits between two function definitions. Move it up with the > other file-scope definitions, or into dpaa2_ethdev.h next to the > related driver constants. Agreed on both. v3 derives the constant from LAST_HDR_INDEX, cast to the 8-bit field it feeds, and moves it up with the other file scope definitions: /* LAST_HDR_INDEX narrowed to the 8-bit dpkg hdr_index field */ #define DPAA2_DIST_HDR_INDEX_LAST ((uint8_t)LAST_HDR_INDEX) ------------------------------- Maxime Leroy maxime@leroys.fr ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v3] net/dpaa2: hash inner IP for tunnelled traffic 2026-07-23 9:35 ` [PATCH v2] net/dpaa2: hash inner IP for " Maxime Leroy 2026-07-26 16:37 ` Stephen Hemminger @ 2026-08-25 7:42 ` Maxime Leroy 2026-08-25 14:14 ` Stephen Hemminger 1 sibling, 1 reply; 15+ messages in thread From: Maxime Leroy @ 2026-08-25 7:42 UTC (permalink / raw) To: Hemant Agrawal, Sachin Saxena; +Cc: dev, stephen, Maxime Leroy The RSS key only extracted the outer IP header. Tunnelled traffic whose outer headers are fixed then carries no entropy for the hash, so every flow lands on a single Rx queue. Extract both the outer IP (header index 0) and the innermost IP instance (HDR_INDEX_LAST). Plain frames keep being hashed on their only IP header; the inner extract resolves to nothing and adds no entropy. Tunnelled frames are also hashed on their inner IP and spread across the Rx queues. That a lone IP header does not resolve HDR_INDEX_LAST is the regression reverted by commit 2b375df07e48 ("net/dpaa2: revert inner RSS level support"): extracted only at HDR_INDEX_LAST, every plain frame hashed to the same value and landed on one Rx queue. The worst case, requesting every type the PMD advertises, is 16 extracts out of the DPKG_MAX_NUM_OF_EXTRACTS 20. On LX2160A dpni_set_rx_hash_dist() accepts the key, and plain IPv4, plain IPv6, VLAN tagged and tunnelled IPv6 traffic all spread across the Rx queues. This is the PMD default hash: dpaa2 does not expose the ethdev RSS level selector, so it applies to every RSS request. The hardware cannot hash the inner IP alone, as HDR_INDEX_LAST only resolves when several IP headers are stacked and a plain frame would hash to a constant. Folding the outer IP into the key is therefore unavoidable, and two tunnelled flows that share an inner IP but differ in their outer IP may hash to different queues. This is documented in the dpaa2 guide. Signed-off-by: Maxime Leroy <maxime@leroys.fr> --- v3: * Drop the DPAA2_DIST_HDR_INDEX_LAST define and take (uint8_t)LAST_HDR_INDEX directly at its single use site, rather than adding a second name for a constant the driver already has (Stephen Hemminger). * Record the extract budget and the LX2160A results in the commit log (Stephen Hemminger). * Re-added the release notes entry dropped in v2, now under 26.11. v2: * Sent standalone: patch 1/2 of v1, the revert of the inner RSS level support, was applied as 2b375df07e48. * Dropped the release_26_07.rst entry, that release having been tagged. Unchanged otherwise. doc/guides/nics/dpaa2.rst | 3 ++ doc/guides/rel_notes/release_26_11.rst | 5 +++ drivers/net/dpaa2/base/dpaa2_hw_dpni.c | 60 +++++++++++++------------- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/doc/guides/nics/dpaa2.rst b/doc/guides/nics/dpaa2.rst index ae8b32af2c..aaaf5f9713 100644 --- a/doc/guides/nics/dpaa2.rst +++ b/doc/guides/nics/dpaa2.rst @@ -588,6 +588,9 @@ Other Limitations - RSS hash key cannot be modified. - RSS RETA cannot be configured. +- RSS hashes on both the outer and the inner IP header. Tunnelled flows + that share the same inner IP but differ in their outer IP may therefore + be steered to different Rx queues. .. _dpaa2_dptmapi: diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst index 87c7e81bde..4887bccbc0 100644 --- a/doc/guides/rel_notes/release_26_11.rst +++ b/doc/guides/rel_notes/release_26_11.rst @@ -55,6 +55,11 @@ New Features Also, make sure to start the actual text at the margin. ======================================================= +* **Updated NXP dpaa2 driver.** + + * Added the inner IP header to the RSS hash so tunnelled traffic is + distributed across the Rx queues. + Removed Items ------------- diff --git a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c index 26ad105c73..83694133f1 100644 --- a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c +++ b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c @@ -381,42 +381,40 @@ dpaa2_distset_to_dpkg_profile_cfg( case RTE_ETH_RSS_IPV6: case RTE_ETH_RSS_FRAG_IPV6: case RTE_ETH_RSS_NONFRAG_IPV6_OTHER: - case RTE_ETH_RSS_IPV6_EX: + case RTE_ETH_RSS_IPV6_EX: { + static const uint32_t ip_fields[] = { + NH_FLD_IP_SRC, NH_FLD_IP_DST, + NH_FLD_IP_PROTO }; + static const uint8_t ip_hdr_index[] = { + 0, (uint8_t)LAST_HDR_INDEX }; + unsigned int f, h; if (l3_configured) break; l3_configured = 1; - kg_cfg->extracts[i].extract.from_hdr.prot = - NET_PROT_IP; - kg_cfg->extracts[i].extract.from_hdr.field = - NH_FLD_IP_SRC; - kg_cfg->extracts[i].type = - DPKG_EXTRACT_FROM_HDR; - kg_cfg->extracts[i].extract.from_hdr.type = - DPKG_FULL_FIELD; - i++; - - kg_cfg->extracts[i].extract.from_hdr.prot = - NET_PROT_IP; - kg_cfg->extracts[i].extract.from_hdr.field = - NH_FLD_IP_DST; - kg_cfg->extracts[i].type = - DPKG_EXTRACT_FROM_HDR; - kg_cfg->extracts[i].extract.from_hdr.type = - DPKG_FULL_FIELD; - i++; - - kg_cfg->extracts[i].extract.from_hdr.prot = - NET_PROT_IP; - kg_cfg->extracts[i].extract.from_hdr.field = - NH_FLD_IP_PROTO; - kg_cfg->extracts[i].type = - DPKG_EXTRACT_FROM_HDR; - kg_cfg->extracts[i].extract.from_hdr.type = - DPKG_FULL_FIELD; - i++; - break; + /* Hash on the outer IP (index 0) and the innermost + * IP instance. A plain frame has a single IP header, + * so only the outer extract resolves; a tunnelled + * frame resolves both and is also spread on its inner + * IP. + */ + for (h = 0; h < RTE_DIM(ip_hdr_index); h++) + for (f = 0; f < RTE_DIM(ip_fields); f++) { + kg_cfg->extracts[i].extract.from_hdr.prot = + NET_PROT_IP; + kg_cfg->extracts[i].extract.from_hdr.hdr_index = + ip_hdr_index[h]; + kg_cfg->extracts[i].extract.from_hdr.field = + ip_fields[f]; + kg_cfg->extracts[i].type = + DPKG_EXTRACT_FROM_HDR; + kg_cfg->extracts[i].extract.from_hdr.type = + DPKG_FULL_FIELD; + i++; + } + break; + } case RTE_ETH_RSS_NONFRAG_IPV4_TCP: case RTE_ETH_RSS_NONFRAG_IPV6_TCP: -- 2.43.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v3] net/dpaa2: hash inner IP for tunnelled traffic 2026-08-25 7:42 ` [PATCH v3] " Maxime Leroy @ 2026-08-25 14:14 ` Stephen Hemminger 0 siblings, 0 replies; 15+ messages in thread From: Stephen Hemminger @ 2026-08-25 14:14 UTC (permalink / raw) To: Maxime Leroy; +Cc: Hemant Agrawal, Sachin Saxena, dev On Tue, 25 Aug 2026 09:42:55 +0200 Maxime Leroy <maxime@leroys.fr> wrote: > The RSS key only extracted the outer IP header. Tunnelled traffic whose > outer headers are fixed then carries no entropy for the hash, so every > flow lands on a single Rx queue. > > Extract both the outer IP (header index 0) and the innermost IP instance > (HDR_INDEX_LAST). Plain frames keep being hashed on their only IP header; > the inner extract resolves to nothing and adds no entropy. Tunnelled > frames are also hashed on their inner IP and spread across the Rx queues. > > That a lone IP header does not resolve HDR_INDEX_LAST is the regression > reverted by commit 2b375df07e48 ("net/dpaa2: revert inner RSS level > support"): extracted only at HDR_INDEX_LAST, every plain frame hashed to > the same value and landed on one Rx queue. > > The worst case, requesting every type the PMD advertises, is 16 extracts > out of the DPKG_MAX_NUM_OF_EXTRACTS 20. On LX2160A > dpni_set_rx_hash_dist() accepts the key, and plain IPv4, plain IPv6, VLAN > tagged and tunnelled IPv6 traffic all spread across the Rx queues. > > This is the PMD default hash: dpaa2 does not expose the ethdev RSS level > selector, so it applies to every RSS request. The hardware cannot hash > the inner IP alone, as HDR_INDEX_LAST only resolves when several IP > headers are stacked and a plain frame would hash to a constant. Folding > the outer IP into the key is therefore unavoidable, and two tunnelled > flows that share an inner IP but differ in their outer IP may hash to > different queues. This is documented in the dpaa2 guide. > > Signed-off-by: Maxime Leroy <maxime@leroys.fr> > --- Applied to next-net ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v1 1/2] net/dpaa2: revert inner RSS level support 2026-06-30 12:38 [RFC PATCH] net/dpaa2: fix RSS at inner level for non-tunnelled traffic Maxime Leroy 2026-07-15 17:00 ` Maxime Leroy 2026-07-20 13:34 ` [PATCH v1 0/2] net/dpaa2: fix RSS for plain and tunnelled traffic Maxime Leroy @ 2026-07-20 13:34 ` Maxime Leroy 2026-07-21 9:56 ` Thomas Monjalon 2026-07-20 13:34 ` [PATCH v1 2/2] net/dpaa2: hash inner IP for tunnelled traffic Maxime Leroy 3 siblings, 1 reply; 15+ messages in thread From: Maxime Leroy @ 2026-07-20 13:34 UTC (permalink / raw) To: dev; +Cc: thomas, david.marchand, hemant.agrawal, Maxime Leroy This reverts commit 618a06c53d479ae576ff01c7d274b10c60b3d3d5. RTE_ETH_RSS_LEVEL_INNERMOST was mapped to the innermost IP instance by programming the IP key extracts with hdr_index = HDR_INDEX_LAST. The hardware only resolves that index when several IP headers are stacked. A non-tunnelled frame carries a single IP header, so the extract resolves to nothing, the RSS hash is constant and every such frame is steered to a single Rx queue. The ethdev API defines INNERMOST by encapsulation level, not by the presence of a tunnel: a plain frame's innermost header is its only IP header and must be hashed. The dpaa2 hardware cannot honour that and keep true inner-only semantics for tunnelled traffic at the same time, so the level cannot be implemented correctly as merged. Revert it. Hashing the outer plus the inner IP under the PMD default level, which spreads both plain and tunnelled traffic, is added in a follow-up. Signed-off-by: Maxime Leroy <maxime@leroys.fr> --- doc/guides/rel_notes/release_26_07.rst | 1 - drivers/net/dpaa2/base/dpaa2_hw_dpni.c | 23 ----------------------- drivers/net/dpaa2/dpaa2_ethdev.c | 3 +-- 3 files changed, 1 insertion(+), 26 deletions(-) diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst index 6badd6d91b..6a528e4a0d 100644 --- a/doc/guides/rel_notes/release_26_07.rst +++ b/doc/guides/rel_notes/release_26_07.rst @@ -162,7 +162,6 @@ New Features * **Updated NXP dpaa2 driver.** - * Added inner RSS level support for tunnelled traffic. * Added RSS RETA query and update support. * Removed the software VLAN strip offload: ``RTE_ETH_RX_OFFLOAD_VLAN_STRIP`` is no longer advertised, diff --git a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c index 07f4a3d414..26ad105c73 100644 --- a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c +++ b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c @@ -236,13 +236,6 @@ dpaa2_remove_flow_dist(struct rte_eth_dev *eth_dev, return ret; } -/* dpkg from_hdr.hdr_index value selecting the innermost IP instance (see - * fsl_dpkg.h, where hdr_index is only defined for NET_PROT_IP/IPv4/IPv6/ - * VLAN/MPLS). Used to hash on the inner IP of tunnelled traffic when - * RTE_ETH_RSS_LEVEL_INNERMOST is requested. - */ -#define DPAA2_DIST_HDR_INDEX_LAST 0xff - int dpaa2_distset_to_dpkg_profile_cfg( uint64_t req_dist_set, @@ -257,18 +250,8 @@ dpaa2_distset_to_dpkg_profile_cfg( int esp_configured = 0; int ah_configured = 0; int pppoe_configured = 0; - uint8_t hdr_index = 0; memset(kg_cfg, 0, sizeof(struct dpkg_profile_cfg)); - - /* RTE_ETH_RSS_LEVEL_INNERMOST asks for the inner header to be hashed. - * Map it to the innermost IP instance in the key extracts; the level - * bits are not protocol bits, so strip them before the loop. - */ - if ((req_dist_set & RTE_ETH_RSS_LEVEL_MASK) == RTE_ETH_RSS_LEVEL_INNERMOST) - hdr_index = DPAA2_DIST_HDR_INDEX_LAST; - req_dist_set &= ~RTE_ETH_RSS_LEVEL_MASK; - while (req_dist_set) { if (req_dist_set % 2 != 0) { dist_field = 1ULL << loop; @@ -406,8 +389,6 @@ dpaa2_distset_to_dpkg_profile_cfg( kg_cfg->extracts[i].extract.from_hdr.prot = NET_PROT_IP; - kg_cfg->extracts[i].extract.from_hdr.hdr_index = - hdr_index; kg_cfg->extracts[i].extract.from_hdr.field = NH_FLD_IP_SRC; kg_cfg->extracts[i].type = @@ -418,8 +399,6 @@ dpaa2_distset_to_dpkg_profile_cfg( kg_cfg->extracts[i].extract.from_hdr.prot = NET_PROT_IP; - kg_cfg->extracts[i].extract.from_hdr.hdr_index = - hdr_index; kg_cfg->extracts[i].extract.from_hdr.field = NH_FLD_IP_DST; kg_cfg->extracts[i].type = @@ -430,8 +409,6 @@ dpaa2_distset_to_dpkg_profile_cfg( kg_cfg->extracts[i].extract.from_hdr.prot = NET_PROT_IP; - kg_cfg->extracts[i].extract.from_hdr.hdr_index = - hdr_index; kg_cfg->extracts[i].extract.from_hdr.field = NH_FLD_IP_PROTO; kg_cfg->extracts[i].type = diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c index 53ea060a4c..f211357919 100644 --- a/drivers/net/dpaa2/dpaa2_ethdev.c +++ b/drivers/net/dpaa2/dpaa2_ethdev.c @@ -453,8 +453,7 @@ dpaa2_dev_info_get(struct rte_eth_dev *dev, dev_info->max_hash_mac_addrs = 0; dev_info->max_vfs = 0; dev_info->max_vmdq_pools = RTE_ETH_16_POOLS; - dev_info->flow_type_rss_offloads = DPAA2_RSS_OFFLOAD_ALL | - RTE_ETH_RSS_LEVEL_OUTERMOST | RTE_ETH_RSS_LEVEL_INNERMOST; + dev_info->flow_type_rss_offloads = DPAA2_RSS_OFFLOAD_ALL; /* DPAA2 has no software-visible indirection table: incoming packets are * dispatched to FQs via 'queue_id = hash % dist_size'. We expose the * standard RETA API as an emulation that only accepts uniform patterns -- 2.43.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v1 1/2] net/dpaa2: revert inner RSS level support 2026-07-20 13:34 ` [PATCH v1 1/2] net/dpaa2: revert inner RSS level support Maxime Leroy @ 2026-07-21 9:56 ` Thomas Monjalon 2026-07-21 12:55 ` Hemant Agrawal 0 siblings, 1 reply; 15+ messages in thread From: Thomas Monjalon @ 2026-07-21 9:56 UTC (permalink / raw) To: hemant.agrawal, Hemant Agrawal, Sachin Saxena, Gagandeep Singh Cc: dev, david.marchand, Maxime Leroy I'm waiting for an urgent reply from the maintainers here. 20/07/2026 15:34, Maxime Leroy: > This reverts commit 618a06c53d479ae576ff01c7d274b10c60b3d3d5. > > RTE_ETH_RSS_LEVEL_INNERMOST was mapped to the innermost IP instance by > programming the IP key extracts with hdr_index = HDR_INDEX_LAST. The > hardware only resolves that index when several IP headers are stacked. > A non-tunnelled frame carries a single IP header, so the extract > resolves to nothing, the RSS hash is constant and every such frame is > steered to a single Rx queue. > > The ethdev API defines INNERMOST by encapsulation level, not by the > presence of a tunnel: a plain frame's innermost header is its only IP > header and must be hashed. The dpaa2 hardware cannot honour that and > keep true inner-only semantics for tunnelled traffic at the same time, > so the level cannot be implemented correctly as merged. > > Revert it. Hashing the outer plus the inner IP under the PMD default > level, which spreads both plain and tunnelled traffic, is added in a > follow-up. > > Signed-off-by: Maxime Leroy <maxime@leroys.fr> ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v1 1/2] net/dpaa2: revert inner RSS level support 2026-07-21 9:56 ` Thomas Monjalon @ 2026-07-21 12:55 ` Hemant Agrawal 2026-07-21 21:25 ` Thomas Monjalon 0 siblings, 1 reply; 15+ messages in thread From: Hemant Agrawal @ 2026-07-21 12:55 UTC (permalink / raw) To: Thomas Monjalon, Hemant Agrawal, Sachin Saxena, Gagandeep Singh Cc: dev, david.marchand, Maxime Leroy Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com> On 21-07-2026 15:26, Thomas Monjalon wrote: > I'm waiting for an urgent reply from the maintainers here. > > > 20/07/2026 15:34, Maxime Leroy: >> This reverts commit 618a06c53d479ae576ff01c7d274b10c60b3d3d5. >> >> RTE_ETH_RSS_LEVEL_INNERMOST was mapped to the innermost IP instance by >> programming the IP key extracts with hdr_index = HDR_INDEX_LAST. The >> hardware only resolves that index when several IP headers are stacked. >> A non-tunnelled frame carries a single IP header, so the extract >> resolves to nothing, the RSS hash is constant and every such frame is >> steered to a single Rx queue. >> >> The ethdev API defines INNERMOST by encapsulation level, not by the >> presence of a tunnel: a plain frame's innermost header is its only IP >> header and must be hashed. The dpaa2 hardware cannot honour that and >> keep true inner-only semantics for tunnelled traffic at the same time, >> so the level cannot be implemented correctly as merged. >> >> Revert it. Hashing the outer plus the inner IP under the PMD default >> level, which spreads both plain and tunnelled traffic, is added in a >> follow-up. >> >> Signed-off-by: Maxime Leroy <maxime@leroys.fr> > > > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v1 1/2] net/dpaa2: revert inner RSS level support 2026-07-21 12:55 ` Hemant Agrawal @ 2026-07-21 21:25 ` Thomas Monjalon 0 siblings, 0 replies; 15+ messages in thread From: Thomas Monjalon @ 2026-07-21 21:25 UTC (permalink / raw) To: Maxime Leroy Cc: Hemant Agrawal, Sachin Saxena, Gagandeep Singh, dev, david.marchand, Hemant Agrawal 21/07/2026 14:55, Hemant Agrawal: > Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com> > > On 21-07-2026 15:26, Thomas Monjalon wrote: > > I'm waiting for an urgent reply from the maintainers here. > > > > > > 20/07/2026 15:34, Maxime Leroy: > >> This reverts commit 618a06c53d479ae576ff01c7d274b10c60b3d3d5. > >> > >> RTE_ETH_RSS_LEVEL_INNERMOST was mapped to the innermost IP instance by > >> programming the IP key extracts with hdr_index = HDR_INDEX_LAST. The > >> hardware only resolves that index when several IP headers are stacked. > >> A non-tunnelled frame carries a single IP header, so the extract > >> resolves to nothing, the RSS hash is constant and every such frame is > >> steered to a single Rx queue. > >> > >> The ethdev API defines INNERMOST by encapsulation level, not by the > >> presence of a tunnel: a plain frame's innermost header is its only IP > >> header and must be hashed. The dpaa2 hardware cannot honour that and > >> keep true inner-only semantics for tunnelled traffic at the same time, > >> so the level cannot be implemented correctly as merged. > >> > >> Revert it. Hashing the outer plus the inner IP under the PMD default > >> level, which spreads both plain and tunnelled traffic, is added in a > >> follow-up. > >> > >> Signed-off-by: Maxime Leroy <maxime@leroys.fr> Applied, thanks. ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v1 2/2] net/dpaa2: hash inner IP for tunnelled traffic 2026-06-30 12:38 [RFC PATCH] net/dpaa2: fix RSS at inner level for non-tunnelled traffic Maxime Leroy ` (2 preceding siblings ...) 2026-07-20 13:34 ` [PATCH v1 1/2] net/dpaa2: revert inner RSS level support Maxime Leroy @ 2026-07-20 13:34 ` Maxime Leroy 3 siblings, 0 replies; 15+ messages in thread From: Maxime Leroy @ 2026-07-20 13:34 UTC (permalink / raw) To: dev; +Cc: thomas, david.marchand, hemant.agrawal, Maxime Leroy The RSS key only extracted the outer IP header. Tunnelled traffic whose outer headers are fixed then carries no entropy for the hash, so every flow lands on a single Rx queue. Extract both the outer IP (header index 0) and the innermost IP instance (HDR_INDEX_LAST). Plain frames keep being hashed on their only IP header; the inner extract resolves to nothing and adds no entropy. Tunnelled frames are also hashed on their inner IP and spread across the Rx queues. This is the PMD default hash: dpaa2 does not expose the ethdev RSS level selector, so it applies to every RSS request. The hardware cannot hash the inner IP alone, as HDR_INDEX_LAST only resolves when several IP headers are stacked and a plain frame would hash to a constant. Folding the outer IP into the key is therefore unavoidable, and two tunnelled flows that share an inner IP but differ in their outer IP may hash to different queues. This is documented in the dpaa2 guide. Signed-off-by: Maxime Leroy <maxime@leroys.fr> --- doc/guides/nics/dpaa2.rst | 3 ++ doc/guides/rel_notes/release_26_07.rst | 2 + drivers/net/dpaa2/base/dpaa2_hw_dpni.c | 63 +++++++++++++------------- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/doc/guides/nics/dpaa2.rst b/doc/guides/nics/dpaa2.rst index ae8b32af2c..aaaf5f9713 100644 --- a/doc/guides/nics/dpaa2.rst +++ b/doc/guides/nics/dpaa2.rst @@ -588,6 +588,9 @@ Other Limitations - RSS hash key cannot be modified. - RSS RETA cannot be configured. +- RSS hashes on both the outer and the inner IP header. Tunnelled flows + that share the same inner IP but differ in their outer IP may therefore + be steered to different Rx queues. .. _dpaa2_dptmapi: diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst index 6a528e4a0d..c952512023 100644 --- a/doc/guides/rel_notes/release_26_07.rst +++ b/doc/guides/rel_notes/release_26_07.rst @@ -163,6 +163,8 @@ New Features * **Updated NXP dpaa2 driver.** * Added RSS RETA query and update support. + * Added the inner IP header to the RSS hash so tunnelled traffic is + distributed across the Rx queues. * Removed the software VLAN strip offload: ``RTE_ETH_RX_OFFLOAD_VLAN_STRIP`` is no longer advertised, as no hardware strip backs it. diff --git a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c index 26ad105c73..5bb9ad4591 100644 --- a/drivers/net/dpaa2/base/dpaa2_hw_dpni.c +++ b/drivers/net/dpaa2/base/dpaa2_hw_dpni.c @@ -236,6 +236,9 @@ dpaa2_remove_flow_dist(struct rte_eth_dev *eth_dev, return ret; } +/* hdr_index selecting the innermost IP instance in a dpkg extract */ +#define DPAA2_DIST_HDR_INDEX_LAST 0xff + int dpaa2_distset_to_dpkg_profile_cfg( uint64_t req_dist_set, @@ -381,42 +384,40 @@ dpaa2_distset_to_dpkg_profile_cfg( case RTE_ETH_RSS_IPV6: case RTE_ETH_RSS_FRAG_IPV6: case RTE_ETH_RSS_NONFRAG_IPV6_OTHER: - case RTE_ETH_RSS_IPV6_EX: + case RTE_ETH_RSS_IPV6_EX: { + static const uint32_t ip_fields[] = { + NH_FLD_IP_SRC, NH_FLD_IP_DST, + NH_FLD_IP_PROTO }; + static const uint8_t ip_hdr_index[] = { + 0, DPAA2_DIST_HDR_INDEX_LAST }; + unsigned int f, h; if (l3_configured) break; l3_configured = 1; - kg_cfg->extracts[i].extract.from_hdr.prot = - NET_PROT_IP; - kg_cfg->extracts[i].extract.from_hdr.field = - NH_FLD_IP_SRC; - kg_cfg->extracts[i].type = - DPKG_EXTRACT_FROM_HDR; - kg_cfg->extracts[i].extract.from_hdr.type = - DPKG_FULL_FIELD; - i++; - - kg_cfg->extracts[i].extract.from_hdr.prot = - NET_PROT_IP; - kg_cfg->extracts[i].extract.from_hdr.field = - NH_FLD_IP_DST; - kg_cfg->extracts[i].type = - DPKG_EXTRACT_FROM_HDR; - kg_cfg->extracts[i].extract.from_hdr.type = - DPKG_FULL_FIELD; - i++; - - kg_cfg->extracts[i].extract.from_hdr.prot = - NET_PROT_IP; - kg_cfg->extracts[i].extract.from_hdr.field = - NH_FLD_IP_PROTO; - kg_cfg->extracts[i].type = - DPKG_EXTRACT_FROM_HDR; - kg_cfg->extracts[i].extract.from_hdr.type = - DPKG_FULL_FIELD; - i++; - break; + /* Hash on the outer IP (index 0) and the innermost + * IP instance. A plain frame has a single IP header, + * so only the outer extract resolves; a tunnelled + * frame resolves both and is also spread on its inner + * IP. + */ + for (h = 0; h < RTE_DIM(ip_hdr_index); h++) + for (f = 0; f < RTE_DIM(ip_fields); f++) { + kg_cfg->extracts[i].extract.from_hdr.prot = + NET_PROT_IP; + kg_cfg->extracts[i].extract.from_hdr.hdr_index = + ip_hdr_index[h]; + kg_cfg->extracts[i].extract.from_hdr.field = + ip_fields[f]; + kg_cfg->extracts[i].type = + DPKG_EXTRACT_FROM_HDR; + kg_cfg->extracts[i].extract.from_hdr.type = + DPKG_FULL_FIELD; + i++; + } + break; + } case RTE_ETH_RSS_NONFRAG_IPV4_TCP: case RTE_ETH_RSS_NONFRAG_IPV6_TCP: -- 2.43.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-08-25 14:15 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-06-30 12:38 [RFC PATCH] net/dpaa2: fix RSS at inner level for non-tunnelled traffic Maxime Leroy 2026-07-15 17:00 ` Maxime Leroy 2026-07-16 7:47 ` Hemant Agrawal 2026-07-16 8:00 ` Maxime Leroy 2026-07-20 13:34 ` [PATCH v1 0/2] net/dpaa2: fix RSS for plain and tunnelled traffic Maxime Leroy 2026-07-23 9:35 ` [PATCH v2] net/dpaa2: hash inner IP for " Maxime Leroy 2026-07-26 16:37 ` Stephen Hemminger 2026-07-27 8:04 ` Maxime Leroy 2026-08-25 7:42 ` [PATCH v3] " Maxime Leroy 2026-08-25 14:14 ` Stephen Hemminger 2026-07-20 13:34 ` [PATCH v1 1/2] net/dpaa2: revert inner RSS level support Maxime Leroy 2026-07-21 9:56 ` Thomas Monjalon 2026-07-21 12:55 ` Hemant Agrawal 2026-07-21 21:25 ` Thomas Monjalon 2026-07-20 13:34 ` [PATCH v1 2/2] net/dpaa2: hash inner IP for tunnelled traffic Maxime Leroy
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.