The flow rule parser was based on a fixed hardcoded pattern table that was
hard to extend. Replace it with a simpler protocol-graph classifier, and
add IP-in-IP and Geneve tunnel patterns.

Signed-off-by: Jiacheng Ye <[email protected]>
---
 doc/guides/nics/features/hinic3.ini |   2 +
 drivers/net/hinic3/hinic3_fdir.c    |  65 ++-
 drivers/net/hinic3/hinic3_fdir.h    |  14 +-
 drivers/net/hinic3/hinic3_flow.c    | 594 ++++++++++++++++++++--------
 drivers/net/hinic3/hinic3_flow.h    | 196 ---------
 5 files changed, 478 insertions(+), 393 deletions(-)
 delete mode 100644 drivers/net/hinic3/hinic3_flow.h

diff --git a/doc/guides/nics/features/hinic3.ini 
b/doc/guides/nics/features/hinic3.ini
index 8083dc63d1..14f152a604 100644
--- a/doc/guides/nics/features/hinic3.ini
+++ b/doc/guides/nics/features/hinic3.ini
@@ -43,12 +43,14 @@ ARMv8                = Y
 [rte_flow items]
 any                  = Y
 eth                  = P
+geneve               = Y
 icmp                 = Y
 ipv4                 = Y
 ipv6                 = Y
 tcp                  = Y
 udp                  = Y
 vxlan                = Y
+vxlan_gpe            = Y
 
 [rte_flow actions]
 queue                = Y
