From 40a389f8a82d04698fb59742ea8987d1025c32ea Mon Sep 17 00:00:00 2001
From: Chengwen Feng <fengchengwen@huawei.com>
Date: Fri, 18 Oct 2024 14:19:41 +0800
Subject: [PATCH] net/hns3: support outer VLAN flow match

[ upstream commit a47328471c9a297dbe6caddf9db867cddc902f6d ]

The hardware FDIR supports many tuples match (including outer vlan),
however, the width of hardware entries is limited, therefore, only
part of tuples are enabled, unfortunately, outer vlan is not enabled.

This commit supports outer vlan match, to avoid affecting the current
use, use runtime config 'fdir_tuple_config' to enable this feature, the
options are as follows:
1. +outvlan-insmac:  means disable inner src mac tuple,
                     and enable outer vlan tuple.
2. +outvlan-indmac:  means disable inner dst mac tuple,
                     and enable outer vlan tuple.
3. +outvlan-insip:   means disable inner src ip tuple,
                     and enable outer vlan tuple.
4. +outvlan-indip:   means disable inner dst ip tuple,
                     and enable outer vlan tuple.
5. +outvlan-sctptag: means disable sctp tag tuple,
                     and enable outer vlan tuple.
6. +outvlan-tunvni:  means disable tunnel vni tuple,
                     and enable outer vlan tuple.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
Signed-off-by: Jie Hai <haijie1@huawei.com>
---
 doc/guides/nics/features/hns3.ini |   2 +-
 doc/guides/nics/hns3.rst          |  10 +++
 drivers/net/hns3/hns3_common.c    |  25 +++++++-
 drivers/net/hns3/hns3_common.h    |   1 +
 drivers/net/hns3/hns3_dump.c      |   4 +-
 drivers/net/hns3/hns3_ethdev.c    |   3 +
 drivers/net/hns3/hns3_fdir.c      | 103 ++++++++++++++++++++++++++++++
 drivers/net/hns3/hns3_fdir.h      |  51 +++++++++++++++
 drivers/net/hns3/hns3_flow.c      |  79 +++++++++++++++++++++--
 9 files changed, 269 insertions(+), 9 deletions(-)

diff --git a/doc/guides/nics/features/hns3.ini b/doc/guides/nics/features/hns3.ini
index a9480d6..6ac55f7 100644
--- a/doc/guides/nics/features/hns3.ini
+++ b/doc/guides/nics/features/hns3.ini
@@ -61,7 +61,7 @@ ptype                = P
 sctp                 = Y
 tcp                  = Y
 udp                  = Y
-vlan                 = P
+vlan                 = Y
 vxlan                = Y
 vxlan_gpe            = Y
 
diff --git a/doc/guides/nics/hns3.rst b/doc/guides/nics/hns3.rst
index 97b4686..4f0bc42 100644
--- a/doc/guides/nics/hns3.rst
+++ b/doc/guides/nics/hns3.rst
@@ -183,6 +183,16 @@ Runtime Configuration
 
     -a 0000:7d:00.0,fdir_vlan_match_mode=nostrict
 
+- ``fdir_tuple_config`` (default ``none``)
+
+  Used to customize the flow director tuples. Current supported options are follows:
+  ``+outvlan-insmac``: means disable inner src mac tuple, and enable outer vlan tuple.
+  ``+outvlan-indmac``: means disable inner dst mac tuple, and enable outer vlan tuple.
+  ``+outvlan-insip``: means disable inner src ip tuple, and enable outer vlan tuple.
+  ``+outvlan-indip``: means disable inner dst ip tuple, and enable outer vlan tuple.
+  ``+outvlan-sctptag``: means disable sctp tag tuple, and enable outer vlan tuple.
+  ``+outvlan-tunvni``: means disable tunnel vni tuple, and enable outer vlan tuple.
+
 Driver compilation and testing
 ------------------------------
 
diff --git a/drivers/net/hns3/hns3_common.c b/drivers/net/hns3/hns3_common.c
index 7a36673..99a1d59 100644
--- a/drivers/net/hns3/hns3_common.c
+++ b/drivers/net/hns3/hns3_common.c
@@ -272,6 +272,24 @@ hns3_parse_vlan_match_mode(const char *key, const char *value, void *args)
 	return 0;
 }
 
