patches for DPDK stable branches
 help / color / mirror / Atom feed
* [PATCH 20.11 0/3] backport some patches for hns3
@ 2023-03-21  9:17 Huisong Li
  2023-03-21  9:17 ` [PATCH 20.11 1/3] net/hns3: fix burst mode query with dummy function Huisong Li
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Huisong Li @ 2023-03-21  9:17 UTC (permalink / raw)
  To: stable, luca.boccassi; +Cc: liudongdong3, huangdaode, liuyonglong, lihuisong

Huisong Li (3):
  net/hns3: fix burst mode query with dummy function
  net/hns3: reimplement hash flow function
  net/hns3: add verification of RSS types

 drivers/net/hns3/hns3_ethdev.h |   9 -
 drivers/net/hns3/hns3_fdir.h   |   4 +-
 drivers/net/hns3/hns3_flow.c   | 983 +++++++++++++++++++++++----------
 drivers/net/hns3/hns3_rss.c    | 202 ++++---
 drivers/net/hns3/hns3_rss.h    | 118 +++-
 drivers/net/hns3/hns3_rxtx.c   |  49 +-
 6 files changed, 939 insertions(+), 426 deletions(-)

-- 
2.22.0


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

* [PATCH 20.11 1/3] net/hns3: fix burst mode query with dummy function
  2023-03-21  9:17 [PATCH 20.11 0/3] backport some patches for hns3 Huisong Li
@ 2023-03-21  9:17 ` Huisong Li
  2023-03-21  9:17 ` [PATCH 20.11 2/3] net/hns3: reimplement hash flow function Huisong Li
  2023-03-21  9:17 ` [PATCH 20.11 3/3] net/hns3: add verification of RSS types Huisong Li
  2 siblings, 0 replies; 4+ messages in thread
From: Huisong Li @ 2023-03-21  9:17 UTC (permalink / raw)
  To: stable, luca.boccassi; +Cc: liudongdong3, huangdaode, liuyonglong, lihuisong

[ upstream commit 10f91af5a5b370df922f888826a4387abebe1cde ]

The rte_eth_rx/tx_burst_mode_get API will fail when Rx/Tx
function is dummy.

Fixes: 7ef933908f04 ("net/hns3: add simple Tx path")
Fixes: 521ab3e93361 ("net/hns3: add simple Rx path")

Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Dongdong Liu <liudongdong3@huawei.com>
---
 drivers/net/hns3/hns3_rxtx.c | 49 +++++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 18 deletions(-)

diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index 1a1e62c1c1..18b2b42508 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -24,6 +24,11 @@
 #define HNS3_CFG_DESC_NUM(num)	((num) / 8 - 1)
 #define HNS3_RX_RING_PREFETCTH_MASK	3
 
