DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH] ethdev: fix RSS flow expansion in case of mismatch
@ 2020-07-27 12:57 Dekel Peled
  2020-07-27 13:25 ` Dekel Peled
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Dekel Peled @ 2020-07-27 12:57 UTC (permalink / raw)
  To: matan, viacheslavo, rasland; +Cc: dev, stable

Function rte_flow_expand_rss() is used to expand a flow rule with
partial pattern into several rules, to ensure all relevant packets
are matched.
It uses utility function rte_flow_expand_rss_item_complete(), to check
if the last valid item in the flow rule pattern needs to be completed.
For example the pattern "eth / ipv4 proto is 17 / end" will be completed
with a "udp" item.
This function returns "void" item in two cases:
1) The last item has empty spec, for example "eth / ipv4 / end".
2) The last itme has spec that can't be expanded for RSS.
   For example the pattern "eth / ipv4 proto is 47 / end" ends with IPv4
   item that has next protocol GRE.

In both cases the flow rule may be expanded, but in the second case such
expansion may create rules with invalid pattern.
For example "eth / ipv4 proto is 47 / udp / end".
In such a case the flow rule should not be expanded.

This patch updates function rte_flow_expand_rss_item_complete().
Return value RTE_FLOW_ITEM_TYPE_END is used to indicate the flow rule
should not be expanded.
In such a case, rte_flow_expand_rss() will return with the original flow
rule only, without any expansion.

Fixes: fc2dd8dd492f ("ethdev: fix expand RSS flows")
Cc: stable@dpdk.org

Signed-off-by: Dekel Peled <dekelp@mellanox.com>
Acked-by: Xiaoyu Min <jackmin@mellanox.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
---
 lib/librte_ethdev/rte_flow.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index f8fdd68..59a386d 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -247,6 +247,8 @@ struct rte_flow_desc_data {
 			ret = RTE_FLOW_ITEM_TYPE_IPV6;
 		else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_VLAN)
 			ret = RTE_FLOW_ITEM_TYPE_VLAN;
+		else
+			ret = RTE_FLOW_ITEM_TYPE_END;
 		break;
 	case RTE_FLOW_ITEM_TYPE_VLAN:
 		if (item->mask)
@@ -264,6 +266,8 @@ struct rte_flow_desc_data {
 			ret = RTE_FLOW_ITEM_TYPE_IPV6;
 		else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_VLAN)
 			ret = RTE_FLOW_ITEM_TYPE_VLAN;
+		else
+			ret = RTE_FLOW_ITEM_TYPE_END;
 		break;
 	case RTE_FLOW_ITEM_TYPE_IPV4:
 		if (item->mask)
@@ -284,6 +288,8 @@ struct rte_flow_desc_data {
 			ret = RTE_FLOW_ITEM_TYPE_IPV4;
 		else if (ip_next_proto == IPPROTO_IPV6)
 			ret = RTE_FLOW_ITEM_TYPE_IPV6;
+		else
+			ret = RTE_FLOW_ITEM_TYPE_END;
 		break;
 	case RTE_FLOW_ITEM_TYPE_IPV6:
 		if (item->mask)
@@ -304,6 +310,8 @@ struct rte_flow_desc_data {
 			ret = RTE_FLOW_ITEM_TYPE_IPV4;
 		else if (ip_next_proto == IPPROTO_IPV6)
 			ret = RTE_FLOW_ITEM_TYPE_IPV6;
+		else
+			ret = RTE_FLOW_ITEM_TYPE_END;
 		break;
 	default:
 		ret = RTE_FLOW_ITEM_TYPE_VOID;
@@ -1110,10 +1118,14 @@ enum rte_flow_conv_item_spec_type {
 	memset(flow_items, 0, sizeof(flow_items));
 	user_pattern_size -= sizeof(*item);
 	/*
-	 * Check if the last valid item has spec set
-	 * and need complete pattern.
+	 * Check if the last valid item has spec set, need complete pattern,
+	 * and the pattern can be used for expansion.
 	 */
 	missed_item.type = rte_flow_expand_rss_item_complete(last_item);
+	if (missed_item.type == RTE_FLOW_ITEM_TYPE_END) {
+		/* Item type END indicates expansion is not required. */
+		return lsize;
+	}
 	if (missed_item.type != RTE_FLOW_ITEM_TYPE_VOID) {
 		next = NULL;
 		missed = 1;
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: fix RSS flow expansion in case of mismatch
  2020-07-27 12:57 [dpdk-dev] [PATCH] ethdev: fix RSS flow expansion in case of mismatch Dekel Peled
@ 2020-07-27 13:25 ` Dekel Peled
  2020-07-27 16:21   ` Ori Kam
  2020-09-02 17:09 ` Ferruh Yigit
  2020-09-24 14:52 ` [dpdk-dev] [PATCH v2 0/2] ethdev: RSS expand code fix and relocate Dekel Peled
  2 siblings, 1 reply; 11+ messages in thread
From: Dekel Peled @ 2020-07-27 13:25 UTC (permalink / raw)
  To: Raslan Darawsheh, Ori Kam, Thomas Monjalon, ferruh.yigit,
	Andrew Rybchenko
  Cc: dev, stable, Matan Azrad, Slava Ovsiienko

Resending To: maintaners.

> -----Original Message-----
> From: Dekel Peled <dekelp@mellanox.com>
> Sent: Monday, July 27, 2020 3:58 PM
> To: Matan Azrad <matan@mellanox.com>; Slava Ovsiienko
> <viacheslavo@mellanox.com>; Raslan Darawsheh <rasland@mellanox.com>
> Cc: dev@dpdk.org; stable@dpdk.org
> Subject: [PATCH] ethdev: fix RSS flow expansion in case of mismatch
> 
> Function rte_flow_expand_rss() is used to expand a flow rule with partial
> pattern into several rules, to ensure all relevant packets are matched.
> It uses utility function rte_flow_expand_rss_item_complete(), to check if
> the last valid item in the flow rule pattern needs to be completed.
> For example the pattern "eth / ipv4 proto is 17 / end" will be completed with
> a "udp" item.
> This function returns "void" item in two cases:
> 1) The last item has empty spec, for example "eth / ipv4 / end".
> 2) The last itme has spec that can't be expanded for RSS.
>    For example the pattern "eth / ipv4 proto is 47 / end" ends with IPv4
>    item that has next protocol GRE.
> 
> In both cases the flow rule may be expanded, but in the second case such
> expansion may create rules with invalid pattern.
> For example "eth / ipv4 proto is 47 / udp / end".
> In such a case the flow rule should not be expanded.
> 
> This patch updates function rte_flow_expand_rss_item_complete().
> Return value RTE_FLOW_ITEM_TYPE_END is used to indicate the flow rule
> should not be expanded.
> In such a case, rte_flow_expand_rss() will return with the original flow rule
> only, without any expansion.
> 
> Fixes: fc2dd8dd492f ("ethdev: fix expand RSS flows")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Dekel Peled <dekelp@mellanox.com>
> Acked-by: Xiaoyu Min <jackmin@mellanox.com>
> Acked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
> ---
>  lib/librte_ethdev/rte_flow.c | 16 ++++++++++++++--
>  1 file changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c index
> f8fdd68..59a386d 100644
> --- a/lib/librte_ethdev/rte_flow.c
> +++ b/lib/librte_ethdev/rte_flow.c
> @@ -247,6 +247,8 @@ struct rte_flow_desc_data {
>  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
>  		else if (rte_be_to_cpu_16(ether_type) ==
> RTE_ETHER_TYPE_VLAN)
>  			ret = RTE_FLOW_ITEM_TYPE_VLAN;
> +		else
> +			ret = RTE_FLOW_ITEM_TYPE_END;
>  		break;
>  	case RTE_FLOW_ITEM_TYPE_VLAN:
>  		if (item->mask)
> @@ -264,6 +266,8 @@ struct rte_flow_desc_data {
>  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
>  		else if (rte_be_to_cpu_16(ether_type) ==
> RTE_ETHER_TYPE_VLAN)
>  			ret = RTE_FLOW_ITEM_TYPE_VLAN;
> +		else
> +			ret = RTE_FLOW_ITEM_TYPE_END;
>  		break;
>  	case RTE_FLOW_ITEM_TYPE_IPV4:
>  		if (item->mask)
> @@ -284,6 +288,8 @@ struct rte_flow_desc_data {
>  			ret = RTE_FLOW_ITEM_TYPE_IPV4;
>  		else if (ip_next_proto == IPPROTO_IPV6)
>  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
> +		else
> +			ret = RTE_FLOW_ITEM_TYPE_END;
>  		break;
>  	case RTE_FLOW_ITEM_TYPE_IPV6:
>  		if (item->mask)
> @@ -304,6 +310,8 @@ struct rte_flow_desc_data {
>  			ret = RTE_FLOW_ITEM_TYPE_IPV4;
>  		else if (ip_next_proto == IPPROTO_IPV6)
>  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
> +		else
> +			ret = RTE_FLOW_ITEM_TYPE_END;
>  		break;
>  	default:
>  		ret = RTE_FLOW_ITEM_TYPE_VOID;
> @@ -1110,10 +1118,14 @@ enum rte_flow_conv_item_spec_type {
>  	memset(flow_items, 0, sizeof(flow_items));
>  	user_pattern_size -= sizeof(*item);
>  	/*
> -	 * Check if the last valid item has spec set
> -	 * and need complete pattern.
> +	 * Check if the last valid item has spec set, need complete pattern,
> +	 * and the pattern can be used for expansion.
>  	 */
>  	missed_item.type =
> rte_flow_expand_rss_item_complete(last_item);
> +	if (missed_item.type == RTE_FLOW_ITEM_TYPE_END) {
> +		/* Item type END indicates expansion is not required. */
> +		return lsize;
> +	}
>  	if (missed_item.type != RTE_FLOW_ITEM_TYPE_VOID) {
>  		next = NULL;
>  		missed = 1;
> --
> 1.8.3.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: fix RSS flow expansion in case of mismatch
  2020-07-27 13:25 ` Dekel Peled
@ 2020-07-27 16:21   ` Ori Kam
  2020-07-28  9:14     ` Dekel Peled
  0 siblings, 1 reply; 11+ messages in thread