+static int
+hns3_parse_fdir_tuple_config(const char *key, const char *value, void *args)
+{
+	enum hns3_fdir_tuple_config tuple_cfg;
+
+	tuple_cfg = hns3_parse_tuple_config(value);
+	if (tuple_cfg == HNS3_FDIR_TUPLE_CONFIG_DEFAULT ||
+	    tuple_cfg == HNS3_FDIR_TUPLE_CONFIG_BUTT) {
+		PMD_INIT_LOG(WARNING, "invalid value:\"%s\" for key:\"%s\"",
+			     value, key);
+		return -1;
+	}
+
+	*(enum hns3_fdir_tuple_config *)args = tuple_cfg;
+
+	return 0;
+}
+
 void
 hns3_parse_devargs(struct rte_eth_dev *dev)
 {
@@ -306,11 +324,16 @@ hns3_parse_devargs(struct rte_eth_dev *dev)
 			   &hns3_parse_dev_caps_mask, &dev_caps_mask);
 	(void)rte_kvargs_process(kvlist, HNS3_DEVARG_MBX_TIME_LIMIT_MS,
 			   &hns3_parse_mbx_time_limit, &mbx_time_limit_ms);
-	if (!hns->is_vf)
+	if (!hns->is_vf) {
 		(void)rte_kvargs_process(kvlist,
 					 HNS3_DEVARG_FDIR_VLAN_MATCH_MODE,
 					 &hns3_parse_vlan_match_mode,
 					 &hns->pf.fdir.vlan_match_mode);
+		(void)rte_kvargs_process(kvlist,
+					 HNS3_DEVARG_FDIR_TUPLE_CONFIG,
+					 &hns3_parse_fdir_tuple_config,
+					 &hns->pf.fdir.tuple_cfg);
+	}
 
 	rte_kvargs_free(kvlist);
 
diff --git a/drivers/net/hns3/hns3_common.h b/drivers/net/hns3/hns3_common.h
index 1668520..ca90936 100644
--- a/drivers/net/hns3/hns3_common.h
+++ b/drivers/net/hns3/hns3_common.h
@@ -28,6 +28,7 @@ enum {
 #define HNS3_DEVARG_MBX_TIME_LIMIT_MS	"mbx_time_limit_ms"
 
 #define HNS3_DEVARG_FDIR_VLAN_MATCH_MODE	"fdir_vlan_match_mode"
+#define HNS3_DEVARG_FDIR_TUPLE_CONFIG	"fdir_tuple_config"
 
 #define MSEC_PER_SEC              1000L
 #define USEC_PER_MSEC             1000L
diff --git a/drivers/net/hns3/hns3_dump.c b/drivers/net/hns3/hns3_dump.c
index 5fee082..fbe3716 100644
--- a/drivers/net/hns3/hns3_dump.c
+++ b/drivers/net/hns3/hns3_dump.c
@@ -169,6 +169,7 @@ hns3_get_fdir_basic_info(FILE *file, struct hns3_pf *pf)
 		"\t  -- mode=%u max_key_len=%u rule_num:%u cnt_num:%u\n"
 		"\t  -- key_sel=%u tuple_active=0x%x meta_data_active=0x%x\n"
 		"\t  -- ipv6_word_en: in_s=%u in_d=%u out_s=%u out_d=%u\n"
+		"\t  -- tuple_config: %s\n"
 		"\t  -- active_tuples:\n",
 		fdcfg->fd_mode, fdcfg->max_key_length,
 		fdcfg->rule_num[HNS3_FD_STAGE_1],
@@ -179,7 +180,8 @@ hns3_get_fdir_basic_info(FILE *file, struct hns3_pf *pf)
 		fdcfg->key_cfg[HNS3_FD_STAGE_1].inner_sipv6_word_en,
 		fdcfg->key_cfg[HNS3_FD_STAGE_1].inner_dipv6_word_en,
 		fdcfg->key_cfg[HNS3_FD_STAGE_1].outer_sipv6_word_en,
-		fdcfg->key_cfg[HNS3_FD_STAGE_1].outer_dipv6_word_en);
+		fdcfg->key_cfg[HNS3_FD_STAGE_1].outer_dipv6_word_en,
+		hns3_tuple_config_name(pf->fdir.tuple_cfg));
 
 	for (i = 0; i < MAX_TUPLE; i++) {
 		if (!(fdcfg->key_cfg[HNS3_FD_STAGE_1].tuple_active & BIT(i)))
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 23a1fca..30b7aaa 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -6670,6 +6670,9 @@ RTE_PMD_REGISTER_PARAM_STRING(net_hns3,
 		HNS3_DEVARG_DEV_CAPS_MASK "=<1-65535> "
 		HNS3_DEVARG_MBX_TIME_LIMIT_MS "=<uint16> "
 		HNS3_DEVARG_FDIR_VLAN_MATCH_MODE "=strict|nostrict "
+		HNS3_DEVARG_FDIR_TUPLE_CONFIG "=+outvlan-insmac|+outvlan-indmac|"
+					      "+outvlan-insip|+outvlan-indip"
+					      "+outvlan-sctptag|+outvlan-tunvni ");
 RTE_LOG_REGISTER_SUFFIX(hns3_logtype_init, init, NOTICE);
 RTE_LOG_REGISTER_SUFFIX(hns3_logtype_driver, driver, NOTICE);
 #ifdef RTE_ETHDEV_DEBUG_RX
diff --git a/drivers/net/hns3/hns3_fdir.c b/drivers/net/hns3/hns3_fdir.c
index d100e58..389dec2 100644
--- a/drivers/net/hns3/hns3_fdir.c
+++ b/drivers/net/hns3/hns3_fdir.c
@@ -300,6 +300,58 @@ static int hns3_set_fd_key_config(struct hns3_adapter *hns)
 	return ret;
 }
 