+static uint16_t
+hns3_dummy_rxtx_burst(void *dpdk_txq __rte_unused,
+		      struct rte_mbuf **pkts __rte_unused,
+		      uint16_t pkts_n __rte_unused);
+
 static void
 hns3_rx_queue_release_mbufs(struct hns3_rx_queue *rxq)
 {
@@ -2528,10 +2533,11 @@ hns3_rx_burst_mode_get(struct rte_eth_dev *dev, __rte_unused uint16_t queue_id,
 		eth_rx_burst_t pkt_burst;
 		const char *info;
 	} burst_infos[] = {
-		{ hns3_recv_pkts,		"Scalar" },
+		{ hns3_recv_pkts,		"Scalar"           },
 		{ hns3_recv_scattered_pkts,	"Scalar Scattered" },
-		{ hns3_recv_pkts_vec,		"Vector Neon" },
-		{ hns3_recv_pkts_vec_sve,	"Vector Sve" },
+		{ hns3_recv_pkts_vec,		"Vector Neon"      },
+		{ hns3_recv_pkts_vec_sve,	"Vector Sve"       },
+		{ hns3_dummy_rxtx_burst,        "Dummy"            },
 	};
 
 	eth_rx_burst_t pkt_burst = dev->rx_pkt_burst;
@@ -3868,24 +3874,31 @@ int
 hns3_tx_burst_mode_get(struct rte_eth_dev *dev, __rte_unused uint16_t queue_id,
 		       struct rte_eth_burst_mode *mode)
 {
+	static const struct {
+		eth_tx_burst_t pkt_burst;
+		const char *info;
+	} burst_infos[] = {
+		{ hns3_xmit_pkts_simple,	"Scalar Simple" },
+		{ hns3_xmit_pkts,		"Scalar"        },
+		{ hns3_xmit_pkts_vec,		"Vector Neon"   },
+		{ hns3_xmit_pkts_vec_sve,	"Vector Sve"    },
+		{ hns3_dummy_rxtx_burst,	"Dummy"         },
+	};
+
 	eth_tx_burst_t pkt_burst = dev->tx_pkt_burst;
-	const char *info = NULL;
-
-	if (pkt_burst == hns3_xmit_pkts_simple)
-		info = "Scalar Simple";
-	else if (pkt_burst == hns3_xmit_pkts)
-		info = "Scalar";
-	else if (pkt_burst == hns3_xmit_pkts_vec)
-		info = "Vector Neon";
-	else if (pkt_burst == hns3_xmit_pkts_vec_sve)
-		info = "Vector Sve";
-
-	if (info == NULL)
-		return -EINVAL;
+	int ret = -EINVAL;
+	unsigned int i;
 
-	snprintf(mode->info, sizeof(mode->info), "%s", info);
+	for (i = 0; i < RTE_DIM(burst_infos); i++) {
+		if (pkt_burst == burst_infos[i].pkt_burst) {
+			snprintf(mode->info, sizeof(mode->info), "%s",
+				 burst_infos[i].info);
+			ret = 0;
+			break;
+		}
+	}
 
-	return 0;
+	return ret;
 }
 
 static eth_tx_burst_t
-- 
2.22.0


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

* [PATCH 20.11 2/3] net/hns3: reimplement hash flow function
  2023-03-21  9:17 [PATCH 20.11 0/3] backport some patches for hns3 Huisong Li
  2023-03-21  9:17 ` [PATCH 20.11 1/3] net/hns3: fix burst mode query with dummy function Huisong Li
@ 2023-03-21  9:17 ` Huisong Li
  2023-03-21  9:17 ` [PATCH 20.11 3/3] net/hns3: add verification of RSS types Huisong Li
  2 siblings, 0 replies; 4+ messages in thread
From: Huisong Li @ 2023-03-21  9:17 UTC (permalink / raw)
  To: stable, luca.boccassi; +Cc: liudongdong3, huangdaode, liuyonglong, lihuisong

[ upstream commit e3069658da9ffb6f83a0d972ff2776c405eb6a8f ]

Currently, hns3 driver supports setting multiple rte flow RSS rule,
but only the last is valid. This implementation is different from
the mainstream usage of rte flow hash in the community. Please see
the discussion threads [1] and [2].

This patch sets RSS hash feature completely based on the request of
the flow rule so that multiple hash rules can take effect at the same
time. Please notice that:
1. For hns3, 'func' has only one hardware. 'key' and 'queue' have only
   one entry in hardware.
2. the overlapping part of the old rule will be overridden if the
   configuration items of a new rule overlap with those of an old rule.

The hns3_flow_validate() verifies and parses RSS or Fdir rules from
user, and saves them to a local variable at the same time. The local
variable is directly used to create RSS or Fdir rules. In this way,
we save one parsing and saving process.

[1] https://lore.kernel.org/all/DM5PR12MB46648085D7CABF1AFF2D75CDD60A9@DM5PR12MB4664.namprd12.prod.outlook.com/
[2] https://lore.kernel.org/all/f7de4db4-1b88-622f-4e03-acd3eee8a72c@oktetlabs.ru/

Fixes: c37ca66f2b27 ("net/hns3: support RSS")

Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Dongdong Liu <liudongdong3@huawei.com>
---
 drivers/net/hns3/hns3_ethdev.h |   9 -
 drivers/net/hns3/hns3_fdir.h   |   4 +-
 drivers/net/hns3/hns3_flow.c   | 983 +++++++++++++++++++++++----------
 drivers/net/hns3/hns3_rss.c    | 144 ++---
 drivers/net/hns3/hns3_rss.h    | 118 +++-
 5 files changed, 864 insertions(+), 394 deletions(-)

diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index 03969bccee..00571fa457 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -896,15 +896,6 @@ static inline uint32_t hns3_read_reg(void *base, uint32_t reg)
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
-#define NEXT_ITEM_OF_ACTION(act, actions, index)                        \
-	do {								\
-		(act) = (actions) + (index);				\
-		while ((act)->type == RTE_FLOW_ACTION_TYPE_VOID) {	\
-			(index)++;					\
-			(act) = (actions) + (index);				\
-		}							\
-	} while (0)
-
 #define MSEC_PER_SEC              1000L
 #define USEC_PER_MSEC             1000L
 
diff --git a/drivers/net/hns3/hns3_fdir.h b/drivers/net/hns3/hns3_fdir.h
index 11c2d82238..cba6bef0b0 100644
--- a/drivers/net/hns3/hns3_fdir.h
+++ b/drivers/net/hns3/hns3_fdir.h
@@ -177,10 +177,10 @@ struct hns3_fdir_rule_ele {
 
 struct hns3_flow_rss_conf {
 	struct rte_flow_action_rss conf;
-	uint8_t hash_algo;
 	uint8_t key[HNS3_RSS_KEY_SIZE_MAX];  /* Hash key */
 	uint16_t queue[HNS3_RSS_QUEUES_BUFFER_NUM]; /* Queues indices to use */
-	bool valid; /* check if RSS rule is valid */
+	uint64_t pattern_type;
+	uint64_t hw_pctypes; /* packet types in driver */
 };
 
 /* rss filter list structure */
diff --git a/drivers/net/hns3/hns3_flow.c b/drivers/net/hns3/hns3_flow.c
index 47ea9f71e8..202e4fafcd 100644
--- a/drivers/net/hns3/hns3_flow.c
+++ b/drivers/net/hns3/hns3_flow.c
@@ -5,10 +5,140 @@
 #include <rte_flow_driver.h>
 #include <rte_io.h>
 #include <rte_malloc.h>
+#include <rte_bitops.h>
 
 #include "hns3_ethdev.h"
 #include "hns3_logs.h"
 
+union hns3_filter_conf {
+	struct hns3_fdir_rule fdir_conf;
+	struct hns3_flow_rss_conf rss_conf;
+};
+
+struct hns3_filter_info {
+	enum rte_filter_type type;
+	union hns3_filter_conf conf;
+};
+
+#define NEXT_ITEM_OF_ACTION(act, actions, index) \
+	do { \
+		(act) = (actions) + (index); \
+		while ((act)->type == RTE_FLOW_ACTION_TYPE_VOID) { \
+			(index)++; \
+			(act) = (actions) + (index); \
+		} \
+	} while (0)
+
+#define NEXT_ITEM_OF_PATTERN(item, pattern, index) \
+	do { \
+		(item) = (pattern) + (index); \
+		while ((item)->type == RTE_FLOW_ITEM_TYPE_VOID) { \
+			(index)++; \
+			(item) = (pattern) + (index); \
+		} \
+	} while (0)
+
+#define HNS3_HASH_HDR_ETH	RTE_BIT64(0)
+#define HNS3_HASH_HDR_IPV4	RTE_BIT64(1)
+#define HNS3_HASH_HDR_IPV6	RTE_BIT64(2)
+#define HNS3_HASH_HDR_TCP	RTE_BIT64(3)
+#define HNS3_HASH_HDR_UDP	RTE_BIT64(4)
+#define HNS3_HASH_HDR_SCTP	RTE_BIT64(5)
+
+#define HNS3_HASH_VOID_NEXT_ALLOW	BIT_ULL(RTE_FLOW_ITEM_TYPE_ETH)
+
+#define HNS3_HASH_ETH_NEXT_ALLOW	(BIT_ULL(RTE_FLOW_ITEM_TYPE_IPV4) | \
+					 BIT_ULL(RTE_FLOW_ITEM_TYPE_IPV6))
+
+#define HNS3_HASH_IP_NEXT_ALLOW		(BIT_ULL(RTE_FLOW_ITEM_TYPE_TCP) | \
+					 BIT_ULL(RTE_FLOW_ITEM_TYPE_UDP) | \
+					 BIT_ULL(RTE_FLOW_ITEM_TYPE_SCTP))
+
+static const uint64_t hash_pattern_next_allow_items[] = {
+	[RTE_FLOW_ITEM_TYPE_VOID] = HNS3_HASH_VOID_NEXT_ALLOW,
+	[RTE_FLOW_ITEM_TYPE_ETH]  = HNS3_HASH_ETH_NEXT_ALLOW,
+	[RTE_FLOW_ITEM_TYPE_IPV4] = HNS3_HASH_IP_NEXT_ALLOW,
+	[RTE_FLOW_ITEM_TYPE_IPV6] = HNS3_HASH_IP_NEXT_ALLOW,
+};
+
+static const uint64_t hash_pattern_item_header[] = {
+	[RTE_FLOW_ITEM_TYPE_ETH]  = HNS3_HASH_HDR_ETH,
+	[RTE_FLOW_ITEM_TYPE_IPV4] = HNS3_HASH_HDR_IPV4,
+	[RTE_FLOW_ITEM_TYPE_IPV6] = HNS3_HASH_HDR_IPV6,
+	[RTE_FLOW_ITEM_TYPE_TCP]  = HNS3_HASH_HDR_TCP,
+	[RTE_FLOW_ITEM_TYPE_UDP]  = HNS3_HASH_HDR_UDP,
+	[RTE_FLOW_ITEM_TYPE_SCTP] = HNS3_HASH_HDR_SCTP,
+};
+
+#define HNS3_HASH_IPV4		(HNS3_HASH_HDR_ETH | HNS3_HASH_HDR_IPV4)
+#define HNS3_HASH_IPV4_TCP	(HNS3_HASH_HDR_ETH | \
+				 HNS3_HASH_HDR_IPV4 | \
+				 HNS3_HASH_HDR_TCP)
+#define HNS3_HASH_IPV4_UDP	(HNS3_HASH_HDR_ETH | \
+				 HNS3_HASH_HDR_IPV4 | \
+				 HNS3_HASH_HDR_UDP)
+#define HNS3_HASH_IPV4_SCTP	(HNS3_HASH_HDR_ETH | \
+				 HNS3_HASH_HDR_IPV4 | \
+				 HNS3_HASH_HDR_SCTP)
+#define HNS3_HASH_IPV6		(HNS3_HASH_HDR_ETH | HNS3_HASH_HDR_IPV6)
+#define HNS3_HASH_IPV6_TCP	(HNS3_HASH_HDR_ETH | \
+				 HNS3_HASH_HDR_IPV6 | \
+				 HNS3_HASH_HDR_TCP)
+#define HNS3_HASH_IPV6_UDP	(HNS3_HASH_HDR_ETH | \
+				 HNS3_HASH_HDR_IPV6 | \
+				 HNS3_HASH_HDR_UDP)
+#define HNS3_HASH_IPV6_SCTP	(HNS3_HASH_HDR_ETH | \
+				 HNS3_HASH_HDR_IPV6 | \
+				 HNS3_HASH_HDR_SCTP)
+
+static const struct hns3_hash_map_info {
+	/* flow type specified, zero means action works for all flow types. */
+	uint64_t pattern_type;
+	uint64_t rss_pctype; /* packet type with prefix RTE_ETH_RSS_xxx */
+	uint64_t l3l4_types; /* Supported L3/L4 RSS types for this packet type */
+	uint64_t hw_pctype; /* packet type in driver */
+	uint64_t tuple_mask; /* full tuples of the hw_pctype */
+} hash_map_table[] = {
+	/* IPV4 */
+	{ HNS3_HASH_IPV4,
+	  ETH_RSS_IPV4, HNS3_RSS_SUPPORT_L3_SRC_DST,
+	  HNS3_RSS_PCTYPE_IPV4_NONF, HNS3_RSS_TUPLE_IPV4_NONF_M },
+	{ HNS3_HASH_IPV4,
+	  ETH_RSS_NONFRAG_IPV4_OTHER, HNS3_RSS_SUPPORT_L3_SRC_DST,
+	  HNS3_RSS_PCTYPE_IPV4_NONF, HNS3_RSS_TUPLE_IPV4_NONF_M },
+	{ HNS3_HASH_IPV4,
+	  ETH_RSS_FRAG_IPV4, HNS3_RSS_SUPPORT_L3_SRC_DST,
+	  HNS3_RSS_PCTYPE_IPV4_FLAG, HNS3_RSS_TUPLE_IPV4_FLAG_M },
+	{ HNS3_HASH_IPV4_TCP,
+	  ETH_RSS_NONFRAG_IPV4_TCP, HNS3_RSS_SUPPORT_L3L4,
+	  HNS3_RSS_PCTYPE_IPV4_TCP, HNS3_RSS_TUPLE_IPV4_TCP_M },
+	{ HNS3_HASH_IPV4_UDP,
+	  ETH_RSS_NONFRAG_IPV4_UDP, HNS3_RSS_SUPPORT_L3L4,
+	  HNS3_RSS_PCTYPE_IPV4_UDP, HNS3_RSS_TUPLE_IPV4_UDP_M },
+	{ HNS3_HASH_IPV4_SCTP,
+	  ETH_RSS_NONFRAG_IPV4_SCTP, HNS3_RSS_SUPPORT_L3L4,
+	  HNS3_RSS_PCTYPE_IPV4_SCTP, HNS3_RSS_TUPLE_IPV4_SCTP_M },
+	/* IPV6 */
+	{ HNS3_HASH_IPV6,
+	  ETH_RSS_IPV6, HNS3_RSS_SUPPORT_L3_SRC_DST,
+	  HNS3_RSS_PCTYPE_IPV6_NONF, HNS3_RSS_TUPLE_IPV6_NONF_M },
+	{ HNS3_HASH_IPV6,
+	  ETH_RSS_NONFRAG_IPV6_OTHER, HNS3_RSS_SUPPORT_L3_SRC_DST,
+	  HNS3_RSS_PCTYPE_IPV6_NONF, HNS3_RSS_TUPLE_IPV6_NONF_M },
+	{ HNS3_HASH_IPV6,
+	  ETH_RSS_FRAG_IPV6, HNS3_RSS_SUPPORT_L3_SRC_DST,
+	  HNS3_RSS_PCTYPE_IPV6_FLAG, HNS3_RSS_TUPLE_IPV6_FLAG_M },
+	{ HNS3_HASH_IPV6_TCP,
+	  ETH_RSS_NONFRAG_IPV6_TCP, HNS3_RSS_SUPPORT_L3L4,
+	  HNS3_RSS_PCTYPE_IPV6_TCP, HNS3_RSS_TUPLE_IPV6_TCP_M },
+	{ HNS3_HASH_IPV6_UDP,
+	  ETH_RSS_NONFRAG_IPV6_UDP, HNS3_RSS_SUPPORT_L3L4,
+	  HNS3_RSS_PCTYPE_IPV6_UDP, HNS3_RSS_TUPLE_IPV6_UDP_M },
+	{ HNS3_HASH_IPV6_SCTP,
+	  ETH_RSS_NONFRAG_IPV6_SCTP, HNS3_RSS_SUPPORT_L3L4,
+	  HNS3_RSS_PCTYPE_IPV6_SCTP, HNS3_RSS_TUPLE_IPV6_SCTP_M },
+};
+
 static const uint8_t full_mask[VNI_OR_TNI_LEN] = { 0xFF, 0xFF, 0xFF };
 static const uint8_t zero_mask[VNI_OR_TNI_LEN] = { 0x00, 0x00, 0x00 };
 
@@ -78,7 +208,7 @@ net_addr_to_host(uint32_t *dst, const rte_be32_t *src, size_t len)
 }
 
 /*
- * This function is used to find rss general action.
+ * This function is used to parse filter type.
  * 1. As we know RSS is used to spread packets among several queues, the flow
  *    API provide the struct rte_flow_action_rss, user could config its field
  *    sush as: func/level/types/key/queue to control RSS function.
@@ -86,16 +216,18 @@ net_addr_to_host(uint32_t *dst, const rte_be32_t *src, size_t len)
  *    implemented by FDIR + RSS in hns3 hardware, user can create one FDIR rule
  *    which action is RSS queues region.
  * 3. When action is RSS, we use the following rule to distinguish:
- *    Case 1: pattern have ETH and action's queue_num > 0, indicate it is queue
- *            region configuration.
+ *    Case 1: pattern has ETH and all fields in RSS action except 'queues' are
+ *            zero or default, indicate it is queue region configuration.
  *    Case other: an rss general action.
  */
-static const struct rte_flow_action *
-hns3_find_rss_general_action(const struct rte_flow_item pattern[],
-			     const struct rte_flow_action actions[])
+static void
+hns3_parse_filter_type(const struct rte_flow_item pattern[],
+		       const struct rte_flow_action actions[],
+		       struct hns3_filter_info *filter_info)
 {
 	const struct rte_flow_action_rss *rss_act;
 	const struct rte_flow_action *act = NULL;
+	bool only_has_queues = false;
 	bool have_eth = false;
 
 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
@@ -104,8 +236,10 @@ hns3_find_rss_general_action(const struct rte_flow_item pattern[],
 			break;
 		}
 	}
-	if (!act)
-		return NULL;
+	if (act == NULL) {
+		filter_info->type = RTE_ETH_FILTER_FDIR;
+		return;
+	}
 
 	for (; pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {
 		if (pattern->type == RTE_FLOW_ITEM_TYPE_ETH) {
@@ -115,18 +249,20 @@ hns3_find_rss_general_action(const struct rte_flow_item pattern[],
 	}
 
 	rss_act = act->conf;
-	if (have_eth && rss_act->queue_num) {
+	only_has_queues = (rss_act->queue_num > 0) &&
+			  (rss_act->func == RTE_ETH_HASH_FUNCTION_DEFAULT &&
+			   rss_act->types == 0 && rss_act->key_len == 0);
+	if (have_eth && only_has_queues) {
 		/*
-		 * Pattern have ETH and action's queue_num > 0, indicate this is
-		 * queue region configuration.
-		 * Because queue region is implemented by FDIR + RSS in hns3
-		 * hardware, it needs to enter FDIR process, so here return NULL
-		 * to avoid enter RSS process.
+		 * Pattern has ETH and all fields in RSS action except 'queues'
+		 * are zero or default, which indicates this is queue region
+		 * configuration.
 		 */
-		return NULL;
+		filter_info->type = RTE_ETH_FILTER_FDIR;
+		return;
 	}
 
-	return act;
+	filter_info->type = RTE_ETH_FILTER_HASH;
 }
 
 static inline struct hns3_flow_counter *
@@ -1225,7 +1361,6 @@ hns3_filterlist_flush(struct rte_eth_dev *dev)
 {
 	struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct hns3_fdir_rule_ele *fdir_rule_ptr;
-	struct hns3_rss_conf_ele *rss_filter_ptr;
 	struct hns3_flow_mem *flow_node;
 
 	fdir_rule_ptr = TAILQ_FIRST(&hw->flow_fdir_list);
@@ -1235,13 +1370,6 @@ hns3_filterlist_flush(struct rte_eth_dev *dev)
 		fdir_rule_ptr = TAILQ_FIRST(&hw->flow_fdir_list);
 	}
 
-	rss_filter_ptr = TAILQ_FIRST(&hw->flow_rss_list);
-	while (rss_filter_ptr) {
-		TAILQ_REMOVE(&hw->flow_rss_list, rss_filter_ptr, entries);
-		rte_free(rss_filter_ptr);
-		rss_filter_ptr = TAILQ_FIRST(&hw->flow_rss_list);
-	}
-
 	flow_node = TAILQ_FIRST(&hw->flow_list);
 	while (flow_node) {
 		TAILQ_REMOVE(&hw->flow_list, flow_node, entries);
@@ -1306,186 +1434,423 @@ hns3_action_rss_same(const struct rte_flow_action_rss *comp,
 		hns3_flow_rule_queues_same(comp, with);
 }
 
-/*
- * This function is used to parse rss action validation.
- */
+static bool
+hns3_valid_ipv6_sctp_rss_types(struct hns3_hw *hw, uint64_t types)
+{
+	/*
+	 * Some hardware don't support to use src/dst port fields to hash
+	 * for IPV6 SCTP packet type.
+	 */
+	if (types & ETH_RSS_NONFRAG_IPV6_SCTP &&
+	    types & HNS3_RSS_SUPPORT_L4_SRC_DST &&
+	    !hw->rss_info.ipv6_sctp_offload_supported)
+		return false;
+
+	return true;
+}
+
 static int
-hns3_parse_rss_filter(struct rte_eth_dev *dev,
-		      const struct rte_flow_action *actions,
-		      struct rte_flow_error *error)
+hns3_flow_parse_hash_func(const struct rte_flow_action_rss *rss_act,
+			  struct hns3_flow_rss_conf *rss_conf,
+			  struct rte_flow_error *error)
 {
-	struct hns3_adapter *hns = dev->data->dev_private;
-	struct hns3_hw *hw = &hns->hw;
-	const struct rte_flow_action_rss *rss;
-	const struct rte_flow_action *act;
-	uint32_t act_index = 0;
-	uint16_t n;
+	if (rss_act->func >= RTE_ETH_HASH_FUNCTION_MAX)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  NULL, "RSS hash func are not supported");
 
-	NEXT_ITEM_OF_ACTION(act, actions, act_index);
-	rss = act->conf;
+	rss_conf->conf.func = rss_act->func;
+	return 0;
+}
 
-	if (rss == NULL) {
+static int
+hns3_flow_parse_hash_key(struct hns3_hw *hw,
+			 const struct rte_flow_action_rss *rss_act,
+			 struct hns3_flow_rss_conf *rss_conf,
+			 struct rte_flow_error *error)
+{
+	if (rss_act->key_len != hw->rss_key_size)
 		return rte_flow_error_set(error, EINVAL,
 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
-					  act, "no valid queues");
-	}
+					  NULL, "invalid RSS key length");
 
-	if (rss->queue_num > HNS3_RSS_QUEUES_BUFFER_NUM)
-		return rte_flow_error_set(error, ENOTSUP,
-					  RTE_FLOW_ERROR_TYPE_ACTION_CONF, act,
-					  "queue number configured exceeds "
-					  "queue buffer size driver supported");
+	if (rss_act->key != NULL)
+		memcpy(rss_conf->key, rss_act->key, rss_act->key_len);
+	else
+		memcpy(rss_conf->key, hns3_hash_key,
+			RTE_MIN(sizeof(hns3_hash_key), rss_act->key_len));
+	/* Need to record if user sets hash key. */
+	rss_conf->conf.key = rss_act->key;
+	rss_conf->conf.key_len = rss_act->key_len;
 
-	for (n = 0; n < rss->queue_num; n++) {
-		if (rss->queue[n] < hw->alloc_rss_size)
-			continue;
-		return rte_flow_error_set(error, EINVAL,
-					  RTE_FLOW_ERROR_TYPE_ACTION_CONF, act,
-					  "queue id must be less than queue number allocated to a TC");
-	}
+	return 0;
+}
 
-	if (!(rss->types & HNS3_ETH_RSS_SUPPORT) && rss->types)
-		return rte_flow_error_set(error, EINVAL,
-					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
-					  act,
-					  "Flow types is unsupported by "
-					  "hns3's RSS");
-	if (rss->func >= RTE_ETH_HASH_FUNCTION_MAX)
-		return rte_flow_error_set(error, ENOTSUP,
-					  RTE_FLOW_ERROR_TYPE_ACTION_CONF, act,
-					  "RSS hash func are not supported");
-	if (rss->level)
+static int
+hns3_flow_parse_queues(struct hns3_hw *hw,
+		       const struct rte_flow_action_rss *rss_act,
+		       struct hns3_flow_rss_conf *rss_conf,
+		       struct rte_flow_error *error)
+{
+	uint16_t i;
+
+	if (rss_act->queue_num > hw->rss_ind_tbl_size)
 		return rte_flow_error_set(error, ENOTSUP,
-					  RTE_FLOW_ERROR_TYPE_ACTION_CONF, act,
-					  "a nonzero RSS encapsulation level is not supported");
-	if (rss->key_len && rss->key_len != hw->rss_key_size)
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  NULL,
+					  "queue number can not exceed RSS indirection table.");
+
+	if (rss_act->queue_num > HNS3_RSS_QUEUES_BUFFER_NUM)
 		return rte_flow_error_set(error, ENOTSUP,
-					  RTE_FLOW_ERROR_TYPE_ACTION_CONF, act,
-					  "invalid RSS key length");
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  NULL,
+					  "queue number configured exceeds queue buffer size driver supported");
+
+	for (i = 0; i < rss_act->queue_num; i++) {
+		if (rss_act->queue[i] >= hw->alloc_rss_size)
+			return rte_flow_error_set(error, EINVAL,
+						RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+						NULL,
+						"queue id must be less than queue number allocated to a TC");
+	}
+
+	memcpy(rss_conf->queue, rss_act->queue,
+	       rss_act->queue_num * sizeof(rss_conf->queue[0]));
+	rss_conf->conf.queue = rss_conf->queue;
+	rss_conf->conf.queue_num = rss_act->queue_num;
+
+	return 0;
+}
+
+static int
+hns3_flow_get_hw_pctype(struct hns3_hw *hw,
+			const struct rte_flow_action_rss *rss_act,
+			const struct hns3_hash_map_info *map,
+			struct hns3_flow_rss_conf *rss_conf,
+			struct rte_flow_error *error)
+{
+	uint64_t l3l4_src_dst, l3l4_refine, left_types;
+
+	if (rss_act->types == 0) {
+		/* Disable RSS hash of this packet type if types is zero. */
+		rss_conf->hw_pctypes |= map->hw_pctype;
+		return 0;
+	}
 
 	/*
-	 * For Kunpeng920 and Kunpeng930 NIC hardware, it is not supported to
-	 * use dst port/src port fields to RSS hash for the following packet
-	 * types.
-	 * - IPV4 FRAG | IPV4 NONFRAG | IPV6 FRAG | IPV6 NONFRAG
-	 * Besides, for Kunpeng920, The NIC hardware is not supported to use
-	 * src/dst port fields to RSS hash for IPV6 SCTP packet type.
+	 * Can not have extra types except rss_pctype and l3l4_type in this map.
 	 */
-	if (rss->types & (ETH_RSS_L4_DST_ONLY | ETH_RSS_L4_SRC_ONLY) &&
-	   (rss->types & ETH_RSS_IP ||
-	   (!hw->rss_info.ipv6_sctp_offload_supported &&
-	   rss->types & ETH_RSS_NONFRAG_IPV6_SCTP)))
+	left_types = ~map->rss_pctype & rss_act->types;
+	if (left_types & ~map->l3l4_types)
 		return rte_flow_error_set(error, EINVAL,
-					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
-					  &rss->types,
-					  "input RSS types are not supported");
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
+					  "cannot set extra types.");
+
+	l3l4_src_dst = left_types;
+	/* L3/L4 SRC and DST shouldn't be specified at the same time. */
+	l3l4_refine = rte_eth_rss_hf_refine(l3l4_src_dst);
+	if (l3l4_refine != l3l4_src_dst)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
+					  "cannot specify L3_SRC/DST_ONLY or L4_SRC/DST_ONLY at the same.");
 
-	act_index++;
+	if (!hns3_valid_ipv6_sctp_rss_types(hw, rss_act->types))
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL,
+					  "hardware doesn't support to use L4 src/dst to hash for IPV6-SCTP.");
 
-	/* Check if the next not void action is END */
-	NEXT_ITEM_OF_ACTION(act, actions, act_index);
-	if (act->type != RTE_FLOW_ACTION_TYPE_END)
-		return rte_flow_error_set(error, EINVAL,
-					  RTE_FLOW_ERROR_TYPE_ACTION,
-					  act, "Not supported action.");
+	rss_conf->hw_pctypes |= map->hw_pctype;
 
 	return 0;
 }
 
 static int
-hns3_disable_rss(struct hns3_hw *hw)
+hns3_flow_parse_rss_types_by_ptype(struct hns3_hw *hw,
+				   const struct rte_flow_action_rss *rss_act,
+				   uint64_t pattern_type,
+				   struct hns3_flow_rss_conf *rss_conf,
+				   struct rte_flow_error *error)
 {
+	const struct hns3_hash_map_info *map;
+	bool matched = false;
+	uint16_t i;
 	int ret;
 
-	ret = hns3_set_rss_tuple_by_rss_hf(hw, 0);
-	if (ret)
-		return ret;
-	hw->rss_info.rss_hf = 0;
+	for (i = 0; i < RTE_DIM(hash_map_table); i++) {
+		map = &hash_map_table[i];
+		if (map->pattern_type != pattern_type) {
+			/*
+			 * If the target pattern type is already matched with
+			 * the one before this pattern in the hash map table,
+			 * no need to continue walk.
+			 */
+			if (matched)
+				break;
+			continue;
+		}
+		matched = true;
 
-	return 0;
+		/*
+		 * If pattern type is matched and the 'types' is zero, all packet flow
+		 * types related to this pattern type disable RSS hash.
+		 * Otherwise, RSS types must match the pattern type and cannot have no
+		 * extra or unsupported types.
+		 */
+		if (rss_act->types != 0 && !(map->rss_pctype & rss_act->types))
+			continue;
+
+		ret = hns3_flow_get_hw_pctype(hw, rss_act, map, rss_conf, error);
+		if (ret != 0)
+			return ret;
+	}
+
+	if (rss_conf->hw_pctypes != 0)
+		return 0;
+
+	if (matched)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  NULL, "RSS types are unsupported");
+
+	return rte_flow_error_set(error, ENOTSUP,
+				  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+				  NULL, "Pattern specified is unsupported");
+}
+
+static uint64_t
+hns3_flow_get_all_hw_pctypes(uint64_t types)
+{
+	uint64_t hw_pctypes = 0;
+	uint16_t i;
+
+	for (i = 0; i < RTE_DIM(hash_map_table); i++) {
+		if (types & hash_map_table[i].rss_pctype)
+			hw_pctypes |= hash_map_table[i].hw_pctype;
+	}
+
+	return hw_pctypes;
 }
 
 static int
-hns3_parse_rss_algorithm(struct hns3_hw *hw, struct hns3_flow_rss_conf *rss_conf,
-			 uint8_t *hash_algo)
-{
-	const uint8_t hash_func_map[] = {
-		[RTE_ETH_HASH_FUNCTION_DEFAULT] = HNS3_RSS_HASH_ALGO_TOEPLITZ,
-		[RTE_ETH_HASH_FUNCTION_TOEPLITZ] = HNS3_RSS_HASH_ALGO_TOEPLITZ,
-		[RTE_ETH_HASH_FUNCTION_SIMPLE_XOR] = HNS3_RSS_HASH_ALGO_SIMPLE,
-		[RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ] = HNS3_RSS_HASH_ALGO_SYMMETRIC_TOEP,
-	};
-	uint8_t key[HNS3_RSS_KEY_SIZE_MAX] = {0};
+hns3_flow_parse_rss_types(struct hns3_hw *hw,
+			  const struct rte_flow_action_rss *rss_act,
+			  uint64_t pattern_type,
+			  struct hns3_flow_rss_conf *rss_conf,
+			  struct rte_flow_error *error)
+{
+	rss_conf->conf.types = rss_act->types;
+
+	/* no pattern specified to set global RSS types. */
+	if (pattern_type == 0) {
+		if (rss_act->types & ~HNS3_ETH_RSS_SUPPORT)
+			hns3_warn(hw, "some types in the requested RSS types (0x%" PRIx64 ") aren't supported, they are ignored.",
+				  rss_act->types);
+		rss_conf->hw_pctypes =
+				hns3_flow_get_all_hw_pctypes(rss_act->types);
+		return 0;
+	}
+
+	return hns3_flow_parse_rss_types_by_ptype(hw, rss_act, pattern_type,
+						  rss_conf, error);
+}
+
+static int
+hns3_flow_parse_hash_global_conf(struct rte_eth_dev *dev,
+				 const struct rte_flow_action_rss *rss_act,
+				 struct hns3_flow_rss_conf *rss_conf,
+				 struct rte_flow_error *error)
+{
+	struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	int ret;
 
-	if (rss_conf->conf.func == RTE_ETH_HASH_FUNCTION_DEFAULT) {
-		ret = hns3_rss_get_algo_key(hw, hash_algo, key,
-					    hw->rss_key_size);
-		if (ret != 0) {
-			hns3_err(hw, "fail to get current RSS hash algorithm, ret = %d",
-				 ret);
+	ret = hns3_flow_parse_hash_func(rss_act, rss_conf, error);
+	if (ret != 0)
+		return ret;
+
+	if (rss_act->queue_num > 0) {
+		ret = hns3_flow_parse_queues(hw, rss_act, rss_conf, error);
+		if (ret != 0)
+			return ret;
+	}
+
+	if (rss_act->key_len > 0) {
+		ret = hns3_flow_parse_hash_key(hw, rss_act, rss_conf, error);
+		if (ret != 0)
 			return ret;
+	}
+
+	return hns3_flow_parse_rss_types(hw, rss_act, rss_conf->pattern_type,
+					 rss_conf, error);
+}
+
+static int
+hns3_flow_parse_pattern_type(const struct rte_flow_item pattern[],
+			     uint64_t *ptype, struct rte_flow_error *error)
+{
+	enum rte_flow_item_type pre_type = RTE_FLOW_ITEM_TYPE_VOID;
+	const char *message = "Pattern specified isn't supported";
+	uint64_t item_hdr, pattern_hdrs = 0;
+	enum rte_flow_item_type cur_type;
+
+	for (; pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {
+		if (pattern->type == RTE_FLOW_ITEM_TYPE_VOID)
+			continue;
+		if (pattern->mask || pattern->spec || pattern->last) {
+			message = "Header info shouldn't be specified";
+			goto unsup;
 		}
 
-		/*
-		 * During the phase of reset recovery, the hash algorithm
-		 * obtained from hardware may not be the one used(saved in
-		 * rte_flow_hash_algo) when this rule is delivered.
-		 */
-		if (__atomic_load_n((uint16_t *)&hw->reset.resetting, __ATOMIC_RELAXED) &&
-		    *hash_algo != rss_conf->hash_algo)
-			*hash_algo = rss_conf->hash_algo;
+		/* Check the sub-item allowed by the previous item . */
+		if (pre_type >= RTE_DIM(hash_pattern_next_allow_items) ||
+		    !(hash_pattern_next_allow_items[pre_type] &
+				BIT_ULL(pattern->type)))
+			goto unsup;
+
+		cur_type = pattern->type;
+		/* Unsupported for current type being greater than array size. */
+		if (cur_type >= RTE_DIM(hash_pattern_item_header))
+			goto unsup;
+
+		/* The value is zero, which means unsupported current header. */
+		item_hdr = hash_pattern_item_header[cur_type];
+		if (item_hdr == 0)
+			goto unsup;
+
+		/* Have duplicate pattern header. */
+		if (item_hdr & pattern_hdrs)
+			goto unsup;
+		pre_type = cur_type;
+		pattern_hdrs |= item_hdr;
+	}
 
+	if (pattern_hdrs != 0) {
+		*ptype = pattern_hdrs;
 		return 0;
 	}
 
-	*hash_algo = hash_func_map[rss_conf->conf.func];
+unsup:
+	return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
+				  pattern, message);
+}
+
+static int
+hns3_flow_parse_pattern_act(struct rte_eth_dev *dev,
+			    const struct rte_flow_item pattern[],
+			    const struct rte_flow_action_rss *rss_act,
+			    struct hns3_flow_rss_conf *rss_conf,
+			    struct rte_flow_error *error)
+{
+	struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret;
+
+	ret = hns3_flow_parse_hash_func(rss_act, rss_conf, error);
+	if (ret != 0)
+		return ret;
+
+	if (rss_act->key_len > 0) {
+		ret = hns3_flow_parse_hash_key(hw, rss_act, rss_conf, error);
+		if (ret != 0)
+			return ret;
+	}
+
+	if (rss_act->queue_num > 0) {
+		ret = hns3_flow_parse_queues(hw, rss_act, rss_conf, error);
+		if (ret != 0)
+			return ret;
+	}
+
+	ret = hns3_flow_parse_pattern_type(pattern, &rss_conf->pattern_type,
+					   error);
+	if (ret != 0)
+		return ret;
+
+	ret = hns3_flow_parse_rss_types(hw, rss_act, rss_conf->pattern_type,
+					rss_conf, error);
+	if (ret != 0)
+		return ret;
+
+	if (rss_act->func != RTE_ETH_HASH_FUNCTION_DEFAULT ||
+	    rss_act->key_len > 0 || rss_act->queue_num > 0)
+		hns3_warn(hw, "hash func, key and queues are global config, which work for all flow types. "
+			  "Recommend: don't set them together with pattern.");
 
 	return 0;
 }
 
+static bool
+hns3_rss_action_is_dup(struct hns3_hw *hw,
+		       const struct hns3_flow_rss_conf *conf)
+{
+	struct hns3_rss_conf_ele *filter;
+
+	TAILQ_FOREACH(filter, &hw->flow_rss_list, entries) {
+		if (conf->pattern_type != filter->filter_info.pattern_type)
+			continue;
+
+		if (hns3_action_rss_same(&filter->filter_info.conf, &conf->conf))
+			return true;
+	}
+
+	return false;
+}
+
+/*
+ * This function is used to parse rss action validation.
+ */
 static int
-hns3_hw_rss_hash_set(struct hns3_hw *hw, struct hns3_flow_rss_conf *conf)
+hns3_parse_rss_filter(struct rte_eth_dev *dev,
+		      const struct rte_flow_item pattern[],
+		      const struct rte_flow_action *actions,
+		      struct hns3_flow_rss_conf *rss_conf,
+		      struct rte_flow_error *error)
 {
-	struct rte_flow_action_rss *rss_config = &conf->conf;
-	uint8_t rss_key[HNS3_RSS_KEY_SIZE_MAX] = {0};
-	bool use_default_key = false;
-	uint64_t flow_types;
-	uint8_t hash_algo;
+	struct hns3_adapter *hns = dev->data->dev_private;
+	const struct rte_flow_action_rss *rss_act;
+	const struct rte_flow_action *act;
+	const struct rte_flow_item *pat;
+	struct hns3_hw *hw = &hns->hw;
+	uint32_t index = 0;
 	int ret;
 
-	if (rss_config->key == NULL || rss_config->key_len != hw->rss_key_size) {
-		hns3_warn(hw, "Default RSS hash key to be set");
-		memcpy(rss_key, hns3_hash_key,
-			RTE_MIN(sizeof(hns3_hash_key), hw->rss_key_size));
-		use_default_key = true;
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	if (actions[1].type != RTE_FLOW_ACTION_TYPE_END)
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION,
+					  &actions[1],
+					  "Only support one action for RSS.");
+
+	rss_act = (const struct rte_flow_action_rss *)act->conf;
+	if (rss_act == NULL) {
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  act, "lost RSS action configuration");
 	}
 
-	ret = hns3_parse_rss_algorithm(hw, conf, &hash_algo);
-	if (ret)
+	if (rss_act->level != 0)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  act,
+					  "RSS level is not supported");
+
+	index = 0;
+	NEXT_ITEM_OF_PATTERN(pat, pattern, index);
+	if (pat[0].type == RTE_FLOW_ITEM_TYPE_END) {
+		rss_conf->pattern_type = 0;
+		ret = hns3_flow_parse_hash_global_conf(dev, rss_act,
+						       rss_conf, error);
+	} else {
+		ret = hns3_flow_parse_pattern_act(dev, pat, rss_act,
+						  rss_conf, error);
+	}
+	if (ret != 0)
 		return ret;
 
-	ret = hns3_set_rss_algo_key(hw, hash_algo,
-				    use_default_key ? rss_key : rss_config->key,
-				    hw->rss_key_size);
-	if (ret)
-		return ret;
-	conf->hash_algo = hash_algo;
-
-	/* Filter the unsupported flow types */
-	flow_types = rss_config->types ?
-		     rss_config->types & HNS3_ETH_RSS_SUPPORT :
-		     hw->rss_info.rss_hf;
-	if (flow_types != rss_config->types)
-		hns3_warn(hw, "modified RSS types based on hardware support,"
-			  " requested:0x%" PRIx64 " configured:0x%" PRIx64,
-			  rss_config->types, flow_types);
-
-	ret = hns3_set_rss_tuple_by_rss_hf(hw, flow_types);
-	if (ret)
-		hns3_err(hw, "Update RSS tuples by rss hf failed %d", ret);
+	if (hns3_rss_action_is_dup(hw, rss_conf))
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  act, "duplicate RSS rule");
 
-	return ret;
+	return 0;
 }
 
 static int
@@ -1511,44 +1876,106 @@ hns3_update_indir_table(struct hns3_hw *hw,
 	return hns3_set_rss_indir_table(hw, indir_tbl, hw->rss_ind_tbl_size);
 }
 
+static uint64_t
+hns3_flow_get_pctype_tuple_mask(uint64_t hw_pctype)
+{
+	uint64_t tuple_mask = 0;
+	uint16_t i;
+
+	for (i = 0; i < RTE_DIM(hash_map_table); i++) {
+		if (hw_pctype == hash_map_table[i].hw_pctype) {
+			tuple_mask = hash_map_table[i].tuple_mask;
+			break;
+		}
+	}
+
+	return tuple_mask;
+}
+
 static int
-hns3_reset_rss_filter(struct hns3_hw *hw,
-		      const struct hns3_flow_rss_conf *conf)
+hns3_flow_set_rss_ptype_tuple(struct hns3_hw *hw,
+			      struct hns3_flow_rss_conf *rss_conf)
 {
+	uint64_t old_tuple_fields, new_tuple_fields;
+	uint64_t hw_pctypes, tuples, tuple_mask = 0;
+	bool cfg_global_tuple;
 	int ret;
 
-	if (!conf->valid)
-		return 0;
+	cfg_global_tuple = (rss_conf->pattern_type == 0);
+	if (!cfg_global_tuple) {
+		/*
+		 * To ensure that different packets do not affect each other,
+		 * we have to first read all tuple fields, and then only modify
+		 * the tuples for the specified packet type.
+		 */
+		ret = hns3_get_rss_tuple_field(hw, &old_tuple_fields);
+		if (ret != 0)
+			return ret;
 
-	ret = hns3_disable_rss(hw);
-	if (ret)
-		hns3_err(hw, "RSS disable failed(%d)", ret);
+		new_tuple_fields = old_tuple_fields;
+		hw_pctypes = rss_conf->hw_pctypes;
+		while (hw_pctypes > 0) {
+			uint32_t idx = rte_bsf64(hw_pctypes);
+			uint64_t pctype = BIT_ULL(idx);
+
+			tuple_mask = hns3_flow_get_pctype_tuple_mask(pctype);
+			tuples = hns3_rss_calc_tuple_filed(hw,
+							rss_conf->conf.types);
+			new_tuple_fields &= ~tuple_mask;
+			new_tuple_fields |= tuples;
+			hw_pctypes &= ~pctype;
+		}
+	} else {
+		new_tuple_fields =
+			hns3_rss_calc_tuple_filed(hw, rss_conf->conf.types);
+	}
 
-	return ret;
+	ret = hns3_set_rss_tuple_field(hw, new_tuple_fields);
+	if (ret != 0)
+		return ret;
+
+	hns3_info(hw, "RSS tuple fields changed from 0x%" PRIx64 " to 0x%" PRIx64,
+		  old_tuple_fields, new_tuple_fields);
+
+	return 0;
 }
 
 static int
-hns3_config_rss_filter(struct hns3_hw *hw, struct hns3_flow_rss_conf *conf)
+hns3_config_rss_filter(struct hns3_hw *hw,
+		       struct hns3_flow_rss_conf *rss_conf)
 {
 	struct rte_flow_action_rss *rss_act;
-	uint16_t num;
 	int ret;
 
-	rss_act = &conf->conf;
-	/* Set rx queues to use */
-	num = RTE_MIN(hw->data->nb_rx_queues, rss_act->queue_num);
-	if (rss_act->queue_num > num)
-		hns3_warn(hw, "Config queue numbers %u are beyond the scope of truncated",
-			  rss_act->queue_num);
-	hns3_info(hw, "Max of contiguous %u PF queues are configured", num);
-	if (num) {
-		ret = hns3_update_indir_table(hw, rss_act, num);
-		if (ret)
+	rss_act = &rss_conf->conf;
+	if (rss_act->queue_num > 0) {
+		ret = hns3_update_indir_table(hw, rss_act, rss_act->queue_num);
+		if (ret) {
+			hns3_err(hw, "set queues action failed, ret = %d", ret);
 			return ret;
+		}
 	}
 
-	/* Set hash algorithm and flow types by the user's config */
-	return hns3_hw_rss_hash_set(hw, conf);
+	if (rss_act->key_len > 0 ||
+	    rss_act->func != RTE_ETH_HASH_FUNCTION_DEFAULT) {
+		ret = hns3_update_rss_algo_key(hw, rss_act->func, rss_conf->key,
+					       rss_act->key_len);
+		if (ret != 0) {
+			hns3_err(hw, "set func or hash key action failed, ret = %d",
+				 ret);
+			return ret;
+		}
+	}
+
+	if (rss_conf->hw_pctypes > 0) {
+		ret = hns3_flow_set_rss_ptype_tuple(hw, rss_conf);
+		if (ret != 0) {
+			hns3_err(hw, "set types action failed, ret = %d", ret);
+			return ret;
+		}
+	}
+
+	return 0;
 }
 
 static int
@@ -1557,51 +1984,44 @@ hns3_clear_rss_filter(struct rte_eth_dev *dev)
 	struct hns3_adapter *hns = dev->data->dev_private;
 	struct hns3_rss_conf_ele *rss_filter_ptr;
 	struct hns3_hw *hw = &hns->hw;
-	int rss_rule_succ_cnt = 0; /* count for success of clearing RSS rules */
-	int rss_rule_fail_cnt = 0; /* count for failure of clearing RSS rules */
-	int ret = 0;
 
 	rss_filter_ptr = TAILQ_FIRST(&hw->flow_rss_list);
 	while (rss_filter_ptr) {
 		TAILQ_REMOVE(&hw->flow_rss_list, rss_filter_ptr, entries);
-		ret = hns3_reset_rss_filter(hw, &rss_filter_ptr->filter_info);
-		if (ret)
-			rss_rule_fail_cnt++;
-		else
-			rss_rule_succ_cnt++;
 		rte_free(rss_filter_ptr);
 		rss_filter_ptr = TAILQ_FIRST(&hw->flow_rss_list);
 	}
 
-	if (rss_rule_fail_cnt) {
-		hns3_err(hw, "fail to delete all RSS filters, success num = %d "
-			     "fail num = %d", rss_rule_succ_cnt,
-			     rss_rule_fail_cnt);
-		ret = -EIO;
-	}
-
-	return ret;
+	return hns3_config_rss(hns);
 }
 
 static int
-hns3_restore_rss_filter(struct hns3_hw *hw)
+hns3_reconfig_all_rss_filter(struct hns3_hw *hw)
 {
 	struct hns3_rss_conf_ele *filter;
-	int ret = 0;
+	uint32_t rule_no = 0;
+	int ret;
 
-	pthread_mutex_lock(&hw->flows_lock);
 	TAILQ_FOREACH(filter, &hw->flow_rss_list, entries) {
-		if (!filter->filter_info.valid)
-			continue;
-
 		ret = hns3_config_rss_filter(hw, &filter->filter_info);
 		if (ret != 0) {
-			hns3_err(hw, "restore RSS filter failed, ret=%d", ret);
-			goto out;
+			hns3_err(hw, "config %uth RSS filter failed, ret = %d",
+				 rule_no, ret);
+			return ret;
 		}
+		rule_no++;
 	}
 
-out:
+	return 0;
+}
+
+static int
+hns3_restore_rss_filter(struct hns3_hw *hw)
+{
+	int ret;
+
+	pthread_mutex_lock(&hw->flows_lock);
+	ret = hns3_reconfig_all_rss_filter(hw);
 	pthread_mutex_unlock(&hw->flows_lock);
 
 	return ret;
@@ -1620,38 +2040,6 @@ hns3_restore_filter(struct hns3_adapter *hns)
 	return hns3_restore_rss_filter(hw);
 }
 
-static bool
-hns3_rss_action_is_dup(struct hns3_hw *hw,
-		       const struct rte_flow_action_rss *act)
-{
-	struct hns3_rss_conf_ele *filter;
-
-	TAILQ_FOREACH(filter, &hw->flow_rss_list, entries) {
-		if (!filter->filter_info.valid)
-			continue;
-
-		if (hns3_action_rss_same(&filter->filter_info.conf, act))
-			return true;
-	}
-
-	return false;
-}
-
-static int
-hns3_flow_parse_rss(struct rte_eth_dev *dev,
-		    struct hns3_flow_rss_conf *conf)
-{
-	struct hns3_adapter *hns = dev->data->dev_private;
-	struct hns3_hw *hw = &hns->hw;
-
-	if (hns3_rss_action_is_dup(hw, &conf->conf)) {
-		hns3_err(hw, "duplicate RSS configuration");
-		return -EINVAL;
-	}
-
-	return hns3_config_rss_filter(hw, conf);
-}
-
 static int
 hns3_flow_args_check(const struct rte_flow_attr *attr,
 		     const struct rte_flow_item pattern[],
@@ -1685,32 +2073,55 @@ static int
 hns3_flow_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 		   const struct rte_flow_item pattern[],
 		   const struct rte_flow_action actions[],
-		   struct rte_flow_error *error)
+		   struct rte_flow_error *error,
+		   struct hns3_filter_info *filter_info)
 {
-	struct hns3_fdir_rule fdir_rule;
+	union hns3_filter_conf *conf;
 	int ret;
 
 	ret = hns3_flow_args_check(attr, pattern, actions, error);
 	if (ret)
 		return ret;
 
-	if (hns3_find_rss_general_action(pattern, actions))
-		return hns3_parse_rss_filter(dev, actions, error);
+	hns3_parse_filter_type(pattern, actions, filter_info);
+	conf = &filter_info->conf;
+	if (filter_info->type == RTE_ETH_FILTER_HASH)
+		return hns3_parse_rss_filter(dev, pattern, actions,
+					     &conf->rss_conf, error);
 
-	memset(&fdir_rule, 0, sizeof(struct hns3_fdir_rule));
-	return hns3_parse_fdir_filter(dev, pattern, actions, &fdir_rule, error);
+	return hns3_parse_fdir_filter(dev, pattern, actions,
+				      &conf->fdir_conf, error);
+}
+
+static int
+hns3_flow_rebuild_all_rss_filter(struct hns3_adapter *hns)
+{
+	struct hns3_hw *hw = &hns->hw;
+	int ret;
+
+	ret = hns3_config_rss(hns);
+	if (ret != 0) {
+		hns3_err(hw, "restore original RSS configuration failed, ret = %d.",
+			 ret);
+		return ret;
+	}
+	ret = hns3_reconfig_all_rss_filter(hw);
+	if (ret != 0)
+		hns3_err(hw, "rebuild all RSS filter failed, ret = %d.", ret);
+
+	return ret;
 }
 
 static int
 hns3_flow_create_rss_rule(struct rte_eth_dev *dev,
-			  const struct rte_flow_action *act,
+			  struct hns3_flow_rss_conf *rss_conf,
 			  struct rte_flow *flow)
 {
 	struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	const struct rte_flow_action_rss *rss_act;
+	struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
 	struct hns3_rss_conf_ele *rss_filter_ptr;
 	struct hns3_flow_rss_conf *new_conf;
-	struct hns3_rss_conf_ele *filter_ptr;
+	struct rte_flow_action_rss *rss_act;
 	int ret;
 
 	rss_filter_ptr = rte_zmalloc("hns3 rss filter",
@@ -1720,35 +2131,28 @@ hns3_flow_create_rss_rule(struct rte_eth_dev *dev,
 		return -ENOMEM;
 	}
 
-	rss_act = (const struct rte_flow_action_rss *)act->conf;
 	new_conf = &rss_filter_ptr->filter_info;
-	memcpy(&new_conf->conf, rss_act, sizeof(*rss_act));
-	if (rss_act->queue_num > 0) {
-		memcpy(new_conf->queue, rss_act->queue,
-		       rss_act->queue_num * sizeof(new_conf->queue[0]));
+	memcpy(new_conf, rss_conf, sizeof(*new_conf));
+	rss_act = &new_conf->conf;
+	if (rss_act->queue_num > 0)
 		new_conf->conf.queue = new_conf->queue;
-	}
-	if (rss_act->key_len > 0) {
-		if (rss_act->key != NULL) {
-			memcpy(new_conf->key, rss_act->key,
-			       rss_act->key_len * sizeof(new_conf->key[0]));
-			new_conf->conf.key = new_conf->key;
-		}
-	}
+	/*
+	 * There are two ways to deliver hash key action:
+	 * 1> 'key_len' is greater than zero and 'key' isn't NULL.
+	 * 2> 'key_len' is greater than zero, but 'key' is NULL.
+	 * For case 2, we need to keep 'key' of the new_conf is NULL so as to
+	 * inherit the configuration from user in case of failing to verify
+	 * duplicate rule later.
+	 */
+	if (rss_act->key_len > 0 && rss_act->key != NULL)
+		new_conf->conf.key = new_conf->key;
 
-	ret = hns3_flow_parse_rss(dev, new_conf);
+	ret = hns3_config_rss_filter(hw, new_conf);
 	if (ret != 0) {
 		rte_free(rss_filter_ptr);
+		(void)hns3_flow_rebuild_all_rss_filter(hns);
 		return ret;
 	}
-	rss_filter_ptr->filter_info.valid = true;
-
-	/*
-	 * When create a new RSS rule, the old rule will be overlaid and set
-	 * invalid.
-	 */
-	TAILQ_FOREACH(filter_ptr, &hw->flow_rss_list, entries)
-		filter_ptr->filter_info.valid = false;
 
 	TAILQ_INSERT_TAIL(&hw->flow_rss_list, rss_filter_ptr, entries);
 	flow->rule = rss_filter_ptr;
@@ -1759,29 +2163,22 @@ hns3_flow_create_rss_rule(struct rte_eth_dev *dev,
 
 static int
 hns3_flow_create_fdir_rule(struct rte_eth_dev *dev,
-			   const struct rte_flow_item pattern[],
-			   const struct rte_flow_action actions[],
+			   struct hns3_fdir_rule *fdir_rule,
 			   struct rte_flow_error *error,
 			   struct rte_flow *flow)
 {
 	struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 	struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
 	struct hns3_fdir_rule_ele *fdir_rule_ptr;
-	struct hns3_fdir_rule fdir_rule;
 	int ret;
 
-	memset(&fdir_rule, 0, sizeof(struct hns3_fdir_rule));
-	ret = hns3_parse_fdir_filter(dev, pattern, actions, &fdir_rule, error);
-	if (ret != 0)
-		return ret;
-
-	if (fdir_rule.flags & HNS3_RULE_FLAG_COUNTER) {
-		ret = hns3_counter_new(dev, fdir_rule.act_cnt.shared,
-				       fdir_rule.act_cnt.id, error);
+	if (fdir_rule->flags & HNS3_RULE_FLAG_COUNTER) {
+		ret = hns3_counter_new(dev, fdir_rule->act_cnt.shared,
+				       fdir_rule->act_cnt.id, error);
 		if (ret != 0)
 			return ret;
 
-		flow->counter_id = fdir_rule.act_cnt.id;
+		flow->counter_id = fdir_rule->act_cnt.id;
 	}
 
 	fdir_rule_ptr = rte_zmalloc("hns3 fdir rule",
@@ -1797,11 +2194,11 @@ hns3_flow_create_fdir_rule(struct rte_eth_dev *dev,
 	 * rules to the hardware to simplify the rollback of rules in the
 	 * hardware.
 	 */
-	ret = hns3_fdir_filter_program(hns, &fdir_rule, false);
+	ret = hns3_fdir_filter_program(hns, fdir_rule, false);
 	if (ret != 0)
 		goto err_fdir_filter;
 
-	memcpy(&fdir_rule_ptr->fdir_conf, &fdir_rule,
+	memcpy(&fdir_rule_ptr->fdir_conf, fdir_rule,
 		sizeof(struct hns3_fdir_rule));
 	TAILQ_INSERT_TAIL(&hw->flow_fdir_list, fdir_rule_ptr, entries);
 	flow->rule = fdir_rule_ptr;
@@ -1812,8 +2209,8 @@ hns3_flow_create_fdir_rule(struct rte_eth_dev *dev,
 err_fdir_filter:
 	rte_free(fdir_rule_ptr);
 err_malloc:
-	if (fdir_rule.flags & HNS3_RULE_FLAG_COUNTER)
-		hns3_counter_release(dev, fdir_rule.act_cnt.id);
+	if (fdir_rule->flags & HNS3_RULE_FLAG_COUNTER)
+		hns3_counter_release(dev, fdir_rule->act_cnt.id);
 
 	return ret;
 }
@@ -1831,13 +2228,15 @@ hns3_flow_create(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 		 struct rte_flow_error *error)
 {
 	struct hns3_adapter *hns = dev->data->dev_private;
-	struct hns3_hw *hw = &hns->hw;
+	struct hns3_filter_info filter_info = {0};
 	struct hns3_flow_mem *flow_node;
-	const struct rte_flow_action *act;
+	struct hns3_hw *hw = &hns->hw;
+	union hns3_filter_conf *conf;
 	struct rte_flow *flow;
 	int ret;
 
-	ret = hns3_flow_validate(dev, attr, pattern, actions, error);
+	ret = hns3_flow_validate(dev, attr, pattern, actions, error,
+				 &filter_info);
 	if (ret)
 		return NULL;
 
@@ -1857,13 +2256,12 @@ hns3_flow_create(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 	}
 
 	flow_node->flow = flow;
+	conf = &filter_info.conf;
 	TAILQ_INSERT_TAIL(&hw->flow_list, flow_node, entries);
-
-	act = hns3_find_rss_general_action(pattern, actions);
-	if (act)
-		ret = hns3_flow_create_rss_rule(dev, act, flow);
+	if (filter_info.type == RTE_ETH_FILTER_HASH)
+		ret = hns3_flow_create_rss_rule(dev, &conf->rss_conf, flow);
 	else
-		ret = hns3_flow_create_fdir_rule(dev, pattern, actions,
+		ret = hns3_flow_create_fdir_rule(dev, &conf->fdir_conf,
 						 error, flow);
 	if (ret == 0)
 		return flow;
@@ -1916,15 +2314,10 @@ hns3_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow,
 		break;
 	case RTE_ETH_FILTER_HASH:
 		rss_filter_ptr = (struct hns3_rss_conf_ele *)flow->rule;
-		ret = hns3_reset_rss_filter(hw, &rss_filter_ptr->filter_info);
-		if (ret)
-			return rte_flow_error_set(error, EIO,
-						  RTE_FLOW_ERROR_TYPE_HANDLE,
-						  flow,
-						  "Destroy RSS fail.Try again");
 		TAILQ_REMOVE(&hw->flow_rss_list, rss_filter_ptr, entries);
 		rte_free(rss_filter_ptr);
 		rss_filter_ptr = NULL;
+		(void)hns3_flow_rebuild_all_rss_filter(hns);
 		break;
 	default:
 		return rte_flow_error_set(error, EINVAL,
@@ -2031,10 +2424,12 @@ hns3_flow_validate_wrap(struct rte_eth_dev *dev,
 			struct rte_flow_error *error)
 {
 	struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct hns3_filter_info filter_info = {0};
 	int ret;
 
 	pthread_mutex_lock(&hw->flows_lock);
-	ret = hns3_flow_validate(dev, attr, pattern, actions, error);
+	ret = hns3_flow_validate(dev, attr, pattern, actions, error,
+				 &filter_info);
 	pthread_mutex_unlock(&hw->flows_lock);
 
 	return ret;
diff --git a/drivers/net/hns3/hns3_rss.c b/drivers/net/hns3/hns3_rss.c
index 12a2f0e6f6..931ec61293 100644
--- a/drivers/net/hns3/hns3_rss.c
+++ b/drivers/net/hns3/hns3_rss.c
@@ -18,69 +18,13 @@ const uint8_t hns3_hash_key[HNS3_RSS_KEY_SIZE] = {
 	0x6A, 0x42, 0xB7, 0x3B, 0xBE, 0xAC, 0x01, 0xFA
 };
 
-enum hns3_tuple_field {
-	/* IPV4_TCP ENABLE FIELD */
-	HNS3_RSS_FIELD_IPV4_TCP_EN_TCP_D = 0,
-	HNS3_RSS_FIELD_IPV4_TCP_EN_TCP_S,
-	HNS3_RSS_FIELD_IPV4_TCP_EN_IP_D,
-	HNS3_RSS_FIELD_IPV4_TCP_EN_IP_S,
-
-	/* IPV4_UDP ENABLE FIELD */
-	HNS3_RSS_FIELD_IPV4_UDP_EN_UDP_D = 8,
-	HNS3_RSS_FIELD_IPV4_UDP_EN_UDP_S,
-	HNS3_RSS_FIELD_IPV4_UDP_EN_IP_D,
-	HNS3_RSS_FIELD_IPV4_UDP_EN_IP_S,
-
-	/* IPV4_SCTP ENABLE FIELD */
-	HNS3_RSS_FIELD_IPV4_SCTP_EN_SCTP_D = 16,
-	HNS3_RSS_FIELD_IPV4_SCTP_EN_SCTP_S,
-	HNS3_RSS_FIELD_IPV4_SCTP_EN_IP_D,
-	HNS3_RSS_FIELD_IPV4_SCTP_EN_IP_S,
-	HNS3_RSS_FIELD_IPV4_SCTP_EN_SCTP_VER,
-
-	/* IPV4 ENABLE FIELD */
-	HNS3_RSS_FIELD_IPV4_EN_NONFRAG_IP_D = 24,
-	HNS3_RSS_FIELD_IPV4_EN_NONFRAG_IP_S,
-	HNS3_RSS_FIELD_IPV4_EN_FRAG_IP_D,
-	HNS3_RSS_FIELD_IPV4_EN_FRAG_IP_S,
-
-	/* IPV6_TCP ENABLE FIELD */
-	HNS3_RSS_FIELD_IPV6_TCP_EN_TCP_D = 32,
-	HNS3_RSS_FIELD_IPV6_TCP_EN_TCP_S,
-	HNS3_RSS_FIELD_IPV6_TCP_EN_IP_D,
-	HNS3_RSS_FIELD_IPV6_TCP_EN_IP_S,
-
-	/* IPV6_UDP ENABLE FIELD */
-	HNS3_RSS_FIELD_IPV6_UDP_EN_UDP_D = 40,
-	HNS3_RSS_FIELD_IPV6_UDP_EN_UDP_S,
-	HNS3_RSS_FIELD_IPV6_UDP_EN_IP_D,
-	HNS3_RSS_FIELD_IPV6_UDP_EN_IP_S,
-
-	/* IPV6_SCTP ENABLE FIELD */
-	HNS3_RSS_FIELD_IPV6_SCTP_EN_SCTP_D = 48,
-	HNS3_RSS_FIELD_IPV6_SCTP_EN_SCTP_S,
-	HNS3_RSS_FIELD_IPV6_SCTP_EN_IP_D,
-	HNS3_RSS_FIELD_IPV6_SCTP_EN_IP_S,
-	HNS3_RSS_FIELD_IPV6_SCTP_EN_SCTP_VER,
-
-	/* IPV6 ENABLE FIELD */
-	HNS3_RSS_FIELD_IPV6_NONFRAG_IP_D = 56,
-	HNS3_RSS_FIELD_IPV6_NONFRAG_IP_S,
-	HNS3_RSS_FIELD_IPV6_FRAG_IP_D,
-	HNS3_RSS_FIELD_IPV6_FRAG_IP_S
+const uint8_t hns3_hash_func_map[] = {
+	[RTE_ETH_HASH_FUNCTION_DEFAULT] = HNS3_RSS_HASH_ALGO_TOEPLITZ,
+	[RTE_ETH_HASH_FUNCTION_TOEPLITZ] = HNS3_RSS_HASH_ALGO_TOEPLITZ,
+	[RTE_ETH_HASH_FUNCTION_SIMPLE_XOR] = HNS3_RSS_HASH_ALGO_SIMPLE,
+	[RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ] = HNS3_RSS_HASH_ALGO_SYMMETRIC_TOEP,
 };
 
-#define HNS3_RSS_TUPLE_IPV4_TCP_M	GENMASK(3, 0)
-#define HNS3_RSS_TUPLE_IPV4_UDP_M	GENMASK(11, 8)
-#define HNS3_RSS_TUPLE_IPV4_SCTP_M	GENMASK(20, 16)
-#define HNS3_RSS_TUPLE_IPV4_NONF_M	GENMASK(25, 24)
-#define HNS3_RSS_TUPLE_IPV4_FLAG_M	GENMASK(27, 26)
-#define HNS3_RSS_TUPLE_IPV6_TCP_M	GENMASK(35, 32)
-#define HNS3_RSS_TUPLE_IPV6_UDP_M	GENMASK(43, 40)
-#define HNS3_RSS_TUPLE_IPV6_SCTP_M	GENMASK(52, 48)
-#define HNS3_RSS_TUPLE_IPV6_NONF_M	GENMASK(57, 56)
-#define HNS3_RSS_TUPLE_IPV6_FLAG_M	GENMASK(59, 58)
-
 enum hns3_rss_tuple_type {
 	HNS3_RSS_IP_TUPLE,
 	HNS3_RSS_IP_L4_TUPLE,
@@ -574,7 +518,7 @@ hns3_rss_check_l3l4_types(struct hns3_hw *hw, uint64_t rss_hf)
 		hns3_warn(hw, "packet type isn't specified, L4_SRC/DST_ONLY is ignored.");
 }
 
-static uint64_t
+uint64_t
 hns3_rss_calc_tuple_filed(struct hns3_hw *hw, uint64_t rss_hf)
 {
 	uint64_t l3_only_mask = ETH_RSS_L3_SRC_ONLY |
@@ -610,25 +554,35 @@ hns3_rss_calc_tuple_filed(struct hns3_hw *hw, uint64_t rss_hf)
 }
 
 int
-hns3_set_rss_tuple_by_rss_hf(struct hns3_hw *hw, uint64_t rss_hf)
+hns3_set_rss_tuple_field(struct hns3_hw *hw, uint64_t tuple_fields)
 {
 	struct hns3_rss_input_tuple_cmd *req;
 	struct hns3_cmd_desc desc;
-	uint64_t tuple_field;
 	int ret;
 
 	hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RSS_INPUT_TUPLE, false);
 	req = (struct hns3_rss_input_tuple_cmd *)desc.data;
-
-	tuple_field = hns3_rss_calc_tuple_filed(hw, rss_hf);
-	req->tuple_field = rte_cpu_to_le_64(tuple_field);
+	req->tuple_field = rte_cpu_to_le_64(tuple_fields);
 	ret = hns3_cmd_send(hw, &desc, 1);
-	if (ret) {
-		hns3_err(hw, "Update RSS flow types tuples failed %d", ret);
-		return ret;
-	}
+	if (ret != 0)
+		hns3_err(hw, "set RSS hash tuple fields failed ret = %d", ret);
 
-	return 0;
+	return ret;
+}
+
+int
+hns3_set_rss_tuple_by_rss_hf(struct hns3_hw *hw, uint64_t rss_hf)
+{
+	uint64_t tuple_fields;
+	int ret;
+
+	tuple_fields = hns3_rss_calc_tuple_filed(hw, rss_hf);
+	ret = hns3_set_rss_tuple_field(hw, tuple_fields);
+	if (ret != 0)
+		hns3_err(hw, "Update RSS flow types tuples failed, ret = %d",
+			 ret);
+
+	return ret;
 }
 
 /*
@@ -1000,6 +954,52 @@ hns3_set_rss_tc_mode(struct hns3_hw *hw)
 	return ret;
 }
 
+/*
+ * Note: the 'hash_algo' is defined by enum rte_eth_hash_function.
+ */
+int
+hns3_update_rss_algo_key(struct hns3_hw *hw, uint8_t hash_func,
+			 uint8_t *key, uint8_t key_len)
+{
+	uint8_t rss_key[HNS3_RSS_KEY_SIZE_MAX] = {0};
+	bool modify_key, modify_algo;
+	uint8_t hash_algo;
+	int ret;
+
+	modify_key = (key != NULL && key_len > 0);
+	modify_algo = hash_func != RTE_ETH_HASH_FUNCTION_DEFAULT;
+	if (!modify_key && !modify_algo)
+		return 0;
+
+	if (modify_algo && hash_func >= RTE_DIM(hns3_hash_func_map)) {
+		hns3_err(hw, "hash func (%u) is unsupported.", hash_func);
+		return -ENOTSUP;
+	}
+	if (modify_key && key_len != hw->rss_key_size) {
+		hns3_err(hw, "hash key length (%u) is invalid.", key_len);
+		return -EINVAL;
+	}
+
+	ret = hns3_rss_get_algo_key(hw, &hash_algo, rss_key, hw->rss_key_size);
+	if (ret != 0) {
+		hns3_err(hw, "fail to get RSS hash algorithm and key, ret = %d",
+			 ret);
+		return ret;
+	}
+
+	if (modify_algo)
+		hash_algo = hns3_hash_func_map[hash_func];
+	if (modify_key)
+		memcpy(rss_key, key, key_len);
+
+	ret = hns3_set_rss_algo_key(hw, hash_algo, rss_key, hw->rss_key_size);
+	if (ret != 0)
+		hns3_err(hw, "fail to set RSS hash algorithm and key, ret = %d",
+			 ret);
+
+	return ret;
+}
+
 static void
 hns3_rss_tuple_uninit(struct hns3_hw *hw)
 {
diff --git a/drivers/net/hns3/hns3_rss.h b/drivers/net/hns3/hns3_rss.h
index dfd07930f4..dc6f3cedd3 100644
--- a/drivers/net/hns3/hns3_rss.h
+++ b/drivers/net/hns3/hns3_rss.h
@@ -8,23 +8,102 @@
 #include <rte_ethdev.h>
 #include <rte_flow.h>
 
-#define HNS3_ETH_RSS_SUPPORT ( \
-	ETH_RSS_IPV4 | \
-	ETH_RSS_FRAG_IPV4 | \
-	ETH_RSS_NONFRAG_IPV4_TCP | \
-	ETH_RSS_NONFRAG_IPV4_UDP | \
-	ETH_RSS_NONFRAG_IPV4_SCTP | \
-	ETH_RSS_NONFRAG_IPV4_OTHER | \
-	ETH_RSS_IPV6 | \
-	ETH_RSS_FRAG_IPV6 | \
-	ETH_RSS_NONFRAG_IPV6_TCP | \
-	ETH_RSS_NONFRAG_IPV6_UDP | \
-	ETH_RSS_NONFRAG_IPV6_SCTP | \
-	ETH_RSS_NONFRAG_IPV6_OTHER | \
-	ETH_RSS_L3_SRC_ONLY | \
-	ETH_RSS_L3_DST_ONLY | \
-	ETH_RSS_L4_SRC_ONLY | \
-	ETH_RSS_L4_DST_ONLY)
+#define HNS3_RSS_SUPPORT_L3_SRC_DST	(ETH_RSS_L3_SRC_ONLY | \
+					 ETH_RSS_L3_DST_ONLY)
+#define HNS3_RSS_SUPPORT_L4_SRC_DST	(ETH_RSS_L4_SRC_ONLY | \
+					 ETH_RSS_L4_DST_ONLY)
+#define HNS3_RSS_SUPPORT_L3L4		(HNS3_RSS_SUPPORT_L3_SRC_DST | \
+					 HNS3_RSS_SUPPORT_L4_SRC_DST)
+
+#define HNS3_RSS_SUPPORT_FLOW_TYPE	(ETH_RSS_IPV4 | \
+					 ETH_RSS_FRAG_IPV4 | \
+					 ETH_RSS_NONFRAG_IPV4_TCP | \
+					 ETH_RSS_NONFRAG_IPV4_UDP | \
+					 ETH_RSS_NONFRAG_IPV4_SCTP | \
+					 ETH_RSS_NONFRAG_IPV4_OTHER | \
+					 ETH_RSS_IPV6 | \
+					 ETH_RSS_FRAG_IPV6 | \
+					 ETH_RSS_NONFRAG_IPV6_TCP | \
+					 ETH_RSS_NONFRAG_IPV6_UDP | \
+					 ETH_RSS_NONFRAG_IPV6_SCTP | \
+					 ETH_RSS_NONFRAG_IPV6_OTHER)
+
+#define HNS3_ETH_RSS_SUPPORT		(HNS3_RSS_SUPPORT_FLOW_TYPE | \
+					 HNS3_RSS_SUPPORT_L3L4)
+
+enum hns3_tuple_field {
+	/* IPV4_TCP ENABLE FIELD */
+	HNS3_RSS_FIELD_IPV4_TCP_EN_TCP_D = 0,
+	HNS3_RSS_FIELD_IPV4_TCP_EN_TCP_S,
+	HNS3_RSS_FIELD_IPV4_TCP_EN_IP_D,
+	HNS3_RSS_FIELD_IPV4_TCP_EN_IP_S,
+
+	/* IPV4_UDP ENABLE FIELD */
+	HNS3_RSS_FIELD_IPV4_UDP_EN_UDP_D = 8,
+	HNS3_RSS_FIELD_IPV4_UDP_EN_UDP_S,
+	HNS3_RSS_FIELD_IPV4_UDP_EN_IP_D,
+	HNS3_RSS_FIELD_IPV4_UDP_EN_IP_S,
+
+	/* IPV4_SCTP ENABLE FIELD */
+	HNS3_RSS_FIELD_IPV4_SCTP_EN_SCTP_D = 16,
+	HNS3_RSS_FIELD_IPV4_SCTP_EN_SCTP_S,
+	HNS3_RSS_FIELD_IPV4_SCTP_EN_IP_D,
+	HNS3_RSS_FIELD_IPV4_SCTP_EN_IP_S,
+	HNS3_RSS_FIELD_IPV4_SCTP_EN_SCTP_VER,
+
+	/* IPV4 ENABLE FIELD */
+	HNS3_RSS_FIELD_IPV4_EN_NONFRAG_IP_D = 24,
+	HNS3_RSS_FIELD_IPV4_EN_NONFRAG_IP_S,
+	HNS3_RSS_FIELD_IPV4_EN_FRAG_IP_D,
+	HNS3_RSS_FIELD_IPV4_EN_FRAG_IP_S,
+
+	/* IPV6_TCP ENABLE FIELD */
+	HNS3_RSS_FIELD_IPV6_TCP_EN_TCP_D = 32,
+	HNS3_RSS_FIELD_IPV6_TCP_EN_TCP_S,
+	HNS3_RSS_FIELD_IPV6_TCP_EN_IP_D,
+	HNS3_RSS_FIELD_IPV6_TCP_EN_IP_S,
+
+	/* IPV6_UDP ENABLE FIELD */
+	HNS3_RSS_FIELD_IPV6_UDP_EN_UDP_D = 40,
+	HNS3_RSS_FIELD_IPV6_UDP_EN_UDP_S,
+	HNS3_RSS_FIELD_IPV6_UDP_EN_IP_D,
+	HNS3_RSS_FIELD_IPV6_UDP_EN_IP_S,
+
+	/* IPV6_SCTP ENABLE FIELD */
+	HNS3_RSS_FIELD_IPV6_SCTP_EN_SCTP_D = 48,
+	HNS3_RSS_FIELD_IPV6_SCTP_EN_SCTP_S,
+	HNS3_RSS_FIELD_IPV6_SCTP_EN_IP_D,
+	HNS3_RSS_FIELD_IPV6_SCTP_EN_IP_S,
+	HNS3_RSS_FIELD_IPV6_SCTP_EN_SCTP_VER,
+
+	/* IPV6 ENABLE FIELD */
+	HNS3_RSS_FIELD_IPV6_NONFRAG_IP_D = 56,
+	HNS3_RSS_FIELD_IPV6_NONFRAG_IP_S,
+	HNS3_RSS_FIELD_IPV6_FRAG_IP_D,
+	HNS3_RSS_FIELD_IPV6_FRAG_IP_S
+};
+
+#define HNS3_RSS_PCTYPE_IPV4_TCP	BIT_ULL(0)
+#define HNS3_RSS_PCTYPE_IPV4_UDP	BIT_ULL(8)
+#define HNS3_RSS_PCTYPE_IPV4_SCTP	BIT_ULL(16)
+#define HNS3_RSS_PCTYPE_IPV4_NONF	BIT_ULL(24)
+#define HNS3_RSS_PCTYPE_IPV4_FLAG	BIT_ULL(26)
+#define HNS3_RSS_PCTYPE_IPV6_TCP	BIT_ULL(32)
+#define HNS3_RSS_PCTYPE_IPV6_UDP	BIT_ULL(40)
+#define HNS3_RSS_PCTYPE_IPV6_SCTP	BIT_ULL(48)
+#define HNS3_RSS_PCTYPE_IPV6_NONF	BIT_ULL(56)
+#define HNS3_RSS_PCTYPE_IPV6_FLAG	BIT_ULL(58)
+
+#define HNS3_RSS_TUPLE_IPV4_TCP_M	GENMASK(3, 0)
+#define HNS3_RSS_TUPLE_IPV4_UDP_M	GENMASK(11, 8)
+#define HNS3_RSS_TUPLE_IPV4_SCTP_M	GENMASK(20, 16)
+#define HNS3_RSS_TUPLE_IPV4_NONF_M	GENMASK(25, 24)
+#define HNS3_RSS_TUPLE_IPV4_FLAG_M	GENMASK(27, 26)
+#define HNS3_RSS_TUPLE_IPV6_TCP_M	GENMASK(35, 32)
+#define HNS3_RSS_TUPLE_IPV6_UDP_M	GENMASK(43, 40)
+#define HNS3_RSS_TUPLE_IPV6_SCTP_M	GENMASK(52, 48)
+#define HNS3_RSS_TUPLE_IPV6_NONF_M	GENMASK(57, 56)
+#define HNS3_RSS_TUPLE_IPV6_FLAG_M	GENMASK(59, 58)
 
 #define HNS3_RSS_IND_TBL_SIZE	512 /* The size of hash lookup table */
 #define HNS3_RSS_IND_TBL_SIZE_MAX 2048
@@ -111,12 +190,17 @@ int hns3_set_rss_indir_table(struct hns3_hw *hw, uint16_t *indir,
 int hns3_rss_reset_indir_table(struct hns3_hw *hw);
 int hns3_config_rss(struct hns3_adapter *hns);
 void hns3_rss_uninit(struct hns3_adapter *hns);
+bool hns3_check_rss_types_valid(struct hns3_hw *hw, uint64_t types);
 int hns3_set_rss_tuple_by_rss_hf(struct hns3_hw *hw, uint64_t rss_hf);
+int hns3_set_rss_tuple_field(struct hns3_hw *hw, uint64_t tuple_fields);
 int hns3_get_rss_tuple_field(struct hns3_hw *hw, uint64_t *tuple_fields);
 int hns3_set_rss_algo_key(struct hns3_hw *hw, uint8_t hash_algo,
 			  const uint8_t *key, uint8_t key_len);
 int hns3_restore_filter(struct hns3_adapter *hns);
 int hns3_rss_get_algo_key(struct hns3_hw *hw,  uint8_t *hash_algo,
 			  uint8_t *key, uint8_t key_len);
+uint64_t hns3_rss_calc_tuple_filed(struct hns3_hw *hw, uint64_t rss_hf);
+int hns3_update_rss_algo_key(struct hns3_hw *hw, uint8_t hash_algo,
+			     uint8_t *key, uint8_t key_len);
 
 #endif /* _HNS3_RSS_H_ */
-- 
2.22.0


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

* [PATCH 20.11 3/3] net/hns3: add verification of RSS types
  2023-03-21  9:17 [PATCH 20.11 0/3] backport some patches for hns3 Huisong Li
  2023-03-21  9:17 ` [PATCH 20.11 1/3] net/hns3: fix burst mode query with dummy function Huisong Li
  2023-03-21  9:17 ` [PATCH 20.11 2/3] net/hns3: reimplement hash flow function Huisong Li
@ 2023-03-21  9:17 ` Huisong Li
  2 siblings, 0 replies; 4+ messages in thread
From: Huisong Li @ 2023-03-21  9:17 UTC (permalink / raw)
  To: stable, luca.boccassi; +Cc: liudongdong3, huangdaode, liuyonglong, lihuisong

[ upstream commit eb3ef9e0d7eb54b47ab58d3d14f9f5fff3f4120b ]

Add the verification of RSS types from ethdev ops and rte flow without
pattern attribute. The following cases are invalid:
1. types contains unsupported RSS type but hasn't type driver support.
2. types has L3 src/dst but hasn't supported packet type.
3. types has L4 src/dst but hasn't supported packet type and hasn't IP
   packet type.

Signed-off-by: Huisong Li <lihuisong@huawei.com>
Signed-off-by: Dongdong Liu <liudongdong3@huawei.com>
---
 drivers/net/hns3/hns3_flow.c | 12 ++++----
 drivers/net/hns3/hns3_rss.c  | 60 +++++++++++++++++++++++++++---------
 drivers/net/hns3/hns3_rss.h  |  2 +-
 3 files changed, 52 insertions(+), 22 deletions(-)

diff --git a/drivers/net/hns3/hns3_flow.c b/drivers/net/hns3/hns3_flow.c
index 202e4fafcd..3bc6061f30 100644
--- a/drivers/net/hns3/hns3_flow.c
+++ b/drivers/net/hns3/hns3_flow.c
@@ -1642,9 +1642,10 @@ hns3_flow_parse_rss_types(struct hns3_hw *hw,
 
 	/* no pattern specified to set global RSS types. */
 	if (pattern_type == 0) {
-		if (rss_act->types & ~HNS3_ETH_RSS_SUPPORT)
-			hns3_warn(hw, "some types in the requested RSS types (0x%" PRIx64 ") aren't supported, they are ignored.",
-				  rss_act->types);
+		if (!hns3_check_rss_types_valid(hw, rss_act->types))
+			return rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					NULL, "RSS types is invalid.");
 		rss_conf->hw_pctypes =
 				hns3_flow_get_all_hw_pctypes(rss_act->types);
 		return 0;
@@ -1919,15 +1920,14 @@ hns3_flow_set_rss_ptype_tuple(struct hns3_hw *hw,
 			uint64_t pctype = BIT_ULL(idx);
 
 			tuple_mask = hns3_flow_get_pctype_tuple_mask(pctype);
-			tuples = hns3_rss_calc_tuple_filed(hw,
-							rss_conf->conf.types);
+			tuples = hns3_rss_calc_tuple_filed(rss_conf->conf.types);
 			new_tuple_fields &= ~tuple_mask;
 			new_tuple_fields |= tuples;
 			hw_pctypes &= ~pctype;
 		}
 	} else {
 		new_tuple_fields =
-			hns3_rss_calc_tuple_filed(hw, rss_conf->conf.types);
+			hns3_rss_calc_tuple_filed(rss_conf->conf.types);
 	}
 
 	ret = hns3_set_rss_tuple_field(hw, new_tuple_fields);
diff --git a/drivers/net/hns3/hns3_rss.c b/drivers/net/hns3/hns3_rss.c
index 931ec61293..cb4a2bbede 100644
--- a/drivers/net/hns3/hns3_rss.c
+++ b/drivers/net/hns3/hns3_rss.c
@@ -492,34 +492,62 @@ hns3_rss_reset_indir_table(struct hns3_hw *hw)
 	return ret;
 }
 
