Use the new flow graph API and the common parsing framework to implement
flow parser for flow director.

As a result of transitioning to more formalized validation, some checks
have become more stringent. In particular, some protocols (such as SCTP)
were previously accepting non-zero or invalid masks and either ignoring
them or misinterpreting them to mean "fully masked". This has now been
corrected.

The FDIR engine in i40e has also relied on a custom memory allocation
scheme for fdir flows - also migrated to the new infrastructure.

Signed-off-by: Anatoly Burakov <[email protected]>
---
 drivers/net/intel/i40e/i40e_ethdev.c    |   48 -
 drivers/net/intel/i40e/i40e_ethdev.h    |   25 +-
 drivers/net/intel/i40e/i40e_fdir.c      |   47 -
 drivers/net/intel/i40e/i40e_flow.c      | 1965 +----------------------
 drivers/net/intel/i40e/i40e_flow.h      |    6 +
 drivers/net/intel/i40e/i40e_flow_fdir.c | 1806 +++++++++++++++++++++
 drivers/net/intel/i40e/meson.build      |    1 +
 7 files changed, 1824 insertions(+), 2074 deletions(-)
 create mode 100644 drivers/net/intel/i40e/i40e_flow_fdir.c

diff --git a/drivers/net/intel/i40e/i40e_ethdev.c 
b/drivers/net/intel/i40e/i40e_ethdev.c
index b71a4fb0d1..d4b5d36465 100644
--- a/drivers/net/intel/i40e/i40e_ethdev.c
+++ b/drivers/net/intel/i40e/i40e_ethdev.c
@@ -1104,10 +1104,6 @@ i40e_init_fdir_filter_list(struct rte_eth_dev *dev)
        uint32_t alloc = hw->func_caps.fd_filters_guaranteed;
        uint32_t best = hw->func_caps.fd_filters_best_effort;
        enum i40e_filter_pctype pctype;
-       struct rte_bitmap *bmp = NULL;
-       uint32_t bmp_size;
-       void *mem = NULL;
-       uint32_t i = 0;
        int ret;
 
        struct rte_hash_parameters fdir_hash_params = {
@@ -1164,50 +1160,8 @@ i40e_init_fdir_filter_list(struct rte_eth_dev *dev)
 
        PMD_DRV_LOG(INFO, "FDIR guarantee space: %u, best_effort space %u.", 
alloc, best);
 
-       fdir_info->fdir_flow_pool.pool =
-                       rte_zmalloc("i40e_fdir_entry",
-                               sizeof(struct i40e_fdir_entry) *
-                               fdir_info->fdir_space_size,
-                               0);
-
-       if (!fdir_info->fdir_flow_pool.pool) {
-               PMD_INIT_LOG(ERR,
-                            "Failed to allocate memory for bitmap flow!");
-               ret = -ENOMEM;
-               goto err_fdir_bitmap_flow_alloc;
-       }
-
-       for (i = 0; i < fdir_info->fdir_space_size; i++)
-               fdir_info->fdir_flow_pool.pool[i].idx = i;
-
-       bmp_size =
-               rte_bitmap_get_memory_footprint(fdir_info->fdir_space_size);
-       mem = rte_zmalloc("fdir_bmap", bmp_size, RTE_CACHE_LINE_SIZE);
-       if (mem == NULL) {
-               PMD_INIT_LOG(ERR,
-                            "Failed to allocate memory for fdir bitmap!");
-               ret = -ENOMEM;
-               goto err_fdir_mem_alloc;
-       }
-       bmp = rte_bitmap_init(fdir_info->fdir_space_size, mem, bmp_size);
-       if (bmp == NULL) {
-               PMD_INIT_LOG(ERR,
-                            "Failed to initialization fdir bitmap!");
-               ret = -ENOMEM;
-               goto err_fdir_bmp_alloc;
-       }
-       for (i = 0; i < fdir_info->fdir_space_size; i++)
-               rte_bitmap_set(bmp, i);
-
-       fdir_info->fdir_flow_pool.bitmap = bmp;
-
        return 0;
 
-err_fdir_bmp_alloc:
-       rte_free(mem);
-err_fdir_mem_alloc:
-       rte_free(fdir_info->fdir_flow_pool.pool);
-err_fdir_bitmap_flow_alloc:
        rte_free(fdir_info->fdir_filter_array);
 err_fdir_filter_array_alloc:
        rte_free(fdir_info->hash_map);
@@ -1940,8 +1894,6 @@ i40e_fdir_memory_cleanup(struct i40e_pf *pf)
        /* flow director memory cleanup */
        rte_free(fdir_info->hash_map);
        rte_hash_free(fdir_info->hash_table);
-       rte_free(fdir_info->fdir_flow_pool.bitmap);
-       rte_free(fdir_info->fdir_flow_pool.pool);
        rte_free(fdir_info->fdir_filter_array);
 }
 
diff --git a/drivers/net/intel/i40e/i40e_ethdev.h 
b/drivers/net/intel/i40e/i40e_ethdev.h
index 118ba8a6c7..7c4786bec0 100644
--- a/drivers/net/intel/i40e/i40e_ethdev.h
+++ b/drivers/net/intel/i40e/i40e_ethdev.h
@@ -718,28 +718,12 @@ struct i40e_fdir_filter {
        struct i40e_fdir_filter_conf fdir;
 };
 