From: Ori Kam @ 2020-07-27 16:21 UTC (permalink / raw)
  To: Dekel Peled, Raslan Darawsheh, Thomas Monjalon, ferruh.yigit,
	Andrew Rybchenko
  Cc: dev, stable, Matan Azrad, Slava Ovsiienko

Hi Dekel,

> -----Original Message-----
> From: Dekel Peled <dekelp@mellanox.com>
> 
> Resending To: maintaners.
> 
> > -----Original Message-----
> > From: Dekel Peled <dekelp@mellanox.com>
> >
> > Function rte_flow_expand_rss() is used to expand a flow rule with partial
> > pattern into several rules, to ensure all relevant packets are matched.
> > It uses utility function rte_flow_expand_rss_item_complete(), to check if
> > the last valid item in the flow rule pattern needs to be completed.

Which is also based on the requested RSS type. Right? If no RSS type is set then
the issue will not appear.

> > For example the pattern "eth / ipv4 proto is 17 / end" will be completed with
> > a "udp" item.

Only if UDP rss type is selected, if TCP is selected then it will be TCP right?

> > This function returns "void" item in two cases:
> > 1) The last item has empty spec, for example "eth / ipv4 / end".
> > 2) The last itme has spec that can't be expanded for RSS.
> >    For example the pattern "eth / ipv4 proto is 47 / end" ends with IPv4
> >    item that has next protocol GRE.
> >
Typo in itme -> item?

> > In both cases the flow rule may be expanded, but in the second case such
> > expansion may create rules with invalid pattern.

You mean that in both cases the flow will be expanded, that is the issue.
That in the second case the flow shouldn't be expended.

> > For example "eth / ipv4 proto is 47 / udp / end".
> > In such a case the flow rule should not be expanded.
> >
> > This patch updates function rte_flow_expand_rss_item_complete().
> > Return value RTE_FLOW_ITEM_TYPE_END is used to indicate the flow rule
> > should not be expanded.
> > In such a case, rte_flow_expand_rss() will return with the original flow rule
> > only, without any expansion.
> >


> > Fixes: fc2dd8dd492f ("ethdev: fix expand RSS flows")
> > Cc: stable@dpdk.org
> >
> > Signed-off-by: Dekel Peled <dekelp@mellanox.com>
> > Acked-by: Xiaoyu Min <jackmin@mellanox.com>
> > Acked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
> > ---
> >  lib/librte_ethdev/rte_flow.c | 16 ++++++++++++++--
> >  1 file changed, 14 insertions(+), 2 deletions(-)
> >
> > diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c index
> > f8fdd68..59a386d 100644
> > --- a/lib/librte_ethdev/rte_flow.c
> > +++ b/lib/librte_ethdev/rte_flow.c
> > @@ -247,6 +247,8 @@ struct rte_flow_desc_data {
> >  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
> >  		else if (rte_be_to_cpu_16(ether_type) ==
> > RTE_ETHER_TYPE_VLAN)
> >  			ret = RTE_FLOW_ITEM_TYPE_VLAN;
> > +		else
> > +			ret = RTE_FLOW_ITEM_TYPE_END;
> >  		break;
> >  	case RTE_FLOW_ITEM_TYPE_VLAN:
> >  		if (item->mask)
> > @@ -264,6 +266,8 @@ struct rte_flow_desc_data {
> >  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
> >  		else if (rte_be_to_cpu_16(ether_type) ==
> > RTE_ETHER_TYPE_VLAN)
> >  			ret = RTE_FLOW_ITEM_TYPE_VLAN;
> > +		else
> > +			ret = RTE_FLOW_ITEM_TYPE_END;
> >  		break;
> >  	case RTE_FLOW_ITEM_TYPE_IPV4:
> >  		if (item->mask)
> > @@ -284,6 +288,8 @@ struct rte_flow_desc_data {
> >  			ret = RTE_FLOW_ITEM_TYPE_IPV4;
> >  		else if (ip_next_proto == IPPROTO_IPV6)
> >  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
> > +		else
> > +			ret = RTE_FLOW_ITEM_TYPE_END;
> >  		break;
> >  	case RTE_FLOW_ITEM_TYPE_IPV6:
> >  		if (item->mask)
> > @@ -304,6 +310,8 @@ struct rte_flow_desc_data {
> >  			ret = RTE_FLOW_ITEM_TYPE_IPV4;
> >  		else if (ip_next_proto == IPPROTO_IPV6)
> >  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
> > +		else
> > +			ret = RTE_FLOW_ITEM_TYPE_END;
> >  		break;
> >  	default:
> >  		ret = RTE_FLOW_ITEM_TYPE_VOID;
> > @@ -1110,10 +1118,14 @@ enum rte_flow_conv_item_spec_type {
> >  	memset(flow_items, 0, sizeof(flow_items));
> >  	user_pattern_size -= sizeof(*item);
> >  	/*
> > -	 * Check if the last valid item has spec set
> > -	 * and need complete pattern.
> > +	 * Check if the last valid item has spec set, need complete pattern,
> > +	 * and the pattern can be used for expansion.
> >  	 */
> >  	missed_item.type =
> > rte_flow_expand_rss_item_complete(last_item);
> > +	if (missed_item.type == RTE_FLOW_ITEM_TYPE_END) {
> > +		/* Item type END indicates expansion is not required. */
> > +		return lsize;
> > +	}
> >  	if (missed_item.type != RTE_FLOW_ITEM_TYPE_VOID) {
> >  		next = NULL;
> >  		missed = 1;
> > --
> > 1.8.3.1

I don't think this is the correct solution.
The idea of the rte_flow_expand_rss_item_complete function is to add
the last item so later the parsing will be based on items regardless of spec.
This mean the function already support pattern with the following format:
Eth / ipv4 / gre. What the result will be? Will it be expended? 

I think the solution should be that the function will return the correct item. Assuming there
is such an item.

Best,
Ori


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: fix RSS flow expansion in case of mismatch
  2020-07-27 16:21   ` Ori Kam
@ 2020-07-28  9:14     ` Dekel Peled
  2020-08-17  8:16       ` Ori Kam
  0 siblings, 1 reply; 11+ messages in thread
From: Dekel Peled @ 2020-07-28  9:14 UTC (permalink / raw)
  To: Ori Kam, Raslan Darawsheh, Thomas Monjalon, ferruh.yigit,
	Andrew Rybchenko
  Cc: dev, stable, Matan Azrad, Slava Ovsiienko

Hi, PSB.

> -----Original Message-----
> From: Ori Kam <orika@mellanox.com>
> Sent: Monday, July 27, 2020 7:21 PM
> To: Dekel Peled <dekelp@mellanox.com>; Raslan Darawsheh
> <rasland@mellanox.com>; Thomas Monjalon <thomasm@mellanox.com>;
> ferruh.yigit@intel.com; Andrew Rybchenko <arybchenko@solarflare.com>
> Cc: dev@dpdk.org; stable@dpdk.org; Matan Azrad <matan@mellanox.com>;
> Slava Ovsiienko <viacheslavo@mellanox.com>
> Subject: RE: [PATCH] ethdev: fix RSS flow expansion in case of mismatch
> 
> Hi Dekel,
> 
> > -----Original Message-----
> > From: Dekel Peled <dekelp@mellanox.com>
> >
> > Resending To: maintaners.
> >
> > > -----Original Message-----
> > > From: Dekel Peled <dekelp@mellanox.com>
> > >
> > > Function rte_flow_expand_rss() is used to expand a flow rule with
> > > partial pattern into several rules, to ensure all relevant packets are
> matched.
> > > It uses utility function rte_flow_expand_rss_item_complete(), to
> > > check if the last valid item in the flow rule pattern needs to be
> completed.
> 
> Which is also based on the requested RSS type. Right? If no RSS type is set
> then the issue will not appear.

Correct.

> 
> > > For example the pattern "eth / ipv4 proto is 17 / end" will be
> > > completed with a "udp" item.
> 
> Only if UDP rss type is selected, if TCP is selected then it will be TCP right?

Correct.

> 
> > > This function returns "void" item in two cases:
> > > 1) The last item has empty spec, for example "eth / ipv4 / end".
> > > 2) The last itme has spec that can't be expanded for RSS.
> > >    For example the pattern "eth / ipv4 proto is 47 / end" ends with IPv4
> > >    item that has next protocol GRE.
> > >
> Typo in itme -> item?

Indeed.

> 
> > > In both cases the flow rule may be expanded, but in the second case
> > > such expansion may create rules with invalid pattern.
> 
> You mean that in both cases the flow will be expanded, that is the issue.
> That in the second case the flow shouldn't be expended.

Correct.

> 
> > > For example "eth / ipv4 proto is 47 / udp / end".
> > > In such a case the flow rule should not be expanded.
> > >
> > > This patch updates function rte_flow_expand_rss_item_complete().
> > > Return value RTE_FLOW_ITEM_TYPE_END is used to indicate the flow
> > > rule should not be expanded.
> > > In such a case, rte_flow_expand_rss() will return with the original
> > > flow rule only, without any expansion.
> > >
> 
> 
> > > Fixes: fc2dd8dd492f ("ethdev: fix expand RSS flows")
> > > Cc: stable@dpdk.org
> > >
> > > Signed-off-by: Dekel Peled <dekelp@mellanox.com>
> > > Acked-by: Xiaoyu Min <jackmin@mellanox.com>
> > > Acked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
> > > ---
> > >  lib/librte_ethdev/rte_flow.c | 16 ++++++++++++++--
> > >  1 file changed, 14 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/lib/librte_ethdev/rte_flow.c
> > > b/lib/librte_ethdev/rte_flow.c index f8fdd68..59a386d 100644
> > > --- a/lib/librte_ethdev/rte_flow.c
> > > +++ b/lib/librte_ethdev/rte_flow.c
> > > @@ -247,6 +247,8 @@ struct rte_flow_desc_data {
> > >  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
> > >  		else if (rte_be_to_cpu_16(ether_type) ==
> > > RTE_ETHER_TYPE_VLAN)
> > >  			ret = RTE_FLOW_ITEM_TYPE_VLAN;
> > > +		else
> > > +			ret = RTE_FLOW_ITEM_TYPE_END;
> > >  		break;
> > >  	case RTE_FLOW_ITEM_TYPE_VLAN:
> > >  		if (item->mask)
> > > @@ -264,6 +266,8 @@ struct rte_flow_desc_data {
> > >  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
> > >  		else if (rte_be_to_cpu_16(ether_type) ==
> > > RTE_ETHER_TYPE_VLAN)
> > >  			ret = RTE_FLOW_ITEM_TYPE_VLAN;
> > > +		else
> > > +			ret = RTE_FLOW_ITEM_TYPE_END;
> > >  		break;
> > >  	case RTE_FLOW_ITEM_TYPE_IPV4:
> > >  		if (item->mask)
> > > @@ -284,6 +288,8 @@ struct rte_flow_desc_data {
> > >  			ret = RTE_FLOW_ITEM_TYPE_IPV4;
> > >  		else if (ip_next_proto == IPPROTO_IPV6)
> > >  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
> > > +		else
> > > +			ret = RTE_FLOW_ITEM_TYPE_END;
> > >  		break;
> > >  	case RTE_FLOW_ITEM_TYPE_IPV6:
> > >  		if (item->mask)
> > > @@ -304,6 +310,8 @@ struct rte_flow_desc_data {
> > >  			ret = RTE_FLOW_ITEM_TYPE_IPV4;
> > >  		else if (ip_next_proto == IPPROTO_IPV6)
> > >  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
> > > +		else
> > > +			ret = RTE_FLOW_ITEM_TYPE_END;
> > >  		break;
> > >  	default:
> > >  		ret = RTE_FLOW_ITEM_TYPE_VOID;
> > > @@ -1110,10 +1118,14 @@ enum rte_flow_conv_item_spec_type {
> > >  	memset(flow_items, 0, sizeof(flow_items));
> > >  	user_pattern_size -= sizeof(*item);
> > >  	/*
> > > -	 * Check if the last valid item has spec set
> > > -	 * and need complete pattern.
> > > +	 * Check if the last valid item has spec set, need complete pattern,
> > > +	 * and the pattern can be used for expansion.
> > >  	 */
> > >  	missed_item.type =
> > > rte_flow_expand_rss_item_complete(last_item);
> > > +	if (missed_item.type == RTE_FLOW_ITEM_TYPE_END) {
> > > +		/* Item type END indicates expansion is not required. */
> > > +		return lsize;
> > > +	}
> > >  	if (missed_item.type != RTE_FLOW_ITEM_TYPE_VOID) {
> > >  		next = NULL;
> > >  		missed = 1;
> > > --
> > > 1.8.3.1
> 
> I don't think this is the correct solution.
> The idea of the rte_flow_expand_rss_item_complete function is to add the
> last item so later the parsing will be based on items regardless of spec.
> This mean the function already support pattern with the following format:
> Eth / ipv4 / gre. What the result will be? Will it be expended?

Flow rule with such pattern will not be expanded using the current mlx5_support_expansion array.

> 
> I think the solution should be that the function will return the correct item.
> Assuming there is such an item.

This is what the current solution does.

> 
> Best,
> Ori


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: fix RSS flow expansion in case of mismatch
  2020-07-28  9:14     ` Dekel Peled
@ 2020-08-17  8:16       ` Ori Kam
  0 siblings, 0 replies; 11+ messages in thread
From: Ori Kam @ 2020-08-17  8:16 UTC (permalink / raw)
  To: Dekel Peled, Ori Kam, Raslan Darawsheh,
	NBU-Contact-Thomas Monjalon, ferruh.yigit, Andrew Rybchenko
  Cc: dev, stable, Matan Azrad, Slava Ovsiienko



> -----Original Message-----
> From: Dekel Peled <dekelp@mellanox.com>
> Subject: RE: [PATCH] ethdev: fix RSS flow expansion in case of mismatch


[...]

Acked-by: Ori Kam <orika@nvidia.com>
Thanks,
Ori


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: fix RSS flow expansion in case of mismatch
  2020-07-27 12:57 [dpdk-dev] [PATCH] ethdev: fix RSS flow expansion in case of mismatch Dekel Peled
  2020-07-27 13:25 ` Dekel Peled
@ 2020-09-02 17:09 ` Ferruh Yigit
  2020-09-24 14:52 ` [dpdk-dev] [PATCH v2 0/2] ethdev: RSS expand code fix and relocate Dekel Peled
  2 siblings, 0 replies; 11+ messages in thread
From: Ferruh Yigit @ 2020-09-02 17:09 UTC (permalink / raw)
  To: Dekel Peled, matan, viacheslavo, rasland
  Cc: dev, stable, Andrew Rybchenko, Thomas Monjalon, Qi Zhang

On 7/27/2020 1:57 PM, Dekel Peled wrote:
> Function rte_flow_expand_rss() is used to expand a flow rule with
> partial pattern into several rules, to ensure all relevant packets
> are matched.
> It uses utility function rte_flow_expand_rss_item_complete(), to check
> if the last valid item in the flow rule pattern needs to be completed.
> For example the pattern "eth / ipv4 proto is 17 / end" will be completed
> with a "udp" item.

better to add the "actions rss types udp" part of the rule to clarify why the
original rule will be completed with 'udp'.

> This function returns "void" item in two cases:

Can you please clarify what does function returning 'void' mean, so people won't
need to dig the code to find out.

> 1) The last item has empty spec, for example "eth / ipv4 / end".
> 2) The last itme has spec that can't be expanded for RSS.
>    For example the pattern "eth / ipv4 proto is 47 / end" ends with IPv4
>    item that has next protocol GRE.
> 
> In both cases the flow rule may be expanded, but in the second case such
> expansion may create rules with invalid pattern.
> For example "eth / ipv4 proto is 47 / udp / end".
> In such a case the flow rule should not be expanded.

OK, got the problem.

> 
> This patch updates function rte_flow_expand_rss_item_complete().
> Return value RTE_FLOW_ITEM_TYPE_END is used to indicate the flow rule
> should not be expanded.

But there is only limited number of check in
'rte_flow_expand_rss_item_complete()', like for ipv4 it checks the proto
udp/tcp/ip. What if other proto is part of rule, won't sending END cause the
initial problem of missing pattern.

I mean, for following rule,
... pattern eth / ipv4 proto is 47 / end actions rss type gre end ...

With your update, rule is not expanded and the 'gre' pattern is not added, won't
this cause not matching the rule for rss?


I may be missing something here, or if not I am sure you can fix it,
BUT I am not sure if this is right way to proceed.

This expansion operation is complex, it is hard to verify it without debugging,
and I can see it has been fixed a few times already.
It is trying to construct the correct pattern by trying to understand the user's
intention.
Overall it has two problems I think,
1) It is hard to make it correct, and not sure if we can rely on the user input
to create *correct* patterns.
2) Only mlx is using this function  (and mlx developed and acked it), so other
vendors doesn't try to expand the rules, so same rule may work different for
different PMDs (assuming with same HW capabilities).
Like just giving 'ip' pattern and request 'udp' rss will fail on Intel but will
work on mlx because of this expansion.

What about other two alternatives:
a) If the rule doesn't work, return error. stop. user should fix it. Don't try
to expand or fix the rule implicitly.

b) If mlx is strong on having the expansion, what about moving it to the PMD. It
won't cause more defects for others, cleans the common code and highlights that
this behavior is unique to a vendor.
Unless there are any other vendor willing to use it. Or is it part of the
rte_flow contract already, @Ori, do you know if this expansion behavior
documented anywhere?