-static void
-hns3_rss_check_l3l4_types(struct hns3_hw *hw, uint64_t rss_hf)
+bool
+hns3_check_rss_types_valid(struct hns3_hw *hw, uint64_t types)
 {
 	uint64_t ip_mask = ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4 |
 			   ETH_RSS_NONFRAG_IPV4_OTHER |
 			   ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6 |
 			   ETH_RSS_NONFRAG_IPV6_OTHER;
-	uint64_t l4_mask = ETH_RSS_NONFRAG_IPV4_TCP |
+	uint64_t ip_l4_mask = ETH_RSS_NONFRAG_IPV4_TCP |
 			   ETH_RSS_NONFRAG_IPV4_UDP |
 			   ETH_RSS_NONFRAG_IPV4_SCTP |
 			   ETH_RSS_NONFRAG_IPV6_TCP |
 			   ETH_RSS_NONFRAG_IPV6_UDP |
 			   ETH_RSS_NONFRAG_IPV6_SCTP;
-	uint64_t l3_src_dst_mask = ETH_RSS_L3_SRC_ONLY |
-				   ETH_RSS_L3_DST_ONLY;
-	uint64_t l4_src_dst_mask = ETH_RSS_L4_SRC_ONLY |
-				   ETH_RSS_L4_DST_ONLY;
+	bool has_l4_src_dst = !!(types & HNS3_RSS_SUPPORT_L4_SRC_DST);
+	bool has_ip_pkt = !!(types & ip_mask);
+	uint64_t final_types;
+
+	if (types == 0)
+		return true;
+
+	if ((types & HNS3_ETH_RSS_SUPPORT) == 0) {
+		hns3_err(hw, "specified types(0x%" PRIx64 ") are unsupported.",
+			 types);
+		return false;
+	}
+
+	if ((types & HNS3_RSS_SUPPORT_L3_SRC_DST) != 0 &&
+	    (types & HNS3_RSS_SUPPORT_FLOW_TYPE) == 0) {
+		hns3_err(hw, "IP or IP-TCP/UDP/SCTP packet type isn't specified, L3_SRC/DST_ONLY cannot be set.");
+		return false;
+	}
+
+	if (has_l4_src_dst && (types & ip_l4_mask) == 0) {
+		if (!has_ip_pkt) {
+			hns3_err(hw, "IP-TCP/UDP/SCTP packet type isn't specified, L4_SRC/DST_ONLY cannot be set.");
+			return false;
+		}
+		/*
+		 * For the case that the types has L4_SRC/DST_ONLY but hasn't
+		 * IP-TCP/UDP/SCTP packet type, this types is considered valid
+		 * if it also has IP packet type.
+		 */
+		hns3_warn(hw, "L4_SRC/DST_ONLY is ignored because of no including L4 packet.");
+	}
 
-	if (rss_hf & l3_src_dst_mask &&
-	    !(rss_hf & ip_mask || rss_hf & l4_mask))
-		hns3_warn(hw, "packet type isn't specified, L3_SRC/DST_ONLY is ignored.");
+	if ((types & ~HNS3_ETH_RSS_SUPPORT) != 0) {
+		final_types = types & HNS3_ETH_RSS_SUPPORT;
+		hns3_warn(hw, "set RSS types based on hardware support, requested:0x%" PRIx64 " configured:0x%" PRIx64 "",
+			  types, final_types);
+	}
 
-	if (rss_hf & l4_src_dst_mask && !(rss_hf & l4_mask))
-		hns3_warn(hw, "packet type isn't specified, L4_SRC/DST_ONLY is ignored.");
+	return true;
 }
 
 uint64_t