-/* fdir memory pool entry */
-struct i40e_fdir_entry {
-       struct rte_flow flow;
-       uint32_t idx;
-};
-
-/* pre-allocated fdir memory pool */
-struct i40e_fdir_flow_pool {
-       /* a bitmap to manage the fdir pool */
-       struct rte_bitmap *bitmap;
-       /* the size the pool is pf->fdir->fdir_space_size */
-       struct i40e_fdir_entry *pool;
-};
-
-#define FLOW_TO_FLOW_BITMAP(f) \
-       container_of((f), struct i40e_fdir_entry, flow)
-
 TAILQ_HEAD(i40e_fdir_filter_list, i40e_fdir_filter);
 /*
  *  A structure used to define fields of a FDIR related info.
  */
 struct i40e_fdir_info {
+       uint64_t num_fdir_flows;
        struct i40e_vsi *fdir_vsi;     /* pointer to fdir VSI structure */
        uint16_t match_counter_index;  /* Statistic counter index used for 
fdir*/
        struct ci_tx_queue *txq;
@@ -790,8 +774,6 @@ struct i40e_fdir_info {
        uint32_t fdir_guarantee_free_space;
        /* the fdir total guaranteed space */
        uint32_t fdir_guarantee_total_space;
-       /* the pre-allocated pool of the rte_flow */
-       struct i40e_fdir_flow_pool fdir_flow_pool;
 
        /* Mark if flex pit and mask is set */
        bool flex_pit_flag[I40E_MAX_FLXPLD_LAYER];
@@ -1311,7 +1293,6 @@ extern const struct rte_flow_ops i40e_flow_ops;
 
 struct i40e_filter_ctx {
        union {
-               struct i40e_fdir_filter_conf fdir_filter;
                struct i40e_tunnel_filter_conf consistent_tunnel_filter;
                struct i40e_rte_flow_rss_conf rss_conf;
        };
@@ -1408,10 +1389,6 @@ uint64_t i40e_get_default_input_set(uint16_t pctype);
 int i40e_ethertype_filter_set(struct i40e_pf *pf,
                              struct rte_eth_ethertype_filter *filter,
                              bool add);
-struct rte_flow *
-i40e_fdir_entry_pool_get(struct i40e_fdir_info *fdir_info);
-void i40e_fdir_entry_pool_put(struct i40e_fdir_info *fdir_info,
-               struct rte_flow *flow);
 int i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev,
                              const struct i40e_fdir_filter_conf *filter,
                              bool add);
diff --git a/drivers/net/intel/i40e/i40e_fdir.c 
b/drivers/net/intel/i40e/i40e_fdir.c
index 3b099d5a9e..8f72801206 100644
--- a/drivers/net/intel/i40e/i40e_fdir.c
+++ b/drivers/net/intel/i40e/i40e_fdir.c
@@ -1093,53 +1093,6 @@ i40e_sw_fdir_filter_del(struct i40e_pf *pf, struct 
i40e_fdir_input *input)
        return 0;
 }
 
-struct rte_flow *
-i40e_fdir_entry_pool_get(struct i40e_fdir_info *fdir_info)
-{
-       struct rte_flow *flow = NULL;
-       uint64_t slab = 0;
-       uint32_t pos = 0;
-       uint32_t i = 0;
-       int ret;
-
-       if (fdir_info->fdir_actual_cnt >=
-                       fdir_info->fdir_space_size) {
-               PMD_DRV_LOG(ERR, "Fdir space full");
-               return NULL;
-       }
-
-       ret = rte_bitmap_scan(fdir_info->fdir_flow_pool.bitmap, &pos,
-                       &slab);
-
-       /* normally this won't happen as the fdir_actual_cnt should be
-        * same with the number of the set bits in fdir_flow_pool,
-        * but anyway handle this error condition here for safe
-        */
-       if (ret == 0) {
-               PMD_DRV_LOG(ERR, "fdir_actual_cnt out of sync");
-               return NULL;
-       }
-
-       i = rte_bsf64(slab);
-       pos += i;
-       rte_bitmap_clear(fdir_info->fdir_flow_pool.bitmap, pos);
-       flow = &fdir_info->fdir_flow_pool.pool[pos].flow;
-
-       memset(flow, 0, sizeof(struct rte_flow));
-
-       return flow;
-}
-
-void
-i40e_fdir_entry_pool_put(struct i40e_fdir_info *fdir_info,
-               struct rte_flow *flow)
-{
-       struct i40e_fdir_entry *f;
-
-       f = FLOW_TO_FLOW_BITMAP(flow);
-       rte_bitmap_set(fdir_info->fdir_flow_pool.bitmap, f->idx);
-}
-
 static int
 i40e_flow_store_flex_pit(struct i40e_pf *pf,
                         struct i40e_fdir_flex_pit *flex_pit,
diff --git a/drivers/net/intel/i40e/i40e_flow.c 
b/drivers/net/intel/i40e/i40e_flow.c
index 68155a58b4..44dcb4f5b2 100644
--- a/drivers/net/intel/i40e/i40e_flow.c
+++ b/drivers/net/intel/i40e/i40e_flow.c
@@ -32,12 +32,10 @@
 const struct ci_flow_engine_list i40e_flow_engine_list = {
        {
                &i40e_flow_engine_ethertype,
+               &i40e_flow_engine_fdir,
        }
 };
 
-#define I40E_IPV6_TC_MASK      (0xFF << I40E_FDIR_IPv6_TC_OFFSET)
-#define I40E_IPV6_FRAG_HEADER  44
-#define I40E_TENANT_ARRAY_NUM  3
 #define I40E_VLAN_TCI_MASK     0xFFFF
 #define I40E_VLAN_PRI_MASK     0xE000
 #define I40E_VLAN_CFI_MASK     0x1000
@@ -62,23 +60,10 @@ static int i40e_flow_query(struct rte_eth_dev *dev,
                           struct rte_flow *flow,
                           const struct rte_flow_action *actions,
                           void *data, struct rte_flow_error *error);
-static int i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
-                                       const struct rte_flow_item *pattern,
-                                       struct rte_flow_error *error,
-                                       struct i40e_fdir_filter_conf *filter);
-static int i40e_flow_parse_fdir_action(struct rte_eth_dev *dev,
-                                      const struct rte_flow_action *actions,
-                                      struct rte_flow_error *error,
-                                      struct i40e_fdir_filter_conf *filter);
 static int i40e_flow_parse_tunnel_action(struct rte_eth_dev *dev,
                                 const struct rte_flow_action *actions,
                                 struct rte_flow_error *error,
                                 struct i40e_tunnel_filter_conf *filter);
-static int i40e_flow_parse_fdir_filter(struct rte_eth_dev *dev,
-                                      const struct rte_flow_item pattern[],
-                                      const struct rte_flow_action actions[],
-                                      struct rte_flow_error *error,
-                                      struct i40e_filter_ctx *filter);
 static int i40e_flow_parse_vxlan_filter(struct rte_eth_dev *dev,
                                        const struct rte_flow_item pattern[],
                                        const struct rte_flow_action actions[],
@@ -101,7 +86,6 @@ static int i40e_flow_parse_gtp_filter(struct rte_eth_dev 
*dev,
                                      struct i40e_filter_ctx *filter);
 static int i40e_flow_destroy_tunnel_filter(struct i40e_pf *pf,
                                           struct i40e_tunnel_filter *filter);
-static int i40e_flow_flush_fdir_filter(struct i40e_pf *pf);
 static int i40e_flow_flush_tunnel_filter(struct i40e_pf *pf);
 static int
 i40e_flow_parse_qinq_filter(struct rte_eth_dev *dev,
@@ -128,19 +112,6 @@ const struct rte_flow_ops i40e_flow_ops = {
        .query = i40e_flow_query,
 };
 
-/* Pattern matched ethertype filter */
-static enum rte_flow_item_type pattern_ethertype[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-/* Pattern matched flow director filter */
-static enum rte_flow_item_type pattern_fdir_ipv4[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
 static enum rte_flow_item_type pattern_fdir_ipv4_udp[] = {
        RTE_FLOW_ITEM_TYPE_ETH,
        RTE_FLOW_ITEM_TYPE_IPV4,
@@ -178,30 +149,6 @@ static enum rte_flow_item_type pattern_fdir_ipv4_gtpu[] = {
        RTE_FLOW_ITEM_TYPE_END,
 };
 
-static enum rte_flow_item_type pattern_fdir_ipv4_gtpu_ipv4[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_GTPU,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_gtpu_ipv6[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_GTPU,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
 static enum rte_flow_item_type pattern_fdir_ipv6_udp[] = {
        RTE_FLOW_ITEM_TYPE_ETH,
        RTE_FLOW_ITEM_TYPE_IPV6,
@@ -239,581 +186,6 @@ static enum rte_flow_item_type pattern_fdir_ipv6_gtpu[] = 
{
        RTE_FLOW_ITEM_TYPE_END,
 };
 
-static enum rte_flow_item_type pattern_fdir_ipv6_gtpu_ipv4[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_GTPU,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_gtpu_ipv6[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_GTPU,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ethertype_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ethertype_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ethertype_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_udp_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_udp_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_udp_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_tcp_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_tcp_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_tcp_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_sctp_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_SCTP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_sctp_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_SCTP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_sctp_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_SCTP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_udp_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_udp_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_udp_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_tcp_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_tcp_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_tcp_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_sctp_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_SCTP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_sctp_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_SCTP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_sctp_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_SCTP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ethertype_vlan[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_udp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_tcp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_sctp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_SCTP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_udp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_tcp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_sctp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_SCTP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ethertype_vlan_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ethertype_vlan_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ethertype_vlan_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_udp_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_udp_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_udp_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_tcp_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_tcp_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_tcp_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_sctp_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_SCTP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_sctp_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_SCTP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv4_sctp_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_SCTP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_udp_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_udp_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_udp_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_tcp_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_tcp_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_tcp_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_TCP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_sctp_raw_1[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_SCTP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_sctp_raw_2[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_SCTP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_vlan_ipv6_sctp_raw_3[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_VLAN,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_SCTP,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_RAW,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
 /* Pattern matched tunnel filter */
 static enum rte_flow_item_type pattern_vxlan_1[] = {
        RTE_FLOW_ITEM_TYPE_ETH,
@@ -926,138 +298,7 @@ static enum rte_flow_item_type pattern_qinq_1[] = {
        RTE_FLOW_ITEM_TYPE_END,
 };
 
-static enum rte_flow_item_type pattern_fdir_ipv4_l2tpv3oip[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_L2TPV3OIP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_l2tpv3oip[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_L2TPV3OIP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_esp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_ESP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_esp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_ESP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv4_udp_esp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV4,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_ESP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
-static enum rte_flow_item_type pattern_fdir_ipv6_udp_esp[] = {
-       RTE_FLOW_ITEM_TYPE_ETH,
-       RTE_FLOW_ITEM_TYPE_IPV6,
-       RTE_FLOW_ITEM_TYPE_UDP,
-       RTE_FLOW_ITEM_TYPE_ESP,
-       RTE_FLOW_ITEM_TYPE_END,
-};
-
 static struct i40e_valid_pattern i40e_supported_patterns[] = {
-       /* FDIR - support default flow type without flexible payload*/
-       { pattern_ethertype, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_udp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_tcp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_sctp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_gtpc, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_gtpu, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_gtpu_ipv4, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_gtpu_ipv6, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_esp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_udp_esp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_udp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_tcp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_sctp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_gtpc, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_gtpu, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_gtpu_ipv4, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_gtpu_ipv6, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_esp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_udp_esp, i40e_flow_parse_fdir_filter },
-       /* FDIR - support default flow type with flexible payload */
-       { pattern_fdir_ethertype_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ethertype_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ethertype_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_udp_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_udp_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_udp_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_tcp_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_tcp_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_tcp_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_sctp_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_sctp_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv4_sctp_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_udp_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_udp_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_udp_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_tcp_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_tcp_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_tcp_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_sctp_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_sctp_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_sctp_raw_3, i40e_flow_parse_fdir_filter },
-       /* FDIR - support single vlan input set */
-       { pattern_fdir_ethertype_vlan, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_udp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_tcp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_sctp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_udp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_tcp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_sctp, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ethertype_vlan_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ethertype_vlan_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ethertype_vlan_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_udp_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_udp_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_udp_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_tcp_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_tcp_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_tcp_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_sctp_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_sctp_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv4_sctp_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_udp_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_udp_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_udp_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_tcp_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_tcp_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_tcp_raw_3, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_sctp_raw_1, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_sctp_raw_2, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_vlan_ipv6_sctp_raw_3, i40e_flow_parse_fdir_filter },
        /* VXLAN */
        { pattern_vxlan_1, i40e_flow_parse_vxlan_filter },
        { pattern_vxlan_2, i40e_flow_parse_vxlan_filter },
@@ -1080,9 +321,6 @@ static struct i40e_valid_pattern i40e_supported_patterns[] 
= {
        { pattern_fdir_ipv6_gtpu, i40e_flow_parse_gtp_filter },
        /* QINQ */
        { pattern_qinq_1, i40e_flow_parse_qinq_filter },
-       /* L2TPv3 over IP */
-       { pattern_fdir_ipv4_l2tpv3oip, i40e_flow_parse_fdir_filter },
-       { pattern_fdir_ipv6_l2tpv3oip, i40e_flow_parse_fdir_filter },
        /* L4 over port */
        { pattern_fdir_ipv4_udp, i40e_flow_parse_l4_cloud_filter },
        { pattern_fdir_ipv4_tcp, i40e_flow_parse_l4_cloud_filter },
@@ -1209,47 +447,7 @@ i40e_get_outer_vlan(struct rte_eth_dev *dev, uint16_t 
*tpid)
        return 0;
 }
 
-static int
-i40e_flow_check_raw_item(const struct rte_flow_item *item,
-                        const struct rte_flow_item_raw *raw_spec,
-                        struct rte_flow_error *error)
-{
-       if (!raw_spec->relative) {
-               rte_flow_error_set(error, EINVAL,
-                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                  item,
-                                  "Relative should be 1.");
-               return -rte_errno;
-       }
-
-       if (raw_spec->offset % sizeof(uint16_t)) {
-               rte_flow_error_set(error, EINVAL,
-                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                  item,
-                                  "Offset should be even.");
-               return -rte_errno;
-       }
-
-       if (raw_spec->search || raw_spec->limit) {
-               rte_flow_error_set(error, EINVAL,
-                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                  item,
-                                  "search or limit is not supported.");
-               return -rte_errno;
-       }
-
-       if (raw_spec->offset < 0) {
-               rte_flow_error_set(error, EINVAL,
-                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                  item,
-                                  "Offset should be non-negative.");
-               return -rte_errno;
-       }
-       return 0;
-}
-
-
-static uint8_t
+uint8_t
 i40e_flow_fdir_get_pctype_value(struct i40e_pf *pf,
                                enum rte_flow_item_type item_type,
                                struct i40e_fdir_filter_conf *filter)
@@ -1316,1023 +514,6 @@ i40e_flow_fdir_get_pctype_value(struct i40e_pf *pf,
        return I40E_FILTER_PCTYPE_INVALID;
 }
 
-static void
-i40e_flow_set_filter_spi(struct i40e_fdir_filter_conf *filter,
-       const struct rte_flow_item_esp *esp_spec)
-{
-       if (filter->input.flow_ext.oip_type ==
-               I40E_FDIR_IPTYPE_IPV4) {
-               if (filter->input.flow_ext.is_udp)
-                       filter->input.flow.esp_ipv4_udp_flow.spi =
-                               esp_spec->hdr.spi;
-               else
-                       filter->input.flow.esp_ipv4_flow.spi =
-                               esp_spec->hdr.spi;
-       }
-       if (filter->input.flow_ext.oip_type ==
-               I40E_FDIR_IPTYPE_IPV6) {
-               if (filter->input.flow_ext.is_udp)
-                       filter->input.flow.esp_ipv6_udp_flow.spi =
-                               esp_spec->hdr.spi;
-               else
-                       filter->input.flow.esp_ipv6_flow.spi =
-                               esp_spec->hdr.spi;
-       }
-}
-
-/* 1. Last in item should be NULL as range is not supported.
- * 2. Supported patterns: refer to array i40e_supported_patterns.
- * 3. Default supported flow type and input set: refer to array
- *    valid_fdir_inset_table in i40e_ethdev.c.
- * 4. Mask of fields which need to be matched should be
- *    filled with 1.
- * 5. Mask of fields which needn't to be matched should be
- *    filled with 0.
- * 6. GTP profile supports GTPv1 only.
- * 7. GTP-C response message ('source_port' = 2123) is not supported.
- */
-static int
-i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
-                            const struct rte_flow_item *pattern,
-                            struct rte_flow_error *error,
-                            struct i40e_fdir_filter_conf *filter)
-{
-       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-       const struct rte_flow_item *item = pattern;
-       const struct rte_flow_item_eth *eth_spec, *eth_mask;
-       const struct rte_flow_item_vlan *vlan_spec, *vlan_mask;
-       const struct rte_flow_item_ipv4 *ipv4_spec, *ipv4_last, *ipv4_mask;
-       const struct rte_flow_item_ipv6 *ipv6_spec, *ipv6_mask;
-       const struct rte_flow_item_tcp *tcp_spec, *tcp_mask;
-       const struct rte_flow_item_udp *udp_spec, *udp_mask;
-       const struct rte_flow_item_sctp *sctp_spec, *sctp_mask;
-       const struct rte_flow_item_gtp *gtp_spec, *gtp_mask;
-       const struct rte_flow_item_esp *esp_spec, *esp_mask;
-       const struct rte_flow_item_raw *raw_spec, *raw_mask;
-       const struct rte_flow_item_l2tpv3oip *l2tpv3oip_spec, *l2tpv3oip_mask;
-
-       uint8_t pctype = 0;
-       uint64_t input_set = I40E_INSET_NONE;
-       enum rte_flow_item_type item_type;
-       enum rte_flow_item_type next_type;
-       enum rte_flow_item_type l3 = RTE_FLOW_ITEM_TYPE_END;
-       enum rte_flow_item_type cus_proto = RTE_FLOW_ITEM_TYPE_END;
-       uint32_t i, j;
-       uint8_t  ipv6_addr_mask[16] = {
-               0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-               0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-       enum i40e_flxpld_layer_idx layer_idx = I40E_FLXPLD_L2_IDX;
-       uint8_t raw_id = 0;
-       int32_t off_arr[I40E_MAX_FLXPLD_FIED];
-       uint16_t len_arr[I40E_MAX_FLXPLD_FIED];
-       struct i40e_fdir_flex_pit flex_pit;
-       uint8_t next_dst_off = 0;
-       uint16_t flex_size;
-       uint16_t ether_type;
-       uint32_t vtc_flow_cpu;
-       bool outer_ip = true;
-       uint8_t field_idx;
-       int ret;
-       uint16_t tpid;
-
-       memset(off_arr, 0, sizeof(off_arr));
-       memset(len_arr, 0, sizeof(len_arr));
-       filter->input.flow_ext.customized_pctype = false;
-       for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
-               if (item->last && item->type != RTE_FLOW_ITEM_TYPE_IPV4) {
-                       rte_flow_error_set(error, EINVAL,
-                                          RTE_FLOW_ERROR_TYPE_ITEM,
-                                          item,
-                                          "Not support range");
-                       return -rte_errno;
-               }
-               item_type = item->type;
-               switch (item_type) {
-               case RTE_FLOW_ITEM_TYPE_ETH:
-                       eth_spec = item->spec;
-                       eth_mask = item->mask;
-                       next_type = (item + 1)->type;
-
-                       if (next_type == RTE_FLOW_ITEM_TYPE_END &&
-                                               (!eth_spec || !eth_mask)) {
-                               rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "NULL eth spec/mask.");
-                               return -rte_errno;
-                       }
-
-                       if (eth_spec && eth_mask) {
-                               if 
(rte_is_broadcast_ether_addr(&eth_mask->hdr.dst_addr) &&
-                                       
rte_is_zero_ether_addr(&eth_mask->hdr.src_addr)) {
-                                       filter->input.flow.l2_flow.dst =
-                                               eth_spec->hdr.dst_addr;
-                                       input_set |= I40E_INSET_DMAC;
-                               } else if 
(rte_is_zero_ether_addr(&eth_mask->hdr.dst_addr) &&
-                                       
rte_is_broadcast_ether_addr(&eth_mask->hdr.src_addr)) {
-                                       filter->input.flow.l2_flow.src =
-                                               eth_spec->hdr.src_addr;
-                                       input_set |= I40E_INSET_SMAC;
-                               } else if 
(rte_is_broadcast_ether_addr(&eth_mask->hdr.dst_addr) &&
-                                       
rte_is_broadcast_ether_addr(&eth_mask->hdr.src_addr)) {
-                                       filter->input.flow.l2_flow.dst =
-                                               eth_spec->hdr.dst_addr;
-                                       filter->input.flow.l2_flow.src =
-                                               eth_spec->hdr.src_addr;
-                                       input_set |= (I40E_INSET_DMAC | 
I40E_INSET_SMAC);
-                               } else if 
(!rte_is_zero_ether_addr(&eth_mask->hdr.src_addr) ||
-                                          
!rte_is_zero_ether_addr(&eth_mask->hdr.dst_addr)) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                     RTE_FLOW_ERROR_TYPE_ITEM,
-                                                     item,
-                                                     "Invalid MAC_addr mask.");
-                                       return -rte_errno;
-                               }
-                       }
-                       if (eth_spec && eth_mask &&
-                       next_type == RTE_FLOW_ITEM_TYPE_END) {
-                               if (eth_mask->hdr.ether_type != 
RTE_BE16(0xffff)) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                     RTE_FLOW_ERROR_TYPE_ITEM,
-                                                     item,
-                                                     "Invalid type mask.");
-                                       return -rte_errno;
-                               }
-
-                               ether_type = 
rte_be_to_cpu_16(eth_spec->hdr.ether_type);
-
-                               if (ether_type == RTE_ETHER_TYPE_IPV4 ||
-                                   ether_type == RTE_ETHER_TYPE_IPV6) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                    RTE_FLOW_ERROR_TYPE_ITEM,
-                                                    item,
-                                                    "Unsupported ether_type.");
-                                       return -rte_errno;
-                               }
-                               ret = i40e_get_outer_vlan(dev, &tpid);
-                               if (ret != 0) {
-                                       rte_flow_error_set(error, EIO,
-                                                       
RTE_FLOW_ERROR_TYPE_ITEM,
-                                                       item,
-                                                       "Can not get the 
Ethertype identifying the L2 tag");
-                                       return -rte_errno;
-                               }
-                               if (ether_type == tpid) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                    RTE_FLOW_ERROR_TYPE_ITEM,
-                                                    item,
-                                                    "Unsupported ether_type.");
-                                       return -rte_errno;
-                               }
-
-                               input_set |= I40E_INSET_LAST_ETHER_TYPE;
-                               filter->input.flow.l2_flow.ether_type =
-                                       eth_spec->hdr.ether_type;
-                       }
-
-                       pctype = I40E_FILTER_PCTYPE_L2_PAYLOAD;
-                       layer_idx = I40E_FLXPLD_L2_IDX;
-
-                       break;
-               case RTE_FLOW_ITEM_TYPE_VLAN:
-                       vlan_spec = item->spec;
-                       vlan_mask = item->mask;
-
-                       RTE_ASSERT(!(input_set & I40E_INSET_LAST_ETHER_TYPE));
-                       if (vlan_spec && vlan_mask) {
-                               if (vlan_mask->hdr.vlan_tci !=
-                                   rte_cpu_to_be_16(I40E_VLAN_TCI_MASK) &&
-                                   vlan_mask->hdr.vlan_tci !=
-                                   rte_cpu_to_be_16(I40E_VLAN_PRI_MASK) &&
-                                   vlan_mask->hdr.vlan_tci !=
-                                   rte_cpu_to_be_16(I40E_VLAN_CFI_MASK) &&
-                                   vlan_mask->hdr.vlan_tci !=
-                                   rte_cpu_to_be_16(I40E_VLAN_VID_MASK)) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Unsupported TCI mask.");
-                               }
-                               input_set |= I40E_INSET_VLAN_INNER;
-                               filter->input.flow_ext.vlan_tci =
-                                       vlan_spec->hdr.vlan_tci;
-                       }
-                       if (vlan_spec && vlan_mask && vlan_mask->hdr.eth_proto) 
{
-                               if (vlan_mask->hdr.eth_proto != 
RTE_BE16(0xffff)) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                     RTE_FLOW_ERROR_TYPE_ITEM,
-                                                     item,
-                                                     "Invalid inner_type"
-                                                     " mask.");
-                                       return -rte_errno;
-                               }
-
-                               ether_type =
-                                       
rte_be_to_cpu_16(vlan_spec->hdr.eth_proto);
-
-                               if (ether_type == RTE_ETHER_TYPE_IPV4 ||
-                                   ether_type == RTE_ETHER_TYPE_IPV6) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                    RTE_FLOW_ERROR_TYPE_ITEM,
-                                                    item,
-                                                    "Unsupported inner_type.");
-                                       return -rte_errno;
-                               }
-                               ret = i40e_get_outer_vlan(dev, &tpid);
-                               if (ret != 0) {
-                                       rte_flow_error_set(error, EIO,
-                                                       
RTE_FLOW_ERROR_TYPE_ITEM,
-                                                       item,
-                                                       "Can not get the 
Ethertype identifying the L2 tag");
-                                       return -rte_errno;
-                               }
-                               if (ether_type == tpid) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                    RTE_FLOW_ERROR_TYPE_ITEM,
-                                                    item,
-                                                    "Unsupported ether_type.");
-                                       return -rte_errno;
-                               }
-
-                               input_set |= I40E_INSET_LAST_ETHER_TYPE;
-                               filter->input.flow.l2_flow.ether_type =
-                                       vlan_spec->hdr.eth_proto;
-                       }
-
-                       pctype = I40E_FILTER_PCTYPE_L2_PAYLOAD;
-                       layer_idx = I40E_FLXPLD_L2_IDX;
-
-                       break;
-               case RTE_FLOW_ITEM_TYPE_IPV4:
-                       l3 = RTE_FLOW_ITEM_TYPE_IPV4;
-                       ipv4_spec = item->spec;
-                       ipv4_mask = item->mask;
-                       ipv4_last = item->last;
-                       pctype = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
-                       layer_idx = I40E_FLXPLD_L3_IDX;
-
-                       if (ipv4_last) {
-                               if (!ipv4_spec || !ipv4_mask || !outer_ip) {
-                                       rte_flow_error_set(error, EINVAL,
-                                               RTE_FLOW_ERROR_TYPE_ITEM,
-                                               item,
-                                               "Not support range");
-                                       return -rte_errno;
-                               }
-                               /* Only fragment_offset supports range */
-                               if (ipv4_last->hdr.version_ihl ||
-                                   ipv4_last->hdr.type_of_service ||
-                                   ipv4_last->hdr.total_length ||
-                                   ipv4_last->hdr.packet_id ||
-                                   ipv4_last->hdr.time_to_live ||
-                                   ipv4_last->hdr.next_proto_id ||
-                                   ipv4_last->hdr.hdr_checksum ||
-                                   ipv4_last->hdr.src_addr ||
-                                   ipv4_last->hdr.dst_addr) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Not support range");
-                                       return -rte_errno;
-                               }
-                       }
-                       if (ipv4_spec && ipv4_mask && outer_ip) {
-                               /* Check IPv4 mask and update input set */
-                               if (ipv4_mask->hdr.version_ihl ||
-                                   ipv4_mask->hdr.total_length ||
-                                   ipv4_mask->hdr.packet_id ||
-                                   ipv4_mask->hdr.hdr_checksum) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Invalid IPv4 mask.");
-                                       return -rte_errno;
-                               }
-
-                               if (ipv4_mask->hdr.src_addr == UINT32_MAX)
-                                       input_set |= I40E_INSET_IPV4_SRC;
-                               if (ipv4_mask->hdr.dst_addr == UINT32_MAX)
-                                       input_set |= I40E_INSET_IPV4_DST;
-                               if (ipv4_mask->hdr.type_of_service == UINT8_MAX)
-                                       input_set |= I40E_INSET_IPV4_TOS;
-                               if (ipv4_mask->hdr.time_to_live == UINT8_MAX)
-                                       input_set |= I40E_INSET_IPV4_TTL;
-                               if (ipv4_mask->hdr.next_proto_id == UINT8_MAX)
-                                       input_set |= I40E_INSET_IPV4_PROTO;
-
-                               /* Check if it is fragment. */
-                               uint16_t frag_mask =
-                                       ipv4_mask->hdr.fragment_offset;
-                               uint16_t frag_spec =
-                                       ipv4_spec->hdr.fragment_offset;
-                               uint16_t frag_last = 0;
-                               if (ipv4_last)
-                                       frag_last =
-                                       ipv4_last->hdr.fragment_offset;
-                               if (frag_mask) {
-                                       frag_mask = rte_be_to_cpu_16(frag_mask);
-                                       frag_spec = rte_be_to_cpu_16(frag_spec);
-                                       frag_last = rte_be_to_cpu_16(frag_last);
-                                       /* frag_off mask has to be 0x3fff */
-                                       if (frag_mask !=
-                                           (RTE_IPV4_HDR_OFFSET_MASK |
-                                           RTE_IPV4_HDR_MF_FLAG)) {
-                                               rte_flow_error_set(error,
-                                                  EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Invalid IPv4 
fragment_offset mask");
-                                               return -rte_errno;
-                                       }
-                                       /*
-                                        * non-frag rule:
-                                        * mask=0x3fff,spec=0
-                                        * frag rule:
-                                        * mask=0x3fff,spec=0x8,last=0x2000
-                                        */
-                                       if (frag_spec ==
-                                           (1 << RTE_IPV4_HDR_FO_SHIFT) &&
-                                           frag_last == RTE_IPV4_HDR_MF_FLAG) {
-                                               pctype =
-                                                 I40E_FILTER_PCTYPE_FRAG_IPV4;
-                                       } else if (frag_spec || frag_last) {
-                                               rte_flow_error_set(error,
-                                                  EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Invalid IPv4 
fragment_offset rule");
-                                               return -rte_errno;
-                                       }
-                               } else if (frag_spec || frag_last) {
-                                       rte_flow_error_set(error,
-                                               EINVAL,
-                                               RTE_FLOW_ERROR_TYPE_ITEM,
-                                               item,
-                                               "Invalid fragment_offset");
-                                       return -rte_errno;
-                               }
-
-                               if (input_set & (I40E_INSET_DMAC | 
I40E_INSET_SMAC)) {
-                                       if (input_set & (I40E_INSET_IPV4_SRC |
-                                               I40E_INSET_IPV4_DST | 
I40E_INSET_IPV4_TOS |
-                                               I40E_INSET_IPV4_TTL | 
I40E_INSET_IPV4_PROTO)) {
-                                               rte_flow_error_set(error, 
EINVAL,
-                                                       
RTE_FLOW_ERROR_TYPE_ITEM,
-                                                       item,
-                                                       "L2 and L3 input set 
are exclusive.");
-                                               return -rte_errno;
-                                       }
-                               } else {
-                                       /* Get the filter info */
-                                       filter->input.flow.ip4_flow.proto =
-                                               ipv4_spec->hdr.next_proto_id;
-                                       filter->input.flow.ip4_flow.tos =
-                                               ipv4_spec->hdr.type_of_service;
-                                       filter->input.flow.ip4_flow.ttl =
-                                               ipv4_spec->hdr.time_to_live;
-                                       filter->input.flow.ip4_flow.src_ip =
-                                               ipv4_spec->hdr.src_addr;
-                                       filter->input.flow.ip4_flow.dst_ip =
-                                               ipv4_spec->hdr.dst_addr;
-
-                                       filter->input.flow_ext.inner_ip = false;
-                                       filter->input.flow_ext.oip_type =
-                                               I40E_FDIR_IPTYPE_IPV4;
-                               }
-                       } else if (!ipv4_spec && !ipv4_mask && !outer_ip) {
-                               filter->input.flow_ext.inner_ip = true;
-                               filter->input.flow_ext.iip_type =
-                                       I40E_FDIR_IPTYPE_IPV4;
-                       } else if (!ipv4_spec && !ipv4_mask && outer_ip) {
-                               filter->input.flow_ext.inner_ip = false;
-                               filter->input.flow_ext.oip_type =
-                                       I40E_FDIR_IPTYPE_IPV4;
-                       } else if ((ipv4_spec || ipv4_mask) && !outer_ip) {
-                               rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Invalid inner IPv4 mask.");
-                               return -rte_errno;
-                       }
-
-                       if (outer_ip)
-                               outer_ip = false;
-
-                       break;
-               case RTE_FLOW_ITEM_TYPE_IPV6:
-                       l3 = RTE_FLOW_ITEM_TYPE_IPV6;
-                       ipv6_spec = item->spec;
-                       ipv6_mask = item->mask;
-                       pctype = I40E_FILTER_PCTYPE_NONF_IPV6_OTHER;
-                       layer_idx = I40E_FLXPLD_L3_IDX;
-
-                       if (ipv6_spec && ipv6_mask && outer_ip) {
-                               /* Check IPv6 mask and update input set */
-                               if (ipv6_mask->hdr.payload_len) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Invalid IPv6 mask");
-                                       return -rte_errno;
-                               }
-
-                               if (!memcmp(&ipv6_mask->hdr.src_addr,
-                                           ipv6_addr_mask,
-                                           sizeof(ipv6_mask->hdr.src_addr)))
-                                       input_set |= I40E_INSET_IPV6_SRC;
-                               if (!memcmp(&ipv6_mask->hdr.dst_addr,
-                                           ipv6_addr_mask,
-                                           sizeof(ipv6_mask->hdr.dst_addr)))
-                                       input_set |= I40E_INSET_IPV6_DST;
-
-                               if ((ipv6_mask->hdr.vtc_flow &
-                                    rte_cpu_to_be_32(I40E_IPV6_TC_MASK))
-                                   == rte_cpu_to_be_32(I40E_IPV6_TC_MASK))
-                                       input_set |= I40E_INSET_IPV6_TC;
-                               if (ipv6_mask->hdr.proto == UINT8_MAX)
-                                       input_set |= I40E_INSET_IPV6_NEXT_HDR;
-                               if (ipv6_mask->hdr.hop_limits == UINT8_MAX)
-                                       input_set |= I40E_INSET_IPV6_HOP_LIMIT;
-
-                               /* Get filter info */
-                               vtc_flow_cpu =
-                                     rte_be_to_cpu_32(ipv6_spec->hdr.vtc_flow);
-                               filter->input.flow.ipv6_flow.tc =
-                                       (uint8_t)(vtc_flow_cpu >>
-                                                 I40E_FDIR_IPv6_TC_OFFSET);
-                               filter->input.flow.ipv6_flow.proto =
-                                       ipv6_spec->hdr.proto;
-                               filter->input.flow.ipv6_flow.hop_limits =
-                                       ipv6_spec->hdr.hop_limits;
-
-                               filter->input.flow_ext.inner_ip = false;
-                               filter->input.flow_ext.oip_type =
-                                       I40E_FDIR_IPTYPE_IPV6;
-
-                               rte_memcpy(filter->input.flow.ipv6_flow.src_ip,
-                                          &ipv6_spec->hdr.src_addr, 16);
-                               rte_memcpy(filter->input.flow.ipv6_flow.dst_ip,
-                                          &ipv6_spec->hdr.dst_addr, 16);
-
-                               /* Check if it is fragment. */
-                               if (ipv6_spec->hdr.proto ==
-                                   I40E_IPV6_FRAG_HEADER)
-                                       pctype = I40E_FILTER_PCTYPE_FRAG_IPV6;
-                       } else if (!ipv6_spec && !ipv6_mask && !outer_ip) {
-                               filter->input.flow_ext.inner_ip = true;
-                               filter->input.flow_ext.iip_type =
-                                       I40E_FDIR_IPTYPE_IPV6;
-                       } else if (!ipv6_spec && !ipv6_mask && outer_ip) {
-                               filter->input.flow_ext.inner_ip = false;
-                               filter->input.flow_ext.oip_type =
-                                       I40E_FDIR_IPTYPE_IPV6;
-                       } else if ((ipv6_spec || ipv6_mask) && !outer_ip) {
-                               rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Invalid inner IPv6 mask");
-                               return -rte_errno;
-                       }
-
-                       if (outer_ip)
-                               outer_ip = false;
-                       break;
-               case RTE_FLOW_ITEM_TYPE_TCP:
-                       tcp_spec = item->spec;
-                       tcp_mask = item->mask;
-
-                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
-                               pctype =
-                                       I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
-                       else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
-                               pctype =
-                                       I40E_FILTER_PCTYPE_NONF_IPV6_TCP;
-                       if (tcp_spec && tcp_mask) {
-                               /* Check TCP mask and update input set */
-                               if (tcp_mask->hdr.sent_seq ||
-                                   tcp_mask->hdr.recv_ack ||
-                                   tcp_mask->hdr.data_off ||
-                                   tcp_mask->hdr.tcp_flags ||
-                                   tcp_mask->hdr.rx_win ||
-                                   tcp_mask->hdr.cksum ||
-                                   tcp_mask->hdr.tcp_urp) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Invalid TCP mask");
-                                       return -rte_errno;
-                               }
-
-                               if (tcp_mask->hdr.src_port == UINT16_MAX)
-                                       input_set |= I40E_INSET_SRC_PORT;
-                               if (tcp_mask->hdr.dst_port == UINT16_MAX)
-                                       input_set |= I40E_INSET_DST_PORT;
-
-                               if (input_set & (I40E_INSET_DMAC | 
I40E_INSET_SMAC)) {
-                                       if (input_set &
-                                               (I40E_INSET_SRC_PORT | 
I40E_INSET_DST_PORT)) {
-                                               rte_flow_error_set(error, 
EINVAL,
-                                                       
RTE_FLOW_ERROR_TYPE_ITEM,
-                                                       item,
-                                                       "L2 and L4 input set 
are exclusive.");
-                                               return -rte_errno;
-                                       }
-                               } else {
-                                       /* Get filter info */
-                                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
-                                               
filter->input.flow.tcp4_flow.src_port =
-                                                       tcp_spec->hdr.src_port;
-                                               
filter->input.flow.tcp4_flow.dst_port =
-                                                       tcp_spec->hdr.dst_port;
-                                       } else if (l3 == 
RTE_FLOW_ITEM_TYPE_IPV6) {
-                                               
filter->input.flow.tcp6_flow.src_port =
-                                                       tcp_spec->hdr.src_port;
-                                               
filter->input.flow.tcp6_flow.dst_port =
-                                                       tcp_spec->hdr.dst_port;
-                                       }
-                               }
-                       }
-
-                       layer_idx = I40E_FLXPLD_L4_IDX;
-
-                       break;
-               case RTE_FLOW_ITEM_TYPE_UDP:
-                       udp_spec = item->spec;
-                       udp_mask = item->mask;
-
-                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
-                               pctype =
-                                       I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
-                       else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
-                               pctype =
-                                       I40E_FILTER_PCTYPE_NONF_IPV6_UDP;
-
-                       if (udp_spec && udp_mask) {
-                               /* Check UDP mask and update input set*/
-                               if (udp_mask->hdr.dgram_len ||
-                                   udp_mask->hdr.dgram_cksum) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Invalid UDP mask");
-                                       return -rte_errno;
-                               }
-
-                               if (udp_mask->hdr.src_port == UINT16_MAX)
-                                       input_set |= I40E_INSET_SRC_PORT;
-                               if (udp_mask->hdr.dst_port == UINT16_MAX)
-                                       input_set |= I40E_INSET_DST_PORT;
-
-                               if (input_set & (I40E_INSET_DMAC | 
I40E_INSET_SMAC)) {
-                                       if (input_set &
-                                               (I40E_INSET_SRC_PORT | 
I40E_INSET_DST_PORT)) {
-                                               rte_flow_error_set(error, 
EINVAL,
-                                                       
RTE_FLOW_ERROR_TYPE_ITEM,
-                                                       item,
-                                                       "L2 and L4 input set 
are exclusive.");
-                                               return -rte_errno;
-                                       }
-                               } else {
-                                       /* Get filter info */
-                                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
-                                               
filter->input.flow.udp4_flow.src_port =
-                                                       udp_spec->hdr.src_port;
-                                               
filter->input.flow.udp4_flow.dst_port =
-                                                       udp_spec->hdr.dst_port;
-                                       } else if (l3 == 
RTE_FLOW_ITEM_TYPE_IPV6) {
-                                               
filter->input.flow.udp6_flow.src_port =
-                                                       udp_spec->hdr.src_port;
-                                               
filter->input.flow.udp6_flow.dst_port =
-                                                       udp_spec->hdr.dst_port;
-                                       }
-                               }
-                       }
-                       filter->input.flow_ext.is_udp = true;
-                       layer_idx = I40E_FLXPLD_L4_IDX;
-
-                       break;
-               case RTE_FLOW_ITEM_TYPE_GTPC:
-               case RTE_FLOW_ITEM_TYPE_GTPU:
-                       if (!pf->gtp_support) {
-                               rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Unsupported protocol");
-                               return -rte_errno;
-                       }
-
-                       gtp_spec = item->spec;
-                       gtp_mask = item->mask;
-
-                       if (gtp_spec && gtp_mask) {
-                               if (gtp_mask->hdr.gtp_hdr_info ||
-                                   gtp_mask->hdr.msg_type ||
-                                   gtp_mask->hdr.plen ||
-                                   gtp_mask->hdr.teid != UINT32_MAX) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Invalid GTP mask");
-                                       return -rte_errno;
-                               }
-
-                               filter->input.flow.gtp_flow.teid =
-                                       gtp_spec->hdr.teid;
-                               filter->input.flow_ext.customized_pctype = true;
-                               cus_proto = item_type;
-                       }
-                       break;
-               case RTE_FLOW_ITEM_TYPE_ESP:
-                       if (!pf->esp_support) {
-                               rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Unsupported ESP protocol");
-                               return -rte_errno;
-                       }
-
-                       esp_spec = item->spec;
-                       esp_mask = item->mask;
-
-                       if (!esp_spec || !esp_mask) {
-                               rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Invalid ESP item");
-                               return -rte_errno;
-                       }
-
-                       if (esp_spec && esp_mask) {
-                               if (esp_mask->hdr.spi != UINT32_MAX) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Invalid ESP mask");
-                                       return -rte_errno;
-                               }
-                               i40e_flow_set_filter_spi(filter, esp_spec);
-                               filter->input.flow_ext.customized_pctype = true;
-                               cus_proto = item_type;
-                       }
-                       break;
-               case RTE_FLOW_ITEM_TYPE_SCTP:
-                       sctp_spec = item->spec;
-                       sctp_mask = item->mask;
-
-                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
-                               pctype =
-                                       I40E_FILTER_PCTYPE_NONF_IPV4_SCTP;
-                       else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
-                               pctype =
-                                       I40E_FILTER_PCTYPE_NONF_IPV6_SCTP;
-
-                       if (sctp_spec && sctp_mask) {
-                               /* Check SCTP mask and update input set */
-                               if (sctp_mask->hdr.cksum) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Invalid UDP mask");
-                                       return -rte_errno;
-                               }
-
-                               if (sctp_mask->hdr.src_port == UINT16_MAX)
-                                       input_set |= I40E_INSET_SRC_PORT;
-                               if (sctp_mask->hdr.dst_port == UINT16_MAX)
-                                       input_set |= I40E_INSET_DST_PORT;
-                               if (sctp_mask->hdr.tag == UINT32_MAX)
-                                       input_set |= I40E_INSET_SCTP_VT;
-
-                               /* Get filter info */
-                               if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
-                                       filter->input.flow.sctp4_flow.src_port =
-                                               sctp_spec->hdr.src_port;
-                                       filter->input.flow.sctp4_flow.dst_port =
-                                               sctp_spec->hdr.dst_port;
-                                       filter->input.flow.sctp4_flow.verify_tag
-                                               = sctp_spec->hdr.tag;
-                               } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) {
-                                       filter->input.flow.sctp6_flow.src_port =
-                                               sctp_spec->hdr.src_port;
-                                       filter->input.flow.sctp6_flow.dst_port =
-                                               sctp_spec->hdr.dst_port;
-                                       filter->input.flow.sctp6_flow.verify_tag
-                                               = sctp_spec->hdr.tag;
-                               }
-                       }
-
-                       layer_idx = I40E_FLXPLD_L4_IDX;
-
-                       break;
-               case RTE_FLOW_ITEM_TYPE_RAW:
-                       raw_spec = item->spec;
-                       raw_mask = item->mask;
-
-                       if (!raw_spec || !raw_mask) {
-                               rte_flow_error_set(error, EINVAL,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "NULL RAW spec/mask");
-                               return -rte_errno;
-                       }
-
-                       if (pf->support_multi_driver) {
-                               rte_flow_error_set(error, ENOTSUP,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  item,
-                                                  "Unsupported flexible 
payload.");
-                               return -rte_errno;
-                       }
-
-                       ret = i40e_flow_check_raw_item(item, raw_spec, error);
-                       if (ret < 0)
-                               return ret;
-
-                       off_arr[raw_id] = raw_spec->offset;
-                       len_arr[raw_id] = raw_spec->length;
-
-                       flex_size = 0;
-                       memset(&flex_pit, 0, sizeof(struct i40e_fdir_flex_pit));
-                       field_idx = layer_idx * I40E_MAX_FLXPLD_FIED + raw_id;
-                       flex_pit.size =
-                               raw_spec->length / sizeof(uint16_t);
-                       flex_pit.dst_offset =
-                               next_dst_off / sizeof(uint16_t);
-
-                       for (i = 0; i <= raw_id; i++) {
-                               if (i == raw_id)
-                                       flex_pit.src_offset +=
-                                               raw_spec->offset /
-                                               sizeof(uint16_t);
-                               else
-                                       flex_pit.src_offset +=
-                                               (off_arr[i] + len_arr[i]) /
-                                               sizeof(uint16_t);
-                               flex_size += len_arr[i];
-                       }
-                       if (((flex_pit.src_offset + flex_pit.size) >=
-                            I40E_MAX_FLX_SOURCE_OFF / sizeof(uint16_t)) ||
-                               flex_size > I40E_FDIR_MAX_FLEXLEN) {
-                               rte_flow_error_set(error, EINVAL,
-                                          RTE_FLOW_ERROR_TYPE_ITEM,
-                                          item,
-                                          "Exceeds maximal payload limit.");
-                               return -rte_errno;
-                       }
-
-                       if (raw_spec->length != 0) {
-                               if (raw_spec->pattern == NULL) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                          
RTE_FLOW_ERROR_TYPE_ITEM,
-                                                          item,
-                                                          "NULL RAW spec 
pattern");
-                                       return -rte_errno;
-                               }
-                               if (raw_mask->pattern == NULL) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                          
RTE_FLOW_ERROR_TYPE_ITEM,
-                                                          item,
-                                                          "NULL RAW mask 
pattern");
-                                       return -rte_errno;
-                               }
-                               if (raw_spec->length != raw_mask->length) {
-                                       rte_flow_error_set(error, EINVAL,
-                                                          
RTE_FLOW_ERROR_TYPE_ITEM,
-                                                          item,
-                                                          "RAW spec and mask 
length mismatch");
-                                       return -rte_errno;
-                               }
-                       }
-
-                       for (i = 0; i < raw_spec->length; i++) {
-                               j = i + next_dst_off;
-                               if (j >= RTE_ETH_FDIR_MAX_FLEXLEN ||
-                                               j >= I40E_FDIR_MAX_FLEX_LEN)
-                                       break;
-                               filter->input.flow_ext.flexbytes[j] =
-                                       raw_spec->pattern[i];
-                               filter->input.flow_ext.flex_mask[j] =
-                                       raw_mask->pattern[i];
-                       }
-
-                       next_dst_off += raw_spec->length;
-                       raw_id++;
-
-                       filter->input.flow_ext.flex_pit[field_idx] = flex_pit;
-                       filter->input.flow_ext.layer_idx = layer_idx;
-                       filter->input.flow_ext.raw_id = raw_id;
-                       filter->input.flow_ext.is_flex_flow = true;
-                       break;
-               case RTE_FLOW_ITEM_TYPE_L2TPV3OIP:
-                       l2tpv3oip_spec = item->spec;
-                       l2tpv3oip_mask = item->mask;
-
-                       if (!l2tpv3oip_spec || !l2tpv3oip_mask)
-                               break;
-
-                       if (l2tpv3oip_mask->session_id != UINT32_MAX) {
-                               rte_flow_error_set(error, EINVAL,
-                                       RTE_FLOW_ERROR_TYPE_ITEM,
-                                       item,
-                                       "Invalid L2TPv3 mask");
-                               return -rte_errno;
-                       }
-
-                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
-                               
filter->input.flow.ip4_l2tpv3oip_flow.session_id =
-                                       l2tpv3oip_spec->session_id;
-                               filter->input.flow_ext.oip_type =
-                                       I40E_FDIR_IPTYPE_IPV4;
-                       } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) {
-                               
filter->input.flow.ip6_l2tpv3oip_flow.session_id =
-                                       l2tpv3oip_spec->session_id;
-                               filter->input.flow_ext.oip_type =
-                                       I40E_FDIR_IPTYPE_IPV6;
-                       }
-
-                       filter->input.flow_ext.customized_pctype = true;
-                       cus_proto = item_type;
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       /* Get customized pctype value */
-       if (filter->input.flow_ext.customized_pctype) {
-               pctype = i40e_flow_fdir_get_pctype_value(pf, cus_proto, filter);
-               if (pctype == I40E_FILTER_PCTYPE_INVALID) {
-                       rte_flow_error_set(error, EINVAL,
-                                          RTE_FLOW_ERROR_TYPE_ITEM,
-                                          item,
-                                          "Unsupported pctype");
-                       return -rte_errno;
-               }
-       }
-
-       /* If customized pctype is not used, set fdir configuration.*/
-       if (!filter->input.flow_ext.customized_pctype) {
-               /* Check if the input set is valid */
-               if (i40e_validate_input_set(pctype, RTE_ETH_FILTER_FDIR,
-                                               input_set) != 0) {
-                       rte_flow_error_set(error, EINVAL,
-                                          RTE_FLOW_ERROR_TYPE_ITEM,
-                                          item,
-                                          "Invalid input set");
-                       return -rte_errno;
-               }
-
-               filter->input.flow_ext.input_set = input_set;
-       }
-
-       filter->input.pctype = pctype;
-
-       return 0;
-}
-
-/* Parse to get the action info of a FDIR filter.
- * FDIR action supports QUEUE or (QUEUE + MARK).
- */
-static int
-i40e_flow_parse_fdir_action(struct rte_eth_dev *dev,
-                           const struct rte_flow_action *actions,
-                           struct rte_flow_error *error,
-                           struct i40e_fdir_filter_conf *filter)
-{
-       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-       struct ci_flow_actions parsed_actions = {0};
-       struct ci_flow_actions_check_param ac_param = {
-               .allowed_types = (enum rte_flow_action_type[]) {
-                       RTE_FLOW_ACTION_TYPE_QUEUE,
-                       RTE_FLOW_ACTION_TYPE_DROP,
-                       RTE_FLOW_ACTION_TYPE_PASSTHRU,
-                       RTE_FLOW_ACTION_TYPE_MARK,
-                       RTE_FLOW_ACTION_TYPE_FLAG,
-                       RTE_FLOW_ACTION_TYPE_RSS,
-                       RTE_FLOW_ACTION_TYPE_END
-               },
-               .max_actions = 2,
-       };
-       const struct rte_flow_action *first, *second;
-       int ret;
-
-       ret = ci_flow_check_actions(actions, &ac_param, &parsed_actions, error);
-       if (ret)
-               return ret;
-       first = parsed_actions.actions[0];
-       /* can be NULL */
-       second = parsed_actions.actions[1];
-
-       switch (first->type) {
-       case RTE_FLOW_ACTION_TYPE_QUEUE:
-       {
-               const struct rte_flow_action_queue *act_q = first->conf;
-               /* check against PF constraints */
-               if (!filter->input.flow_ext.is_vf && act_q->index >= 
pf->dev_data->nb_rx_queues) {
-                       return rte_flow_error_set(error, EINVAL,
-                                       RTE_FLOW_ERROR_TYPE_ACTION, first,
-                                       "Invalid queue ID for FDIR");
-               }
-               /* check against VF constraints */
-               if (filter->input.flow_ext.is_vf && act_q->index >= 
pf->vf_nb_qps) {
-                       return rte_flow_error_set(error, EINVAL,
-                                       RTE_FLOW_ERROR_TYPE_ACTION, first,
-                                       "Invalid queue ID for FDIR");
-               }
-               filter->action.rx_queue = act_q->index;
-               filter->action.behavior = I40E_FDIR_ACCEPT;
-               break;
-       }
-       case RTE_FLOW_ACTION_TYPE_DROP:
-               filter->action.behavior = I40E_FDIR_REJECT;
-               break;
-       case RTE_FLOW_ACTION_TYPE_PASSTHRU:
-               filter->action.behavior = I40E_FDIR_PASSTHRU;
-               break;
-       case RTE_FLOW_ACTION_TYPE_MARK:
-       {
-               const struct rte_flow_action_mark *act_m = first->conf;
-               filter->action.behavior = I40E_FDIR_PASSTHRU;
-               filter->action.report_status = I40E_FDIR_REPORT_ID;
-               filter->soft_id = act_m->id;
-               break;
-       }
-       default:
-               return rte_flow_error_set(error, EINVAL,
-                               RTE_FLOW_ERROR_TYPE_ACTION, first,
-                               "Invalid first action for FDIR");
-       }
-
-       /* do we have another? */
-       if (second == NULL)
-               return 0;
-
-       switch (second->type) {
-       case RTE_FLOW_ACTION_TYPE_MARK:
-       {
-               const struct rte_flow_action_mark *act_m = second->conf;
-               /* only one mark action can be specified */
-               if (first->type == RTE_FLOW_ACTION_TYPE_MARK) {
-                       return rte_flow_error_set(error, EINVAL,
-                                                 RTE_FLOW_ERROR_TYPE_ACTION, 
second,
-                                                 "Invalid second action for 
FDIR");
-               }
-               filter->action.report_status = I40E_FDIR_REPORT_ID;
-               filter->soft_id = act_m->id;
-               break;
-       }
-       case RTE_FLOW_ACTION_TYPE_FLAG:
-       {
-               /* mark + flag is unsupported */
-               if (first->type == RTE_FLOW_ACTION_TYPE_MARK) {
-                       return rte_flow_error_set(error, EINVAL,
-                                       RTE_FLOW_ERROR_TYPE_ACTION, second,
-                                       "Invalid second action for FDIR");
-               }
-               filter->action.report_status = I40E_FDIR_NO_REPORT_STATUS;
-               break;
-       }
-       case RTE_FLOW_ACTION_TYPE_RSS:
-               /* RSS filter only can be after passthru or mark */
-               if (first->type != RTE_FLOW_ACTION_TYPE_PASSTHRU &&
-                               first->type != RTE_FLOW_ACTION_TYPE_MARK) {
-                       return rte_flow_error_set(error, EINVAL,
-                                       RTE_FLOW_ERROR_TYPE_ACTION, second,
-                                       "Invalid second action for FDIR");
-               }
-               break;
-       default:
-               return rte_flow_error_set(error, EINVAL,
-                                         RTE_FLOW_ERROR_TYPE_ACTION, second,
-                                         "Invalid second action for FDIR");
-       }
-
-       return 0;
-}
-
-static int
-i40e_flow_parse_fdir_filter(struct rte_eth_dev *dev,
-                           const struct rte_flow_item pattern[],
-                           const struct rte_flow_action actions[],
-                           struct rte_flow_error *error,
-                           struct i40e_filter_ctx *filter)
-{
-       struct i40e_fdir_filter_conf *fdir_filter = &filter->fdir_filter;
-       int ret;
-
-       ret = i40e_flow_parse_fdir_pattern(dev, pattern, error, fdir_filter);
-       if (ret)
-               return ret;
-
-       ret = i40e_flow_parse_fdir_action(dev, actions, error, fdir_filter);
-       if (ret)
-               return ret;
-
-       filter->type = RTE_ETH_FILTER_FDIR;
-
-       return 0;
-}
-
 /* Parse to get the action info of a tunnel filter
  * Tunnel action only supports PF, VF and QUEUE.
  */
@@ -3632,7 +1813,6 @@ i40e_flow_create(struct rte_eth_dev *dev,
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        struct i40e_filter_ctx filter_ctx = {0};
        struct rte_flow *flow = NULL;
-       struct i40e_fdir_info *fdir_info = &pf->fdir;
        int ret;
 
        /* try the new engine first */
@@ -3645,55 +1825,15 @@ i40e_flow_create(struct rte_eth_dev *dev,
        if (ret < 0)
                return NULL;
 
-       if (filter_ctx.type == RTE_ETH_FILTER_FDIR) {
-               /* if this is the first time we're creating an fdir flow */
-               if (pf->fdir.fdir_vsi == NULL) {
-                       ret = i40e_fdir_setup(pf);
-                       if (ret != I40E_SUCCESS) {
-                               rte_flow_error_set(error, ENOTSUP,
-                                               RTE_FLOW_ERROR_TYPE_HANDLE,
-                                               NULL, "Failed to setup fdir.");
-                               return NULL;
-                       }
-                       ret = i40e_fdir_configure(dev);
-                       if (ret < 0) {
-                               rte_flow_error_set(error, ENOTSUP,
-                                               RTE_FLOW_ERROR_TYPE_HANDLE,
-                                               NULL, "Failed to configure 
fdir.");
-                               i40e_fdir_teardown(pf);
-                               return NULL;
-                       }
-               }
-               /* If create the first fdir rule, enable fdir check for rx 
queues */
-               if (TAILQ_EMPTY(&pf->fdir.fdir_list))
-                       i40e_fdir_rx_proc_enable(dev, 1);
-
-               flow = i40e_fdir_entry_pool_get(fdir_info);
-               if (flow == NULL) {
-                       rte_flow_error_set(error, ENOBUFS,
-                          RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-                          "Fdir space full");
-
-                       return flow;
-               }
-       } else {
-               flow = rte_zmalloc("i40e_flow", sizeof(struct rte_flow), 0);
-               if (!flow) {
-                       rte_flow_error_set(error, ENOMEM,
-                                          RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-                                          "Failed to allocate memory");
-                       return flow;
-               }
+       flow = rte_zmalloc("i40e_flow", sizeof(struct rte_flow), 0);
+       if (!flow) {
+               rte_flow_error_set(error, ENOMEM,
+                                       RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+                                       "Failed to allocate memory");
+               return flow;
        }
 
        switch (filter_ctx.type) {
-       case RTE_ETH_FILTER_FDIR:
-               ret = i40e_flow_add_del_fdir_filter(dev, 
&filter_ctx.fdir_filter, 1);
-               if (ret)
-                       goto free_flow;
-               flow->rule = TAILQ_LAST(&pf->fdir.fdir_list,
-                                       i40e_fdir_filter_list);
-               break;
        case RTE_ETH_FILTER_TUNNEL:
                ret = i40e_dev_consistent_tunnel_filter_set(pf,
                                &filter_ctx.consistent_tunnel_filter, 1);
@@ -3722,10 +1862,7 @@ i40e_flow_create(struct rte_eth_dev *dev,
                           RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
                           "Failed to create flow.");
 
-       if (filter_ctx.type != RTE_ETH_FILTER_FDIR)
-               rte_free(flow);
-       else
-               i40e_fdir_entry_pool_put(fdir_info, flow);
+       rte_free(flow);
 
        return NULL;
 }
@@ -3737,7 +1874,6 @@ i40e_flow_destroy(struct rte_eth_dev *dev,
 {
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        enum rte_filter_type filter_type = flow->filter_type;
-       struct i40e_fdir_info *fdir_info = &pf->fdir;
        int ret = 0;
 
        /* try the new engine first */
@@ -3751,16 +1887,6 @@ i40e_flow_destroy(struct rte_eth_dev *dev,
                ret = i40e_flow_destroy_tunnel_filter(pf,
                              (struct i40e_tunnel_filter *)flow->rule);
                break;
-       case RTE_ETH_FILTER_FDIR:
-               ret = i40e_flow_add_del_fdir_filter(dev,
-                               &((struct i40e_fdir_filter *)flow->rule)->fdir,
-                               0);
-
-               /* If the last flow is destroyed, disable fdir. */
-               if (!ret && TAILQ_EMPTY(&pf->fdir.fdir_list)) {
-                       i40e_fdir_rx_proc_enable(dev, 0);
-               }
-               break;
        case RTE_ETH_FILTER_HASH:
                ret = i40e_hash_filter_destroy(pf, flow->rule);
                break;
@@ -3773,10 +1899,7 @@ i40e_flow_destroy(struct rte_eth_dev *dev,
 
        if (!ret) {
                TAILQ_REMOVE(&pf->flow_list, flow, node);
-               if (filter_type == RTE_ETH_FILTER_FDIR)
-                       i40e_fdir_entry_pool_put(fdir_info, flow);
-               else
-                       rte_free(flow);
+               rte_free(flow);
 
        } else
                rte_flow_error_set(error, -ret,
@@ -3856,14 +1979,6 @@ i40e_flow_flush(struct rte_eth_dev *dev, struct 
rte_flow_error *error)
        if (ret != 0)
                return ret;
 
-       ret = i40e_flow_flush_fdir_filter(pf);
-       if (ret) {
-               rte_flow_error_set(error, -ret,
-                                  RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-                                  "Failed to flush FDIR flows.");
-               return -rte_errno;
-       }
-
        ret = i40e_flow_flush_tunnel_filter(pf);
        if (ret) {
                rte_flow_error_set(error, -ret,
@@ -3880,66 +1995,6 @@ i40e_flow_flush(struct rte_eth_dev *dev, struct 
rte_flow_error *error)
        return ret;
 }
 
-static int
-i40e_flow_flush_fdir_filter(struct i40e_pf *pf)
-{
-       struct rte_eth_dev *dev = &rte_eth_devices[pf->dev_data->port_id];
-       struct i40e_fdir_info *fdir_info = &pf->fdir;
-       struct i40e_fdir_filter *fdir_filter;
-       enum i40e_filter_pctype pctype;
-       struct rte_flow *flow;
-       void *temp;
-       int ret;
-       uint32_t i = 0;
-
-       ret = i40e_fdir_flush(dev);
-       if (!ret) {
-               /* Delete FDIR filters in FDIR list. */
-               while ((fdir_filter = TAILQ_FIRST(&fdir_info->fdir_list))) {
-                       ret = i40e_sw_fdir_filter_del(pf,
-                                                     &fdir_filter->fdir.input);
-                       if (ret < 0)
-                               return ret;
-               }
-
-               /* Delete FDIR flows in flow list. */
-               RTE_TAILQ_FOREACH_SAFE(flow, &pf->flow_list, node, temp) {
-                       if (flow->filter_type == RTE_ETH_FILTER_FDIR) {
-                               TAILQ_REMOVE(&pf->flow_list, flow, node);
-                       }
-               }
-
-               /* reset bitmap */
-               rte_bitmap_reset(fdir_info->fdir_flow_pool.bitmap);
-               for (i = 0; i < fdir_info->fdir_space_size; i++) {
-                       fdir_info->fdir_flow_pool.pool[i].idx = i;
-                       rte_bitmap_set(fdir_info->fdir_flow_pool.bitmap, i);
-               }
-
-               fdir_info->fdir_actual_cnt = 0;
-               fdir_info->fdir_guarantee_free_space =
-                       fdir_info->fdir_guarantee_total_space;
-               memset(fdir_info->fdir_filter_array,
-                       0,
-                       sizeof(struct i40e_fdir_filter) *
-                       I40E_MAX_FDIR_FILTER_NUM);
-
-               for (pctype = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
-                    pctype <= I40E_FILTER_PCTYPE_L2_PAYLOAD; pctype++) {
-                       pf->fdir.flow_count[pctype] = 0;
-                       pf->fdir.flex_mask_flag[pctype] = 0;
-               }
-
-               for (i = 0; i < I40E_MAX_FLXPLD_LAYER; i++)
-                       pf->fdir.flex_pit_flag[i] = 0;
-
-               /* Disable FDIR processing as all FDIR rules are now flushed */
-               i40e_fdir_rx_proc_enable(dev, 0);
-       }
-
-       return ret;
-}
-
 /* Flush all tunnel filters */
 static int
 i40e_flow_flush_tunnel_filter(struct i40e_pf *pf)
diff --git a/drivers/net/intel/i40e/i40e_flow.h 
b/drivers/net/intel/i40e/i40e_flow.h
index d6efd95216..e6ad1afdba 100644
--- a/drivers/net/intel/i40e/i40e_flow.h
+++ b/drivers/net/intel/i40e/i40e_flow.h
@@ -8,13 +8,19 @@
 #include "../common/flow_engine.h"
 
 int i40e_get_outer_vlan(struct rte_eth_dev *dev, uint16_t *tpid);
+uint8_t
+i40e_flow_fdir_get_pctype_value(struct i40e_pf *pf,
+               enum rte_flow_item_type item_type,
+               struct i40e_fdir_filter_conf *filter);
 
 enum i40e_flow_engine_type {
        I40E_FLOW_ENGINE_TYPE_ETHERTYPE = 0,
+       I40E_FLOW_ENGINE_TYPE_FDIR,
 };
 
 extern const struct ci_flow_engine_list i40e_flow_engine_list;
 
 extern const struct ci_flow_engine i40e_flow_engine_ethertype;
+extern const struct ci_flow_engine i40e_flow_engine_fdir;
 
 #endif /* _I40E_FLOW_H_ */
diff --git a/drivers/net/intel/i40e/i40e_flow_fdir.c 
b/drivers/net/intel/i40e/i40e_flow_fdir.c
new file mode 100644
index 0000000000..87435e9d2b
--- /dev/null
+++ b/drivers/net/intel/i40e/i40e_flow_fdir.c
@@ -0,0 +1,1806 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Intel Corporation
+ */
+
+#include "i40e_ethdev.h"
+#include "i40e_flow.h"
+
+#include <rte_bitmap.h>
+#include <rte_malloc.h>
+
+#include "../common/flow_engine.h"
+#include "../common/flow_check.h"
+#include "../common/flow_util.h"
+
+struct i40e_fdir_ctx {
+       struct ci_flow_engine_ctx base;
+       struct i40e_fdir_filter_conf fdir_filter;
+       enum rte_flow_item_type custom_pctype;
+       struct flex_item {
+               size_t size;
+               size_t offset;
+       } flex_data[I40E_MAX_FLXPLD_FIED];
+};
+
+struct i40e_flow_engine_fdir_flow {
+       struct rte_flow base;
+       struct i40e_fdir_filter_conf fdir_filter;
+};
+
+struct i40e_fdir_flow_pool_entry {
+       struct i40e_flow_engine_fdir_flow flow;
+       uint32_t idx;
+};
+
+struct i40e_fdir_engine_priv {
+       struct rte_bitmap *bmp;
+       struct i40e_fdir_flow_pool_entry *pool;
+};
+
+#define I40E_FDIR_FLOW_ENTRY(flow_ptr) \
+       container_of((flow_ptr), struct i40e_fdir_flow_pool_entry, flow)
+
+#define I40E_IPV6_FRAG_HEADER  44
+#define I40E_IPV6_TC_MASK      (0xFF << I40E_FDIR_IPv6_TC_OFFSET)
+#define I40E_VLAN_TCI_MASK     0xFFFF
+#define I40E_VLAN_PRI_MASK     0xE000
+#define I40E_VLAN_CFI_MASK     0x1000
+#define I40E_VLAN_VID_MASK     0x0FFF
+
+/**
+ * FDIR graph implementation (non-tunnel)
+ * Pattern: START -> ETH -> [VLAN] -> (IPv4 | IPv6) -> [TCP | UDP | SCTP | ESP 
| L2TPv3 | GTP] -> END
+ * With RAW flexible payload support:
+ *   - L2: ETH/VLAN -> RAW -> RAW -> RAW -> END
+ *   - L3: IPv4/IPv6 -> RAW -> RAW -> RAW -> END
+ *   - L4: TCP/UDP/SCTP -> RAW -> RAW -> RAW -> END
+ * GTP tunnel support:
+ *   - IPv4/IPv6 -> UDP -> GTP -> END (GTP-C, GTP-U outer)
+ *   - IPv4/IPv6 -> UDP -> GTP -> IPv4/IPv6 -> END (GTP-U with inner IP)
+ */
+
+enum i40e_fdir_node_id {
+       I40E_FDIR_NODE_START = RTE_FLOW_NODE_FIRST,
+       I40E_FDIR_NODE_ETH,
+       I40E_FDIR_NODE_VLAN,
+       I40E_FDIR_NODE_IPV4,
+       I40E_FDIR_NODE_IPV6,
+       I40E_FDIR_NODE_TCP,
+       I40E_FDIR_NODE_UDP,
+       I40E_FDIR_NODE_SCTP,
+       I40E_FDIR_NODE_ESP,
+       I40E_FDIR_NODE_L2TPV3OIP,
+       I40E_FDIR_NODE_GTPC,
+       I40E_FDIR_NODE_GTPU,
+       I40E_FDIR_NODE_INNER_IPV4,
+       I40E_FDIR_NODE_INNER_IPV6,
+       I40E_FDIR_NODE_RAW,
+       I40E_FDIR_NODE_END,
+       I40E_FDIR_NODE_MAX,
+};
+
+static int
+i40e_fdir_node_eth_validate(const void *ctx __rte_unused, const struct 
rte_flow_item *item,
+               struct rte_flow_error *error)
+{
+       const struct rte_flow_item_eth *eth_spec = item->spec;
+       const struct rte_flow_item_eth *eth_mask = item->mask;
+       bool no_src_mac, no_dst_mac, src_mac, dst_mac;
+
+       /* may be empty */
+       if (eth_spec == NULL && eth_mask == NULL)
+               return 0;
+
+       /* source and destination masks may be all zero or all one */
+       no_src_mac = CI_FIELD_IS_ZERO(&eth_mask->hdr.src_addr);
+       no_dst_mac = CI_FIELD_IS_ZERO(&eth_mask->hdr.dst_addr);
+       src_mac = CI_FIELD_IS_MASKED(&eth_mask->hdr.src_addr);
+       dst_mac = CI_FIELD_IS_MASKED(&eth_mask->hdr.dst_addr);
+
+       /* can't be all zero */
+       if (no_src_mac && no_dst_mac) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item, "Invalid eth 
mask");
+       }
+       /* can't be neither zero nor ones */
+       if ((!no_src_mac && !src_mac) ||
+           (!no_dst_mac && !dst_mac)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item, "Invalid eth 
mask");
+       }
+
+       /* ethertype can either be unmasked or fully masked */
+       if (CI_FIELD_IS_ZERO(&eth_mask->hdr.ether_type))
+               return 0;
+
+       if (!CI_FIELD_IS_MASKED(&eth_mask->hdr.ether_type)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item, "Invalid 
ethertype mask");
+       }
+
+       /* Check for valid ethertype (not IPv4/IPv6) */
+       uint16_t ether_type = rte_be_to_cpu_16(eth_spec->hdr.ether_type);
+       if (ether_type == RTE_ETHER_TYPE_IPV4 ||
+           ether_type == RTE_ETHER_TYPE_IPV6) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "IPv4/IPv6 not supported by ethertype filter");
+       }
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_eth_process(void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error)
+{
+       struct i40e_fdir_ctx *fdir_ctx = ctx;
+       struct i40e_fdir_filter_conf *fdir_conf = &fdir_ctx->fdir_filter;
+       const struct rte_flow_item_eth *eth_spec = item->spec;
+       const struct rte_flow_item_eth *eth_mask = item->mask;
+       uint16_t tpid, ether_type;
+       uint64_t input_set = 0;
+       int ret;
+
+       /* Set layer index for L2 flexible payload (after ETH/VLAN) */
+       fdir_conf->input.flow_ext.layer_idx = I40E_FLXPLD_L2_IDX;
+
+       /* set packet type */
+       fdir_conf->input.pctype = I40E_FILTER_PCTYPE_L2_PAYLOAD;
+
+       /* do we need to set up MAC addresses? */
+       if (eth_spec == NULL && eth_mask == NULL)
+               return 0;
+
+       /* do we care for source address? */
+       if (CI_FIELD_IS_MASKED(&eth_mask->hdr.src_addr)) {
+               fdir_conf->input.flow.l2_flow.src = eth_spec->hdr.src_addr;
+               input_set |= I40E_INSET_SMAC;
+       }
+       /* do we care for destination address? */
+       if (CI_FIELD_IS_MASKED(&eth_mask->hdr.dst_addr)) {
+               fdir_conf->input.flow.l2_flow.dst = eth_spec->hdr.dst_addr;
+               input_set |= I40E_INSET_DMAC;
+       }
+
+       /* do we care for ethertype? */
+       if (eth_mask->hdr.ether_type) {
+               ether_type = rte_be_to_cpu_16(eth_spec->hdr.ether_type);
+               ret = i40e_get_outer_vlan(fdir_ctx->base.dev, &tpid);
+               if (ret != 0) {
+                       return rte_flow_error_set(error, EIO,
+                                       RTE_FLOW_ERROR_TYPE_ITEM, item,
+                                       "Can not get the Ethertype identifying 
the L2 tag");
+               }
+               if (ether_type == tpid) {
+                       return rte_flow_error_set(error, EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                                               "Unsupported ether_type in 
control packet filter.");
+               }
+               fdir_conf->input.flow.l2_flow.ether_type = 
eth_spec->hdr.ether_type;
+               input_set |= I40E_INSET_LAST_ETHER_TYPE;
+       }
+
+       fdir_conf->input.flow_ext.input_set = input_set;
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_vlan_validate(const void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error)
+{
+       const struct rte_flow_item_vlan *vlan_spec = item->spec;
+       const struct rte_flow_item_vlan *vlan_mask = item->mask;
+       const struct i40e_fdir_ctx *fdir_ctx = ctx;
+       const struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+       uint16_t ether_type;
+
+       if (vlan_spec == NULL && vlan_mask == NULL)
+               return 0;
+
+       /* TCI mask is required but must be one of the supported masks */
+       if (vlan_mask->hdr.vlan_tci != rte_cpu_to_be_16(I40E_VLAN_TCI_MASK) &&
+           vlan_mask->hdr.vlan_tci != rte_cpu_to_be_16(I40E_VLAN_PRI_MASK) &&
+           vlan_mask->hdr.vlan_tci != rte_cpu_to_be_16(I40E_VLAN_CFI_MASK) &&
+           vlan_mask->hdr.vlan_tci != rte_cpu_to_be_16(I40E_VLAN_VID_MASK)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Unsupported TCI mask");
+       }
+       if (CI_FIELD_IS_ZERO(&vlan_mask->hdr.eth_proto))
+               return 0;
+
+       if (!CI_FIELD_IS_MASKED(&vlan_mask->hdr.eth_proto)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid VLAN header mask");
+       }
+
+       /* can't match on eth_proto as we're already matching on ethertype */
+       if (filter->input.flow_ext.input_set & I40E_INSET_LAST_ETHER_TYPE) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Cannot set two ethertype filters");
+       }
+
+       ether_type = rte_be_to_cpu_16(vlan_spec->hdr.eth_proto);
+       if (ether_type == RTE_ETHER_TYPE_IPV4 ||
+           ether_type == RTE_ETHER_TYPE_IPV6) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "IPv4/IPv6 not supported by VLAN protocol 
filter");
+       }
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_vlan_process(void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error)
+{
+       const struct rte_flow_item_vlan *vlan_spec = item->spec;
+       const struct rte_flow_item_vlan *vlan_mask = item->mask;
+       struct i40e_fdir_ctx *fdir_ctx = ctx;
+       struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+
+       /* Set layer index for L2 flexible payload (after ETH/VLAN) */
+       filter->input.flow_ext.layer_idx = I40E_FLXPLD_L2_IDX;
+
+       /* set packet type */
+       filter->input.pctype = I40E_FILTER_PCTYPE_L2_PAYLOAD;
+
+       if (vlan_spec == NULL && vlan_mask == NULL)
+               return 0;
+
+       /* Store TCI value if requested */
+       if (vlan_mask->hdr.vlan_tci) {
+               filter->input.flow_ext.vlan_tci = vlan_spec->hdr.vlan_tci;
+               filter->input.flow_ext.input_set |= I40E_INSET_VLAN_INNER;
+       }
+
+       /* if ethertype specified, store it */
+       if (vlan_mask->hdr.eth_proto) {
+               uint16_t tpid, ether_type;
+               int ret;
+
+               ether_type = rte_be_to_cpu_16(vlan_spec->hdr.eth_proto);
+
+               ret = i40e_get_outer_vlan(fdir_ctx->base.dev, &tpid);
+               if (ret != 0) {
+                       return rte_flow_error_set(error, EIO,
+                                       RTE_FLOW_ERROR_TYPE_ITEM, item,
+                                       "Can not get the Ethertype identifying 
the L2 tag");
+               }
+               if (ether_type == tpid) {
+                       return rte_flow_error_set(error, EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                                               "Unsupported ether_type in 
control packet filter.");
+               }
+               filter->input.flow.l2_flow.ether_type = 
vlan_spec->hdr.eth_proto;
+               filter->input.flow_ext.input_set |= I40E_INSET_LAST_ETHER_TYPE;
+       }
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_ipv4_validate(const void *ctx __rte_unused, const struct 
rte_flow_item *item,
+               struct rte_flow_error *error)
+{
+       const struct rte_flow_item_ipv4 *ipv4_spec = item->spec;
+       const struct rte_flow_item_ipv4 *ipv4_mask = item->mask;
+       const struct rte_flow_item_ipv4 *ipv4_last = item->last;
+
+       if (ipv4_mask == NULL && ipv4_spec == NULL)
+               return 0;
+
+       /* Validate mask fields */
+       if (ipv4_mask->hdr.version_ihl ||
+                       ipv4_mask->hdr.total_length ||
+                       ipv4_mask->hdr.packet_id ||
+                       ipv4_mask->hdr.hdr_checksum) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid IPv4 header mask");
+       }
+       if (!CI_FIELD_IS_ZERO_OR_MASKED(&ipv4_mask->hdr.src_addr) ||
+                       !CI_FIELD_IS_ZERO_OR_MASKED(&ipv4_mask->hdr.dst_addr) ||
+                       
!CI_FIELD_IS_ZERO_OR_MASKED(&ipv4_mask->hdr.type_of_service) ||
+                       
!CI_FIELD_IS_ZERO_OR_MASKED(&ipv4_mask->hdr.time_to_live) ||
+                       
!CI_FIELD_IS_ZERO_OR_MASKED(&ipv4_mask->hdr.next_proto_id)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid IPv4 header mask");
+       }
+
+       if (ipv4_last == NULL)
+               return 0;
+
+       /* Only fragment_offset supports range */
+       if (ipv4_last->hdr.version_ihl ||
+           ipv4_last->hdr.type_of_service ||
+           ipv4_last->hdr.total_length ||
+           ipv4_last->hdr.packet_id ||
+           ipv4_last->hdr.time_to_live ||
+           ipv4_last->hdr.next_proto_id ||
+           ipv4_last->hdr.hdr_checksum ||
+           ipv4_last->hdr.src_addr ||
+           ipv4_last->hdr.dst_addr) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "IPv4 range only supported for 
fragment_offset");
+       }
+
+       /* Validate fragment_offset range values */
+       uint16_t frag_mask = rte_be_to_cpu_16(ipv4_mask->hdr.fragment_offset);
+       uint16_t frag_spec = rte_be_to_cpu_16(ipv4_spec->hdr.fragment_offset);
+       uint16_t frag_last = rte_be_to_cpu_16(ipv4_last->hdr.fragment_offset);
+
+       /* Mask must be 0x3fff (fragment offset + MF flag) */
+       if (frag_mask != (RTE_IPV4_HDR_OFFSET_MASK | RTE_IPV4_HDR_MF_FLAG)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid IPv4 fragment_offset mask");
+       }
+
+       /* Only allow: frag rule (spec=0x8, last=0x2000) or non-frag (spec=0, 
last=0) */
+       if (frag_spec == (1 << RTE_IPV4_HDR_FO_SHIFT) &&
+           frag_last == RTE_IPV4_HDR_MF_FLAG)
+               return 0; /* Fragment rule */
+
+       if (frag_spec == 0 && frag_last == 0)
+               return 0; /* Non-fragment rule */
+
+       return rte_flow_error_set(error, EINVAL,
+                       RTE_FLOW_ERROR_TYPE_ITEM, item,
+                       "Invalid IPv4 fragment_offset rule");
+}
+
+static int
+i40e_fdir_node_ipv4_process(void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error __rte_unused)
+{
+       const struct rte_flow_item_ipv4 *ipv4_spec = item->spec;
+       const struct rte_flow_item_ipv4 *ipv4_mask = item->mask;
+       const struct rte_flow_item_ipv4 *ipv4_last = item->last;
+       struct i40e_fdir_ctx *fdir_ctx = ctx;
+       struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+
+       /* Set layer index for L2 flexible payload (after ETH/VLAN) */
+       filter->input.flow_ext.layer_idx = I40E_FLXPLD_L3_IDX;
+
+       /* set packet type */
+       filter->input.pctype = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
+
+       /* set up flow type */
+       filter->input.flow_ext.inner_ip = false;
+       filter->input.flow_ext.oip_type = I40E_FDIR_IPTYPE_IPV4;
+
+       if (ipv4_mask == NULL && ipv4_spec == NULL)
+               return 0;
+
+       /* Mark that IPv4 fields are used */
+       if (!CI_FIELD_IS_ZERO(&ipv4_mask->hdr.next_proto_id)) {
+               filter->input.flow.ip4_flow.proto = 
ipv4_spec->hdr.next_proto_id;
+               filter->input.flow_ext.input_set |= I40E_INSET_IPV4_PROTO;
+       }
+       if (!CI_FIELD_IS_ZERO(&ipv4_mask->hdr.type_of_service)) {
+               filter->input.flow.ip4_flow.tos = 
ipv4_spec->hdr.type_of_service;
+               filter->input.flow_ext.input_set |= I40E_INSET_IPV4_TOS;
+       }
+       if (!CI_FIELD_IS_ZERO(&ipv4_mask->hdr.time_to_live)) {
+               filter->input.flow.ip4_flow.ttl = ipv4_spec->hdr.time_to_live;
+               filter->input.flow_ext.input_set |= I40E_INSET_IPV4_TTL;
+       }
+       if (!CI_FIELD_IS_ZERO(&ipv4_mask->hdr.src_addr)) {
+               filter->input.flow.ip4_flow.src_ip = ipv4_spec->hdr.src_addr;
+               filter->input.flow_ext.input_set |= I40E_INSET_IPV4_SRC;
+       }
+       if (!CI_FIELD_IS_ZERO(&ipv4_mask->hdr.dst_addr)) {
+               filter->input.flow.ip4_flow.dst_ip = ipv4_spec->hdr.dst_addr;
+               filter->input.flow_ext.input_set |= I40E_INSET_IPV4_DST;
+       }
+
+       /* do we have range? */
+       if (ipv4_last == NULL) {
+               filter->input.pctype = I40E_FILTER_PCTYPE_FRAG_IPV4;
+               filter->input.flow_ext.customized_pctype = true;
+       }
+
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_ipv6_validate(const void *ctx __rte_unused, const struct 
rte_flow_item *item,
+               struct rte_flow_error *error)
+{
+       const struct rte_flow_item_ipv6 *ipv6_spec = item->spec;
+       const struct rte_flow_item_ipv6 *ipv6_mask = item->mask;
+       if (ipv6_mask == NULL && ipv6_spec == NULL)
+               return 0;
+
+       /* payload len isn't supported */
+       if (ipv6_mask->hdr.payload_len) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid IPv6 header mask");
+       }
+       /* source and destination mask can either be all zeroes or all ones */
+       if (!CI_FIELD_IS_ZERO_OR_MASKED(&ipv6_mask->hdr.src_addr)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid IPv6 source address mask");
+       }
+       if (!CI_FIELD_IS_ZERO_OR_MASKED(&ipv6_mask->hdr.dst_addr)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid IPv6 destination address mask");
+       }
+
+       /* check other supported fields */
+       if (!ci_is_zero_or_masked(ipv6_mask->hdr.vtc_flow, 
rte_cpu_to_be_32(I40E_IPV6_TC_MASK)) ||
+           !CI_FIELD_IS_ZERO_OR_MASKED(&ipv6_mask->hdr.proto) ||
+           !CI_FIELD_IS_ZERO_OR_MASKED(&ipv6_mask->hdr.hop_limits)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid IPv6 header mask");
+       }
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_ipv6_process(void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error __rte_unused)
+{
+       const struct rte_flow_item_ipv6 *ipv6_spec = item->spec;
+       const struct rte_flow_item_ipv6 *ipv6_mask = item->mask;
+       struct i40e_fdir_ctx *fdir_ctx = ctx;
+       struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+
+       /* Set layer index for L2 flexible payload (after ETH/VLAN) */
+       filter->input.flow_ext.layer_idx = I40E_FLXPLD_L3_IDX;
+
+       /* set packet type */
+       filter->input.pctype = I40E_FILTER_PCTYPE_NONF_IPV6_OTHER;
+
+       /* set up flow type */
+       filter->input.flow_ext.inner_ip = false;
+       filter->input.flow_ext.oip_type = I40E_FDIR_IPTYPE_IPV6;
+
+       if (ipv6_mask == NULL && ipv6_spec == NULL)
+               return 0;
+       if (CI_FIELD_IS_MASKED(&ipv6_mask->hdr.src_addr)) {
+               memcpy(&filter->input.flow.ipv6_flow.src_ip, 
&ipv6_spec->hdr.src_addr, sizeof(ipv6_spec->hdr.src_addr));
+               filter->input.flow_ext.input_set |= I40E_INSET_IPV6_SRC;
+       }
+       if (CI_FIELD_IS_MASKED(&ipv6_mask->hdr.dst_addr)) {
+               memcpy(&filter->input.flow.ipv6_flow.dst_ip, 
&ipv6_spec->hdr.dst_addr, sizeof(ipv6_spec->hdr.dst_addr));
+               filter->input.flow_ext.input_set |= I40E_INSET_IPV6_DST;
+       }
+
+       if (!CI_FIELD_IS_ZERO(&ipv6_mask->hdr.vtc_flow)) {
+               rte_be32_t vtc_flow = rte_be_to_cpu_32(ipv6_mask->hdr.vtc_flow);
+               uint8_t tc = (uint8_t)(vtc_flow & I40E_IPV6_TC_MASK) >> 
I40E_FDIR_IPv6_TC_OFFSET;
+               filter->input.flow.ipv6_flow.tc = tc;
+               filter->input.flow_ext.input_set |= I40E_INSET_IPV6_TC;
+       }
+       if (!CI_FIELD_IS_ZERO(&ipv6_mask->hdr.proto)) {
+               filter->input.flow.ipv6_flow.proto = ipv6_spec->hdr.proto;
+               filter->input.flow_ext.input_set |= I40E_INSET_IPV6_NEXT_HDR;
+       }
+       if (!CI_FIELD_IS_ZERO(&ipv6_mask->hdr.hop_limits)) {
+               filter->input.flow.ipv6_flow.hop_limits = 
ipv6_spec->hdr.hop_limits;
+               filter->input.flow_ext.input_set |= I40E_INSET_IPV6_HOP_LIMIT;
+       }
+       /* mark as fragment traffic if necessary */
+       if (ipv6_spec->hdr.proto == I40E_IPV6_FRAG_HEADER) {
+               filter->input.pctype = I40E_FILTER_PCTYPE_FRAG_IPV6;
+       }
+
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_tcp_validate(const void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error)
+{
+       const struct i40e_fdir_ctx *fdir_ctx = ctx;
+       const struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+       const struct rte_flow_item_tcp *tcp_spec = item->spec;
+       const struct rte_flow_item_tcp *tcp_mask = item->mask;
+
+       /* cannot match both fragmented and TCP */
+       if (filter->input.pctype == I40E_FILTER_PCTYPE_FRAG_IPV4 ||
+           filter->input.pctype == I40E_FILTER_PCTYPE_FRAG_IPV6) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Cannot combine fragmented IP and TCP match");
+       }
+
+       if (tcp_spec == NULL && tcp_mask == NULL)
+               return 0;
+
+       if (tcp_mask->hdr.sent_seq ||
+           tcp_mask->hdr.recv_ack ||
+           tcp_mask->hdr.data_off ||
+           tcp_mask->hdr.tcp_flags ||
+           tcp_mask->hdr.rx_win ||
+           tcp_mask->hdr.cksum ||
+           tcp_mask->hdr.tcp_urp) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid TCP header mask");
+       }
+       if (!CI_FIELD_IS_ZERO_OR_MASKED(&tcp_mask->hdr.src_port) ||
+           !CI_FIELD_IS_ZERO_OR_MASKED(&tcp_mask->hdr.dst_port)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid TCP header mask");
+       }
+       return 0;
+}
+
+static int
+i40e_fdir_node_tcp_process(void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error __rte_unused)
+{
+       struct i40e_fdir_ctx *fdir_ctx = ctx;
+       struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+       const struct rte_flow_item_tcp *tcp_spec = item->spec;
+       const struct rte_flow_item_tcp *tcp_mask = item->mask;
+       rte_be16_t src_spec, dst_spec, src_mask, dst_mask;
+       bool is_ipv4;
+
+       /* Set layer index for L4 flexible payload */
+       filter->input.flow_ext.layer_idx = I40E_FLXPLD_L4_IDX;
+
+       /* set packet type depending on L3 type */
+       if (filter->input.flow_ext.oip_type == I40E_FDIR_IPTYPE_IPV4) {
+               filter->input.pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
+       } else if (filter->input.flow_ext.oip_type == I40E_FDIR_IPTYPE_IPV6) {
+               filter->input.pctype = I40E_FILTER_PCTYPE_NONF_IPV6_TCP;
+       }
+
+       if (tcp_spec == NULL && tcp_mask == NULL)
+               return 0;
+
+       src_spec = tcp_spec->hdr.src_port;
+       dst_spec = tcp_spec->hdr.dst_port;
+       src_mask = tcp_mask->hdr.src_port;
+       dst_mask = tcp_mask->hdr.dst_port;
+       is_ipv4 = filter->input.flow_ext.oip_type == I40E_FDIR_IPTYPE_IPV4;
+
+       if (is_ipv4) {
+               if (src_mask != 0) {
+                       filter->input.flow_ext.input_set |= I40E_INSET_SRC_PORT;
+                       filter->input.flow.tcp4_flow.src_port = src_spec;
+               }
+               if (dst_mask) {
+                       filter->input.flow_ext.input_set |= I40E_INSET_DST_PORT;
+                       filter->input.flow.tcp4_flow.dst_port = dst_spec;
+               }
+       } else {
+               if (src_mask != 0) {
+                       filter->input.flow_ext.input_set |= I40E_INSET_SRC_PORT;
+                       filter->input.flow.tcp6_flow.src_port = src_spec;
+               }
+               if (dst_mask) {
+                       filter->input.flow_ext.input_set |= I40E_INSET_DST_PORT;
+                       filter->input.flow.tcp6_flow.dst_port = dst_spec;
+               }
+       }
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_udp_validate(const void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error)
+{
+       const struct i40e_fdir_ctx *fdir_ctx = ctx;
+       const struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+       const struct rte_flow_item_udp *udp_spec = item->spec;
+       const struct rte_flow_item_udp *udp_mask = item->mask;
+
+       /* cannot match both fragmented and TCP */
+       if (filter->input.pctype == I40E_FILTER_PCTYPE_FRAG_IPV4 ||
+           filter->input.pctype == I40E_FILTER_PCTYPE_FRAG_IPV6) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Cannot combine fragmented IP and UDP match");
+       }
+
+       if (udp_spec == NULL && udp_mask == NULL)
+               return 0;
+
+       if (udp_mask->hdr.dgram_len || udp_mask->hdr.dgram_cksum) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid UDP header mask");
+       }
+       if (!CI_FIELD_IS_ZERO_OR_MASKED(&udp_mask->hdr.src_port) ||
+           !CI_FIELD_IS_ZERO_OR_MASKED(&udp_mask->hdr.dst_port)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid UDP header mask");
+       }
+       return 0;
+}
+
+static int
+i40e_fdir_node_udp_process(void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error __rte_unused)
+{
+       struct i40e_fdir_ctx *fdir_ctx = ctx;
+       struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+       const struct rte_flow_item_udp *udp_spec = item->spec;
+       const struct rte_flow_item_udp *udp_mask = item->mask;
+       rte_be16_t src_spec, dst_spec, src_mask, dst_mask;
+       bool is_ipv4;
+
+       /* Set layer index for L4 flexible payload */
+       filter->input.flow_ext.layer_idx = I40E_FLXPLD_L4_IDX;
+
+       /* set packet type depending on L3 type */
+       if (filter->input.flow_ext.oip_type == I40E_FDIR_IPTYPE_IPV4) {
+               filter->input.pctype = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
+       } else if (filter->input.flow_ext.oip_type == I40E_FDIR_IPTYPE_IPV6) {
+               filter->input.pctype = I40E_FILTER_PCTYPE_NONF_IPV6_UDP;
+       }
+
+       /* set UDP */
+       filter->input.flow_ext.is_udp = true;
+
+       if (udp_spec == NULL && udp_mask == NULL)
+               return 0;
+
+       src_spec = udp_spec->hdr.src_port;
+       dst_spec = udp_spec->hdr.dst_port;
+       src_mask = udp_mask->hdr.src_port;
+       dst_mask = udp_mask->hdr.dst_port;
+       is_ipv4 = filter->input.flow_ext.oip_type == I40E_FDIR_IPTYPE_IPV4;
+
+       if (is_ipv4) {
+               if (src_mask) {
+                       filter->input.flow_ext.input_set |= I40E_INSET_SRC_PORT;
+                       filter->input.flow.udp4_flow.src_port = src_spec;
+               }
+               if (dst_mask) {
+                       filter->input.flow_ext.input_set |= I40E_INSET_DST_PORT;
+                       filter->input.flow.udp4_flow.dst_port = dst_spec;
+               }
+       } else {
+               if (src_mask) {
+                       filter->input.flow_ext.input_set |= I40E_INSET_SRC_PORT;
+                       filter->input.flow.udp6_flow.src_port = src_spec;
+               }
+               if (dst_mask) {
+                       filter->input.flow_ext.input_set |= I40E_INSET_DST_PORT;
+                       filter->input.flow.udp6_flow.dst_port = dst_spec;
+               }
+       }
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_sctp_validate(const void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error)
+{
+       const struct i40e_fdir_ctx *fdir_ctx = ctx;
+       const struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+       const struct rte_flow_item_sctp *sctp_spec = item->spec;
+       const struct rte_flow_item_sctp *sctp_mask = item->mask;
+
+       /* cannot match both fragmented and TCP */
+       if (filter->input.pctype == I40E_FILTER_PCTYPE_FRAG_IPV4 ||
+           filter->input.pctype == I40E_FILTER_PCTYPE_FRAG_IPV6) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Cannot combine fragmented IP and SCTP match");
+       }
+
+       if (sctp_spec == NULL && sctp_mask == NULL)
+               return 0;
+
+       if (sctp_mask->hdr.cksum) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid SCTP header mask");
+       }
+       if (!CI_FIELD_IS_ZERO_OR_MASKED(&sctp_mask->hdr.src_port) ||
+           !CI_FIELD_IS_ZERO_OR_MASKED(&sctp_mask->hdr.dst_port) ||
+           !CI_FIELD_IS_ZERO_OR_MASKED(&sctp_mask->hdr.tag)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid SCTP header mask");
+       }
+       return 0;
+}
+
+static int
+i40e_fdir_node_sctp_process(void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error __rte_unused)
+{
+       struct i40e_fdir_ctx *fdir_ctx = ctx;
+       struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+       const struct rte_flow_item_sctp *sctp_spec = item->spec;
+       const struct rte_flow_item_sctp *sctp_mask = item->mask;
+       rte_be16_t src_spec, dst_spec, src_mask, dst_mask, tag_spec, tag_mask;
+       bool is_ipv4;
+
+       /* Set layer index for L4 flexible payload */
+       filter->input.flow_ext.layer_idx = I40E_FLXPLD_L4_IDX;
+
+       /* set packet type depending on L3 type */
+       if (filter->input.flow_ext.oip_type == I40E_FDIR_IPTYPE_IPV4) {
+               filter->input.pctype = I40E_FILTER_PCTYPE_NONF_IPV4_SCTP;
+       } else if (filter->input.flow_ext.oip_type == I40E_FDIR_IPTYPE_IPV6) {
+               filter->input.pctype = I40E_FILTER_PCTYPE_NONF_IPV6_SCTP;
+       }
+
+       if (sctp_spec == NULL && sctp_mask == NULL)
+               return 0;
+
+       if (!CI_FIELD_IS_ZERO(&sctp_mask->hdr.tag)) {
+               filter->input.flow_ext.input_set |= I40E_INSET_SCTP_VT;
+       }
+
+       src_spec = sctp_spec->hdr.src_port;
+       dst_spec = sctp_spec->hdr.dst_port;
+       src_mask = sctp_mask->hdr.src_port;
+       dst_mask = sctp_mask->hdr.dst_port;
+       tag_spec = sctp_spec->hdr.tag;
+       tag_mask = sctp_mask->hdr.tag;
+       is_ipv4 = filter->input.flow_ext.oip_type == I40E_FDIR_IPTYPE_IPV4;
+
+       if (is_ipv4) {
+               if (src_mask) {
+                       filter->input.flow_ext.input_set |= I40E_INSET_SRC_PORT;
+                       filter->input.flow.sctp4_flow.src_port = src_spec;
+               }
+               if (dst_mask) {
+                       filter->input.flow_ext.input_set |= I40E_INSET_DST_PORT;
+                       filter->input.flow.sctp4_flow.dst_port = dst_spec;
+               }
+               if (tag_mask) {
+                       filter->input.flow_ext.input_set |= I40E_INSET_SCTP_VT;
+                       filter->input.flow.sctp4_flow.verify_tag = tag_spec;
+               }
+       } else {
+               if (src_mask) {
+                       filter->input.flow_ext.input_set |= I40E_INSET_SRC_PORT;
+                       filter->input.flow.sctp6_flow.src_port = src_spec;
+               }
+               if (dst_mask) {
+                       filter->input.flow_ext.input_set |= I40E_INSET_DST_PORT;
+                       filter->input.flow.sctp6_flow.dst_port = dst_spec;
+               }
+               if (tag_mask) {
+                       filter->input.flow_ext.input_set |= I40E_INSET_SCTP_VT;
+                       filter->input.flow.sctp6_flow.verify_tag = tag_spec;
+               }
+       }
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_raw_validate(const void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error)
+{
+       const struct i40e_fdir_ctx *fdir_ctx = ctx;
+       const struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+       const struct rte_eth_dev *dev = fdir_ctx->base.dev;
+       const struct i40e_pf *pf = 
I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       const struct rte_flow_item_raw *raw_spec = item->spec;
+       const struct rte_flow_item_raw *raw_mask = item->mask;
+       enum i40e_flxpld_layer_idx raw_id = filter->input.flow_ext.raw_id;
+       size_t spec_size, spec_offset;
+       size_t total_size, i;
+       size_t new_src_offset;
+
+       /* we shouldn't write to global registers on some hardware */
+       if (pf->support_multi_driver) {
+               return rte_flow_error_set(error, ENOTSUP,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Unsupported flexible payload.");
+       }
+
+       /* Check max RAW items limit */
+       RTE_BUILD_BUG_ON(I40E_MAX_FLXPLD_LAYER != I40E_MAX_FLXPLD_FIED);
+       if (raw_id >= I40E_MAX_FLXPLD_LAYER) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Maximum 3 RAW items allowed per layer");
+       }
+
+       /* Check spec/mask lengths */
+       if (raw_spec->length != raw_mask->length) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid RAW length");
+       }
+
+       /* Relative offset is mandatory */
+       if (!raw_spec->relative) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "RAW relative must be 1");
+       }
+
+       /* Offset must be 16-bit aligned */
+       if (raw_spec->offset % sizeof(uint16_t)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "RAW offset must be even");
+       }
+
+       /* Search and limit not supported */
+       if (raw_spec->search || raw_spec->limit) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "RAW search/limit not supported");
+       }
+
+       /* Offset must be non-negative */
+       if (raw_spec->offset < 0) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "RAW offset must be non-negative");
+       }
+
+       /*
+        * RAW node can be triggered multiple times, each time we will be 
copying more data to the
+        * flexbyte buffer. we need to validate total size/offset against max 
allowed because we
+        * cannot overflow our flexbyte buffer.
+        *
+        * all data in the flex pit is stored in units of 2 bytes (words), but 
all the limits are in
+        * bytes, so we need to convert sizes/offsets accordingly.
+        */
+
+       /* flex size/offset for current item (in bytes) */
+       spec_size = raw_spec->length;
+       spec_offset = raw_spec->offset;
+
+       /* accumulate all raw items size/offset */
+       total_size = 0;
+       new_src_offset = 0;
+       for (i = 0; i < raw_id; i++) {
+               const struct flex_item *fi = &fdir_ctx->flex_data[i];
+               total_size += fi->size;
+               /* offset is relative to end of previous item */
+               new_src_offset += fi->offset + fi->size;
+       }
+       /* add current item to totals */
+       total_size += spec_size;
+       new_src_offset += spec_offset;
+
+       /* validate against max offset/size */
+       if (spec_size + new_src_offset > I40E_MAX_FLX_SOURCE_OFF) {
+               return rte_flow_error_set(error, EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                                               "RAW total offset exceeds 
maximum");
+       }
+       if (total_size > I40E_FDIR_MAX_FLEXLEN) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "RAW total size exceeds maximum");
+       }
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_raw_process(void *ctx,
+                           const struct rte_flow_item *item,
+                           struct rte_flow_error *error __rte_unused)
+{
+       struct i40e_fdir_ctx *fdir_ctx = ctx;
+       struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+       const struct rte_flow_item_raw *raw_spec = item->spec;
+       const struct rte_flow_item_raw *raw_mask = item->mask;
+       enum i40e_flxpld_layer_idx raw_id = filter->input.flow_ext.raw_id;
+       enum i40e_flxpld_layer_idx layer_idx = filter->input.flow_ext.layer_idx;
+       size_t flex_pit_field_idx = layer_idx * I40E_MAX_FLXPLD_FIED + raw_id;
+       struct i40e_fdir_flex_pit *flex_pit;
+       size_t spec_size, spec_offset, i;
+       size_t total_size, new_src_offset;
+
+       /* flex size for current item */
+       spec_size = raw_spec->length;
+       spec_offset = raw_spec->offset;
+
+       /* store these for future reference */
+       fdir_ctx->flex_data[raw_id].size = spec_size;
+       fdir_ctx->flex_data[raw_id].offset = spec_offset;
+
+       /* accumulate all raw items size/offset */
+       total_size = 0;
+       new_src_offset = 0;
+       for (i = 0; i < raw_id; i++) {
+               const struct flex_item *fi = &fdir_ctx->flex_data[i];
+               total_size += fi->size;
+               /* offset is relative to end of previous item */
+               new_src_offset += fi->offset + fi->size;
+       }
+
+       /* copy bytes into the flex pit buffer */
+       for (i = 0; i < spec_size; i++) {
+               /* convert to byte offset */
+               const size_t start = total_size * sizeof(uint16_t);
+               size_t j = start + i;
+               filter->input.flow_ext.flexbytes[j] = raw_spec->pattern[i];
+               filter->input.flow_ext.flex_mask[j] = raw_mask->pattern[i];
+       }
+
+       /* populate flex pit */
+       flex_pit = &filter->input.flow_ext.flex_pit[flex_pit_field_idx];
+       /* convert to words (2-byte units) */
+       flex_pit->src_offset = (uint16_t)new_src_offset / sizeof(uint16_t);
+       flex_pit->dst_offset = (uint16_t)total_size / sizeof(uint16_t);
+       flex_pit->size = (uint16_t)spec_size / sizeof(uint16_t);
+
+       /* increment raw item index */
+       filter->input.flow_ext.raw_id++;
+
+       /* mark as flex flow */
+       filter->input.flow_ext.is_flex_flow = true;
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_esp_validate(const void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error)
+{
+       const struct i40e_fdir_ctx *fdir_ctx = ctx;
+       const struct rte_eth_dev *dev = fdir_ctx->base.dev;
+       const struct i40e_pf *pf = 
I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       const struct rte_flow_item_esp *esp_mask = item->mask;
+
+       if (!pf->esp_support) {
+               return rte_flow_error_set(error, ENOTSUP,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Protocol not supported");
+       }
+
+       /* SPI must be fully masked */
+       if (!CI_FIELD_IS_MASKED(&esp_mask->hdr.spi)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid ESP header mask");
+       }
+       return 0;
+}
+
+static int
+i40e_fdir_node_esp_process(void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error __rte_unused)
+{
+       struct i40e_fdir_ctx *fdir_ctx = ctx;
+       struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+       const struct rte_flow_item_esp *esp_spec = item->spec;
+       bool is_ipv4 = filter->input.flow_ext.oip_type == I40E_FDIR_IPTYPE_IPV4;
+       bool is_udp = filter->input.flow_ext.is_udp;
+
+       /* ESP uses customized pctype */
+       filter->input.flow_ext.customized_pctype = true;
+       fdir_ctx->custom_pctype = item->type;
+
+       if (is_ipv4) {
+               if (is_udp)
+                       filter->input.flow.esp_ipv4_udp_flow.spi = 
esp_spec->hdr.spi;
+               else {
+                       filter->input.flow.esp_ipv4_flow.spi = 
esp_spec->hdr.spi;
+               }
+       } else {
+               if (is_udp)
+                       filter->input.flow.esp_ipv6_udp_flow.spi = 
esp_spec->hdr.spi;
+               else {
+                       filter->input.flow.esp_ipv6_flow.spi = 
esp_spec->hdr.spi;
+               }
+       }
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_l2tpv3oip_validate(const void *ctx __rte_unused,
+                                  const struct rte_flow_item *item,
+                                  struct rte_flow_error *error)
+{
+       const struct rte_flow_item_l2tpv3oip *l2tp_mask = item->mask;
+
+       if (!CI_FIELD_IS_MASKED(&l2tp_mask->session_id)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid L2TPv3oIP header mask");
+       }
+       return 0;
+
+}
+
+static int
+i40e_fdir_node_l2tpv3oip_process(void *ctx,
+                                 const struct rte_flow_item *item,
+                                 struct rte_flow_error *error __rte_unused)
+{
+       struct i40e_fdir_ctx *fdir_ctx = ctx;
+       struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+       const struct rte_flow_item_l2tpv3oip *l2tp_spec = item->spec;
+
+       /* L2TPv3 uses customized pctype */
+       filter->input.flow_ext.customized_pctype = true;
+       fdir_ctx->custom_pctype = item->type;
+
+       /* Store session_id in appropriate flow union member based on IP 
version */
+       if (filter->input.flow_ext.oip_type == I40E_FDIR_IPTYPE_IPV4) {
+               filter->input.flow.ip4_l2tpv3oip_flow.session_id = 
l2tp_spec->session_id;
+       } else if (filter->input.flow_ext.oip_type == I40E_FDIR_IPTYPE_IPV6) {
+               filter->input.flow.ip6_l2tpv3oip_flow.session_id = 
l2tp_spec->session_id;
+       }
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_gtp_validate(const void *ctx __rte_unused, const struct 
rte_flow_item *item,
+               struct rte_flow_error *error)
+{
+       const struct i40e_fdir_ctx *fdir_ctx = ctx;
+       const struct rte_eth_dev *dev = fdir_ctx->base.dev;
+       const struct i40e_pf *pf = 
I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       const struct rte_flow_item_gtp *gtp_mask = item->mask;
+
+       /* DDP may not support this packet type */
+       if (!pf->gtp_support) {
+               return rte_flow_error_set(error, ENOTSUP,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Protocol not supported");
+       }
+
+       if (gtp_mask->hdr.gtp_hdr_info ||
+           gtp_mask->hdr.msg_type ||
+           gtp_mask->hdr.plen) {
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ITEM, item,
+                                         "Invalid GTP header mask");
+       }
+       /* if GTP is specified, TEID must be masked */
+       if (!CI_FIELD_IS_MASKED(&gtp_mask->hdr.teid)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Invalid GTP header mask");
+       }
+       return 0;
+}
+
+static int
+i40e_fdir_node_gtp_process(void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error __rte_unused)
+{
+       struct i40e_fdir_ctx *fdir_ctx = ctx;
+       struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+       const struct rte_flow_item_gtp *gtp_spec = item->spec;
+
+       /* Mark as GTP tunnel with customized pctype */
+       filter->input.flow_ext.customized_pctype = true;
+       fdir_ctx->custom_pctype = item->type;
+
+       filter->input.flow.gtp_flow.teid = gtp_spec->teid;
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_inner_ipv4_process(void *ctx, const struct rte_flow_item *item 
__rte_unused,
+               struct rte_flow_error *error __rte_unused)
+{
+       struct i40e_fdir_ctx *fdir_ctx = ctx;
+       struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+
+       /* Mark as inner IP */
+       filter->input.flow_ext.inner_ip = true;
+       filter->input.flow_ext.iip_type = I40E_FDIR_IPTYPE_IPV4;
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_inner_ipv6_process(void *ctx, const struct rte_flow_item *item 
__rte_unused,
+               struct rte_flow_error *error __rte_unused)
+{
+       struct i40e_fdir_ctx *fdir_ctx = ctx;
+       struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+
+       /* Mark as inner IP */
+       filter->input.flow_ext.inner_ip = true;
+       filter->input.flow_ext.iip_type = I40E_FDIR_IPTYPE_IPV6;
+
+       return 0;
+}
+
+/* END node validation for FDIR - performs pctype determination and input_set 
validation */
+static int
+i40e_fdir_node_end_validate(const void *ctx, const struct rte_flow_item *item,
+               struct rte_flow_error *error)
+{
+       const struct i40e_fdir_ctx *fdir_ctx = ctx;
+       const struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+       uint64_t input_set = filter->input.flow_ext.input_set;
+       enum i40e_filter_pctype pctype = filter->input.pctype;
+
+       /*
+        * Before sending the configuration down to hardware, we need to make
+        * sure that the configuration makes sense - more specifically, that the
+        * input set is a valid one that is actually supported by the hardware.
+        * This is validated for built-in ptypes, however for customized ptypes,
+        * the validation is skipped, and we have no way of validating the input
+        * set because we do not have that information at our disposal - the
+        * input set for customized packet type is not available through DDP
+        * queries.
+        *
+        * However, we do know that some things are unsupported by the hardware 
no matter the
+        * configuration. We can check for them here.
+        */
+       const uint64_t i40e_l2_input_set = I40E_INSET_DMAC | I40E_INSET_SMAC;
+       const uint64_t i40e_l3_input_set = (I40E_INSET_IPV4_SRC | 
I40E_INSET_IPV4_DST |
+                                           I40E_INSET_IPV4_TOS | 
I40E_INSET_IPV4_TTL |
+                                           I40E_INSET_IPV4_PROTO);
+       const uint64_t i40e_l4_input_set = (I40E_INSET_SRC_PORT | 
I40E_INSET_DST_PORT);
+       const bool l2_in_set = (input_set & i40e_l2_input_set) != 0;
+       const bool l3_in_set = (input_set & i40e_l3_input_set) != 0;
+       const bool l4_in_set = (input_set & i40e_l4_input_set) != 0;
+
+       /* if we're matching ethertype, we may be matching L2 only, and cannot 
have RAW patterns */
+       if ((input_set & I40E_INSET_LAST_ETHER_TYPE) != 0 &&
+            (pctype != I40E_FILTER_PCTYPE_L2_PAYLOAD ||
+             filter->input.flow_ext.is_flex_flow)) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Cannot match ethertype with L3/L4 or RAW 
patterns");
+       }
+
+       /* L2 and L3 input sets are exclusive */
+       if (l2_in_set && l3_in_set) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Matching both L2 and L3 is not supported");
+       }
+       /* L2 and L4 input sets are exclusive */
+       if (l2_in_set && l4_in_set) {
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM, item,
+                               "Matching both L2 and L4 is not supported");
+       }
+
+       /* if we are using one of the builtin packet types, validate it */
+       if (!filter->input.flow_ext.customized_pctype) {
+               /* validate the input set for the built-in pctype */
+               if (i40e_validate_input_set(pctype, RTE_ETH_FILTER_FDIR, 
input_set) != 0) {
+                       return rte_flow_error_set(error, EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_ITEM, item,
+                                       "Invalid input set");
+                       return -rte_errno;
+               }
+       }
+
+       return 0;
+}
+
+static int
+i40e_fdir_node_end_process(void *ctx __rte_unused, const struct rte_flow_item 
*item __rte_unused,
+               struct rte_flow_error *error __rte_unused)
+{
+       struct i40e_fdir_ctx *fdir_ctx = ctx;
+       struct i40e_fdir_filter_conf *filter = &fdir_ctx->fdir_filter;
+       struct i40e_pf *pf = 
I40E_DEV_PRIVATE_TO_PF(fdir_ctx->base.dev->data->dev_private);
+
+       /* Get customized pctype value */
+       if (filter->input.flow_ext.customized_pctype) {
+               enum i40e_filter_pctype pctype = 
i40e_flow_fdir_get_pctype_value(pf,
+                               fdir_ctx->custom_pctype, filter);
+               if (pctype == I40E_FILTER_PCTYPE_INVALID) {
+                       rte_flow_error_set(error, EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_ITEM, item,
+                                       "Unsupported packet type");
+                       return -rte_errno;
+               }
+               /* update FDIR packet type */
+               filter->input.pctype = pctype;
+       }
+
+       return 0;
+}
+
+const struct rte_flow_graph i40e_fdir_graph = {
+       .nodes = (struct rte_flow_graph_node[]) {
+               [I40E_FDIR_NODE_START] = { .name = "START" },
+               [I40E_FDIR_NODE_ETH] = {
+                       .name = "ETH",
+                       .type = RTE_FLOW_ITEM_TYPE_ETH,
+                       .constraints = RTE_FLOW_NODE_EXPECT_EMPTY |
+                                      RTE_FLOW_NODE_EXPECT_SPEC_MASK,
+                       .validate = i40e_fdir_node_eth_validate,
+                       .process = i40e_fdir_node_eth_process,
+               },
+               [I40E_FDIR_NODE_VLAN] = {
+                       .name = "VLAN",
+                       .type = RTE_FLOW_ITEM_TYPE_VLAN,
+                       .constraints = RTE_FLOW_NODE_EXPECT_EMPTY |
+                                      RTE_FLOW_NODE_EXPECT_SPEC_MASK,
+                       .validate = i40e_fdir_node_vlan_validate,
+                       .process = i40e_fdir_node_vlan_process,
+               },
+               [I40E_FDIR_NODE_IPV4] = {
+                       .name = "IPv4",
+                       .type = RTE_FLOW_ITEM_TYPE_IPV4,
+                       .constraints = RTE_FLOW_NODE_EXPECT_EMPTY |
+                                      RTE_FLOW_NODE_EXPECT_SPEC_MASK |
+                                      RTE_FLOW_NODE_EXPECT_RANGE,
+                       .validate = i40e_fdir_node_ipv4_validate,
+                       .process = i40e_fdir_node_ipv4_process,
+               },
+               [I40E_FDIR_NODE_IPV6] = {
+                       .name = "IPv6",
+                       .type = RTE_FLOW_ITEM_TYPE_IPV6,
+                       .constraints = RTE_FLOW_NODE_EXPECT_EMPTY |
+                                      RTE_FLOW_NODE_EXPECT_SPEC_MASK,
+                       .validate = i40e_fdir_node_ipv6_validate,
+                       .process = i40e_fdir_node_ipv6_process,
+               },
+               [I40E_FDIR_NODE_TCP] = {
+                       .name = "TCP",
+                       .type = RTE_FLOW_ITEM_TYPE_TCP,
+                       .constraints = RTE_FLOW_NODE_EXPECT_EMPTY |
+                                      RTE_FLOW_NODE_EXPECT_SPEC_MASK,
+                       .validate = i40e_fdir_node_tcp_validate,
+                       .process = i40e_fdir_node_tcp_process,
+               },
+               [I40E_FDIR_NODE_UDP] = {
+                       .name = "UDP",
+                       .type = RTE_FLOW_ITEM_TYPE_UDP,
+                       .constraints = RTE_FLOW_NODE_EXPECT_EMPTY |
+                                      RTE_FLOW_NODE_EXPECT_SPEC_MASK,
+                       .validate = i40e_fdir_node_udp_validate,
+                       .process = i40e_fdir_node_udp_process,
+               },
+               [I40E_FDIR_NODE_SCTP] = {
+                       .name = "SCTP",
+                       .type = RTE_FLOW_ITEM_TYPE_SCTP,
+                       .constraints = RTE_FLOW_NODE_EXPECT_EMPTY |
+                                      RTE_FLOW_NODE_EXPECT_SPEC_MASK,
+                       .validate = i40e_fdir_node_sctp_validate,
+                       .process = i40e_fdir_node_sctp_process,
+               },
+               [I40E_FDIR_NODE_ESP] = {
+                       .name = "ESP",
+                       .type = RTE_FLOW_ITEM_TYPE_ESP,
+                       .constraints = RTE_FLOW_NODE_EXPECT_SPEC_MASK,
+                       .validate = i40e_fdir_node_esp_validate,
+                       .process = i40e_fdir_node_esp_process,
+               },
+               [I40E_FDIR_NODE_L2TPV3OIP] = {
+                       .name = "L2TPV3OIP",
+                       .type = RTE_FLOW_ITEM_TYPE_L2TPV3OIP,
+                       .constraints = RTE_FLOW_NODE_EXPECT_SPEC_MASK,
+                       .validate = i40e_fdir_node_l2tpv3oip_validate,
+                       .process = i40e_fdir_node_l2tpv3oip_process,
+               },
+               [I40E_FDIR_NODE_GTPC] = {
+                       .name = "GTPC",
+                       .type = RTE_FLOW_ITEM_TYPE_GTPC,
+                       .constraints = RTE_FLOW_NODE_EXPECT_SPEC_MASK,
+                       .validate = i40e_fdir_node_gtp_validate,
+                       .process = i40e_fdir_node_gtp_process,
+               },
+               [I40E_FDIR_NODE_GTPU] = {
+                       .name = "GTPU",
+                       .type = RTE_FLOW_ITEM_TYPE_GTPU,
+                       .constraints = RTE_FLOW_NODE_EXPECT_SPEC_MASK,
+                       .validate = i40e_fdir_node_gtp_validate,
+                       .process = i40e_fdir_node_gtp_process,
+               },
+               [I40E_FDIR_NODE_INNER_IPV4] = {
+                       .name = "INNER_IPv4",
+                       .type = RTE_FLOW_ITEM_TYPE_IPV4,
+                       .constraints = RTE_FLOW_NODE_EXPECT_EMPTY,
+                       .validate = i40e_fdir_node_ipv4_validate,
+                       .process = i40e_fdir_node_inner_ipv4_process,
+               },
+               [I40E_FDIR_NODE_INNER_IPV6] = {
+                       .name = "INNER_IPv6",
+                       .type = RTE_FLOW_ITEM_TYPE_IPV6,
+                       .constraints = RTE_FLOW_NODE_EXPECT_EMPTY,
+                       .validate = i40e_fdir_node_ipv6_validate,
+                       .process = i40e_fdir_node_inner_ipv6_process,
+               },
+               [I40E_FDIR_NODE_RAW] = {
+                       .name = "RAW",
+                       .type = RTE_FLOW_ITEM_TYPE_RAW,
+                       .constraints = RTE_FLOW_NODE_EXPECT_SPEC_MASK,
+                       .validate = i40e_fdir_node_raw_validate,
+                       .process = i40e_fdir_node_raw_process,
+               },
+               [I40E_FDIR_NODE_END] = {
+                       .name = "END",
+                       .type = RTE_FLOW_ITEM_TYPE_END,
+                       .validate = i40e_fdir_node_end_validate,
+                       .process = i40e_fdir_node_end_process
+               },
+       },
+       .edges = (struct rte_flow_graph_edge[]) {
+               [I40E_FDIR_NODE_START] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_ETH,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+               [I40E_FDIR_NODE_ETH] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_VLAN,
+                               I40E_FDIR_NODE_IPV4,
+                               I40E_FDIR_NODE_IPV6,
+                               I40E_FDIR_NODE_RAW,
+                               I40E_FDIR_NODE_END,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+               [I40E_FDIR_NODE_VLAN] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_IPV4,
+                               I40E_FDIR_NODE_IPV6,
+                               I40E_FDIR_NODE_RAW,
+                               I40E_FDIR_NODE_END,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+               [I40E_FDIR_NODE_IPV4] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_TCP,
+                               I40E_FDIR_NODE_UDP,
+                               I40E_FDIR_NODE_SCTP,
+                               I40E_FDIR_NODE_ESP,
+                               I40E_FDIR_NODE_L2TPV3OIP,
+                               I40E_FDIR_NODE_RAW,
+                               I40E_FDIR_NODE_END,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+               [I40E_FDIR_NODE_IPV6] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_TCP,
+                               I40E_FDIR_NODE_UDP,
+                               I40E_FDIR_NODE_SCTP,
+                               I40E_FDIR_NODE_ESP,
+                               I40E_FDIR_NODE_L2TPV3OIP,
+                               I40E_FDIR_NODE_RAW,
+                               I40E_FDIR_NODE_END,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+               [I40E_FDIR_NODE_TCP] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_RAW,
+                               I40E_FDIR_NODE_END,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+               [I40E_FDIR_NODE_UDP] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_GTPC,
+                               I40E_FDIR_NODE_GTPU,
+                               I40E_FDIR_NODE_ESP,
+                               I40E_FDIR_NODE_RAW,
+                               I40E_FDIR_NODE_END,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+               [I40E_FDIR_NODE_SCTP] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_RAW,
+                               I40E_FDIR_NODE_END,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+               [I40E_FDIR_NODE_ESP] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_END,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+               [I40E_FDIR_NODE_L2TPV3OIP] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_END,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+               [I40E_FDIR_NODE_GTPC] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_END,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+               [I40E_FDIR_NODE_GTPU] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_INNER_IPV4,
+                               I40E_FDIR_NODE_INNER_IPV6,
+                               I40E_FDIR_NODE_END,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+               [I40E_FDIR_NODE_INNER_IPV4] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_END,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+               [I40E_FDIR_NODE_INNER_IPV6] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_END,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+               [I40E_FDIR_NODE_RAW] = {
+                       .next = (const size_t[]) {
+                               I40E_FDIR_NODE_RAW,
+                               I40E_FDIR_NODE_END,
+                               RTE_FLOW_NODE_EDGE_END
+                       }
+               },
+       },
+};
+
+static int
+i40e_fdir_action_check(const struct ci_flow_actions *actions,
+               const struct ci_flow_actions_check_param *param,
+               struct rte_flow_error *error)
+{
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(param->driver_ctx);
+       const struct rte_flow_action *first, *second;
+
+       first = actions->actions[0];
+       /* can be NULL */
+       second = actions->actions[1];
+
+       switch (first->type) {
+       case RTE_FLOW_ACTION_TYPE_QUEUE:
+       {
+               const struct rte_flow_action_queue *act_q = first->conf;
+               /* check against PF constraints */
+               if (act_q->index >= pf->dev_data->nb_rx_queues) {
+                       return rte_flow_error_set(error, EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_ACTION, first,
+                                       "Invalid queue ID for FDIR");
+               }
+               break;
+       }
+       case RTE_FLOW_ACTION_TYPE_DROP:
+       case RTE_FLOW_ACTION_TYPE_PASSTHRU:
+       case RTE_FLOW_ACTION_TYPE_MARK:
+               break;
+       default:
+               return rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ACTION, first,
+                               "Invalid first action for FDIR");
+       }
+
+       /* do we have another? */
+       if (second == NULL)
+               return 0;
+
+       switch (second->type) {
+       case RTE_FLOW_ACTION_TYPE_MARK:
+       {
+               /* only one mark action can be specified */
+               if (first->type == RTE_FLOW_ACTION_TYPE_MARK) {
+                       return rte_flow_error_set(error, EINVAL,
+                                                 RTE_FLOW_ERROR_TYPE_ACTION, 
second,
+                                                 "Invalid second action for 
FDIR");
+               }
+               break;
+       }
+       case RTE_FLOW_ACTION_TYPE_FLAG:
+       {
+               /* mark + flag is unsupported */
+               if (first->type == RTE_FLOW_ACTION_TYPE_MARK) {
+                       return rte_flow_error_set(error, EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_ACTION, second,
+                                       "Invalid second action for FDIR");
+               }
+               break;
+       }
+       case RTE_FLOW_ACTION_TYPE_RSS:
+               /* RSS filter only can be after passthru or mark */
+               if (first->type != RTE_FLOW_ACTION_TYPE_PASSTHRU &&
+                               first->type != RTE_FLOW_ACTION_TYPE_MARK) {
+                       return rte_flow_error_set(error, EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_ACTION, second,
+                                       "Invalid second action for FDIR");
+               }
+               break;
+       default:
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION, second,
+                                         "Invalid second action for FDIR");
+       }
+
+       return 0;
+}
+
+static int
+i40e_fdir_ctx_parse(const struct rte_flow_action *actions,
+               const struct rte_flow_attr *attr,
+               struct ci_flow_engine_ctx *ctx,
+               struct rte_flow_error *error)
+{
+       struct i40e_adapter *adapter = ctx->dev->data->dev_private;
+       struct i40e_fdir_ctx *fdir_ctx = (struct i40e_fdir_ctx *)ctx;
+       struct ci_flow_actions parsed_actions = {0};
+       struct ci_flow_actions_check_param ac_param = {
+               .allowed_types = (enum rte_flow_action_type[]) {
+                       RTE_FLOW_ACTION_TYPE_QUEUE,
+                       RTE_FLOW_ACTION_TYPE_DROP,
+                       RTE_FLOW_ACTION_TYPE_PASSTHRU,
+                       RTE_FLOW_ACTION_TYPE_MARK,
+                       RTE_FLOW_ACTION_TYPE_FLAG,
+                       RTE_FLOW_ACTION_TYPE_RSS,
+                       RTE_FLOW_ACTION_TYPE_END
+               },
+               .max_actions = 2,
+               .driver_ctx = adapter,
+               .check = i40e_fdir_action_check,
+       };
+       int ret;
+       const struct rte_flow_action *first, *second;
+
+       ret = ci_flow_check_attr(attr, NULL, error);
+       if (ret) {
+               return ret;
+       }
+
+       ret = ci_flow_check_actions(actions, &ac_param, &parsed_actions, error);
+       if (ret) {
+               return ret;
+       }
+
+       first = parsed_actions.actions[0];
+       /* can be NULL */
+       second = parsed_actions.actions[1];
+
+       if (first->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
+               const struct rte_flow_action_queue *act_q = first->conf;
+               fdir_ctx->fdir_filter.action.rx_queue = act_q->index;
+               fdir_ctx->fdir_filter.action.behavior = I40E_FDIR_ACCEPT;
+       } else if (first->type == RTE_FLOW_ACTION_TYPE_DROP) {
+               fdir_ctx->fdir_filter.action.behavior = I40E_FDIR_REJECT;
+       } else if (first->type == RTE_FLOW_ACTION_TYPE_PASSTHRU) {
+               fdir_ctx->fdir_filter.action.behavior = I40E_FDIR_PASSTHRU;
+       } else if (first->type == RTE_FLOW_ACTION_TYPE_MARK) {
+               const struct rte_flow_action_mark *act_m = first->conf;
+               fdir_ctx->fdir_filter.action.behavior = I40E_FDIR_PASSTHRU;
+               fdir_ctx->fdir_filter.action.report_status = 
I40E_FDIR_REPORT_ID;
+               fdir_ctx->fdir_filter.soft_id = act_m->id;
+       }
+
+       if (second != NULL) {
+               if (second->type == RTE_FLOW_ACTION_TYPE_MARK) {
+                       const struct rte_flow_action_mark *act_m = second->conf;
+                       fdir_ctx->fdir_filter.action.report_status = 
I40E_FDIR_REPORT_ID;
+                       fdir_ctx->fdir_filter.soft_id = act_m->id;
+               } else if (second->type == RTE_FLOW_ACTION_TYPE_FLAG) {
+                       fdir_ctx->fdir_filter.action.report_status = 
I40E_FDIR_NO_REPORT_STATUS;
+               }
+               /* RSS action does nothing */
+       }
+       return 0;
+}
+
+static int
+i40e_fdir_flow_install(struct ci_flow *flow, struct rte_flow_error *error)
+{
+       struct i40e_flow_engine_fdir_flow *fdir_flow = (struct 
i40e_flow_engine_fdir_flow *)flow;
+       struct rte_eth_dev *dev = flow->dev;
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       bool need_teardown = false;
+       bool need_rx_proc_disable = false;
+       int ret;
+
+       /* if fdir is not configured, configure it */
+       if (pf->fdir.fdir_vsi == NULL) {
+               ret = i40e_fdir_setup(pf);
+               if (ret != I40E_SUCCESS) {
+                       ret = rte_flow_error_set(error, ENOTSUP,
+                                       RTE_FLOW_ERROR_TYPE_HANDLE,
+                                       NULL, "Failed to setup fdir.");
+                       goto err;
+               }
+               /* if something failed down the line, teardown is needed */
+               need_teardown = true;
+               ret = i40e_fdir_configure(dev);
+               if (ret < 0) {
+                       ret = rte_flow_error_set(error, ENOTSUP,
+                                       RTE_FLOW_ERROR_TYPE_HANDLE,
+                                       NULL, "Failed to configure fdir.");
+                       goto err;
+               }
+       }
+
+       /* if this is first flow, enable fdir check for rx queues */
+       if (pf->fdir.num_fdir_flows == 0) {
+               i40e_fdir_rx_proc_enable(dev, 1);
+               /* if something failed down the line, we need to disable fdir 
check for rx queues */
+               need_rx_proc_disable = true;
+       }
+
+       ret = i40e_flow_add_del_fdir_filter(dev, &fdir_flow->fdir_filter, 1);
+       if (ret != 0) {
+               ret = rte_flow_error_set(error, ENOTSUP,
+                               RTE_FLOW_ERROR_TYPE_HANDLE,
+                               NULL, "Failed to add fdir filter.");
+               goto err;
+       }
+
+       /* we got flows now */
+       pf->fdir.num_fdir_flows++;
+
+       return 0;
+err:
+       if (need_rx_proc_disable)
+               i40e_fdir_rx_proc_enable(dev, 0);
+       if (need_teardown)
+               i40e_fdir_teardown(pf);
+       return ret;
+}
+
+static int
+i40e_fdir_flow_uninstall(struct ci_flow *flow, struct rte_flow_error *error 
__rte_unused)
+{
+       struct rte_eth_dev *dev = flow->dev;
+       struct i40e_flow_engine_fdir_flow *fdir_flow = (struct 
i40e_flow_engine_fdir_flow *)flow;
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       int ret;
+
+       ret = i40e_flow_add_del_fdir_filter(dev, &fdir_flow->fdir_filter, 0);
+       if (ret != 0) {
+               return rte_flow_error_set(error, ENOTSUP,
+                               RTE_FLOW_ERROR_TYPE_HANDLE,
+                               NULL, "Failed to delete fdir filter.");
+       }
+
+       /* we are removing a flow */
+       if (pf->fdir.num_fdir_flows > 0)
+               pf->fdir.num_fdir_flows--;
+
+       /* if there are no more flows, disable fdir check for rx queues and 
teardown fdir */
+       if (pf->fdir.num_fdir_flows == 0) {
+               i40e_fdir_rx_proc_enable(dev, 0);
+               i40e_fdir_teardown(pf);
+       }
+
+       return 0;
+}
+
+static int
+i40e_fdir_flow_engine_init(const struct ci_flow_engine *engine,
+               struct rte_eth_dev *dev,
+               void *priv_data)
+{
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct i40e_fdir_info *fdir_info = &pf->fdir;
+       struct i40e_fdir_engine_priv *priv = priv_data;
+       struct i40e_fdir_flow_pool_entry *pool;
+       struct rte_bitmap *bmp;
+       uint32_t bmp_size;
+       void *bmp_mem;
+       uint32_t i;
+
+       pool = rte_zmalloc(engine->name,
+                       fdir_info->fdir_space_size * sizeof(*pool), 0);
+       if (pool == NULL)
+               return -ENOMEM;
+
+       bmp_size = rte_bitmap_get_memory_footprint(fdir_info->fdir_space_size);
+       bmp_mem = rte_zmalloc("fdir_bmap", bmp_size, RTE_CACHE_LINE_SIZE);
+       if (bmp_mem == NULL) {
+               rte_free(pool);
+               return -ENOMEM;
+       }
+
+       bmp = rte_bitmap_init(fdir_info->fdir_space_size, bmp_mem, bmp_size);
+       if (bmp == NULL) {
+               if (bmp_mem != NULL)
+                       rte_free(bmp_mem);
+               if (pool != NULL)
+                       rte_free(pool);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < fdir_info->fdir_space_size; i++) {
+               pool[i].idx = i;
+               rte_bitmap_set(bmp, i);
+       }
+
+       priv->pool = pool;
+       priv->bmp = bmp;
+
+       return 0;
+}
+
+static void
+i40e_fdir_flow_engine_uninit(const struct ci_flow_engine *engine __rte_unused,
+               void *priv_data)
+{
+       struct i40e_fdir_engine_priv *priv = priv_data;
+
+       if (priv->bmp != NULL)
+               rte_free(priv->bmp);
+       if (priv->pool != NULL)
+               rte_free(priv->pool);
+}
+
+static struct ci_flow *
+i40e_fdir_flow_alloc(const struct ci_flow_engine *engine,
+               struct rte_eth_dev *dev)
+{
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct i40e_fdir_info *fdir_info = &pf->fdir;
+       struct i40e_fdir_engine_priv *priv = 
ci_flow_engine_priv(&pf->flow_engine_conf, engine->type);
+       uint64_t slab = 0;
+       uint32_t pos = 0;
+       uint32_t bit;
+       int ret;
+
+       if (priv == NULL || priv->pool == NULL || priv->bmp == NULL)
+               return NULL;
+
+       if (fdir_info->fdir_actual_cnt >= fdir_info->fdir_space_size)
+               return NULL;
+
+       ret = rte_bitmap_scan(priv->bmp, &pos, &slab);
+       if (ret == 0)
+               return NULL;
+
+       bit = rte_bsf64(slab);
+       pos += bit;
+       rte_bitmap_clear(priv->bmp, pos);
+
+       memset(&priv->pool[pos].flow, 0, sizeof(priv->pool[pos].flow));
+       return (struct ci_flow *)&priv->pool[pos].flow;
+}
+
+static void
+i40e_fdir_flow_free(struct ci_flow *flow)
+{
+       struct i40e_pf *pf = 
I40E_DEV_PRIVATE_TO_PF(flow->dev->data->dev_private);
+       struct i40e_fdir_engine_priv *priv = 
ci_flow_engine_priv(&pf->flow_engine_conf, flow->engine_type);
+       struct i40e_fdir_flow_pool_entry *entry;
+
+       entry = I40E_FDIR_FLOW_ENTRY((struct i40e_flow_engine_fdir_flow *)flow);
+       rte_bitmap_set(priv->bmp, entry->idx);
+}
+
+const struct ci_flow_engine_ops i40e_flow_engine_fdir_ops = {
+       .init = i40e_fdir_flow_engine_init,
+       .uninit = i40e_fdir_flow_engine_uninit,
+       .flow_alloc = i40e_fdir_flow_alloc,
+       .flow_free = i40e_fdir_flow_free,
+       .ctx_parse = i40e_fdir_ctx_parse,
+       .flow_install = i40e_fdir_flow_install,
+       .flow_uninstall = i40e_fdir_flow_uninstall,
+};
+
+const struct ci_flow_engine i40e_flow_engine_fdir = {
+       .name = "i40e_fdir",
+       .type = I40E_FLOW_ENGINE_TYPE_FDIR,
+       .ops = &i40e_flow_engine_fdir_ops,
+       .ctx_size = sizeof(struct i40e_fdir_ctx),
+       .flow_size = sizeof(struct i40e_flow_engine_fdir_flow),
+       .priv_size = sizeof(struct i40e_fdir_engine_priv),
+       .graph = &i40e_fdir_graph,
+};
diff --git a/drivers/net/intel/i40e/meson.build 
b/drivers/net/intel/i40e/meson.build
index bff0518fc9..0638f873dd 100644
--- a/drivers/net/intel/i40e/meson.build
+++ b/drivers/net/intel/i40e/meson.build
@@ -26,6 +26,7 @@ sources += files(
         'i40e_fdir.c',
         'i40e_flow.c',
         'i40e_flow_ethertype.c',
+        'i40e_flow_fdir.c',
         'i40e_tm.c',
         'i40e_hash.c',
         'i40e_vf_representor.c',
-- 
2.47.3

Reply via email to