Thanks,
ferruh


> In such a case, rte_flow_expand_rss() will return with the original flow
> rule only, without any expansion.
> 
> Fixes: fc2dd8dd492f ("ethdev: fix expand RSS flows")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Dekel Peled <dekelp@mellanox.com>
> Acked-by: Xiaoyu Min <jackmin@mellanox.com>
> Acked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
> ---
>  lib/librte_ethdev/rte_flow.c | 16 ++++++++++++++--
>  1 file changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
> index f8fdd68..59a386d 100644
> --- a/lib/librte_ethdev/rte_flow.c
> +++ b/lib/librte_ethdev/rte_flow.c
> @@ -247,6 +247,8 @@ struct rte_flow_desc_data {
>  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
>  		else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_VLAN)
>  			ret = RTE_FLOW_ITEM_TYPE_VLAN;
> +		else
> +			ret = RTE_FLOW_ITEM_TYPE_END;
>  		break;
>  	case RTE_FLOW_ITEM_TYPE_VLAN:
>  		if (item->mask)
> @@ -264,6 +266,8 @@ struct rte_flow_desc_data {
>  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
>  		else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_VLAN)
>  			ret = RTE_FLOW_ITEM_TYPE_VLAN;
> +		else
> +			ret = RTE_FLOW_ITEM_TYPE_END;
>  		break;
>  	case RTE_FLOW_ITEM_TYPE_IPV4:
>  		if (item->mask)
> @@ -284,6 +288,8 @@ struct rte_flow_desc_data {
>  			ret = RTE_FLOW_ITEM_TYPE_IPV4;
>  		else if (ip_next_proto == IPPROTO_IPV6)
>  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
> +		else
> +			ret = RTE_FLOW_ITEM_TYPE_END;
>  		break;
>  	case RTE_FLOW_ITEM_TYPE_IPV6:
>  		if (item->mask)
> @@ -304,6 +310,8 @@ struct rte_flow_desc_data {
>  			ret = RTE_FLOW_ITEM_TYPE_IPV4;
>  		else if (ip_next_proto == IPPROTO_IPV6)
>  			ret = RTE_FLOW_ITEM_TYPE_IPV6;
> +		else
> +			ret = RTE_FLOW_ITEM_TYPE_END;
>  		break;
>  	default:
>  		ret = RTE_FLOW_ITEM_TYPE_VOID;
> @@ -1110,10 +1118,14 @@ enum rte_flow_conv_item_spec_type {
>  	memset(flow_items, 0, sizeof(flow_items));
>  	user_pattern_size -= sizeof(*item);
>  	/*
> -	 * Check if the last valid item has spec set
> -	 * and need complete pattern.
> +	 * Check if the last valid item has spec set, need complete pattern,
> +	 * and the pattern can be used for expansion.
>  	 */
>  	missed_item.type = rte_flow_expand_rss_item_complete(last_item);
> +	if (missed_item.type == RTE_FLOW_ITEM_TYPE_END) {
> +		/* Item type END indicates expansion is not required. */
> +		return lsize;
> +	}
>  	if (missed_item.type != RTE_FLOW_ITEM_TYPE_VOID) {
>  		next = NULL;
>  		missed = 1;
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [dpdk-dev] [PATCH v2 0/2] ethdev: RSS expand code fix and relocate
  2020-07-27 12:57 [dpdk-dev] [PATCH] ethdev: fix RSS flow expansion in case of mismatch Dekel Peled
  2020-07-27 13:25 ` Dekel Peled
  2020-09-02 17:09 ` Ferruh Yigit
@ 2020-09-24 14:52 ` Dekel Peled
  2020-09-24 14:52   ` [dpdk-dev] [PATCH v2 1/2] ethdev: fix RSS flow expansion in case of mismatch Dekel Peled
                     ` (2 more replies)
  2 siblings, 3 replies; 11+ messages in thread
From: Dekel Peled @ 2020-09-24 14:52 UTC (permalink / raw)
  To: orika, thomas, ferruh.yigit, arybchenko; +Cc: dev, matan

Patch [1] added support for RSS flow expansion.
It was added in ethdev for public use, but until now it is used only
by MLX5 PMD.
This patch series fixes an issue in this code, removes it from ethdev
and moves it to MLX5 PMD file (following maintainer comments on v1).

[1] commit 4ed05fcd441b ("ethdev: add flow API to expand RSS flows")

---
v2: relocate code from ethdev to MLX5 PMD
---

Dekel Peled (2):
  ethdev: fix RSS flow expansion in case of mismatch
  ethdev: move RSS expand code from ethdev to MLX5 PMD

 drivers/net/mlx5/mlx5_flow.c             | 415 +++++++++++++++++++++++++++----
 lib/librte_ethdev/rte_ethdev_version.map |   1 -
 lib/librte_ethdev/rte_flow.c             | 262 -------------------
 lib/librte_ethdev/rte_flow_driver.h      |  62 -----
 4 files changed, 370 insertions(+), 370 deletions(-)

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [dpdk-dev] [PATCH v2 1/2] ethdev: fix RSS flow expansion in case of mismatch
  2020-09-24 14:52 ` [dpdk-dev] [PATCH v2 0/2] ethdev: RSS expand code fix and relocate Dekel Peled
@ 2020-09-24 14:52   ` Dekel Peled
  2020-09-24 14:52   ` [dpdk-dev] [PATCH v2 2/2] ethdev: move RSS expand code from ethdev to MLX5 PMD Dekel Peled
  2020-10-05 17:13   ` [dpdk-dev] [PATCH v2 0/2] ethdev: RSS expand code fix and relocate Ferruh Yigit
  2 siblings, 0 replies; 11+ messages in thread
From: Dekel Peled @ 2020-09-24 14:52 UTC (permalink / raw)
  To: orika, thomas, ferruh.yigit, arybchenko; +Cc: dev, matan, stable

Function rte_flow_expand_rss() is used to expand a flow rule with
partial pattern into several rules, to ensure all relevant packets
are matched.
It uses utility function rte_flow_expand_rss_item_complete(), to check
if the last valid item in the flow rule pattern needs to be completed.
For example the pattern "eth / ipv4 proto is 17 / end" will be completed
with a "udp" item.
This function returns "void" item in two cases:
1) The last item has empty spec, for example "eth / ipv4 / end".
2) The last itme has spec that can't be expanded for RSS.
   For example the pattern "eth / ipv4 proto is 47 / end" ends with IPv4
   item that has next protocol GRE.

In both cases the flow rule may be expanded, but in the second case such
expansion may create rules with invalid pattern.
For example "eth / ipv4 proto is 47 / udp / end".
In such a case the flow rule should not be expanded.

This patch updates function rte_flow_expand_rss_item_complete().
Return value RTE_FLOW_ITEM_TYPE_END is used to indicate the flow rule
should not be expanded.
In such a case, rte_flow_expand_rss() will return with the original flow
rule only, without any expansion.

Fixes: fc2dd8dd492f ("ethdev: fix expand RSS flows")
Cc: stable@dpdk.org

Signed-off-by: Dekel Peled <dekelp@nvidia.com>
Acked-by: Xiaoyu Min <jackmin@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>
---
 lib/librte_ethdev/rte_flow.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index f8fdd68..59a386d 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -247,6 +247,8 @@ struct rte_flow_desc_data {
 			ret = RTE_FLOW_ITEM_TYPE_IPV6;
 		else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_VLAN)
 			ret = RTE_FLOW_ITEM_TYPE_VLAN;
+		else
+			ret = RTE_FLOW_ITEM_TYPE_END;
 		break;
 	case RTE_FLOW_ITEM_TYPE_VLAN:
 		if (item->mask)
@@ -264,6 +266,8 @@ struct rte_flow_desc_data {
 			ret = RTE_FLOW_ITEM_TYPE_IPV6;
 		else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_VLAN)
 			ret = RTE_FLOW_ITEM_TYPE_VLAN;
+		else
+			ret = RTE_FLOW_ITEM_TYPE_END;
 		break;
 	case RTE_FLOW_ITEM_TYPE_IPV4:
 		if (item->mask)
@@ -284,6 +288,8 @@ struct rte_flow_desc_data {
 			ret = RTE_FLOW_ITEM_TYPE_IPV4;
 		else if (ip_next_proto == IPPROTO_IPV6)
 			ret = RTE_FLOW_ITEM_TYPE_IPV6;
+		else
+			ret = RTE_FLOW_ITEM_TYPE_END;
 		break;
 	case RTE_FLOW_ITEM_TYPE_IPV6:
 		if (item->mask)
@@ -304,6 +310,8 @@ struct rte_flow_desc_data {
 			ret = RTE_FLOW_ITEM_TYPE_IPV4;
 		else if (ip_next_proto == IPPROTO_IPV6)
 			ret = RTE_FLOW_ITEM_TYPE_IPV6;
+		else
+			ret = RTE_FLOW_ITEM_TYPE_END;
 		break;
 	default:
 		ret = RTE_FLOW_ITEM_TYPE_VOID;
@@ -1110,10 +1118,14 @@ enum rte_flow_conv_item_spec_type {
 	memset(flow_items, 0, sizeof(flow_items));
 	user_pattern_size -= sizeof(*item);
 	/*
-	 * Check if the last valid item has spec set
-	 * and need complete pattern.
+	 * Check if the last valid item has spec set, need complete pattern,
+	 * and the pattern can be used for expansion.
 	 */
 	missed_item.type = rte_flow_expand_rss_item_complete(last_item);
+	if (missed_item.type == RTE_FLOW_ITEM_TYPE_END) {
+		/* Item type END indicates expansion is not required. */
+		return lsize;
+	}
 	if (missed_item.type != RTE_FLOW_ITEM_TYPE_VOID) {
 		next = NULL;
 		missed = 1;
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [dpdk-dev] [PATCH v2 2/2] ethdev: move RSS expand code from ethdev to MLX5 PMD
  2020-09-24 14:52 ` [dpdk-dev] [PATCH v2 0/2] ethdev: RSS expand code fix and relocate Dekel Peled
  2020-09-24 14:52   ` [dpdk-dev] [PATCH v2 1/2] ethdev: fix RSS flow expansion in case of mismatch Dekel Peled
@ 2020-09-24 14:52   ` Dekel Peled
  2020-10-05 17:12     ` Ferruh Yigit
  2020-10-05 17:13   ` [dpdk-dev] [PATCH v2 0/2] ethdev: RSS expand code fix and relocate Ferruh Yigit
  2 siblings, 1 reply; 11+ messages in thread
From: Dekel Peled @ 2020-09-24 14:52 UTC (permalink / raw)
  To: orika, thomas, ferruh.yigit, arybchenko; +Cc: dev, matan, nelio.laranjeiro

Patch [1] added support for RSS flow expansion.
It was added in ethdev for public use, but until now it is used only
by MLX5 PMD.
To allow local changes in this code, this patch removes it from ethdev
and moves it to MLX5 PMD file.

[1] commit 4ed05fcd441b ("ethdev: add flow API to expand RSS flows")

Signed-off-by: Dekel Peled <dekelp@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
Cc: nelio.laranjeiro@6wind.com
---
 drivers/net/mlx5/mlx5_flow.c             | 415 +++++++++++++++++++++++++++----
 lib/librte_ethdev/rte_ethdev_version.map |   1 -
 lib/librte_ethdev/rte_flow.c             | 274 --------------------
 lib/librte_ethdev/rte_flow_driver.h      |  62 -----
 4 files changed, 370 insertions(+), 382 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 416505f..69dc89f 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -44,6 +44,331 @@
 	[MLX5_FLOW_TYPE_MAX] = &mlx5_flow_null_drv_ops
 };
 
+/** Helper macro to build input graph for mlx5_flow_expand_rss(). */
+#define MLX5_FLOW_EXPAND_RSS_NEXT(...) \
+	(const int []){ \
+		__VA_ARGS__, 0, \
+	}
+
+/** Node object of input graph for mlx5_flow_expand_rss(). */
+struct mlx5_flow_expand_node {
+	const int *const next;
+	/**<
+	 * List of next node indexes. Index 0 is interpreted as a terminator.
+	 */
+	const enum rte_flow_item_type type;
+	/**< Pattern item type of current node. */
+	uint64_t rss_types;
+	/**<
+	 * RSS types bit-field associated with this node
+	 * (see ETH_RSS_* definitions).
+	 */
+};
+
+/** Object returned by mlx5_flow_expand_rss(). */
+struct mlx5_flow_expand_rss {
+	uint32_t entries;
+	/**< Number of entries @p patterns and @p priorities. */
+	struct {
+		struct rte_flow_item *pattern; /**< Expanded pattern array. */
+		uint32_t priority; /**< Priority offset for each expansion. */
+	} entry[];
+};
+
+static enum rte_flow_item_type
+mlx5_flow_expand_rss_item_complete(const struct rte_flow_item *item)
+{
+	enum rte_flow_item_type ret = RTE_FLOW_ITEM_TYPE_VOID;
+	uint16_t ether_type = 0;
+	uint16_t ether_type_m;
+	uint8_t ip_next_proto = 0;
+	uint8_t ip_next_proto_m;
+
+	if (item == NULL || item->spec == NULL)
+		return ret;
+	switch (item->type) {
+	case RTE_FLOW_ITEM_TYPE_ETH:
+		if (item->mask)
+			ether_type_m = ((const struct rte_flow_item_eth *)
+						(item->mask))->type;
+		else
+			ether_type_m = rte_flow_item_eth_mask.type;
+		if (ether_type_m != RTE_BE16(0xFFFF))
+			break;
+		ether_type = ((const struct rte_flow_item_eth *)
+				(item->spec))->type;
+		if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_IPV4)
+			ret = RTE_FLOW_ITEM_TYPE_IPV4;
+		else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_IPV6)
+			ret = RTE_FLOW_ITEM_TYPE_IPV6;
+		else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_VLAN)
+			ret = RTE_FLOW_ITEM_TYPE_VLAN;
+		else
+			ret = RTE_FLOW_ITEM_TYPE_END;
+		break;
+	case RTE_FLOW_ITEM_TYPE_VLAN:
+		if (item->mask)
+			ether_type_m = ((const struct rte_flow_item_vlan *)
+						(item->mask))->inner_type;
+		else
+			ether_type_m = rte_flow_item_vlan_mask.inner_type;
+		if (ether_type_m != RTE_BE16(0xFFFF))
+			break;
+		ether_type = ((const struct rte_flow_item_vlan *)
+				(item->spec))->inner_type;
+		if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_IPV4)
+			ret = RTE_FLOW_ITEM_TYPE_IPV4;
+		else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_IPV6)
+			ret = RTE_FLOW_ITEM_TYPE_IPV6;
+		else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_VLAN)
+			ret = RTE_FLOW_ITEM_TYPE_VLAN;
+		else
+			ret = RTE_FLOW_ITEM_TYPE_END;
+		break;
+	case RTE_FLOW_ITEM_TYPE_IPV4:
+		if (item->mask)
+			ip_next_proto_m = ((const struct rte_flow_item_ipv4 *)
+					(item->mask))->hdr.next_proto_id;
+		else
+			ip_next_proto_m =
+				rte_flow_item_ipv4_mask.hdr.next_proto_id;
+		if (ip_next_proto_m != 0xFF)
+			break;
+		ip_next_proto = ((const struct rte_flow_item_ipv4 *)
+				(item->spec))->hdr.next_proto_id;
+		if (ip_next_proto == IPPROTO_UDP)
+			ret = RTE_FLOW_ITEM_TYPE_UDP;
+		else if (ip_next_proto == IPPROTO_TCP)
+			ret = RTE_FLOW_ITEM_TYPE_TCP;
+		else if (ip_next_proto == IPPROTO_IP)
+			ret = RTE_FLOW_ITEM_TYPE_IPV4;
+		else if (ip_next_proto == IPPROTO_IPV6)
+			ret = RTE_FLOW_ITEM_TYPE_IPV6;
+		else
+			ret = RTE_FLOW_ITEM_TYPE_END;
+		break;
+	case RTE_FLOW_ITEM_TYPE_IPV6:
+		if (item->mask)
+			ip_next_proto_m = ((const struct rte_flow_item_ipv6 *)
+						(item->mask))->hdr.proto;
+		else
+			ip_next_proto_m =
+				rte_flow_item_ipv6_mask.hdr.proto;
+		if (ip_next_proto_m != 0xFF)
+			break;
+		ip_next_proto = ((const struct rte_flow_item_ipv6 *)
+				(item->spec))->hdr.proto;
+		if (ip_next_proto == IPPROTO_UDP)
+			ret = RTE_FLOW_ITEM_TYPE_UDP;
+		else if (ip_next_proto == IPPROTO_TCP)
+			ret = RTE_FLOW_ITEM_TYPE_TCP;
+		else if (ip_next_proto == IPPROTO_IP)
+			ret = RTE_FLOW_ITEM_TYPE_IPV4;
+		else if (ip_next_proto == IPPROTO_IPV6)
+			ret = RTE_FLOW_ITEM_TYPE_IPV6;
+		else
+			ret = RTE_FLOW_ITEM_TYPE_END;
+		break;
+	default:
+		ret = RTE_FLOW_ITEM_TYPE_VOID;
+		break;
+	}
+	return ret;
+}
+
+/**
+ * Expand RSS flows into several possible flows according to the RSS hash
+ * fields requested and the driver capabilities.
+ *
+ * @param[out] buf
+ *   Buffer to store the result expansion.
+ * @param[in] size
+ *   Buffer size in bytes. If 0, @p buf can be NULL.
+ * @param[in] pattern
+ *   User flow pattern.
+ * @param[in] types
+ *   RSS types to expand (see ETH_RSS_* definitions).
+ * @param[in] graph
+ *   Input graph to expand @p pattern according to @p types.
+ * @param[in] graph_root_index
+ *   Index of root node in @p graph, typically 0.
+ *
+ * @return
+ *   A positive value representing the size of @p buf in bytes regardless of
+ *   @p size on success, a negative errno value otherwise and rte_errno is
+ *   set, the following errors are defined:
+ *
+ *   -E2BIG: graph-depth @p graph is too deep.
+ */
+static int
+mlx5_flow_expand_rss(struct mlx5_flow_expand_rss *buf, size_t size,
+		     const struct rte_flow_item *pattern, uint64_t types,
+		     const struct mlx5_flow_expand_node graph[],
+		     int graph_root_index)
+{
+	const int elt_n = 8;
+	const struct rte_flow_item *item;
+	const struct mlx5_flow_expand_node *node = &graph[graph_root_index];
+	const int *next_node;
+	const int *stack[elt_n];
+	int stack_pos = 0;
+	struct rte_flow_item flow_items[elt_n];
+	unsigned int i;
+	size_t lsize;
+	size_t user_pattern_size = 0;
+	void *addr = NULL;
+	const struct mlx5_flow_expand_node *next = NULL;
+	struct rte_flow_item missed_item;
+	int missed = 0;
+	int elt = 0;
+	const struct rte_flow_item *last_item = NULL;
+
+	memset(&missed_item, 0, sizeof(missed_item));
+	lsize = offsetof(struct mlx5_flow_expand_rss, entry) +
+		elt_n * sizeof(buf->entry[0]);
+	if (lsize <= size) {
+		buf->entry[0].priority = 0;
+		buf->entry[0].pattern = (void *)&buf->entry[elt_n];
+		buf->entries = 0;
+		addr = buf->entry[0].pattern;
+	}
+	for (item = pattern; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
+		if (item->type != RTE_FLOW_ITEM_TYPE_VOID)
+			last_item = item;
+		for (i = 0; node->next && node->next[i]; ++i) {
+			next = &graph[node->next[i]];
+			if (next->type == item->type)
+				break;
+		}
+		if (next)
+			node = next;
+		user_pattern_size += sizeof(*item);
+	}
+	user_pattern_size += sizeof(*item); /* Handle END item. */
+	lsize += user_pattern_size;
+	/* Copy the user pattern in the first entry of the buffer. */
+	if (lsize <= size) {
+		rte_memcpy(addr, pattern, user_pattern_size);
+		addr = (void *)(((uintptr_t)addr) + user_pattern_size);
+		buf->entries = 1;
+	}
+	/* Start expanding. */
+	memset(flow_items, 0, sizeof(flow_items));
+	user_pattern_size -= sizeof(*item);
+	/*
+	 * Check if the last valid item has spec set, need complete pattern,
+	 * and the pattern can be used for expansion.
+	 */
+	missed_item.type = mlx5_flow_expand_rss_item_complete(last_item);
+	if (missed_item.type == RTE_FLOW_ITEM_TYPE_END) {
+		/* Item type END indicates expansion is not required. */
+		return lsize;
+	}
+	if (missed_item.type != RTE_FLOW_ITEM_TYPE_VOID) {
+		next = NULL;
+		missed = 1;
+		for (i = 0; node->next && node->next[i]; ++i) {
+			next = &graph[node->next[i]];
+			if (next->type == missed_item.type) {
+				flow_items[0].type = missed_item.type;
+				flow_items[1].type = RTE_FLOW_ITEM_TYPE_END;
+				break;
+			}
+			next = NULL;
+		}
+	}
+	if (next && missed) {
+		elt = 2; /* missed item + item end. */
+		node = next;
+		lsize += elt * sizeof(*item) + user_pattern_size;
+		if ((node->rss_types & types) && lsize <= size) {
+			buf->entry[buf->entries].priority = 1;
+			buf->entry[buf->entries].pattern = addr;
+			buf->entries++;
+			rte_memcpy(addr, buf->entry[0].pattern,
+				   user_pattern_size);
+			addr = (void *)(((uintptr_t)addr) + user_pattern_size);
+			rte_memcpy(addr, flow_items, elt * sizeof(*item));
+			addr = (void *)(((uintptr_t)addr) +
+					elt * sizeof(*item));
+		}
+	}
+	memset(flow_items, 0, sizeof(flow_items));
+	next_node = node->next;
+	stack[stack_pos] = next_node;
+	node = next_node ? &graph[*next_node] : NULL;
+	while (node) {
+		flow_items[stack_pos].type = node->type;
+		if (node->rss_types & types) {
+			/*
+			 * compute the number of items to copy from the
+			 * expansion and copy it.
+			 * When the stack_pos is 0, there are 1 element in it,
+			 * plus the addition END item.
+			 */
+			elt = stack_pos + 2;
+			flow_items[stack_pos + 1].type = RTE_FLOW_ITEM_TYPE_END;
+			lsize += elt * sizeof(*item) + user_pattern_size;
+			if (lsize <= size) {
+				size_t n = elt * sizeof(*item);
+
+				buf->entry[buf->entries].priority =
+					stack_pos + 1 + missed;
+				buf->entry[buf->entries].pattern = addr;
+				buf->entries++;
+				rte_memcpy(addr, buf->entry[0].pattern,
+					   user_pattern_size);
+				addr = (void *)(((uintptr_t)addr) +
+						user_pattern_size);
+				rte_memcpy(addr, &missed_item,
+					   missed * sizeof(*item));
+				addr = (void *)(((uintptr_t)addr) +
+					missed * sizeof(*item));
+				rte_memcpy(addr, flow_items, n);
+				addr = (void *)(((uintptr_t)addr) + n);
+			}
+		}
+		/* Go deeper. */
+		if (node->next) {
+			next_node = node->next;
+			if (stack_pos++ == elt_n) {
+				rte_errno = E2BIG;
+				return -rte_errno;
+			}
+			stack[stack_pos] = next_node;
+		} else if (*(next_node + 1)) {
+			/* Follow up with the next possibility. */
+			++next_node;
+		} else {
+			/* Move to the next path. */
+			if (stack_pos)
+				next_node = stack[--stack_pos];
+			next_node++;
+			stack[stack_pos] = next_node;
+		}
+		node = *next_node ? &graph[*next_node] : NULL;
+	};
+	/* no expanded flows but we have missed item, create one rule for it */
+	if (buf->entries == 1 && missed != 0) {
+		elt = 2;
+		lsize += elt * sizeof(*item) + user_pattern_size;
+		if (lsize <= size) {
+			buf->entry[buf->entries].priority = 1;
+			buf->entry[buf->entries].pattern = addr;
+			buf->entries++;
+			flow_items[0].type = missed_item.type;
+			flow_items[1].type = RTE_FLOW_ITEM_TYPE_END;
+			rte_memcpy(addr, buf->entry[0].pattern,
+				   user_pattern_size);
+			addr = (void *)(((uintptr_t)addr) + user_pattern_size);
+			rte_memcpy(addr, flow_items, elt * sizeof(*item));
+			addr = (void *)(((uintptr_t)addr) +
+					elt * sizeof(*item));
+		}
+	}
+	return lsize;
+}
+
 enum mlx5_expansion {
 	MLX5_EXPANSION_ROOT,
 	MLX5_EXPANSION_ROOT_OUTER,
@@ -74,46 +399,47 @@ enum mlx5_expansion {
 };
 
 /** Supported expansion of items. */
-static const struct rte_flow_expand_node mlx5_support_expansion[] = {
+static const struct mlx5_flow_expand_node mlx5_support_expansion[] = {
 	[MLX5_EXPANSION_ROOT] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_ETH,
-						 MLX5_EXPANSION_IPV4,
-						 MLX5_EXPANSION_IPV6),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_ETH,
+						  MLX5_EXPANSION_IPV4,
+						  MLX5_EXPANSION_IPV6),
 		.type = RTE_FLOW_ITEM_TYPE_END,
 	},
 	[MLX5_EXPANSION_ROOT_OUTER] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_OUTER_ETH,