+static void hns3_set_tuple_config(struct hns3_adapter *hns,
+				  struct hns3_fd_key_cfg *key_cfg)
+{
+	enum hns3_fdir_tuple_config tuple_cfg = hns->pf.fdir.tuple_cfg;
+
+	if (tuple_cfg == HNS3_FDIR_TUPLE_CONFIG_DEFAULT)
+		return;
+
+	if (hns->pf.fdir.fd_cfg.max_key_length != MAX_KEY_LENGTH) {
+		hns3_warn(&hns->hw, "fdir tuple config only valid with 400bit key!");
+		return;
+	}
+
+	switch (tuple_cfg) {
+	case HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_INSMAC:
+		key_cfg->tuple_active &= ~BIT(INNER_SRC_MAC);
+		key_cfg->tuple_active |= BIT(OUTER_VLAN_TAG_FST);
+		key_cfg->tuple_active |= BIT(OUTER_VLAN_TAG_SEC);
+		break;
+	case HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_INDMAC:
+		key_cfg->tuple_active &= ~BIT(INNER_DST_MAC);
+		key_cfg->tuple_active |= BIT(OUTER_VLAN_TAG_FST);
+		key_cfg->tuple_active |= BIT(OUTER_VLAN_TAG_SEC);
+		break;
+	case HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_INSIP:
+		key_cfg->tuple_active &= ~BIT(INNER_SRC_IP);
+		key_cfg->tuple_active |= BIT(OUTER_VLAN_TAG_FST);
+		key_cfg->tuple_active |= BIT(OUTER_VLAN_TAG_SEC);
+		break;
+	case HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_INDIP:
+		key_cfg->tuple_active &= ~BIT(INNER_DST_IP);
+		key_cfg->tuple_active |= BIT(OUTER_VLAN_TAG_FST);
+		key_cfg->tuple_active |= BIT(OUTER_VLAN_TAG_SEC);
+		break;
+	case HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_SCTPTAG:
+		key_cfg->tuple_active &= ~BIT(INNER_SCTP_TAG);
+		key_cfg->tuple_active |= BIT(OUTER_VLAN_TAG_FST);
+		key_cfg->tuple_active |= BIT(OUTER_VLAN_TAG_SEC);
+		break;
+	case HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_TUNVNI:
+		key_cfg->tuple_active &= ~BIT(OUTER_TUN_VNI);
+		key_cfg->tuple_active |= BIT(OUTER_VLAN_TAG_FST);
+		key_cfg->tuple_active |= BIT(OUTER_VLAN_TAG_SEC);
+		break;
+	default:
+		hns3_err(&hns->hw, "invalid fdir tuple config %u!", tuple_cfg);
+		return;
+	}
+
+	hns3_info(&hns->hw, "fdir tuple config %s!", hns3_tuple_config_name(tuple_cfg));
+}
+
 int hns3_init_fd_config(struct hns3_adapter *hns)
 {
 	struct hns3_pf *pf = &hns->pf;
@@ -352,6 +404,8 @@ int hns3_init_fd_config(struct hns3_adapter *hns)
 			 "l4_src_port l4_dst_port tun_vni tun_flow_id>");
 	}
 