-hns3_rss_calc_tuple_filed(struct hns3_hw *hw, uint64_t rss_hf)
+hns3_rss_calc_tuple_filed(uint64_t rss_hf)
 {
 	uint64_t l3_only_mask = ETH_RSS_L3_SRC_ONLY |
 				ETH_RSS_L3_DST_ONLY;
@@ -548,7 +576,6 @@ hns3_rss_calc_tuple_filed(struct hns3_hw *hw, uint64_t rss_hf)
 		    !has_l3_l4_only)
 			tuple |= hns3_set_tuple_table[i].rss_field;
 	}
-	hns3_rss_check_l3l4_types(hw, rss_hf);
 
 	return tuple;
 }
@@ -576,7 +603,7 @@ hns3_set_rss_tuple_by_rss_hf(struct hns3_hw *hw, uint64_t rss_hf)
 	uint64_t tuple_fields;
 	int ret;
 
-	tuple_fields = hns3_rss_calc_tuple_filed(hw, rss_hf);
+	tuple_fields = hns3_rss_calc_tuple_filed(rss_hf);
 	ret = hns3_set_rss_tuple_field(hw, tuple_fields);
 	if (ret != 0)
 		hns3_err(hw, "Update RSS flow types tuples failed, ret = %d",
@@ -611,6 +638,9 @@ hns3_dev_rss_hash_update(struct rte_eth_dev *dev,
 		return -EINVAL;
 	}
 
+	if (!hns3_check_rss_types_valid(hw, rss_hf))
+		return -EINVAL;
+
 	rte_spinlock_lock(&hw->lock);
 	ret = hns3_set_rss_tuple_by_rss_hf(hw, rss_hf);
 	if (ret)
diff --git a/drivers/net/hns3/hns3_rss.h b/drivers/net/hns3/hns3_rss.h
index dc6f3cedd3..151880f65a 100644
--- a/drivers/net/hns3/hns3_rss.h
+++ b/drivers/net/hns3/hns3_rss.h
@@ -199,7 +199,7 @@ int hns3_set_rss_algo_key(struct hns3_hw *hw, uint8_t hash_algo,
 int hns3_restore_filter(struct hns3_adapter *hns);
 int hns3_rss_get_algo_key(struct hns3_hw *hw,  uint8_t *hash_algo,
 			  uint8_t *key, uint8_t key_len);
-uint64_t hns3_rss_calc_tuple_filed(struct hns3_hw *hw, uint64_t rss_hf);
+uint64_t hns3_rss_calc_tuple_filed(uint64_t rss_hf);
 int hns3_update_rss_algo_key(struct hns3_hw *hw, uint8_t hash_algo,
 			     uint8_t *key, uint8_t key_len);
 
-- 
2.22.0


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

end of thread, other threads:[~2023-03-21  9:19 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-21  9:17 [PATCH 20.11 0/3] backport some patches for hns3 Huisong Li
2023-03-21  9:17 ` [PATCH 20.11 1/3] net/hns3: fix burst mode query with dummy function Huisong Li
2023-03-21  9:17 ` [PATCH 20.11 2/3] net/hns3: reimplement hash flow function Huisong Li
2023-03-21  9:17 ` [PATCH 20.11 3/3] net/hns3: add verification of RSS types Huisong Li

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).