-						 MLX5_EXPANSION_OUTER_IPV4,
-						 MLX5_EXPANSION_OUTER_IPV6),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_OUTER_ETH,
+						  MLX5_EXPANSION_OUTER_IPV4,
+						  MLX5_EXPANSION_OUTER_IPV6),
 		.type = RTE_FLOW_ITEM_TYPE_END,
 	},
 	[MLX5_EXPANSION_ROOT_ETH_VLAN] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_ETH_VLAN),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_ETH_VLAN),
 		.type = RTE_FLOW_ITEM_TYPE_END,
 	},
 	[MLX5_EXPANSION_ROOT_OUTER_ETH_VLAN] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_OUTER_ETH_VLAN),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT
+						(MLX5_EXPANSION_OUTER_ETH_VLAN),
 		.type = RTE_FLOW_ITEM_TYPE_END,
 	},
 	[MLX5_EXPANSION_OUTER_ETH] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_OUTER_IPV4,
-						 MLX5_EXPANSION_OUTER_IPV6,
-						 MLX5_EXPANSION_MPLS),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_OUTER_IPV4,
+						  MLX5_EXPANSION_OUTER_IPV6,
+						  MLX5_EXPANSION_MPLS),
 		.type = RTE_FLOW_ITEM_TYPE_ETH,
 		.rss_types = 0,
 	},
 	[MLX5_EXPANSION_OUTER_ETH_VLAN] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_OUTER_VLAN),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_OUTER_VLAN),
 		.type = RTE_FLOW_ITEM_TYPE_ETH,
 		.rss_types = 0,
 	},
 	[MLX5_EXPANSION_OUTER_VLAN] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_OUTER_IPV4,