diff --git a/drivers/net/hinic3/hinic3_fdir.c b/drivers/net/hinic3/hinic3_fdir.c
index 71d50a3d22..2b9b25f65a 100644
--- a/drivers/net/hinic3/hinic3_fdir.c
+++ b/drivers/net/hinic3/hinic3_fdir.c
@@ -77,8 +77,6 @@ hinic3_fdir_tcam_ipv4_init(struct hinic3_fdir_filter *rule,
        /* Fill type of ip. */
        tcam_key->key_mask.ip_type = HINIC3_UINT1_MAX;
        tcam_key->key_info.ip_type = HINIC3_FDIR_IP_TYPE_IPV4;
-       tcam_key->key_mask.vlan_flag = HINIC3_UINT1_MAX;
-       tcam_key->key_info.vlan_flag = 0;
 
        /* Fill src IPv4. */
        tcam_key->key_mask.sipv4_h =
@@ -101,8 +99,9 @@ hinic3_fdir_tcam_ipv4_init(struct hinic3_fdir_filter *rule,
                HINIC3_32_LOWER_16_BITS(rule->key_spec.ipv4.dst_ip);
 }
 
-static void hinic3_fdir_ipv6_tcam_key_init_sip(struct hinic3_fdir_filter *rule,
-                                              struct hinic3_tcam_key *tcam_key)
+static inline void
+hinic3_fdir_ipv6_tcam_key_init_sip(struct hinic3_fdir_filter *rule,
+                                  struct hinic3_tcam_key *tcam_key)
 {
        tcam_key->key_mask_ipv6.sipv6_key0 =
                HINIC3_32_UPPER_16_BITS(rule->key_mask.ipv6.src_ip[0]);
@@ -138,8 +137,9 @@ static void hinic3_fdir_ipv6_tcam_key_init_sip(struct 
hinic3_fdir_filter *rule,
                HINIC3_32_LOWER_16_BITS(rule->key_spec.ipv6.src_ip[0x3]);
 }
 
-static void hinic3_fdir_ipv6_tcam_key_init_dip(struct hinic3_fdir_filter *rule,
-                                              struct hinic3_tcam_key *tcam_key)
+static inline void
+hinic3_fdir_ipv6_tcam_key_init_dip(struct hinic3_fdir_filter *rule,
+                                  struct hinic3_tcam_key *tcam_key)
 {
        tcam_key->key_mask_ipv6.dipv6_key0 =
                HINIC3_32_UPPER_16_BITS(rule->key_mask.ipv6.dst_ip[0]);
@@ -175,8 +175,9 @@ static void hinic3_fdir_ipv6_tcam_key_init_dip(struct 
hinic3_fdir_filter *rule,
                HINIC3_32_LOWER_16_BITS(rule->key_spec.ipv6.dst_ip[0x3]);
 }
 
-static void hinic3_fdir_ipv6_tcam_key_init(struct hinic3_fdir_filter *rule,
-                                          struct hinic3_tcam_key *tcam_key)
+static void
+hinic3_fdir_ipv6_tcam_key_init(struct hinic3_fdir_filter *rule,
+                              struct hinic3_tcam_key *tcam_key)
 {
        hinic3_fdir_ipv6_tcam_key_init_sip(rule, tcam_key);
        hinic3_fdir_ipv6_tcam_key_init_dip(rule, tcam_key);
@@ -240,15 +241,11 @@ hinic3_fdir_tcam_notunnel_init(struct rte_eth_dev *dev,
 }
 
 static void
-hinic3_fdir_tcam_vxlan_ipv4_init(struct hinic3_fdir_filter *rule,
+hinic3_fdir_tcam_vxlan_geneve_ipv4_init(struct hinic3_fdir_filter *rule,
                                 struct hinic3_tcam_key *tcam_key)
 {
-       /* Fill type of ip. */
        tcam_key->key_mask.ip_type = HINIC3_UINT1_MAX;
        tcam_key->key_info.ip_type = HINIC3_FDIR_IP_TYPE_IPV4;
-       tcam_key->key_mask.vlan_flag = HINIC3_UINT1_MAX;
-       tcam_key->key_info.vlan_flag = 0;
-
        /* Fill src ipv4. */
        tcam_key->key_mask.sipv4_h =
                HINIC3_32_UPPER_16_BITS(rule->key_mask.inner_ipv4.src_ip);
@@ -271,7 +268,7 @@ hinic3_fdir_tcam_vxlan_ipv4_init(struct hinic3_fdir_filter 
*rule,
 }
 
 static void
-hinic3_fdir_tcam_vxlan_ipv6_init(struct hinic3_fdir_filter *rule,
+hinic3_fdir_tcam_vxlan_geneve_ipv6_init(struct hinic3_fdir_filter *rule,
                                 struct hinic3_tcam_key *tcam_key)
 {
        /* Fill type of ip. */
@@ -359,7 +356,7 @@ hinic3_fdir_tcam_ipv6_vxlan_init(struct rte_eth_dev *dev,
  * Pointer to the TCAM key.
  */
 static void
-hinic3_fdir_tcam_vxlan_init(struct rte_eth_dev *dev,
+hinic3_fdir_tcam_vxlan_geneve_init(struct rte_eth_dev *dev,
                            struct hinic3_fdir_filter *rule,
                            struct hinic3_tcam_key *tcam_key)
 {
@@ -416,10 +413,10 @@ hinic3_fdir_tcam_vxlan_init(struct rte_eth_dev *dev,
                                         HINIC3_UINT15_MAX;
 
        if (rule->ip_type == HINIC3_FDIR_IP_TYPE_IPV4)
-               hinic3_fdir_tcam_vxlan_ipv4_init(rule, tcam_key);
+               hinic3_fdir_tcam_vxlan_geneve_ipv4_init(rule, tcam_key);
 
        else if (rule->ip_type == HINIC3_FDIR_IP_TYPE_IPV6)
-               hinic3_fdir_tcam_vxlan_ipv6_init(rule, tcam_key);
+               hinic3_fdir_tcam_vxlan_geneve_ipv6_init(rule, tcam_key);
 }
 
 static void
@@ -432,7 +429,7 @@ hinic3_fdir_tcam_info_init(struct rte_eth_dev *dev,
        if (rule->tunnel_type == HINIC3_FDIR_TUNNEL_MODE_NORMAL)
                hinic3_fdir_tcam_notunnel_init(dev, rule, tcam_key);
        else
-               hinic3_fdir_tcam_vxlan_init(dev, rule, tcam_key);
+               hinic3_fdir_tcam_vxlan_geneve_init(dev, rule, tcam_key);
 
        /* Set the queue index. */
        fdir_tcam_rule->data.qid = rule->rq_index;
@@ -841,7 +838,7 @@ hinic3_dynamic_lookup_tcam_filter(struct hinic3_nic_dev 
*nic_dev,
         * capacity of dynamic TCAM blocks.
         */
        if (rule_nums >= block_cnt * HINIC3_TCAM_DYNAMIC_BLOCK_SIZE) {
-               if (block_cnt >= (HINIC3_TCAM_DYNAMIC_MAX_FILTERS /
+               if (block_cnt >= (HINIC3_TCAM_DYNAMIC_MAX_FILTERS(nic_dev) /
                                  HINIC3_TCAM_DYNAMIC_BLOCK_SIZE)) {
                        PMD_DRV_LOG(ERR,
                                "Dynamic tcam block is full, alloc failed!");
@@ -1001,6 +998,9 @@ hinic3_set_fdir_ethertype_filter(void *hwdev, uint8_t 
pkt_type, void *filter, ui
                PMD_DRV_LOG(ERR,
                            "set fdir ethertype rule failed, err: %d, status: 
0x%x, out size: 0x%x, func_id %d",
                            err, ethertype_cmd.head.status, out_size, 
ethertype_cmd.func_id);
+               if ((hinic3_get_driver_feature(nic_dev) & NIC_F_HTN_FDIR) != 0 
&& en != 0)
+                       hinic3_tcam_index_free(nic_dev, 
HINIC3_TCAM_GET_INDEX_IN_BLOCK(index),
+                               HINIC3_TCAM_GET_DYNAMIC_BLOCK_INDEX(index));
                return -EIO;
        }
        if ((hinic3_get_driver_feature(nic_dev) & NIC_F_HTN_FDIR) != 0) {
@@ -1213,24 +1213,16 @@ hinic3_flow_add_del_fdir_filter(struct rte_eth_dev *dev,
        else
                hinic3_fdir_tcam_info_htn_init(dev, fdir_filter, &tcam_key, 
&fdir_tcam_rule);
 
-       /* Search for a filter. */
-       tcam_filter =
-               hinic3_tcam_filter_lookup(&tcam_info->tcam_list, &tcam_key,
-                                         HINIC3_ACTION_ADD, 
HINIC3_INVALID_INDEX);
-       if (tcam_filter != NULL && add) {
-               PMD_DRV_LOG(ERR, "Filter exists.");
-               return -EEXIST;
-       }
-       if (tcam_filter == NULL && !add) {
-               PMD_DRV_LOG(ERR, "Filter doesn't exist.");
-               return -ENOENT;
-       }
-
-       /*
-        * If the value of Add is true, the system performs the adding
-        * operation.
-        */
        if (add) {
+               /* Search for a filter. */
+               tcam_filter =
+                       hinic3_tcam_filter_lookup(&tcam_info->tcam_list, 
&tcam_key,
+                                                 HINIC3_ACTION_ADD, 
HINIC3_INVALID_INDEX);
+               if (tcam_filter != NULL) {
+                       PMD_DRV_LOG(ERR, "Filter exists.");
+                       return -EEXIST;
+               }
+
                ret = hinic3_add_tcam_filter(dev, &tcam_key, &fdir_tcam_rule);
                if (ret)
                        goto cfg_tcam_filter_err;
@@ -1594,6 +1586,7 @@ hinic3_flow_add_del_ethertype_filter(struct rte_eth_dev 
*dev,
        /* Get dev private info. */
        struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
        int ret;
+
        /* Add or remove an Ethernet type filter rule. */
        ret = hinic3_flow_add_del_ethertype_filter_rule(dev, ethertype_filter, 
add);
 
diff --git a/drivers/net/hinic3/hinic3_fdir.h b/drivers/net/hinic3/hinic3_fdir.h
index 277d89d4fd..997587554d 100644
--- a/drivers/net/hinic3/hinic3_fdir.h
+++ b/drivers/net/hinic3/hinic3_fdir.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2025 Huawei Technologies Co., Ltd
+ * Copyright (c) 2025-2026 Huawei Technologies Co., Ltd
  */
 
 #ifndef _HINIC3_FDIR_H_
@@ -8,8 +8,13 @@
 #define HINIC3_FLOW_MAX_PATTERN_NUM 16
 
 #define HINIC3_TCAM_DYNAMIC_BLOCK_SIZE 16
+#define HINIC3_TCAM_DYNAMIC_MAX_FILTERS(nic_dev)         \
+               (HINIC3_IS_SP230_NIC(nic_dev)            \
+               ? HINIC3_TCAM_DYNAMIC_MAX_FILTERS_HTN    \
+               : HINIC3_TCAM_DYNAMIC_MAX_FILTERS_STN)
 
-#define HINIC3_TCAM_DYNAMIC_MAX_FILTERS 1024
+#define HINIC3_TCAM_DYNAMIC_MAX_FILTERS_STN 2048
+#define HINIC3_TCAM_DYNAMIC_MAX_FILTERS_HTN 1024
 
 #define HINIC3_PKT_TCAM_DYNAMIC_INDEX_START(block_index) \
        (HINIC3_TCAM_DYNAMIC_BLOCK_SIZE * (block_index))
@@ -96,6 +101,7 @@ enum hinic3_fdir_tunnel_mode {
        HINIC3_FDIR_TUNNEL_MODE_GENEVE = 5,
        HINIC3_FDIR_TUNNEL_MODE_NSH    = 6,
        HINIC3_FDIR_TUNNEL_MODE_IPIP   = 7,
+       HINIC3_FDIR_TUNNEL_MODE_MAX    = 8,
 };
 
 enum hinic3_fdir_ip_type {
@@ -186,7 +192,7 @@ struct hinic3_tcam_key_mem_htn {
        uint32_t rsvd0 : 16;
        uint32_t ip_proto : 8;
        uint32_t tunnel_type : 3;
-       uint32_t function_id_h: 5;
+       uint32_t function_id_h : 5;
 
        uint32_t function_id_l : 5;
        uint32_t ip_type : 2;
@@ -250,7 +256,7 @@ struct hinic3_tcam_key_mem_htn {
        uint32_t rsvd8 : 16;
 
        uint32_t sport : 16;
-       uint32_t dipv4_l :16;
+       uint32_t dipv4_l : 16;
 
        uint32_t rsvd9 : 16;
        uint32_t dport : 16;
diff --git a/drivers/net/hinic3/hinic3_flow.c b/drivers/net/hinic3/hinic3_flow.c
index 1f686d4675..b2da5c6347 100644
--- a/drivers/net/hinic3/hinic3_flow.c
+++ b/drivers/net/hinic3/hinic3_flow.c
@@ -8,7 +8,6 @@
 #include "base/hinic3_hwdev.h"
 #include "base/hinic3_nic_cfg.h"
 #include "hinic3_ethdev.h"
-#include "hinic3_flow.h"
 
 #define HINIC3_UINT8_MAX 0xff
 
@@ -19,12 +18,6 @@ typedef int (*hinic3_parse_filter_t)(struct rte_eth_dev *dev,
                                     struct rte_flow_error *error,
                                     struct hinic3_filter_t *filter);
 
-/* Indicate valid filter mode . */
-struct hinic3_valid_pattern {
-       enum rte_flow_item_type *items;
-       hinic3_parse_filter_t parse_filter;
-};
-
 static int hinic3_flow_parse_fdir_filter(struct rte_eth_dev *dev,
                                         const struct rte_flow_attr *attr,
                                         const struct rte_flow_item pattern[],
@@ -39,65 +32,12 @@ static int hinic3_flow_parse_ethertype_filter(struct 
rte_eth_dev *dev,
                                              struct rte_flow_error *error,
                                              struct hinic3_filter_t *filter);
 
-static int hinic3_flow_parse_fdir_vxlan_filter(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 hinic3_filter_t *filter);
-
-/*
- * Define a supported pattern array, including the matching patterns of
- * various network protocols and corresponding parsing functions.
- */
-static const struct hinic3_valid_pattern hinic3_supported_patterns[] = {
-       /* Support ethertype. */
-       {pattern_ethertype, hinic3_flow_parse_ethertype_filter},
-       /* Support ipv4 but not tunnel, and any field can be masked. */
-       {pattern_ipv4, hinic3_flow_parse_fdir_filter},
-       {pattern_ipv4_any, hinic3_flow_parse_fdir_filter},
-       /* Support ipv4 + l4 but not tunnel, and any field can be masked. */
-       {pattern_ipv4_udp, hinic3_flow_parse_fdir_filter},
-       {pattern_ipv4_tcp, hinic3_flow_parse_fdir_filter},
-       /* Support ipv4 + icmp not tunnel, and any field can be masked. */
-       {pattern_ipv4_icmp, hinic3_flow_parse_fdir_filter},
-
-       /* Support ipv4 + l4 but not tunnel, and any field can be masked. */
-       {pattern_ethertype_udp, hinic3_flow_parse_fdir_filter},
-       {pattern_ethertype_tcp, hinic3_flow_parse_fdir_filter},
-
-       /* Support ipv4 + vxlan + any, and any field can be masked. */
-       {pattern_ipv4_vxlan, hinic3_flow_parse_fdir_vxlan_filter},
-       /* Support ipv4 + vxlan + ipv4, and any field can be masked. */
-       {pattern_ipv4_vxlan_ipv4, hinic3_flow_parse_fdir_vxlan_filter},
-       /* Support ipv4 + vxlan + ipv4 + l4, and any field can be masked. */
-       {pattern_ipv4_vxlan_ipv4_tcp, hinic3_flow_parse_fdir_vxlan_filter},
-       {pattern_ipv4_vxlan_ipv4_udp, hinic3_flow_parse_fdir_vxlan_filter},
-       /* Support ipv4 + vxlan + ipv6, and any field can be masked. */
-       {pattern_ipv4_vxlan_ipv6, hinic3_flow_parse_fdir_vxlan_filter},
-       /* Support ipv4 + vxlan + ipv6 + l4, and any field can be masked. */
-       {pattern_ipv4_vxlan_ipv6_tcp, hinic3_flow_parse_fdir_vxlan_filter},
-       {pattern_ipv4_vxlan_ipv6_udp, hinic3_flow_parse_fdir_vxlan_filter},
-       /* Support ipv4 + vxlan + l4, and any field can be masked. */
-       {pattern_ipv4_vxlan_tcp, hinic3_flow_parse_fdir_vxlan_filter},
-       {pattern_ipv4_vxlan_udp, hinic3_flow_parse_fdir_vxlan_filter},
-       {pattern_ipv4_vxlan_any, hinic3_flow_parse_fdir_vxlan_filter},
-
-       /* Support ipv6 but not tunnel, and any field can be masked. */
-       {pattern_ipv6, hinic3_flow_parse_fdir_filter},
-       /* Support ipv6 + l4 but not tunnel, and any field can be masked. */
-       {pattern_ipv6_udp, hinic3_flow_parse_fdir_filter},
-       {pattern_ipv6_tcp, hinic3_flow_parse_fdir_filter},
-
-       /* Support ipv6 + vxlan + any, and any field can be masked. */
-       {pattern_ipv6_vxlan, hinic3_flow_parse_fdir_vxlan_filter},
-       {pattern_ipv6_vxlan_any, hinic3_flow_parse_fdir_vxlan_filter},
-
-       /* Support ipv6 + vxlan + l4, and any field can be masked. */
-       {pattern_ipv6_vxlan_tcp, hinic3_flow_parse_fdir_vxlan_filter},
-       {pattern_ipv6_vxlan_udp, hinic3_flow_parse_fdir_vxlan_filter},
-
-};
+static int hinic3_flow_parse_fdir_vxlan_geneve_filter(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 hinic3_filter_t 
*filter);
 
 static inline void
 net_addr_to_host(uint32_t *dst, const uint32_t *src, size_t len)
@@ -107,30 +47,243 @@ net_addr_to_host(uint32_t *dst, const uint32_t *src, 
size_t len)
                dst[i] = rte_be_to_cpu_32(src[i]);
 }
 
-static bool
-hinic3_match_pattern(enum rte_flow_item_type *item_array,
-                    const struct rte_flow_item *pattern)
-{
-       const struct rte_flow_item *item = pattern;
+/* IPINIP and GPE are split out due to chip support differences. */
+enum hinic3_flow_filter_kind {
+       HINIC3_FLOW_KIND_ETHERTYPE,     /* [ETH]. */
+       HINIC3_FLOW_KIND_NON_TUNNEL,    /* single L3/L4 or ethertype L4. */
+       HINIC3_FLOW_KIND_VXLAN_GENEVE,  /* vxlan/geneve. */
+       HINIC3_FLOW_KIND_GPE,           /* vxlan-gpe. */
+       HINIC3_FLOW_KIND_IPINIP,        /* ip-in-ip. */
+       HINIC3_FLOW_KIND_INVALID,
+};
+
+/*
+ * The pattern is parsed as a small protocol graph. Every supported pattern
+ * starts with ETH and then follows one of the supported encapsulation paths
+ * (plain L3/L4, tunneled, or ip-in-ip). VOID items are transparent.
+ */
 
-       /* skip the first void item. */
+/* Peek at the next non-VOID item type. */
+static enum rte_flow_item_type
+hinic3_flow_next(const struct rte_flow_item *item)
+{
        while (item->type == RTE_FLOW_ITEM_TYPE_VOID)
                item++;
 
-       /* Find no void item. */
-       while (((*item_array == item->type) &&
-               (*item_array != RTE_FLOW_ITEM_TYPE_END)) ||
-              (item->type == RTE_FLOW_ITEM_TYPE_VOID)) {
-               if (item->type == RTE_FLOW_ITEM_TYPE_VOID) {
-                       item++;
-               } else {
-                       item_array++;
-                       item++;
+       return item->type;
+}
+
+/* Consume the next non-VOID item when it matches @p type. */
+static bool
+hinic3_flow_take(const struct rte_flow_item **item,
+                enum rte_flow_item_type type)
+{
+       while ((*item)->type == RTE_FLOW_ITEM_TYPE_VOID)
+               (*item)++;
+
+       if ((*item)->type != type)
+               return false;
+
+       (*item)++;
+       return true;
+}
+
+/* Return true when only the END item remains. */
+static bool
+hinic3_flow_at_end(const struct rte_flow_item *item)
+{
+       return hinic3_flow_next(item) == RTE_FLOW_ITEM_TYPE_END;
+}
+
+/* Finish a branch, which is valid only when END is reached. */
+static enum hinic3_flow_filter_kind
+hinic3_flow_finish(const struct rte_flow_item *item,
+                  enum hinic3_flow_filter_kind kind)
+{
+       return hinic3_flow_at_end(item) ? kind : HINIC3_FLOW_KIND_INVALID;
+}
+
+/* Classify an inner L3 (IPv4/IPv6) with an optional L4, returning @p kind. */
+static enum hinic3_flow_filter_kind
+hinic3_flow_classify_inner(const struct rte_flow_item **item,
+                          enum hinic3_flow_filter_kind kind,
+                          enum rte_flow_item_type outer_ip)
+{
+       enum rte_flow_item_type next = hinic3_flow_next(*item);
+
+       if (next != RTE_FLOW_ITEM_TYPE_IPV4 &&
+           next != RTE_FLOW_ITEM_TYPE_IPV6)
+               return HINIC3_FLOW_KIND_INVALID;
+
+       /*
+        * An outer IPv6 plus any inner L3 does not fit in the TCAM, so only
+        * an IPv4 outer (or no outer at all) may carry an inner L3.
+        */
+       if (outer_ip == RTE_FLOW_ITEM_TYPE_IPV6)
+               return HINIC3_FLOW_KIND_INVALID;
+
+       hinic3_flow_take(item, next);
+
+       switch (hinic3_flow_next(*item)) {
+       case RTE_FLOW_ITEM_TYPE_END:
+               return kind;
+       case RTE_FLOW_ITEM_TYPE_TCP:
+       case RTE_FLOW_ITEM_TYPE_UDP:
+               hinic3_flow_take(item, hinic3_flow_next(*item));
+               return hinic3_flow_finish(*item, kind);
+       default:
+               return HINIC3_FLOW_KIND_INVALID;
+       }
+}
+
+/* Consume a tunnel header and classify the payload that follows it. */
+static enum hinic3_flow_filter_kind
+hinic3_flow_classify_tunnel(const struct rte_flow_item **item,
+                           enum rte_flow_item_type tunnel_type,
+                           enum rte_flow_item_type outer_ip)
+{
+       enum hinic3_flow_filter_kind kind =
+               tunnel_type == RTE_FLOW_ITEM_TYPE_VXLAN_GPE ?
+                       HINIC3_FLOW_KIND_GPE : HINIC3_FLOW_KIND_VXLAN_GENEVE;
+       enum rte_flow_item_type next;
+
+       if (!hinic3_flow_take(item, tunnel_type))
+               return HINIC3_FLOW_KIND_INVALID;
+
+       next = hinic3_flow_next(*item);
+
+       /* A bare tunnel with nothing after the header is valid. */
+       if (next == RTE_FLOW_ITEM_TYPE_END)
+               return kind;
+
+       /* GPE: an optional inner ETH (which may be terminal), then an L3(+L4). 
*/
+       if (tunnel_type == RTE_FLOW_ITEM_TYPE_VXLAN_GPE) {
+               if (next == RTE_FLOW_ITEM_TYPE_ETH) {
+                       hinic3_flow_take(item, RTE_FLOW_ITEM_TYPE_ETH);
+                       if (hinic3_flow_at_end(*item))
+                               return kind;
+               }
+               return hinic3_flow_classify_inner(item, kind, outer_ip);
+       }
+
+       /* vxlan/geneve: a bare L4/ANY, or an inner L3(+L4). */
+       switch (next) {
+       case RTE_FLOW_ITEM_TYPE_TCP:
+       case RTE_FLOW_ITEM_TYPE_UDP:
+       case RTE_FLOW_ITEM_TYPE_ANY:
+               hinic3_flow_take(item, next);
+               return hinic3_flow_finish(*item, kind);
+       case RTE_FLOW_ITEM_TYPE_ETH:
+       case RTE_FLOW_ITEM_TYPE_IPV4:
+       case RTE_FLOW_ITEM_TYPE_IPV6:
+               if (next == RTE_FLOW_ITEM_TYPE_ETH) {
+                       hinic3_flow_take(item, RTE_FLOW_ITEM_TYPE_ETH);
+                       break;
+               }
+               /* Geneve accepts a bare inner L3; vxlan requires the inner 
ETH. */
+               if (tunnel_type != RTE_FLOW_ITEM_TYPE_GENEVE)
+                       return HINIC3_FLOW_KIND_INVALID;
+               break;
+       default:
+               return HINIC3_FLOW_KIND_INVALID;
+       }
+
+       return hinic3_flow_classify_inner(item, kind, outer_ip);
+}
+
+/* Classify the payload that follows the outer L3. */
+static enum hinic3_flow_filter_kind
+hinic3_flow_classify_ip(const struct rte_flow_item **item,
+                       enum rte_flow_item_type ip_type)
+{
+       enum rte_flow_item_type next = hinic3_flow_next(*item);
+
+       switch (next) {
+       case RTE_FLOW_ITEM_TYPE_END:
+               return HINIC3_FLOW_KIND_NON_TUNNEL;
+       case RTE_FLOW_ITEM_TYPE_TCP:
+               hinic3_flow_take(item, RTE_FLOW_ITEM_TYPE_TCP);
+               return hinic3_flow_finish(*item, HINIC3_FLOW_KIND_NON_TUNNEL);
+       case RTE_FLOW_ITEM_TYPE_UDP:
+               hinic3_flow_take(item, RTE_FLOW_ITEM_TYPE_UDP);
+               next = hinic3_flow_next(*item);
+               switch (next) {
+               case RTE_FLOW_ITEM_TYPE_END:
+                       return HINIC3_FLOW_KIND_NON_TUNNEL;
+               case RTE_FLOW_ITEM_TYPE_VXLAN:
+               case RTE_FLOW_ITEM_TYPE_GENEVE:
+               case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+                       return hinic3_flow_classify_tunnel(item, next, ip_type);
+               default:
+                       return HINIC3_FLOW_KIND_INVALID;
+               }
+       case RTE_FLOW_ITEM_TYPE_ICMP:
+       case RTE_FLOW_ITEM_TYPE_ANY:
+               /* ICMP and ANY are valid only right after an IPv4 outer. */
+               if (ip_type != RTE_FLOW_ITEM_TYPE_IPV4)
+                       return HINIC3_FLOW_KIND_INVALID;
+               hinic3_flow_take(item, next);
+               return hinic3_flow_finish(*item, HINIC3_FLOW_KIND_NON_TUNNEL);
+       case RTE_FLOW_ITEM_TYPE_IPV4:
+       case RTE_FLOW_ITEM_TYPE_IPV6:
+               /* Ip-in-ip: a second L3 with an optional L4 (or ANY). */
+               hinic3_flow_take(item, next);
+               switch (hinic3_flow_next(*item)) {
+               case RTE_FLOW_ITEM_TYPE_END:
+                       return HINIC3_FLOW_KIND_IPINIP;
+               case RTE_FLOW_ITEM_TYPE_TCP:
+               case RTE_FLOW_ITEM_TYPE_UDP:
+               case RTE_FLOW_ITEM_TYPE_ANY:
+                       hinic3_flow_take(item, hinic3_flow_next(*item));
+                       return hinic3_flow_finish(*item, 
HINIC3_FLOW_KIND_IPINIP);
+               default:
+                       return HINIC3_FLOW_KIND_INVALID;
                }
+       default:
+               return HINIC3_FLOW_KIND_INVALID;
        }
+}
 
-       return (*item_array == RTE_FLOW_ITEM_TYPE_END &&
-               item->type == RTE_FLOW_ITEM_TYPE_END);
+/* Classify a pattern into one of the supported filter kinds. */
+static enum hinic3_flow_filter_kind
+hinic3_flow_classify(const struct rte_flow_item *pattern)
+{
+       const struct rte_flow_item *item = pattern;
+       enum rte_flow_item_type next;
+
+       if (!hinic3_flow_take(&item, RTE_FLOW_ITEM_TYPE_ETH))
+               return HINIC3_FLOW_KIND_INVALID;
+
+       switch (hinic3_flow_next(item)) {
+       case RTE_FLOW_ITEM_TYPE_END:
+               return HINIC3_FLOW_KIND_ETHERTYPE;
+       case RTE_FLOW_ITEM_TYPE_TCP:
+               hinic3_flow_take(&item, RTE_FLOW_ITEM_TYPE_TCP);
+               return hinic3_flow_finish(item, HINIC3_FLOW_KIND_NON_TUNNEL);
+       case RTE_FLOW_ITEM_TYPE_UDP:
+               hinic3_flow_take(&item, RTE_FLOW_ITEM_TYPE_UDP);
+               next = hinic3_flow_next(item);
+               switch (next) {
+               case RTE_FLOW_ITEM_TYPE_END:
+                       return HINIC3_FLOW_KIND_NON_TUNNEL;
+               case RTE_FLOW_ITEM_TYPE_VXLAN:
+               case RTE_FLOW_ITEM_TYPE_GENEVE:
+               case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+                       /* No outer IP: pass END so classify_inner allows it. */
+                       return hinic3_flow_classify_tunnel(&item, next,
+                                                           
RTE_FLOW_ITEM_TYPE_END);
+               default:
+                       return HINIC3_FLOW_KIND_INVALID;
+               }
+       case RTE_FLOW_ITEM_TYPE_IPV4:
+               hinic3_flow_take(&item, RTE_FLOW_ITEM_TYPE_IPV4);
+               return hinic3_flow_classify_ip(&item, RTE_FLOW_ITEM_TYPE_IPV4);
+       case RTE_FLOW_ITEM_TYPE_IPV6:
+               hinic3_flow_take(&item, RTE_FLOW_ITEM_TYPE_IPV6);
+               return hinic3_flow_classify_ip(&item, RTE_FLOW_ITEM_TYPE_IPV6);
+       default:
+               return HINIC3_FLOW_KIND_INVALID;
+       }
 }
 
 /**
@@ -142,20 +295,27 @@ hinic3_match_pattern(enum rte_flow_item_type *item_array,
  * Matched resolution filter. If no resolution filter is found, return NULL.
  */
 static hinic3_parse_filter_t
-hinic3_find_parse_filter_func(const struct rte_flow_item *pattern)
+hinic3_find_parse_filter_func(struct rte_eth_dev *dev,
+                             const struct rte_flow_item *pattern)
 {
-       hinic3_parse_filter_t parse_filter = NULL;
-       uint8_t i;
-       /* Traverse all supported patterns. */
-       for (i = 0; i < RTE_DIM(hinic3_supported_patterns); i++) {
-               if (hinic3_match_pattern(hinic3_supported_patterns[i].items, 
pattern)) {
-                       parse_filter =
-                               hinic3_supported_patterns[i].parse_filter;
-                       break;
-               }
-       }
+       struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
 
-       return parse_filter;
+       switch (hinic3_flow_classify(pattern)) {
+       case HINIC3_FLOW_KIND_ETHERTYPE:
+               return hinic3_flow_parse_ethertype_filter;
+       case HINIC3_FLOW_KIND_NON_TUNNEL:
+               return hinic3_flow_parse_fdir_filter;
+       case HINIC3_FLOW_KIND_VXLAN_GENEVE:
+               return hinic3_flow_parse_fdir_vxlan_geneve_filter;
+       case HINIC3_FLOW_KIND_GPE:
+               return HINIC3_IS_SP620_NIC(nic_dev) ?
+               hinic3_flow_parse_fdir_vxlan_geneve_filter : NULL;
+       case HINIC3_FLOW_KIND_IPINIP:
+               return HINIC3_IS_SP620_NIC(nic_dev) ? NULL :
+               hinic3_flow_parse_fdir_vxlan_geneve_filter;
+       default:
+               return NULL;
+       }
 }
 
 /**
@@ -182,12 +342,36 @@ hinic3_flow_parse_action(struct rte_eth_dev *dev,
        const struct rte_flow_action_queue *act_q;
        const struct rte_flow_action *act = actions;
 
-       /* skip the first void item. */
-       while (act->type == RTE_FLOW_ACTION_TYPE_VOID)
-               act++;
+       /* Only one non-VOID action before END is supported. */
+       const struct rte_flow_action *last_act = NULL;
+       for (act = actions; act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
+               if (act->type == RTE_FLOW_ACTION_TYPE_VOID)
+                       continue;
+               if (last_act != NULL) {
+                       rte_flow_error_set(error, EINVAL,
+                                          RTE_FLOW_ERROR_TYPE_ACTION, act,
+                                          "Multiple actions not supported.");
+                       return -rte_errno;
+               }
+               last_act = act;
+       }
+       if (last_act == NULL) {
+               rte_flow_error_set(error, EINVAL,
+                                  RTE_FLOW_ERROR_TYPE_ACTION, actions,
+                                  "No valid action.");
+               return -rte_errno;
+       }
+
+       act = last_act;
 
        switch (act->type) {
        case RTE_FLOW_ACTION_TYPE_QUEUE:
+               if (act->conf == NULL) {
+                       rte_flow_error_set(error, EINVAL,
+                                          RTE_FLOW_ERROR_TYPE_ACTION,
+                                          act, "Invalid action queue config.");
+                       return -rte_errno;
+               }
                act_q = (const struct rte_flow_action_queue *)act->conf;
                filter->fdir_filter.rq_index = act_q->index;
                if (filter->fdir_filter.rq_index >= dev->data->nb_rx_queues) {
@@ -230,6 +414,14 @@ hinic3_flow_fdir_ipv4(const struct rte_flow_item 
*flow_item,
 
        mask_ipv4 = (const struct rte_flow_item_ipv4 *)flow_item->mask;
        spec_ipv4 = (const struct rte_flow_item_ipv4 *)flow_item->spec;
+
+       filter->fdir_filter.ip_type = HINIC3_FDIR_IP_TYPE_IPV4;
+       filter->fdir_filter.tunnel_type = HINIC3_FDIR_TUNNEL_MODE_NORMAL;
+
+       /* When both L3 mask and spec are empty, return 0, then proceed to 
evaluate L4. */
+       if (!mask_ipv4 && !spec_ipv4)
+               return 0;
+
        if (!mask_ipv4 || !spec_ipv4) {
                rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
                                   flow_item,
@@ -251,9 +443,6 @@ hinic3_flow_fdir_ipv4(const struct rte_flow_item *flow_item,
                return -rte_errno;
        }
 
-       /* Set the filter information. */
-       filter->fdir_filter.ip_type = HINIC3_FDIR_IP_TYPE_IPV4;
-       filter->fdir_filter.tunnel_type = HINIC3_FDIR_TUNNEL_MODE_NORMAL;
        filter->fdir_filter.key_mask.ipv4.src_ip =
                rte_be_to_cpu_32(mask_ipv4->hdr.src_addr);
        filter->fdir_filter.key_spec.ipv4.src_ip =
@@ -277,6 +466,14 @@ hinic3_flow_fdir_ipv6(const struct rte_flow_item 
*flow_item,
 
        mask_ipv6 = (const struct rte_flow_item_ipv6 *)flow_item->mask;
        spec_ipv6 = (const struct rte_flow_item_ipv6 *)flow_item->spec;
+
+       filter->fdir_filter.ip_type = HINIC3_FDIR_IP_TYPE_IPV6;
+       filter->fdir_filter.tunnel_type = HINIC3_FDIR_TUNNEL_MODE_NORMAL;
+
+       /* When both L3 mask and spec are empty, return 0, then proceed to 
evaluate L4. */
+       if (!mask_ipv6 && !spec_ipv6)
+               return 0;
+
        if (!mask_ipv6 || !spec_ipv6) {
                rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
                                   flow_item,
@@ -293,9 +490,6 @@ hinic3_flow_fdir_ipv6(const struct rte_flow_item *flow_item,
                return -rte_errno;
        }
 
-       /* Set the filter information. */
-       filter->fdir_filter.ip_type = HINIC3_FDIR_IP_TYPE_IPV6;
-       filter->fdir_filter.tunnel_type = HINIC3_FDIR_TUNNEL_MODE_NORMAL;
        net_addr_to_host(filter->fdir_filter.key_mask.ipv6.src_ip,
                         (const uint32_t *)mask_ipv6->hdr.src_addr.a, 4);
        net_addr_to_host(filter->fdir_filter.key_spec.ipv6.src_ip,
@@ -639,6 +833,12 @@ hinic3_flow_parse_ethertype_pattern(__rte_unused struct 
rte_eth_dev *dev,
                        case RTE_ETHER_TYPE_LLDP:
                                break;
 
+                       case RTE_ETHER_TYPE_CNM:
+                               break;
+
+                       case RTE_ETHER_TYPE_ECP:
+                               break;
+
                        default:
                                rte_flow_error_set(error, EINVAL,
                                                   RTE_FLOW_ERROR_TYPE_ITEM,
@@ -686,14 +886,15 @@ static int
 hinic3_flow_fdir_tunnel_ipv4(struct rte_flow_error *error,
                             struct hinic3_filter_t *filter,
                             const struct rte_flow_item *flow_item,
-                            enum hinic3_fdir_tunnel_mode tunnel_mode)
+                            enum hinic3_fdir_tunnel_mode *tunnel_mode)
 {
        const struct rte_flow_item_ipv4 *spec_ipv4, *mask_ipv4;
        mask_ipv4 = (const struct rte_flow_item_ipv4 *)flow_item->mask;
        spec_ipv4 = (const struct rte_flow_item_ipv4 *)flow_item->spec;
 
-       if (tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_NORMAL) {
+       if (*tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_MAX) {
                filter->fdir_filter.outer_ip_type = HINIC3_FDIR_IP_TYPE_IPV4;
+               *tunnel_mode = HINIC3_FDIR_TUNNEL_MODE_NORMAL;
 
                if (!mask_ipv4 && !spec_ipv4)
                        return 0;
@@ -702,7 +903,7 @@ hinic3_flow_fdir_tunnel_ipv4(struct rte_flow_error *error,
                        rte_flow_error_set(error, EINVAL,
                                           RTE_FLOW_ERROR_TYPE_ITEM,
                                           flow_item,
-                                          "Invalid fdir filter, vxlan outer 
ipv4 mask or spec");
+                                          "Invalid fdir filter, vxlan/geneve 
outer ipv4 mask or spec");
                        return -rte_errno;
                }
 
@@ -718,7 +919,7 @@ hinic3_flow_fdir_tunnel_ipv4(struct rte_flow_error *error,
                    mask_ipv4->hdr.next_proto_id ||
                    mask_ipv4->hdr.hdr_checksum) {
                        rte_flow_error_set(error, EINVAL, 
RTE_FLOW_ERROR_TYPE_ITEM, flow_item,
-                               "Not supported by fdir filter, vxlan outer ipv4 
only support src ip, dst ip");
+                               "Not supported by fdir filter, vxlan/geneve 
outer ipv4 only support src ip,dst ip");
                        return -rte_errno;
                }
 
@@ -733,6 +934,10 @@ hinic3_flow_fdir_tunnel_ipv4(struct rte_flow_error *error,
                        rte_be_to_cpu_32(spec_ipv4->hdr.dst_addr);
        } else {
                filter->fdir_filter.ip_type = HINIC3_FDIR_IP_TYPE_IPV4;
+               if (*tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_NORMAL) {
+                       *tunnel_mode = HINIC3_FDIR_TUNNEL_MODE_IPIP;
+                       filter->fdir_filter.tunnel_type = *tunnel_mode;
+               }
 
                if (!mask_ipv4 && !spec_ipv4)
                        return 0;
@@ -741,7 +946,7 @@ hinic3_flow_fdir_tunnel_ipv4(struct rte_flow_error *error,
                        rte_flow_error_set(error, EINVAL,
                                           RTE_FLOW_ERROR_TYPE_ITEM,
                                           flow_item,
-                                          "Invalid fdir filter, vxlan inner 
ipv4 mask or spec");
+                                          "Invalid fdir filter, vxlan/geneve 
inner ipv4 mask or spec");
                        return -rte_errno;
                }
 
@@ -758,7 +963,7 @@ hinic3_flow_fdir_tunnel_ipv4(struct rte_flow_error *error,
                        rte_flow_error_set(error, EINVAL,
                                           RTE_FLOW_ERROR_TYPE_ITEM,
                                           flow_item,
-                                          "Not supported by fdir filter, vxlan 
inner ipv4 only support src ip, dst ip, proto");
+                                          "Not supported by fdir filter, 
vxlan/geneve inner ipv4 only support src ip,dst ip, proto");
                        return -rte_errno;
                }
 
@@ -783,15 +988,16 @@ static int
 hinic3_flow_fdir_tunnel_ipv6(struct rte_flow_error *error,
                             struct hinic3_filter_t *filter,
                             const struct rte_flow_item *flow_item,
-                            enum hinic3_fdir_tunnel_mode tunnel_mode)
+                            enum hinic3_fdir_tunnel_mode *tunnel_mode)
 {
        const struct rte_flow_item_ipv6 *spec_ipv6, *mask_ipv6;
 
        mask_ipv6 = (const struct rte_flow_item_ipv6 *)flow_item->mask;
        spec_ipv6 = (const struct rte_flow_item_ipv6 *)flow_item->spec;
 
-       if (tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_NORMAL) {
+       if (*tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_MAX) {
                filter->fdir_filter.outer_ip_type = HINIC3_FDIR_IP_TYPE_IPV6;
+               *tunnel_mode = HINIC3_FDIR_TUNNEL_MODE_NORMAL;
 
                if (!mask_ipv6 && !spec_ipv6)
                        return 0;
@@ -822,7 +1028,10 @@ hinic3_flow_fdir_tunnel_ipv6(struct rte_flow_error *error,
                                 (const uint32_t *)spec_ipv6->hdr.dst_addr.a, 
4);
        } else {
                filter->fdir_filter.ip_type = HINIC3_FDIR_IP_TYPE_IPV6;
-
+               if (*tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_NORMAL) {
+                       *tunnel_mode = HINIC3_FDIR_TUNNEL_MODE_IPIP;
+                       filter->fdir_filter.tunnel_type = *tunnel_mode;
+               }
                if (!mask_ipv6 && !spec_ipv6)
                        return 0;
 
@@ -869,7 +1078,7 @@ hinic3_flow_fdir_tunnel_tcp(struct rte_flow_error *error,
        if (tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_NORMAL) {
                rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
                                   flow_item,
-                                  "Not supported by fdir filter, vxlan only 
support inner tcp");
+                                  "Not supported by fdir filter, vxlan/geneve 
only support inner tcp");
                return -rte_errno;
        }
 
@@ -894,7 +1103,7 @@ hinic3_flow_fdir_tunnel_tcp(struct rte_flow_error *error,
            mask_tcp->hdr.tcp_urp) {
                rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
                                   flow_item,
-                                  "Not supported by fdir filter, vxlan inner 
tcp only support src port,dst port");
+                                  "Not supported by fdir filter, vxlan/geneve 
inner tcp only support src port,dst port");
                return -rte_errno;
        }
 
@@ -921,7 +1130,8 @@ hinic3_flow_fdir_tunnel_udp(struct rte_flow_error *error,
        mask_udp = (const struct rte_flow_item_udp *)flow_item->mask;
        spec_udp = (const struct rte_flow_item_udp *)flow_item->spec;
 
-       if (tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_NORMAL) {
+       if (tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_MAX ||
+           tunnel_mode == HINIC3_FDIR_TUNNEL_MODE_NORMAL) {
                /*
                 * UDP is used to describe protocol,
                 * spec and mask should be NULL.
@@ -942,7 +1152,7 @@ hinic3_flow_fdir_tunnel_udp(struct rte_flow_error *error,
                        rte_flow_error_set(error, EINVAL,
                                           RTE_FLOW_ERROR_TYPE_ITEM,
                                           flow_item,
-                                          "Invalid fdir filter vxlan inner udp 
mask or spec");
+                                          "Invalid fdir filter vxlan/geneve 
inner udp mask or spec");
                        return -rte_errno;
                }
 
@@ -960,57 +1170,114 @@ hinic3_flow_fdir_tunnel_udp(struct rte_flow_error 
*error,
        return 0;
 }
 
+static inline enum hinic3_fdir_tunnel_mode
+hinic3_flow_tunnel_mode(enum rte_flow_item_type type)
+{
+       switch (type) {
+       case RTE_FLOW_ITEM_TYPE_GENEVE:
+               return HINIC3_FDIR_TUNNEL_MODE_GENEVE;
+       case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+               return HINIC3_FDIR_TUNNEL_MODE_GPE;
+       default:
+               return HINIC3_FDIR_TUNNEL_MODE_VXLAN;
+       }
+}
+
 static int
-hinic3_flow_fdir_vxlan(struct rte_flow_error *error,
-                      struct hinic3_filter_t *filter,
-                      const struct rte_flow_item *flow_item)
+hinic3_flow_fdir_vxlan_geneve(struct rte_flow_error      *error,
+                             struct hinic3_filter_t      *filter,
+                             enum hinic3_fdir_tunnel_mode tunnel_mode,
+                             const struct rte_flow_item  *flow_item)
 {
-       const struct rte_flow_item_vxlan *spec_vxlan, *mask_vxlan;
+       const uint8_t *vni;
+       const uint8_t *vni_mask;
        uint32_t vxlan_vni_id = 0;
        uint32_t vxlan_vni_id_mask = 0;
 
-       spec_vxlan = (const struct rte_flow_item_vxlan *)flow_item->spec;
-       mask_vxlan = (const struct rte_flow_item_vxlan *)flow_item->mask;
-
-       filter->fdir_filter.tunnel_type = HINIC3_FDIR_TUNNEL_MODE_VXLAN;
+       filter->fdir_filter.tunnel_type = tunnel_mode;
 
-       if (!spec_vxlan && !mask_vxlan) {
+       if (!flow_item->spec && !flow_item->mask)
                return 0;
-       } else if (filter->fdir_filter.outer_ip_type == 
HINIC3_FDIR_IP_TYPE_IPV6) {
+
+       if (filter->fdir_filter.outer_ip_type == HINIC3_FDIR_IP_TYPE_IPV6) {
                rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
                                   flow_item,
-                                  "Invalid fdir filter vxlan mask or spec, 
ipv6 vxlan, don't support vni");
+                                  "Invalid fdir filter vxlan/geneve mask or 
spec, ipv6 vxlan/geneve, don't support vni");
                return -rte_errno;
        }
 
-       if (!spec_vxlan || !mask_vxlan) {
+       if (!flow_item->spec || !flow_item->mask) {
                rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
                                   flow_item,
-                                  "Invalid fdir filter vxlan mask or spec");
+                                  "Invalid fdir filter vxlan/geneve mask or 
spec");
                return -rte_errno;
        }
 
-       memcpy(((uint8_t *)&vxlan_vni_id + 1), spec_vxlan->vni, 3);
+       switch (tunnel_mode) {
+       case HINIC3_FDIR_TUNNEL_MODE_GENEVE: {
+               const struct rte_flow_item_geneve *spec =
+                       (const struct rte_flow_item_geneve *)flow_item->spec;
+               const struct rte_flow_item_geneve *mask =
+                       (const struct rte_flow_item_geneve *)flow_item->mask;
+
+               /* Only VNI is matched; option length and protocol are not. */
+               if (mask->ver_opt_len_o_c_rsvd0 || mask->protocol)
+                       goto unsupported;
+               vni = spec->vni;
+               vni_mask = mask->vni;
+               break;
+       }
+       case HINIC3_FDIR_TUNNEL_MODE_GPE: {
+               const struct rte_flow_item_vxlan_gpe *spec =
+                       (const struct rte_flow_item_vxlan_gpe *)flow_item->spec;
+               const struct rte_flow_item_vxlan_gpe *mask =
+                       (const struct rte_flow_item_vxlan_gpe *)flow_item->mask;
+
+               /* Only VNI is matched; protocol is not. */
+               if (mask->protocol)
+                       goto unsupported;
+               vni = spec->vni;
+               vni_mask = mask->vni;
+               break;
+       }
+       default:
+               vni = ((const struct rte_flow_item_vxlan 
*)flow_item->spec)->vni;
+               vni_mask =
+                       ((const struct rte_flow_item_vxlan 
*)flow_item->mask)->vni;
+               break;
+       }
+
+       memcpy(((uint8_t *)&vxlan_vni_id + 1), vni, 3);
        filter->fdir_filter.key_spec.tunnel.tunnel_id =
                rte_be_to_cpu_32(vxlan_vni_id);
-       memcpy(((uint8_t *)&vxlan_vni_id_mask + 1), mask_vxlan->vni, 3);
+       memcpy(((uint8_t *)&vxlan_vni_id_mask + 1), vni_mask, 3);
        filter->fdir_filter.key_mask.tunnel.tunnel_id =
                rte_be_to_cpu_32(vxlan_vni_id_mask);
        return 0;
+
+unsupported:
+       rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, flow_item,
+                          "Not supported by fdir filter, only vni is 
supported");
+       return -rte_errno;
 }
 
 static int
-hinic3_flow_parse_fdir_vxlan_pattern(__rte_unused struct rte_eth_dev *dev,
-                                    const struct rte_flow_item *pattern,
-                                    struct rte_flow_error *error,
-                                    struct hinic3_filter_t *filter)
+hinic3_flow_parse_fdir_vxlan_geneve_pattern(__rte_unused struct rte_eth_dev 
*dev,
+                                           const struct rte_flow_item *pattern,
+                                           struct rte_flow_error *error,
+                                           struct hinic3_filter_t *filter)
 {
        const struct rte_flow_item *flow_item = pattern;
-       enum hinic3_fdir_tunnel_mode tunnel_mode =
-               HINIC3_FDIR_TUNNEL_MODE_NORMAL;
+       enum hinic3_fdir_tunnel_mode tunnel_mode = HINIC3_FDIR_TUNNEL_MODE_MAX;
        enum rte_flow_item_type type;
        int err;
 
+       if (pattern == NULL) {
+               rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, 
NULL,
+                                  "Invalid pattern");
+               return -rte_errno;
+       }
+
        /* Inner and outer ip type, set it to any by default */
        filter->fdir_filter.ip_type = HINIC3_FDIR_IP_TYPE_ANY;
        filter->fdir_filter.outer_ip_type = HINIC3_FDIR_IP_TYPE_ANY;
@@ -1038,14 +1305,14 @@ hinic3_flow_parse_fdir_vxlan_pattern(__rte_unused 
struct rte_eth_dev *dev,
 
                case RTE_FLOW_ITEM_TYPE_IPV4:
                        err = hinic3_flow_fdir_tunnel_ipv4(error,
-                               filter, flow_item, tunnel_mode);
+                               filter, flow_item, &tunnel_mode);
                        if (err)
                                return -rte_errno;
                        break;
 
                case RTE_FLOW_ITEM_TYPE_IPV6:
                        err = hinic3_flow_fdir_tunnel_ipv6(error,
-                               filter, flow_item, tunnel_mode);
+                               filter, flow_item, &tunnel_mode);
                        if (err)
                                return -rte_errno;
                        break;
@@ -1065,10 +1332,12 @@ hinic3_flow_parse_fdir_vxlan_pattern(__rte_unused 
struct rte_eth_dev *dev,
                        break;
 
                case RTE_FLOW_ITEM_TYPE_VXLAN:
-                       err = hinic3_flow_fdir_vxlan(error, filter, flow_item);
+               case RTE_FLOW_ITEM_TYPE_GENEVE:
+               case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+                       tunnel_mode = hinic3_flow_tunnel_mode(type);
+                       err = hinic3_flow_fdir_vxlan_geneve(error, filter, 
tunnel_mode, flow_item);
                        if (err)
                                return -rte_errno;
-                       tunnel_mode = HINIC3_FDIR_TUNNEL_MODE_VXLAN;
                        break;
 
                default:
@@ -1099,16 +1368,16 @@ hinic3_flow_parse_fdir_vxlan_pattern(__rte_unused 
struct rte_eth_dev *dev,
  * 0 on success, non-zero on failure.
  */
 static int
-hinic3_flow_parse_fdir_vxlan_filter(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 hinic3_filter_t *filter)
+hinic3_flow_parse_fdir_vxlan_geneve_filter(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 hinic3_filter_t *filter)
 {
        int ret;
 
-       ret = hinic3_flow_parse_fdir_vxlan_pattern(dev, pattern, error, filter);
+       ret = hinic3_flow_parse_fdir_vxlan_geneve_pattern(dev, pattern, error, 
filter);
        if (ret)
                return ret;
 
@@ -1153,11 +1422,25 @@ hinic3_flow_parse(struct rte_eth_dev *dev, const struct 
rte_flow_attr *attr,
        hinic3_parse_filter_t parse_filter;
        uint32_t pattern_num = 0;
        int ret = 0;
-       /* Check whether the parameter is valid. */
-       if (!pattern || !actions || !attr) {
+
+       if (!pattern) {
+               rte_flow_error_set(error, EINVAL,
+                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                  NULL, "Pattern is NULL.");
+               return -rte_errno;
+       }
+
+       if (!actions) {
                rte_flow_error_set(error, EINVAL,
-                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-                                  "NULL param.");
+                                  RTE_FLOW_ERROR_TYPE_ACTION,
+                                  NULL, "Actions is NULL.");
+               return -rte_errno;
+       }
+
+       if (!attr) {
+               rte_flow_error_set(error, EINVAL,
+                                  RTE_FLOW_ERROR_TYPE_ATTR,
+                                  NULL, "Attr is NULL.");
                return -rte_errno;
        }
 
@@ -1174,7 +1457,7 @@ hinic3_flow_parse(struct rte_eth_dev *dev, const struct 
rte_flow_attr *attr,
         * The corresponding filter is returned. If the filter is not found,
         * NULL is returned.
         */
-       parse_filter = hinic3_find_parse_filter_func(pattern);
+       parse_filter = hinic3_find_parse_filter_func(dev, pattern);
        if (!parse_filter) {
                rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
                                   pattern, "Unsupported pattern");
@@ -1303,9 +1586,7 @@ hinic3_flow_create(struct rte_eth_dev *dev, const struct 
rte_flow_attr *attr,
                                   NULL, "Unsupported filter type.");
                goto free_flow;
        }
-
        return flow;
-
 free_flow:
        rte_free(flow);
        rte_free(filter_rules);
@@ -1467,7 +1748,6 @@ hinic3_flow_flush(struct rte_eth_dev *dev, struct 
rte_flow_error *error)
        return ret;
 }
 
-/* Structure for managing flow table operations. */
 const struct rte_flow_ops hinic3_flow_ops = {
        .validate = hinic3_flow_validate,
        .create = hinic3_flow_create,
diff --git a/drivers/net/hinic3/hinic3_flow.h b/drivers/net/hinic3/hinic3_flow.h
deleted file mode 100644
index c4b38e44e7..0000000000
--- a/drivers/net/hinic3/hinic3_flow.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2025 Huawei Technologies Co., Ltd
- */
-
-#ifndef _HINIC3_FLOW_H_
-#define _HINIC3_FLOW_H_
-
-#include <rte_flow.h>
-
-/* Indicate the type of the IPv4 ICPM matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_icmp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_ICMP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 any protocol matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_any[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_ANY,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the Ether matching pattern. */
-static enum rte_flow_item_type pattern_ethertype[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the TCP matching pattern. */
-static enum rte_flow_item_type pattern_ethertype_tcp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the UDP matching pattern. */
-static enum rte_flow_item_type pattern_ethertype_udp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan[] = {
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan any protocol matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_any[] = {
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-       RTE_FLOW_ITEM_TYPE_ANY, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan TCP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_tcp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-       RTE_FLOW_ITEM_TYPE_TCP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan UDP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_udp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan IPv4 matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_ipv4[] = {
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan IPv4 TCP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_ipv4_tcp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_TCP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan IPv4 UDP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_ipv4_udp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan IPv6 matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_ipv6[] = {
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan IPv6 TCP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_ipv6_tcp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_TCP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 vxlan IPv6 UDP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_vxlan_ipv6_udp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 matching pattern. */
-static enum rte_flow_item_type pattern_ipv4[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 UDP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_udp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv4 TCP matching pattern. */
-static enum rte_flow_item_type pattern_ipv4_tcp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv6 matching pattern. */
-static enum rte_flow_item_type pattern_ipv6[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv6 UDP matching pattern. */
-static enum rte_flow_item_type pattern_ipv6_udp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv6 TCP matching pattern. */
-static enum rte_flow_item_type pattern_ipv6_tcp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv6 TCP matching pattern. */
-static enum rte_flow_item_type pattern_ipv6_vxlan[] = {
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv6 VXLAN any protocol matching pattern. */
-static enum rte_flow_item_type pattern_ipv6_vxlan_any[] = {
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-       RTE_FLOW_ITEM_TYPE_ANY, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv6 VXLAN TCP matching pattern. */
-static enum rte_flow_item_type pattern_ipv6_vxlan_tcp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-       RTE_FLOW_ITEM_TYPE_TCP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Indicate the type of the IPv6 VXLAN UDP matching pattern. */
-static enum rte_flow_item_type pattern_ipv6_vxlan_udp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH, RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_VXLAN,
-       RTE_FLOW_ITEM_TYPE_UDP, RTE_FLOW_ITEM_TYPE_END,
-};
-
-#endif /**< _HINIC3_FLOW_H_ */
-- 
2.33.0

Reply via email to