+	hns3_set_tuple_config(hns, key_cfg);
+
 	/* roce_type is used to filter roce frames
 	 * dst_vport is used to specify the rule
 	 */
@@ -500,6 +554,14 @@ static void hns3_fd_convert_int16(uint32_t tuple, struct hns3_fdir_rule *rule,
 	uint16_t key;
 
 	switch (tuple) {
+	case OUTER_VLAN_TAG_FST:
+		key = rule->key_conf.spec.outer_vlan_tag1;
+		mask = rule->key_conf.mask.outer_vlan_tag1;
+		break;
+	case OUTER_VLAN_TAG_SEC:
+		key = rule->key_conf.spec.outer_vlan_tag2;
+		mask = rule->key_conf.mask.outer_vlan_tag2;
+		break;
 	case OUTER_SRC_PORT:
 		key = rule->key_conf.spec.outer_src_port;
 		mask = rule->key_conf.mask.outer_src_port;
@@ -575,6 +637,8 @@ static bool hns3_fd_convert_tuple(struct hns3_hw *hw,
 		hns3_fd_convert_mac(key_conf->spec.src_mac,
 				    key_conf->mask.src_mac, key_x, key_y);
 		break;
+	case OUTER_VLAN_TAG_FST:
+	case OUTER_VLAN_TAG_SEC:
 	case OUTER_SRC_PORT:
 	case OUTER_DST_PORT:
 	case OUTER_ETH_TYPE:
@@ -1128,3 +1192,42 @@ int hns3_fd_get_count(struct hns3_hw *hw, uint32_t id, uint64_t *value)
 
 	return ret;
 }
+
+static struct {
+	enum hns3_fdir_tuple_config tuple_cfg;
+	const char *name;
+} tuple_config_map[] = {
+	{ HNS3_FDIR_TUPLE_CONFIG_DEFAULT,          "default"          },
+	{ HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_INSMAC,  "+outvlan-insmac"  },
+	{ HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_INDMAC,  "+outvlan-indmac"  },
+	{ HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_INSIP,   "+outvlan-insip"   },
+	{ HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_INDIP,   "+outvlan-indip"   },
+	{ HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_SCTPTAG, "+outvlan-sctptag" },
+	{ HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_TUNVNI,  "+outvlan-tunvni"  }
+};
+
+enum hns3_fdir_tuple_config
+hns3_parse_tuple_config(const char *name)
+{
+	uint32_t i;
+
+	for (i = 0; i < RTE_DIM(tuple_config_map); i++) {
+		if (!strcmp(name, tuple_config_map[i].name))
+			return tuple_config_map[i].tuple_cfg;
+	}
+
+	return HNS3_FDIR_TUPLE_CONFIG_BUTT;
+}
+
+const char *
+hns3_tuple_config_name(enum hns3_fdir_tuple_config tuple_cfg)
+{
+	uint32_t i;
+
+	for (i = 0; i < RTE_DIM(tuple_config_map); i++) {
+		if (tuple_cfg == tuple_config_map[i].tuple_cfg)
+			return tuple_config_map[i].name;
+	}
+
+	return "unknown";
+}
diff --git a/drivers/net/hns3/hns3_fdir.h b/drivers/net/hns3/hns3_fdir.h
index 6ccd90a..2d0c9bf 100644
--- a/drivers/net/hns3/hns3_fdir.h
+++ b/drivers/net/hns3/hns3_fdir.h
@@ -97,6 +97,8 @@ struct hns3_fd_rule_tuples {
 	uint32_t sctp_tag;
 	uint16_t outer_src_port;
 	uint16_t tunnel_type;
+	uint16_t outer_vlan_tag1;
+	uint16_t outer_vlan_tag2;
 	uint16_t outer_ether_type;
 	uint8_t outer_proto;
 	uint8_t outer_tun_vni[VNI_OR_TNI_LEN];
@@ -181,6 +183,51 @@ TAILQ_HEAD(hns3_fdir_rule_list, hns3_fdir_rule_ele);
 #define HNS3_FDIR_VLAN_STRICT_MATCH	1
 #define HNS3_FDIR_VLAN_NOSTRICT_MATCH	0
 
+/*
+ * The hardware supports many tuples match (see @enum HNS3_FD_TUPLE),
+ * however, the width of hardware entries is limited, therefore, only part
+ * of tuples are enabled (see as @hns3_init_fd_config).
+ *
+ * We should replace the existing tuples if we want to enable other tuples
+ * because the width capacity is insufficient.
+ */
+enum hns3_fdir_tuple_config {
+	/* Default tuple config (see as @hns3_init_fd_config). */
+	HNS3_FDIR_TUPLE_CONFIG_DEFAULT,
+	/*
+	 * Based on the default tuple config, disable the inner src-mac tuple,
+	 * and enable the outer VLAN tuple.
+	 */
+	HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_INSMAC,
+	/*
+	 * Based on the default tuple config, disable the inner dst-mac tuple,
+	 * and enable the outer VLAN tuple.
+	 */
+	HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_INDMAC,
+	/*
+	 * Based on the default tuple config, disable the inner src-ip tuple,
+	 * and enable the outer VLAN tuple.
+	 */
+	HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_INSIP,
+	/*
+	 * Based on the default tuple config, disable the inner dst-ip tuple,
+	 * and enable the outer VLAN tuple.
+	 */
+	HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_INDIP,
+	/*
+	 * Based on the default tuple config, disable the sctp-tag tuple,
+	 * and enable the outer VLAN tuple.
+	 */
+	HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_SCTPTAG,
+	/*
+	 * Based on the default tuple config, disable the tunnel vni tuple,
+	 * and enable the outer VLAN tuple.
+	 */
+	HNS3_FDIR_TUPLE_OUTVLAN_REPLACE_TUNVNI,
+
+	HNS3_FDIR_TUPLE_CONFIG_BUTT
+};
+
 /*
  *  A structure used to define fields of a FDIR related info.
  */
@@ -190,6 +237,7 @@ struct hns3_fdir_info {
 	struct rte_hash *hash_handle;
 	struct hns3_fd_cfg fd_cfg;
 	uint8_t vlan_match_mode;
+	enum hns3_fdir_tuple_config tuple_cfg;
 };
 
 struct hns3_adapter;
@@ -204,4 +252,7 @@ int hns3_clear_all_fdir_filter(struct hns3_adapter *hns);
 int hns3_fd_get_count(struct hns3_hw *hw, uint32_t id, uint64_t *value);
 int hns3_restore_all_fdir_filter(struct hns3_adapter *hns);
 
+enum hns3_fdir_tuple_config hns3_parse_tuple_config(const char *name);
+const char *hns3_tuple_config_name(enum hns3_fdir_tuple_config tuple_cfg);
+
 #endif /* HNS3_FDIR_H */
diff --git a/drivers/net/hns3/hns3_flow.c b/drivers/net/hns3/hns3_flow.c
index 89ee2c6..4674f74 100644
--- a/drivers/net/hns3/hns3_flow.c
+++ b/drivers/net/hns3/hns3_flow.c
@@ -608,6 +608,59 @@ hns3_check_attr(const struct rte_flow_attr *attr, struct rte_flow_error *error)
 	return 0;
 }
 
+static int
+hns3_check_tuple(const struct rte_eth_dev *dev, const struct hns3_fdir_rule *rule,
+		 struct rte_flow_error *error)
+{
+	const char * const err_msg[] = {
+		"Not support outer dst mac",
+		"Not support outer src mac",
+		"Not support outer vlan1 tag",
+		"Not support outer vlan2 tag",
+		"Not support outer eth type",
+		"Not support outer l2 rsv",
+		"Not support outer ip tos",
+		"Not support outer ip proto",
+		"Not support outer src ip",
+		"Not support outer dst ip",
+		"Not support outer l3 rsv",
+		"Not support outer src port",
+		"Not support outer dst port",
+		"Not support outer l4 rsv",
+		"Not support outer tun vni",
+		"Not support outer tun flow id",
+		"Not support inner dst mac",
+		"Not support inner src mac",
+		"Not support inner vlan tag1",
+		"Not support inner vlan tag2",
+		"Not support inner eth type",
+		"Not support inner l2 rsv",
+		"Not support inner ip tos",
+		"Not support inner ip proto",
+		"Not support inner src ip",
+		"Not support inner dst ip",
+		"Not support inner l3 rsv",
+		"Not support inner src port",
+		"Not support inner dst port",
+		"Not support inner sctp tag",
+	};
+	struct hns3_adapter *hns = dev->data->dev_private;
+	uint32_t tuple_active = hns->pf.fdir.fd_cfg.key_cfg[HNS3_FD_STAGE_1].tuple_active;
+	uint32_t i;
+
+	for (i = 0; i < MAX_TUPLE; i++) {
+		if ((rule->input_set & BIT(i)) == 0)
+			continue;
+		if (tuple_active & BIT(i))
+			continue;
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ITEM,
+					  NULL, err_msg[i]);
+	}
+
+	return 0;
+}
+
 static int
 hns3_parse_eth(const struct rte_flow_item *item, struct hns3_fdir_rule *rule,
 	       struct rte_flow_error *error __rte_unused)
@@ -1029,12 +1082,22 @@ hns3_handle_tunnel(const struct rte_flow_item *item,
 		rule->key_conf.mask.ether_type = 0;
 	}
 
-	/* check vlan config */
-	if (rule->input_set & (BIT(INNER_VLAN_TAG1) | BIT(INNER_VLAN_TAG2)))
-		return rte_flow_error_set(error, EINVAL,
-					  RTE_FLOW_ERROR_TYPE_ITEM,
-					  item,
-					  "Outer vlan tags is unsupported");
+	if (rule->input_set & BIT(INNER_VLAN_TAG1)) {
+		hns3_set_bit(rule->input_set, OUTER_VLAN_TAG_FST, 1);
+		hns3_set_bit(rule->input_set, INNER_VLAN_TAG1, 0);
+		rule->key_conf.spec.outer_vlan_tag1 = rule->key_conf.spec.vlan_tag1;
+		rule->key_conf.mask.outer_vlan_tag1 = rule->key_conf.mask.vlan_tag1;
+		rule->key_conf.spec.vlan_tag1 = 0;
+		rule->key_conf.mask.vlan_tag1 = 0;
+	}
+	if (rule->input_set & BIT(INNER_VLAN_TAG2)) {
+		hns3_set_bit(rule->input_set, OUTER_VLAN_TAG_SEC, 1);
+		hns3_set_bit(rule->input_set, INNER_VLAN_TAG2, 0);
+		rule->key_conf.spec.outer_vlan_tag2 = rule->key_conf.spec.vlan_tag2;
+		rule->key_conf.mask.outer_vlan_tag2 = rule->key_conf.mask.vlan_tag2;
+		rule->key_conf.spec.vlan_tag2 = 0;
+		rule->key_conf.mask.vlan_tag2 = 0;
+	}
 
 	/* clear vlan_num for inner vlan select */
 	rule->key_conf.outer_vlan_num = rule->key_conf.vlan_num;
@@ -1444,6 +1507,10 @@ hns3_parse_fdir_filter(struct rte_eth_dev *dev,
 		}
 	}
 
+	ret = hns3_check_tuple(dev, rule, error);
+	if (ret)
+		return ret;
+
 	return hns3_handle_actions(dev, actions, rule, error);
 }
 
-- 
2.33.0