-						 MLX5_EXPANSION_OUTER_IPV6),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_OUTER_IPV4,
+						  MLX5_EXPANSION_OUTER_IPV6),
 		.type = RTE_FLOW_ITEM_TYPE_VLAN,
 	},
 	[MLX5_EXPANSION_OUTER_IPV4] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT
 			(MLX5_EXPANSION_OUTER_IPV4_UDP,
 			 MLX5_EXPANSION_OUTER_IPV4_TCP,
 			 MLX5_EXPANSION_GRE,
@@ -124,8 +450,8 @@ enum mlx5_expansion {
 			ETH_RSS_NONFRAG_IPV4_OTHER,
 	},
 	[MLX5_EXPANSION_OUTER_IPV4_UDP] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_VXLAN,
-						 MLX5_EXPANSION_VXLAN_GPE),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_VXLAN,
+						  MLX5_EXPANSION_VXLAN_GPE),
 		.type = RTE_FLOW_ITEM_TYPE_UDP,
 		.rss_types = ETH_RSS_NONFRAG_IPV4_UDP,
 	},
@@ -134,7 +460,7 @@ enum mlx5_expansion {
 		.rss_types = ETH_RSS_NONFRAG_IPV4_TCP,
 	},
 	[MLX5_EXPANSION_OUTER_IPV6] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT
 			(MLX5_EXPANSION_OUTER_IPV6_UDP,
 			 MLX5_EXPANSION_OUTER_IPV6_TCP,
 			 MLX5_EXPANSION_IPV4,
@@ -144,8 +470,8 @@ enum mlx5_expansion {
 			ETH_RSS_NONFRAG_IPV6_OTHER,
 	},
 	[MLX5_EXPANSION_OUTER_IPV6_UDP] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_VXLAN,
-						 MLX5_EXPANSION_VXLAN_GPE),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_VXLAN,
+						  MLX5_EXPANSION_VXLAN_GPE),
 		.type = RTE_FLOW_ITEM_TYPE_UDP,
 		.rss_types = ETH_RSS_NONFRAG_IPV6_UDP,
 	},
@@ -154,43 +480,43 @@ enum mlx5_expansion {
 		.rss_types = ETH_RSS_NONFRAG_IPV6_TCP,
 	},
 	[MLX5_EXPANSION_VXLAN] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_ETH,
-						 MLX5_EXPANSION_IPV4,
-						 MLX5_EXPANSION_IPV6),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_ETH,
+						  MLX5_EXPANSION_IPV4,
+						  MLX5_EXPANSION_IPV6),
 		.type = RTE_FLOW_ITEM_TYPE_VXLAN,
 	},
 	[MLX5_EXPANSION_VXLAN_GPE] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_ETH,
-						 MLX5_EXPANSION_IPV4,
-						 MLX5_EXPANSION_IPV6),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_ETH,
+						  MLX5_EXPANSION_IPV4,
+						  MLX5_EXPANSION_IPV6),
 		.type = RTE_FLOW_ITEM_TYPE_VXLAN_GPE,
 	},
 	[MLX5_EXPANSION_GRE] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_IPV4),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_IPV4),
 		.type = RTE_FLOW_ITEM_TYPE_GRE,
 	},
 	[MLX5_EXPANSION_MPLS] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_IPV4,
-						 MLX5_EXPANSION_IPV6),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_IPV4,
+						  MLX5_EXPANSION_IPV6),
 		.type = RTE_FLOW_ITEM_TYPE_MPLS,
 	},
 	[MLX5_EXPANSION_ETH] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_IPV4,
-						 MLX5_EXPANSION_IPV6),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_IPV4,
+						  MLX5_EXPANSION_IPV6),
 		.type = RTE_FLOW_ITEM_TYPE_ETH,
 	},
 	[MLX5_EXPANSION_ETH_VLAN] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_VLAN),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_VLAN),
 		.type = RTE_FLOW_ITEM_TYPE_ETH,
 	},
 	[MLX5_EXPANSION_VLAN] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_IPV4,
-						 MLX5_EXPANSION_IPV6),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_IPV4,
+						  MLX5_EXPANSION_IPV6),
 		.type = RTE_FLOW_ITEM_TYPE_VLAN,
 	},
 	[MLX5_EXPANSION_IPV4] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_IPV4_UDP,
-						 MLX5_EXPANSION_IPV4_TCP),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_IPV4_UDP,
+						  MLX5_EXPANSION_IPV4_TCP),
 		.type = RTE_FLOW_ITEM_TYPE_IPV4,
 		.rss_types = ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4 |
 			ETH_RSS_NONFRAG_IPV4_OTHER,
@@ -204,8 +530,8 @@ enum mlx5_expansion {
 		.rss_types = ETH_RSS_NONFRAG_IPV4_TCP,
 	},
 	[MLX5_EXPANSION_IPV6] = {
-		.next = RTE_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_IPV6_UDP,
-						 MLX5_EXPANSION_IPV6_TCP),
+		.next = MLX5_FLOW_EXPAND_RSS_NEXT(MLX5_EXPANSION_IPV6_UDP,
+						  MLX5_EXPANSION_IPV6_TCP),
 		.type = RTE_FLOW_ITEM_TYPE_IPV6,
 		.rss_types = ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6 |
 			ETH_RSS_NONFRAG_IPV6_OTHER,
@@ -4332,7 +4658,7 @@ struct mlx5_flow_tunnel_info {
 	struct mlx5_flow *dev_flow;
 	const struct rte_flow_action_rss *rss;
 	union {
-		struct rte_flow_expand_rss buf;
+		struct mlx5_flow_expand_rss buf;
 		uint8_t buffer[2048];
 	} expand_buffer;
 	union {
@@ -4347,7 +4673,7 @@ struct mlx5_flow_tunnel_info {
 		struct rte_flow_item items[MLX5_MAX_SPLIT_ITEMS];
 		uint8_t buffer[2048];
 	} items_tx;
-	struct rte_flow_expand_rss *buf = &expand_buffer.buf;
+	struct mlx5_flow_expand_rss *buf = &expand_buffer.buf;
 	struct mlx5_flow_rss_desc *rss_desc = &((struct mlx5_flow_rss_desc *)
 					      priv->rss_desc)[!!priv->flow_idx];
 	const struct rte_flow_action *p_actions_rx = actions;
@@ -4399,10 +4725,9 @@ struct mlx5_flow_tunnel_info {
 		unsigned int graph_root;
 
 		graph_root = find_graph_root(items, rss->level);
-		ret = rte_flow_expand_rss(buf, sizeof(expand_buffer.buffer),
-					  items, rss->types,
-					  mlx5_support_expansion,
-					  graph_root);
+		ret = mlx5_flow_expand_rss(buf, sizeof(expand_buffer.buffer),
+					   items, rss->types,
+					   mlx5_support_expansion, graph_root);
 		MLX5_ASSERT(ret > 0 &&
 		       (unsigned int)ret < sizeof(expand_buffer.buffer));
 	} else {
diff --git a/lib/librte_ethdev/rte_ethdev_version.map b/lib/librte_ethdev/rte_ethdev_version.map
index c95ef51..4d4263a 100644
--- a/lib/librte_ethdev/rte_ethdev_version.map
+++ b/lib/librte_ethdev/rte_ethdev_version.map
@@ -250,5 +250,4 @@ INTERNAL {
 	rte_eth_dma_zone_reserve;
 	rte_eth_switch_domain_alloc;
 	rte_eth_switch_domain_free;
-	rte_flow_expand_rss;
 };
diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index 59a386d..8d1b279 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -219,107 +219,6 @@ struct rte_flow_desc_data {
 	return ret;
 }
 
-static enum rte_flow_item_type
-rte_flow_expand_rss_item_complete(const struct rte_flow_item *item)
-{
-	enum rte_flow_item_type ret = RTE_FLOW_ITEM_TYPE_VOID;
-	uint16_t ether_type = 0;
-	uint16_t ether_type_m;
-	uint8_t ip_next_proto = 0;
-	uint8_t ip_next_proto_m;
-
-	if (item == NULL || item->spec == NULL)
-		return ret;
-	switch (item->type) {
-	case RTE_FLOW_ITEM_TYPE_ETH:
-		if (item->mask)
-			ether_type_m = ((const struct rte_flow_item_eth *)
-						(item->mask))->type;
-		else
-			ether_type_m = rte_flow_item_eth_mask.type;
-		if (ether_type_m != RTE_BE16(0xFFFF))
-			break;
-		ether_type = ((const struct rte_flow_item_eth *)
-				(item->spec))->type;
-		if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_IPV4)
-			ret = RTE_FLOW_ITEM_TYPE_IPV4;
-		else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_IPV6)
-			ret = RTE_FLOW_ITEM_TYPE_IPV6;
-		else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_VLAN)
-			ret = RTE_FLOW_ITEM_TYPE_VLAN;
-		else
-			ret = RTE_FLOW_ITEM_TYPE_END;
-		break;
-	case RTE_FLOW_ITEM_TYPE_VLAN:
-		if (item->mask)
-			ether_type_m = ((const struct rte_flow_item_vlan *)
-						(item->mask))->inner_type;
-		else
-			ether_type_m = rte_flow_item_vlan_mask.inner_type;
-		if (ether_type_m != RTE_BE16(0xFFFF))
-			break;
-		ether_type = ((const struct rte_flow_item_vlan *)
-				(item->spec))->inner_type;
-		if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_IPV4)
-			ret = RTE_FLOW_ITEM_TYPE_IPV4;
-		else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_IPV6)
-			ret = RTE_FLOW_ITEM_TYPE_IPV6;
-		else if (rte_be_to_cpu_16(ether_type) == RTE_ETHER_TYPE_VLAN)
-			ret = RTE_FLOW_ITEM_TYPE_VLAN;
-		else
-			ret = RTE_FLOW_ITEM_TYPE_END;
-		break;
-	case RTE_FLOW_ITEM_TYPE_IPV4:
-		if (item->mask)
-			ip_next_proto_m = ((const struct rte_flow_item_ipv4 *)
-					(item->mask))->hdr.next_proto_id;
-		else
-			ip_next_proto_m =
-				rte_flow_item_ipv4_mask.hdr.next_proto_id;
-		if (ip_next_proto_m != 0xFF)
-			break;
-		ip_next_proto = ((const struct rte_flow_item_ipv4 *)
-				(item->spec))->hdr.next_proto_id;
-		if (ip_next_proto == IPPROTO_UDP)
-			ret = RTE_FLOW_ITEM_TYPE_UDP;
-		else if (ip_next_proto == IPPROTO_TCP)
-			ret = RTE_FLOW_ITEM_TYPE_TCP;
-		else if (ip_next_proto == IPPROTO_IP)
-			ret = RTE_FLOW_ITEM_TYPE_IPV4;
-		else if (ip_next_proto == IPPROTO_IPV6)
-			ret = RTE_FLOW_ITEM_TYPE_IPV6;
-		else
-			ret = RTE_FLOW_ITEM_TYPE_END;
-		break;
-	case RTE_FLOW_ITEM_TYPE_IPV6:
-		if (item->mask)
-			ip_next_proto_m = ((const struct rte_flow_item_ipv6 *)
-						(item->mask))->hdr.proto;
-		else
-			ip_next_proto_m =
-				rte_flow_item_ipv6_mask.hdr.proto;
-		if (ip_next_proto_m != 0xFF)
-			break;
-		ip_next_proto = ((const struct rte_flow_item_ipv6 *)
-				(item->spec))->hdr.proto;
-		if (ip_next_proto == IPPROTO_UDP)
-			ret = RTE_FLOW_ITEM_TYPE_UDP;
-		else if (ip_next_proto == IPPROTO_TCP)
-			ret = RTE_FLOW_ITEM_TYPE_TCP;
-		else if (ip_next_proto == IPPROTO_IP)
-			ret = RTE_FLOW_ITEM_TYPE_IPV4;
-		else if (ip_next_proto == IPPROTO_IPV6)
-			ret = RTE_FLOW_ITEM_TYPE_IPV6;
-		else
-			ret = RTE_FLOW_ITEM_TYPE_END;
-		break;
-	default:
-		ret = RTE_FLOW_ITEM_TYPE_VOID;
-		break;
-	}
-	return ret;
-}
-
 /* Get generic flow operations structure from a port. */
 const struct rte_flow_ops *
 rte_flow_ops_get(uint16_t port_id, struct rte_flow_error *error)
@@ -1058,179 +957,6 @@ enum rte_flow_conv_item_spec_type {
 	return ret;
 }
 
-/**
- * Expand RSS flows into several possible flows according to the RSS hash
- * fields requested and the driver capabilities.
- */
-int
-rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size,
-		    const struct rte_flow_item *pattern, uint64_t types,
-		    const struct rte_flow_expand_node graph[],
-		    int graph_root_index)
-{
-	const int elt_n = 8;
-	const struct rte_flow_item *item;
-	const struct rte_flow_expand_node *node = &graph[graph_root_index];
-	const int *next_node;
-	const int *stack[elt_n];
-	int stack_pos = 0;
-	struct rte_flow_item flow_items[elt_n];
-	unsigned int i;
-	size_t lsize;
-	size_t user_pattern_size = 0;
-	void *addr = NULL;
-	const struct rte_flow_expand_node *next = NULL;
-	struct rte_flow_item missed_item;
-	int missed = 0;
-	int elt = 0;
-	const struct rte_flow_item *last_item = NULL;
-
-	memset(&missed_item, 0, sizeof(missed_item));
-	lsize = offsetof(struct rte_flow_expand_rss, entry) +
-		elt_n * sizeof(buf->entry[0]);
-	if (lsize <= size) {
-		buf->entry[0].priority = 0;
-		buf->entry[0].pattern = (void *)&buf->entry[elt_n];
-		buf->entries = 0;
-		addr = buf->entry[0].pattern;
-	}
-	for (item = pattern; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
-		if (item->type != RTE_FLOW_ITEM_TYPE_VOID)
-			last_item = item;
-		for (i = 0; node->next && node->next[i]; ++i) {
-			next = &graph[node->next[i]];
-			if (next->type == item->type)
-				break;
-		}
-		if (next)
-			node = next;
-		user_pattern_size += sizeof(*item);
-	}
-	user_pattern_size += sizeof(*item); /* Handle END item. */
-	lsize += user_pattern_size;
-	/* Copy the user pattern in the first entry of the buffer. */
-	if (lsize <= size) {
-		rte_memcpy(addr, pattern, user_pattern_size);
-		addr = (void *)(((uintptr_t)addr) + user_pattern_size);
-		buf->entries = 1;
-	}
-	/* Start expanding. */
-	memset(flow_items, 0, sizeof(flow_items));
-	user_pattern_size -= sizeof(*item);
-	/*
-	 * Check if the last valid item has spec set, need complete pattern,
-	 * and the pattern can be used for expansion.
-	 */
-	missed_item.type = rte_flow_expand_rss_item_complete(last_item);
-	if (missed_item.type == RTE_FLOW_ITEM_TYPE_END) {
-		/* Item type END indicates expansion is not required. */
-		return lsize;
-	}
-	if (missed_item.type != RTE_FLOW_ITEM_TYPE_VOID) {
-		next = NULL;
-		missed = 1;
-		for (i = 0; node->next && node->next[i]; ++i) {
-			next = &graph[node->next[i]];
-			if (next->type == missed_item.type) {
-				flow_items[0].type = missed_item.type;
-				flow_items[1].type = RTE_FLOW_ITEM_TYPE_END;
-				break;
-			}
-			next = NULL;
-		}
-	}
-	if (next && missed) {
-		elt = 2; /* missed item + item end. */
-		node = next;
-		lsize += elt * sizeof(*item) + user_pattern_size;
-		if ((node->rss_types & types) && lsize <= size) {
-			buf->entry[buf->entries].priority = 1;
-			buf->entry[buf->entries].pattern = addr;
-			buf->entries++;
-			rte_memcpy(addr, buf->entry[0].pattern,
-				   user_pattern_size);
-			addr = (void *)(((uintptr_t)addr) + user_pattern_size);
-			rte_memcpy(addr, flow_items, elt * sizeof(*item));
-			addr = (void *)(((uintptr_t)addr) +
-					elt * sizeof(*item));
-		}
-	}
-	memset(flow_items, 0, sizeof(flow_items));
-	next_node = node->next;
-	stack[stack_pos] = next_node;
-	node = next_node ? &graph[*next_node] : NULL;
-	while (node) {
-		flow_items[stack_pos].type = node->type;
-		if (node->rss_types & types) {
-			/*
-			 * compute the number of items to copy from the
-			 * expansion and copy it.
-			 * When the stack_pos is 0, there are 1 element in it,
-			 * plus the addition END item.
-			 */
-			elt = stack_pos + 2;
-			flow_items[stack_pos + 1].type = RTE_FLOW_ITEM_TYPE_END;
-			lsize += elt * sizeof(*item) + user_pattern_size;
-			if (lsize <= size) {
-				size_t n = elt * sizeof(*item);
-
-				buf->entry[buf->entries].priority =
-					stack_pos + 1 + missed;
-				buf->entry[buf->entries].pattern = addr;
-				buf->entries++;
-				rte_memcpy(addr, buf->entry[0].pattern,
-					   user_pattern_size);
-				addr = (void *)(((uintptr_t)addr) +
-						user_pattern_size);
-				rte_memcpy(addr, &missed_item,
-					   missed * sizeof(*item));
-				addr = (void *)(((uintptr_t)addr) +
-					missed * sizeof(*item));
-				rte_memcpy(addr, flow_items, n);
-				addr = (void *)(((uintptr_t)addr) + n);
-			}
-		}
-		/* Go deeper. */
-		if (node->next) {
-			next_node = node->next;
-			if (stack_pos++ == elt_n) {
-				rte_errno = E2BIG;
-				return -rte_errno;
-			}
-			stack[stack_pos] = next_node;
-		} else if (*(next_node + 1)) {
-			/* Follow up with the next possibility. */
-			++next_node;
-		} else {
-			/* Move to the next path. */
-			if (stack_pos)
-				next_node = stack[--stack_pos];
-			next_node++;
-			stack[stack_pos] = next_node;
-		}
-		node = *next_node ? &graph[*next_node] : NULL;
-	};
-	/* no expanded flows but we have missed item, create one rule for it */
-	if (buf->entries == 1 && missed != 0) {
-		elt = 2;
-		lsize += elt * sizeof(*item) + user_pattern_size;
-		if (lsize <= size) {
-			buf->entry[buf->entries].priority = 1;
-			buf->entry[buf->entries].pattern = addr;
-			buf->entries++;
-			flow_items[0].type = missed_item.type;
-			flow_items[1].type = RTE_FLOW_ITEM_TYPE_END;
-			rte_memcpy(addr, buf->entry[0].pattern,
-				   user_pattern_size);
-			addr = (void *)(((uintptr_t)addr) + user_pattern_size);
-			rte_memcpy(addr, flow_items, elt * sizeof(*item));
-			addr = (void *)(((uintptr_t)addr) +
-					elt * sizeof(*item));
-		}
-	}
-	return lsize;
-}
-
 int
 rte_flow_dev_dump(uint16_t port_id, FILE *file, struct rte_flow_error *error)
 {
diff --git a/lib/librte_ethdev/rte_flow_driver.h b/lib/librte_ethdev/rte_flow_driver.h
index 3ee871d..11a0f77 100644
--- a/lib/librte_ethdev/rte_flow_driver.h
+++ b/lib/librte_ethdev/rte_flow_driver.h
@@ -126,68 +126,6 @@ struct rte_flow_ops {
 const struct rte_flow_ops *
 rte_flow_ops_get(uint16_t port_id, struct rte_flow_error *error);
 
-/** Helper macro to build input graph for rte_flow_expand_rss(). */
-#define RTE_FLOW_EXPAND_RSS_NEXT(...) \
-	(const int []){ \
-		__VA_ARGS__, 0, \
-	}
-
-/** Node object of input graph for rte_flow_expand_rss(). */
-struct rte_flow_expand_node {
-	const int *const next;
-	/**<
-	 * List of next node indexes. Index 0 is interpreted as a terminator.
-	 */
-	const enum rte_flow_item_type type;
-	/**< Pattern item type of current node. */
-	uint64_t rss_types;
-	/**<
-	 * RSS types bit-field associated with this node
-	 * (see ETH_RSS_* definitions).
-	 */
-};
-
-/** Object returned by rte_flow_expand_rss(). */
-struct rte_flow_expand_rss {
-	uint32_t entries;
-	/**< Number of entries @p patterns and @p priorities. */
-	struct {
-		struct rte_flow_item *pattern; /**< Expanded pattern array. */
-		uint32_t priority; /**< Priority offset for each expansion. */
-	} entry[];
-};
-
-/**
- * Expand RSS flows into several possible flows according to the RSS hash
- * fields requested and the driver capabilities.
- *
- * @param[out] buf
- *   Buffer to store the result expansion.
- * @param[in] size
- *   Buffer size in bytes. If 0, @p buf can be NULL.
- * @param[in] pattern
- *   User flow pattern.
- * @param[in] types
- *   RSS types to expand (see ETH_RSS_* definitions).
- * @param[in] graph
- *   Input graph to expand @p pattern according to @p types.
- * @param[in] graph_root_index
- *   Index of root node in @p graph, typically 0.
- *
- * @return
- *   A positive value representing the size of @p buf in bytes regardless of
- *   @p size on success, a negative errno value otherwise and rte_errno is
- *   set, the following errors are defined:
- *
- *   -E2BIG: graph-depth @p graph is too deep.
- */
-__rte_internal
-int
-rte_flow_expand_rss(struct rte_flow_expand_rss *buf, size_t size,
-		    const struct rte_flow_item *pattern, uint64_t types,
-		    const struct rte_flow_expand_node graph[],
-		    int graph_root_index);
-
 #ifdef __cplusplus
 }
 #endif
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [dpdk-dev] [PATCH v2 2/2] ethdev: move RSS expand code from ethdev to MLX5 PMD
  2020-09-24 14:52   ` [dpdk-dev] [PATCH v2 2/2] ethdev: move RSS expand code from ethdev to MLX5 PMD Dekel Peled
@ 2020-10-05 17:12     ` Ferruh Yigit
  0 siblings, 0 replies; 11+ messages in thread
From: Ferruh Yigit @ 2020-10-05 17:12 UTC (permalink / raw)
  To: Dekel Peled, orika, thomas, arybchenko; +Cc: dev, matan, nelio.laranjeiro

On 9/24/2020 3:52 PM, Dekel Peled wrote:
> Patch [1] added support for RSS flow expansion.
> It was added in ethdev for public use, but until now it is used only
> by MLX5 PMD.
> To allow local changes in this code, this patch removes it from ethdev
> and moves it to MLX5 PMD file.
> 
> [1] commit 4ed05fcd441b ("ethdev: add flow API to expand RSS flows")
> 
> Signed-off-by: Dekel Peled <dekelp@nvidia.com>
> Acked-by: Matan Azrad <matan@nvidia.com>
> Cc: nelio.laranjeiro@6wind.com

Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [dpdk-dev] [PATCH v2 0/2] ethdev: RSS expand code fix and relocate
  2020-09-24 14:52 ` [dpdk-dev] [PATCH v2 0/2] ethdev: RSS expand code fix and relocate Dekel Peled
  2020-09-24 14:52   ` [dpdk-dev] [PATCH v2 1/2] ethdev: fix RSS flow expansion in case of mismatch Dekel Peled
  2020-09-24 14:52   ` [dpdk-dev] [PATCH v2 2/2] ethdev: move RSS expand code from ethdev to MLX5 PMD Dekel Peled
@ 2020-10-05 17:13   ` Ferruh Yigit
  2 siblings, 0 replies; 11+ messages in thread
From: Ferruh Yigit @ 2020-10-05 17:13 UTC (permalink / raw)
  To: Dekel Peled, orika, thomas, arybchenko; +Cc: dev, matan

On 9/24/2020 3:52 PM, Dekel Peled wrote:
> Patch [1] added support for RSS flow expansion.
> It was added in ethdev for public use, but until now it is used only
> by MLX5 PMD.
> This patch series fixes an issue in this code, removes it from ethdev
> and moves it to MLX5 PMD file (following maintainer comments on v1).
> 
> [1] commit 4ed05fcd441b ("ethdev: add flow API to expand RSS flows")
> 
> ---
> v2: relocate code from ethdev to MLX5 PMD
> ---
> 
> Dekel Peled (2):
>    ethdev: fix RSS flow expansion in case of mismatch
>    ethdev: move RSS expand code from ethdev to MLX5 PMD
> 

Series applied to dpdk-next-net/main, thanks.

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2020-10-05 19:02 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-27 12:57 [dpdk-dev] [PATCH] ethdev: fix RSS flow expansion in case of mismatch Dekel Peled
2020-07-27 13:25 ` Dekel Peled
2020-07-27 16:21   ` Ori Kam
2020-07-28  9:14     ` Dekel Peled
2020-08-17  8:16       ` Ori Kam
2020-09-02 17:09 ` Ferruh Yigit
2020-09-24 14:52 ` [dpdk-dev] [PATCH v2 0/2] ethdev: RSS expand code fix and relocate Dekel Peled
2020-09-24 14:52   ` [dpdk-dev] [PATCH v2 1/2] ethdev: fix RSS flow expansion in case of mismatch Dekel Peled
2020-09-24 14:52   ` [dpdk-dev] [PATCH v2 2/2] ethdev: move RSS expand code from ethdev to MLX5 PMD Dekel Peled
2020-10-05 17:12     ` Ferruh Yigit
2020-10-05 17:13   ` [dpdk-dev] [PATCH v2 0/2] ethdev: RSS expand code fix and relocate Ferruh Yigit

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).