From: Subarna Kar <subarna....@intel.com>

---
 drivers/net/i40e/i40e_ethdev.c |  14 +-
 drivers/net/i40e/i40e_ethdev.h | 109 +++++-
 drivers/net/i40e/i40e_fdir.c   | 392 +++++++++++++++++++--
 drivers/net/i40e/i40e_flow.c   | 781 ++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 1250 insertions(+), 46 deletions(-)

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 7030eb1..0e9f22d 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -1788,6 +1788,7 @@ i40e_dev_configure(struct rte_eth_dev *dev)
         * legacy filter API is deprecated, the following codes should also be
         * removed.
         */
+       dev->data->dev_conf.fdir_conf.mode = RTE_FDIR_MODE_PERFECT;
        if (dev->data->dev_conf.fdir_conf.mode == RTE_FDIR_MODE_PERFECT) {
                ret = i40e_fdir_setup(pf);
                if (ret != I40E_SUCCESS) {
@@ -9055,7 +9056,11 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
                I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
                I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                I40E_INSET_IPV4_TOS | I40E_INSET_IPV4_TTL |
-               I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
+               I40E_INSET_IPV4_PROTO | I40E_INSET_TUNNEL_ID |
+               I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
+               I40E_INSET_TUNNEL_IPV4_DST |
+               I40E_INSET_TUNNEL_DST_PORT |
+               I40E_INSET_TUNNEL_IPV6_DST,
                [I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP] =
                I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
                I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
@@ -9096,7 +9101,10 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
                I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
                I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
                I40E_INSET_IPV6_TC | I40E_INSET_IPV6_HOP_LIMIT |
-               I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
+               I40E_INSET_IPV6_NEXT_HDR |
+               I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
+               I40E_INSET_TUNNEL_ID | I40E_INSET_TUNNEL_DST_PORT |
+               I40E_INSET_TUNNEL_IPV4_DST | I40E_INSET_TUNNEL_IPV6_DST,
                [I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP] =
                I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
                I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
@@ -12384,7 +12392,6 @@ i40e_update_customized_info(struct rte_eth_dev *dev, 
uint8_t *pkg,
        uint32_t buff_size;
        uint32_t i;
        int ret;
-
        if (op != RTE_PMD_I40E_PKG_OP_WR_ADD &&
            op != RTE_PMD_I40E_PKG_OP_WR_DEL) {
                PMD_DRV_LOG(ERR, "Unsupported operation.");
@@ -12403,7 +12410,6 @@ i40e_update_customized_info(struct rte_eth_dev *dev, 
uint8_t *pkg,
                PMD_DRV_LOG(INFO, "No new protocol added");
                return;
        }
-
        buff_size = proto_num * sizeof(struct rte_pmd_i40e_proto_info);
        proto = rte_zmalloc("new_proto", buff_size, 0);
        if (!proto) {
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 11ecfc3..f7311ce 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -466,6 +466,92 @@ struct i40e_vmdq_info {
 #define I40E_FLEX_WORD_MASK(off) (0x80 >> (off))
 #define I40E_FDIR_IPv6_TC_OFFSET       20
 
+/* A structure used to define input for MPLSoUDP flow */
+struct i40e_mplsoudpv4_udpv4_flow {
+       struct rte_eth_udpv4_flow outer_udp; //outer IPv4
+       struct rte_flow_item_mpls mpls;
+       struct rte_eth_udpv4_flow inner_udp; //inner IPv4
+};
+
+struct i40e_mplsoudpv4_udpv6_flow {
+       struct rte_eth_udpv4_flow outer_udp; //outer IPv4
+       struct rte_flow_item_mpls mpls;
+       struct rte_eth_udpv6_flow inner6_udp; //inner IPv6
+};
+
+struct i40e_mplsoudpv6_udpv4_flow {
+       struct rte_eth_udpv6_flow outer6_udp; //outer IPv6
+       struct rte_flow_item_mpls mpls;
+       struct rte_eth_udpv4_flow inner_udp; //inner IPv4
+};
+
+struct i40e_mplsoudpv6_udpv6_flow {
+       struct rte_eth_udpv6_flow outer6_udp; //outer IPv6
+       struct rte_flow_item_mpls mpls;
+       struct rte_eth_udpv6_flow inner6_udp; //inner IPv6
+};
+
+/* A structure used to define input for VXLAN flow */
+struct i40e_vxlanv4_udpv4_flow {
+       struct rte_eth_udpv4_flow outer_udp; //outer IPv4
+       struct rte_flow_item_vxlan vxlan;
+       struct rte_eth_udpv4_flow inner_udp; //inner IPv4
+};
+
+struct i40e_vxlanv4_udpv6_flow {
+       struct rte_eth_udpv4_flow outer_udp; //outer IPv4
+       struct rte_flow_item_vxlan vxlan;
+       struct rte_eth_udpv6_flow inner6_udp; //inner IPv6
+};
+
+struct i40e_vxlanv6_udpv4_flow {
+       struct rte_eth_udpv6_flow outer6_udp; //outer IPv6
+       struct rte_flow_item_vxlan vxlan;
+       struct rte_eth_udpv4_flow inner_udp; //inner IPv4
+};
+
+struct i40e_vxlanv6_udpv6_flow {
+       struct rte_eth_udpv6_flow outer6_udp; //outer IPv6
+       struct rte_flow_item_vxlan vxlan;
+       struct rte_eth_udpv6_flow inner6_udp; //inner IPv6
+};
+
+/* A structure used to define input for MPLSoGRE flow */
+
+struct i40e_gre_flow {
+       struct rte_eth_ipv4_flow ip;
+       struct rte_flow_item_gre gre;
+};
+
+struct i40e_mplsogrev4_udpv4_flow {
+       struct i40e_gre_flow outer_gre; //outer IPv4
+       struct rte_flow_item_mpls mpls;
+       struct rte_eth_udpv4_flow inner_udp; //inner IPv4
+};
+
+struct i40e_mplsogrev4_udpv6_flow {
+       struct i40e_gre_flow outer_gre; //outer IPv4
+       struct rte_flow_item_mpls mpls;
+       struct rte_eth_udpv6_flow inner6_udp; //inner IPv6
+};
+
+struct i40e_gre_ipv6_flow {
+       struct rte_eth_ipv6_flow ip;
+       struct rte_flow_item_gre gre;
+};
+
+struct i40e_mplsogrev6_udpv4_flow {
+       struct i40e_gre_ipv6_flow outer6_gre; //outer IPv6
+       struct rte_flow_item_mpls mpls;
+       struct rte_eth_udpv4_flow inner_udp; //inner IPv4
+};
+
+struct i40e_mplsogrev6_udpv6_flow {
+       struct i40e_gre_ipv6_flow outer6_gre; //outer IPv6
+       struct rte_flow_item_mpls mpls;
+       struct rte_eth_udpv6_flow inner6_udp; //inner IPv6
+};
+
 /* A structure used to define the input for GTP flow */
 struct i40e_gtp_flow {
        struct rte_eth_udpv4_flow udp; /* IPv4 UDP fields to match. */
@@ -510,6 +596,19 @@ union i40e_fdir_flow {
        struct i40e_gtp_ipv4_flow  gtp_ipv4_flow;
        struct i40e_gtp_ipv6_flow  gtp_ipv6_flow;
        struct i40e_raw_flow       raw_flow;
+       //this is for tunneled pkts to match on outer and inner
+       struct i40e_mplsoudpv4_udpv4_flow  mplsudp4_flow;
+       struct i40e_mplsoudpv4_udpv6_flow  mplsudp6_flow;
+       struct i40e_mplsoudpv6_udpv4_flow mpls6udp4_flow;
+       struct i40e_mplsoudpv6_udpv6_flow mpls6udp6_flow;
+       struct i40e_mplsogrev4_udpv4_flow  mplsgre4_flow;
+       struct i40e_mplsogrev4_udpv6_flow  mplsgre6_flow;
+       struct i40e_mplsogrev6_udpv4_flow  mpls6gre4_flow;
+       struct i40e_mplsogrev6_udpv6_flow  mpls6gre6_flow;
+       struct i40e_vxlanv4_udpv4_flow  vxlanudp4_flow;
+       struct i40e_vxlanv4_udpv6_flow  vxlanudp6_flow;
+       struct i40e_vxlanv6_udpv4_flow  vxlan6udp4_flow;
+       struct i40e_vxlanv6_udpv6_flow  vxlan6udp6_flow;
 };
 
 enum i40e_fdir_ip_type {
@@ -517,6 +616,12 @@ enum i40e_fdir_ip_type {
        I40E_FDIR_IPTYPE_IPV6,
 };
 
+enum i40e_fdir_tunnel_type {
+       MPLSOUDP,
+       MPLSOGRE,
+       VXLAN,
+};
+
 /* A structure used to contain extend input of flow */
 struct i40e_fdir_flow_ext {
        uint16_t vlan_tci;
@@ -528,6 +633,8 @@ struct i40e_fdir_flow_ext {
        enum i40e_fdir_ip_type iip_type; /* ip type for inner ip */
        bool customized_pctype; /* If customized pctype is used */
        bool pkt_template; /* If raw packet template is used */
+       bool tunnel; /*if its tunnel pkts, then allow inner headers. */
+       enum i40e_fdir_tunnel_type tunnel_val;
 };
 
 /* A structure used to define the input for a flow director filter entry */
@@ -748,8 +855,8 @@ enum i40e_tunnel_type {
        I40E_TUNNEL_TYPE_NVGRE,
        I40E_TUNNEL_TYPE_IP_IN_GRE,
        I40E_L2_TUNNEL_TYPE_E_TAG,
-       I40E_TUNNEL_TYPE_MPLSoUDP,
        I40E_TUNNEL_TYPE_MPLSoGRE,
+       I40E_TUNNEL_TYPE_MPLSoUDP,
        I40E_TUNNEL_TYPE_QINQ,
        I40E_TUNNEL_TYPE_GTPC,
        I40E_TUNNEL_TYPE_GTPU,
diff --git a/drivers/net/i40e/i40e_fdir.c b/drivers/net/i40e/i40e_fdir.c
index d41601a..253ea56 100644
--- a/drivers/net/i40e/i40e_fdir.c
+++ b/drivers/net/i40e/i40e_fdir.c
@@ -35,6 +35,7 @@
 
 #define I40E_FDIR_PKT_LEN                   512
 #define I40E_FDIR_IP_DEFAULT_LEN            420
+#define I40E_FDIR_IP_DEFAULT_LEN_INNER      370
 #define I40E_FDIR_IP_DEFAULT_TTL            0x40
 #define I40E_FDIR_IP_DEFAULT_VERSION_IHL    0x45
 #define I40E_FDIR_TCP_DEFAULT_DATAOFF       0x50
@@ -43,6 +44,7 @@
 #define I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS   0xFF
 #define I40E_FDIR_IPv6_PAYLOAD_LEN          380
 #define I40E_FDIR_UDP_DEFAULT_LEN           400
+#define I40E_FDIR_UDP_DEFAULT_LEN_INNER     350
 #define I40E_FDIR_GTP_DEFAULT_LEN           384
 #define I40E_FDIR_INNER_IP_DEFAULT_LEN      384
 #define I40E_FDIR_INNER_IPV6_DEFAULT_LEN    344
@@ -53,7 +55,7 @@
 #define I40E_FDIR_GTP_VER_FLAG_0X32         0x32
 #define I40E_FDIR_GTP_MSG_TYPE_0X01         0x01
 #define I40E_FDIR_GTP_MSG_TYPE_0XFF         0xFF
-
+#define VXLAN_DEFAULT_FLAG                  0x08
 /* Wait time for fdir filter programming */
 #define I40E_FDIR_MAX_WAIT_US 10000
 
@@ -951,15 +953,138 @@ i40e_flow_fdir_find_customized_pctype(struct i40e_pf 
*pf, uint8_t pctype)
 }
 
 static inline int
+i40e_flow_fdir_fill_outer_header(const struct i40e_fdir_input *fdir_input,
+                                unsigned char *raw_pkt)
+{
+       struct ipv4_hdr *ip;
+       struct ipv6_hdr *ip6;
+       struct udp_hdr *udp;
+       struct rte_flow_item_gre *gre;
+       struct rte_flow_item_mpls *mpls;
+       struct rte_flow_item_vxlan *vxlan;
+       uint16_t *ether_type;
+       uint8_t len = 2 * sizeof(struct ether_addr);
+       raw_pkt += 2 * sizeof(struct ether_addr);
+       ether_type = (uint16_t *)raw_pkt;
+       raw_pkt += sizeof(uint16_t);
+       len += sizeof(uint16_t);
+
+
+       //we don't need ETH, so direct skip to IP
+       if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) {
+               ip = (struct ipv4_hdr *)raw_pkt;
+               *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+               ip->version_ihl =
+                                 I40E_FDIR_IP_DEFAULT_VERSION_IHL;
+               /* set len to by default */
+               ip->total_length =
+                                  rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN);
+               ip->time_to_live = I40E_FDIR_IP_DEFAULT_TTL;
+               ip->type_of_service = fdir_input->flow.ip4_flow.tos;
+               ip->src_addr = fdir_input->flow.ip4_flow.src_ip;
+               ip->dst_addr = fdir_input->flow.ip4_flow.dst_ip;
+               if (fdir_input->flow_ext.tunnel_val == MPLSOGRE)
+                       ip->next_proto_id = IPPROTO_GRE;
+               else
+                       ip->next_proto_id = IPPROTO_UDP;
+               len += sizeof(struct ipv4_hdr);
+               raw_pkt += sizeof(struct ipv4_hdr);
+       }
+       if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV6) {
+               ip6 = (struct ipv6_hdr *)raw_pkt;
+               *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+               ip6->vtc_flow =
+                       rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW);
+               ip6->payload_len =
+                       rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN);
+               ip6->hop_limits =
+                                 I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS;
+               ip6->proto =
+                       fdir_input->flow.mpls6udp4_flow.outer6_udp.ip.proto;
+               rte_memcpy(&ip6->src_addr,
+                       &fdir_input->flow.mpls6udp4_flow.outer6_udp.ip.src_ip,
+                       IPV6_ADDR_LEN);
+               rte_memcpy(&ip6->dst_addr,
+                       &fdir_input->flow.mpls6udp4_flow.outer6_udp.ip.dst_ip,
+                       IPV6_ADDR_LEN);
+               len += sizeof(struct ipv6_hdr);
+               raw_pkt += sizeof(struct ipv6_hdr);
+       }
+       if (fdir_input->flow_ext.tunnel_val == MPLSOGRE) {
+               gre = (struct rte_flow_item_gre *)raw_pkt;
+               gre->protocol =
+                       fdir_input->flow.mplsgre4_flow.outer_gre.gre.protocol;
+               len += sizeof(struct rte_flow_item_gre);
+               raw_pkt += sizeof(struct rte_flow_item_gre);
+       } else {//now put UDP info for VXLAN and MPLSoUDP
+               udp = (struct udp_hdr *)raw_pkt;
+               if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) {
+                       udp->src_port =
+                       fdir_input->flow.mplsudp4_flow.outer_udp.src_port;
+                       udp->dst_port =
+                       fdir_input->flow.mplsudp4_flow.outer_udp.dst_port;
+               } else {
+                       udp->src_port =
+                       fdir_input->flow.mpls6udp4_flow.outer6_udp.src_port;
+                       udp->dst_port =
+                       fdir_input->flow.mpls6udp4_flow.outer6_udp.dst_port;
+               }
+               udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN);
+               len += sizeof(struct udp_hdr);
+               raw_pkt += sizeof(struct udp_hdr);
+       }
+       if (fdir_input->flow_ext.tunnel_val == VXLAN) {
+               vxlan = (struct rte_flow_item_vxlan *)raw_pkt;
+               if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) {
+                       vxlan->vni[0] =
+                               fdir_input->flow.vxlanudp4_flow.vxlan.vni[0];
+                       vxlan->vni[1] =
+                               fdir_input->flow.vxlanudp4_flow.vxlan.vni[1];
+                       vxlan->vni[2] =
+                               fdir_input->flow.vxlanudp4_flow.vxlan.vni[2];
+               } else {
+                       vxlan->vni[0] =
+                               fdir_input->flow.vxlan6udp4_flow.vxlan.vni[0];
+                       vxlan->vni[1] =
+                               fdir_input->flow.vxlan6udp4_flow.vxlan.vni[1];
+                       vxlan->vni[2] =
+                               fdir_input->flow.vxlan6udp4_flow.vxlan.vni[2];
+               }
+               vxlan->flags = VXLAN_DEFAULT_FLAG;
+               len += sizeof(struct rte_flow_item_vxlan);
+       } else {
+      //now put MPLS info for MPLSoUDP and MPLSoGRE
+               mpls = (struct rte_flow_item_mpls *)raw_pkt;
+               if (fdir_input->flow_ext.iip_type == I40E_FDIR_IPTYPE_IPV4) {
+                       mpls->label_tc_s[0] =
+                       fdir_input->flow.mplsudp4_flow.mpls.label_tc_s[0];
+                       mpls->label_tc_s[1] =
+                       fdir_input->flow.mplsudp4_flow.mpls.label_tc_s[1];
+                       mpls->label_tc_s[2] =
+                       fdir_input->flow.mplsudp4_flow.mpls.label_tc_s[2];
+               } else {
+                       mpls->label_tc_s[0] =
+                       fdir_input->flow.mpls6udp4_flow.mpls.label_tc_s[0];
+                       mpls->label_tc_s[1] =
+                       fdir_input->flow.mpls6udp4_flow.mpls.label_tc_s[1];
+                       mpls->label_tc_s[2] =
+                       fdir_input->flow.mpls6udp4_flow.mpls.label_tc_s[2];
+               }
+               len += sizeof(struct rte_flow_item_mpls);
+       }
+       return len;
+}
+
+static inline int
 i40e_flow_fdir_fill_eth_ip_head(struct i40e_pf *pf,
                                const struct i40e_fdir_input *fdir_input,
                                unsigned char *raw_pkt,
-                               bool vlan)
+                               bool vlan, int outer_len)
 {
        struct i40e_customized_pctype *cus_pctype = NULL;
        static uint8_t vlan_frame[] = {0x81, 0, 0, 0};
        uint16_t *ether_type;
-       uint8_t len = 2 * sizeof(struct ether_addr);
+       uint8_t len = 2 * sizeof(struct ether_addr) + outer_len;
        struct ipv4_hdr *ip;
        struct ipv6_hdr *ip6;
        uint8_t pctype = fdir_input->pctype;
@@ -977,7 +1102,7 @@ i40e_flow_fdir_fill_eth_ip_head(struct i40e_pf *pf,
                [I40E_FILTER_PCTYPE_NONF_IPV6_OTHER] = IPPROTO_NONE,
        };
 
-       raw_pkt += 2 * sizeof(struct ether_addr);
+       raw_pkt += 2 * sizeof(struct ether_addr) + outer_len;
        if (vlan && fdir_input->flow_ext.vlan_tci) {
                rte_memcpy(raw_pkt, vlan_frame, sizeof(vlan_frame));
                rte_memcpy(raw_pkt + sizeof(uint16_t),
@@ -1011,12 +1136,82 @@ i40e_flow_fdir_fill_eth_ip_head(struct i40e_pf *pf,
 
                *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
                ip->version_ihl = I40E_FDIR_IP_DEFAULT_VERSION_IHL;
-               /* set len to by default */
-               ip->total_length = rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN);
-               ip->time_to_live = fdir_input->flow.ip4_flow.ttl ?
-                       fdir_input->flow.ip4_flow.ttl :
+
+               if (outer_len) {//we have a tunneled pkt
+                       if (fdir_input->flow_ext.tunnel_val != VXLAN) {
+                               if (fdir_input->flow_ext.iip_type ==
+                                       I40E_FDIR_IPTYPE_IPV4) {
+                                       ip->time_to_live =
+                       fdir_input->flow.mplsudp4_flow.inner_udp.ip.ttl ?
+                       fdir_input->flow.mplsudp4_flow.inner_udp.ip.ttl :
                        I40E_FDIR_IP_DEFAULT_TTL;
-               ip->type_of_service = fdir_input->flow.ip4_flow.tos;
+                                       ip->total_length =
+                       rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN_INNER);
+                                       ip->type_of_service =
+                       fdir_input->flow.mplsudp4_flow.inner_udp.ip.tos;
+                                       ip->src_addr =
+                       fdir_input->flow.mplsudp4_flow.inner_udp.ip.dst_ip;
+                                       ip->dst_addr =
+                       fdir_input->flow.mplsudp4_flow.inner_udp.ip.src_ip;
+                                       ip->next_proto_id =
+                       fdir_input->flow.mplsudp4_flow.inner_udp.ip.proto;
+                               } else {
+                                       ip->time_to_live =
+                       fdir_input->flow.mpls6udp4_flow.inner_udp.ip.ttl ?
+                       fdir_input->flow.mpls6udp4_flow.inner_udp.ip.ttl :
+                       I40E_FDIR_IP_DEFAULT_TTL;
+                                       ip->total_length =
+                       rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN_INNER);
+                                       ip->type_of_service =
+                       fdir_input->flow.mpls6udp4_flow.inner_udp.ip.tos;
+                                       ip->src_addr =
+                       fdir_input->flow.mpls6udp4_flow.inner_udp.ip.dst_ip;
+                                       ip->dst_addr =
+                       fdir_input->flow.mpls6udp4_flow.inner_udp.ip.src_ip;
+                                       ip->next_proto_id =
+                       fdir_input->flow.mpls6udp4_flow.inner_udp.ip.proto;
+                               }
+                       } else {
+                               if (fdir_input->flow_ext.iip_type ==
+                               I40E_FDIR_IPTYPE_IPV4) {
+                                       ip->time_to_live =
+                       fdir_input->flow.vxlanudp4_flow.inner_udp.ip.ttl ?
+                       fdir_input->flow.vxlanudp4_flow.inner_udp.ip.ttl :
+                       I40E_FDIR_IP_DEFAULT_TTL;
+                                       ip->total_length =
+                       rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN_INNER);
+                                       ip->type_of_service =
+                       fdir_input->flow.vxlanudp4_flow.inner_udp.ip.tos;
+                                       ip->src_addr =
+                       fdir_input->flow.vxlanudp4_flow.inner_udp.ip.dst_ip;
+                                       ip->dst_addr =
+                       fdir_input->flow.vxlanudp4_flow.inner_udp.ip.src_ip;
+                                       ip->next_proto_id =
+                       fdir_input->flow.vxlanudp4_flow.inner_udp.ip.proto;
+                               } else {
+                                       ip->time_to_live =
+                       fdir_input->flow.vxlan6udp4_flow.inner_udp.ip.ttl ?
+                       fdir_input->flow.vxlan6udp4_flow.inner_udp.ip.ttl :
+                       I40E_FDIR_IP_DEFAULT_TTL;
+                                       ip->total_length =
+                       rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN_INNER);
+                                       ip->type_of_service =
+                       fdir_input->flow.vxlan6udp4_flow.inner_udp.ip.tos;
+                                       ip->src_addr =
+                       fdir_input->flow.vxlan6udp4_flow.inner_udp.ip.dst_ip;
+                                       ip->dst_addr =
+                       fdir_input->flow.vxlan6udp4_flow.inner_udp.ip.src_ip;
+                                       ip->next_proto_id =
+                       fdir_input->flow.vxlan6udp4_flow.inner_udp.ip.proto;
+                               }
+                       }
+                       len += sizeof(struct ipv4_hdr);
+               } else {
+                       /* set len to by default */
+                       ip->total_length = 
rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN);
+                       ip->time_to_live = fdir_input->flow.ip4_flow.ttl ?
+               fdir_input->flow.ip4_flow.ttl : I40E_FDIR_IP_DEFAULT_TTL;
+                       ip->type_of_service = fdir_input->flow.ip4_flow.tos;
                /**
                 * The source and destination fields in the transmitted packet
                 * need to be presented in a reversed order with respect
@@ -1033,8 +1228,10 @@ i40e_flow_fdir_fill_eth_ip_head(struct i40e_pf *pf,
                         cus_pctype->index == I40E_CUSTOMIZED_GTPU_IPV4 ||
                         cus_pctype->index == I40E_CUSTOMIZED_GTPU_IPV6 ||
                         cus_pctype->index == I40E_CUSTOMIZED_GTPU)
+
                        ip->next_proto_id = IPPROTO_UDP;
                len += sizeof(struct ipv4_hdr);
+               }
        } else if (pctype == I40E_FILTER_PCTYPE_NONF_IPV6_TCP ||
                   pctype == I40E_FILTER_PCTYPE_NONF_IPV6_UDP ||
                   pctype == I40E_FILTER_PCTYPE_NONF_IPV6_SCTP ||
@@ -1043,30 +1240,75 @@ i40e_flow_fdir_fill_eth_ip_head(struct i40e_pf *pf,
                ip6 = (struct ipv6_hdr *)raw_pkt;
 
                *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
-               ip6->vtc_flow =
-                       rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW |
-                                        (fdir_input->flow.ipv6_flow.tc <<
-                                         I40E_FDIR_IPv6_TC_OFFSET));
-               ip6->payload_len =
+
+               if (outer_len) {
+                       ip6->vtc_flow =
+                       rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW);
+                       ip6->payload_len =
                        rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN);
-               ip6->proto = fdir_input->flow.ipv6_flow.proto ?
-                       fdir_input->flow.ipv6_flow.proto :
-                       next_proto[fdir_input->pctype];
-               ip6->hop_limits = fdir_input->flow.ipv6_flow.hop_limits ?
-                       fdir_input->flow.ipv6_flow.hop_limits :
+                       ip6->hop_limits =
                        I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS;
+                       if (fdir_input->flow_ext.tunnel_val != VXLAN) {
+                               if (fdir_input->flow_ext.iip_type ==
+                               I40E_FDIR_IPTYPE_IPV4) {
+                                       ip6->proto =
+                       fdir_input->flow.mplsudp6_flow.inner6_udp.ip.proto;
+                                       rte_memcpy(&ip6->src_addr,
+       &fdir_input->flow.mplsudp6_flow.inner6_udp.ip.dst_ip, IPV6_ADDR_LEN);
+                                       rte_memcpy(&ip6->dst_addr,
+       &fdir_input->flow.mplsudp6_flow.inner6_udp.ip.src_ip, IPV6_ADDR_LEN);
+                               } else {
+                                       ip6->proto =
+                       fdir_input->flow.mpls6udp6_flow.inner6_udp.ip.proto;
+                                       rte_memcpy(&ip6->src_addr,
+       &fdir_input->flow.mpls6udp6_flow.inner6_udp.ip.dst_ip, IPV6_ADDR_LEN);
+                                       rte_memcpy(&ip6->dst_addr,
+       &fdir_input->flow.mpls6udp6_flow.inner6_udp.ip.src_ip, IPV6_ADDR_LEN);
+                               }
+                       } else {
+                               if (fdir_input->flow_ext.iip_type ==
+                               I40E_FDIR_IPTYPE_IPV4) {
+                                       ip6->proto =
+                       fdir_input->flow.vxlanudp6_flow.inner6_udp.ip.proto;
+                                       rte_memcpy(&ip6->src_addr,
+       &fdir_input->flow.vxlanudp6_flow.inner6_udp.ip.dst_ip, IPV6_ADDR_LEN);
+                                       rte_memcpy(&ip6->dst_addr,
+       &fdir_input->flow.vxlanudp6_flow.inner6_udp.ip.src_ip, IPV6_ADDR_LEN);
+                               } else {
+                                       ip6->proto =
+                       fdir_input->flow.vxlan6udp6_flow.inner6_udp.ip.proto;
+                                       rte_memcpy(&ip6->src_addr,
+       &fdir_input->flow.vxlan6udp6_flow.inner6_udp.ip.dst_ip, IPV6_ADDR_LEN);
+                                       rte_memcpy(&ip6->dst_addr,
+       &fdir_input->flow.vxlan6udp6_flow.inner6_udp.ip.src_ip, IPV6_ADDR_LEN);
+                               }
+                       }
+                       len += sizeof(struct ipv6_hdr);
+               } else {
+                       ip6->vtc_flow =
+                       rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW |
+                        (fdir_input->flow.ipv6_flow.tc <<
+                         I40E_FDIR_IPv6_TC_OFFSET));
+                       ip6->payload_len =
+                       rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN);
+                       ip6->proto = fdir_input->flow.ipv6_flow.proto ?
+                                       fdir_input->flow.ipv6_flow.proto :
+                                       next_proto[fdir_input->pctype];
+                       ip6->hop_limits =
+                                       fdir_input->flow.ipv6_flow.hop_limits ?
+                                       fdir_input->flow.ipv6_flow.hop_limits :
+                                       I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS;
                /**
                 * The source and destination fields in the transmitted packet
                 * need to be presented in a reversed order with respect
                 * to the expected received packets.
                 */
-               rte_memcpy(&ip6->src_addr,
-                          &fdir_input->flow.ipv6_flow.dst_ip,
-                          IPV6_ADDR_LEN);
-               rte_memcpy(&ip6->dst_addr,
-                          &fdir_input->flow.ipv6_flow.src_ip,
-                          IPV6_ADDR_LEN);
-               len += sizeof(struct ipv6_hdr);
+                       rte_memcpy(&ip6->src_addr,
+                          &fdir_input->flow.ipv6_flow.dst_ip, IPV6_ADDR_LEN);
+                       rte_memcpy(&ip6->dst_addr,
+                         &fdir_input->flow.ipv6_flow.src_ip, IPV6_ADDR_LEN);
+                       len += sizeof(struct ipv6_hdr);
+               }
        } else {
                PMD_DRV_LOG(ERR, "unknown pctype %u.",
                            fdir_input->pctype);
@@ -1097,7 +1339,7 @@ i40e_flow_fdir_construct_pkt(struct i40e_pf *pf,
        struct ipv6_hdr *gtp_ipv6;
        uint8_t size, dst = 0;
        uint8_t i, pit_idx, set_idx = I40E_FLXPLD_L4_IDX; /* use l4 by default*/
-       int len;
+       int len, outer_len = 0;
        uint8_t pctype = fdir_input->pctype;
        struct i40e_customized_pctype *cus_pctype;
 
@@ -1108,9 +1350,14 @@ i40e_flow_fdir_construct_pkt(struct i40e_pf *pf,
                return 0;
        }
 
+       //add outer header info to raw pkt, if tunnel flow
+       if (fdir_input->flow_ext.tunnel)
+               outer_len = i40e_flow_fdir_fill_outer_header(fdir_input, 
raw_pkt);
+
        /* fill the ethernet and IP head */
        len = i40e_flow_fdir_fill_eth_ip_head(pf, fdir_input, raw_pkt,
-                                             !!fdir_input->flow_ext.vlan_tci);
+                                             !!fdir_input->flow_ext.vlan_tci,
+                                               outer_len);
        if (len < 0)
                return -EINVAL;
 
@@ -1123,9 +1370,46 @@ i40e_flow_fdir_construct_pkt(struct i40e_pf *pf,
                 * need to be presented in a reversed order with respect
                 * to the expected received packets.
                 */
-               udp->src_port = fdir_input->flow.udp4_flow.dst_port;
-               udp->dst_port = fdir_input->flow.udp4_flow.src_port;
-               udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN);
+               if (fdir_input->flow_ext.tunnel_val != VXLAN) {
+                       if (fdir_input->flow_ext.iip_type ==
+                       I40E_FDIR_IPTYPE_IPV4) {
+                               udp->src_port =
+                       fdir_input->flow.mplsudp4_flow.inner_udp.dst_port;
+                               udp->dst_port =
+                       fdir_input->flow.mplsudp4_flow.inner_udp.src_port;
+                               udp->dgram_len =
+                       rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER);
+                       } else {
+                               udp->src_port =
+                       fdir_input->flow.mpls6udp4_flow.inner_udp.dst_port;
+                               udp->dst_port =
+                       fdir_input->flow.mpls6udp4_flow.inner_udp.src_port;
+                               udp->dgram_len =
+                       rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER);
+                       }
+               } else if (fdir_input->flow_ext.tunnel_val == VXLAN) {
+                       if (fdir_input->flow_ext.iip_type ==
+                       I40E_FDIR_IPTYPE_IPV4) {
+                               udp->src_port =
+                       fdir_input->flow.vxlanudp4_flow.inner_udp.dst_port;
+                               udp->dst_port =
+                       fdir_input->flow.vxlanudp4_flow.inner_udp.src_port;
+                               udp->dgram_len =
+                       rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER);
+                       } else {
+                               udp->src_port =
+                       fdir_input->flow.vxlan6udp4_flow.inner_udp.dst_port;
+                               udp->dst_port =
+                       fdir_input->flow.vxlan6udp4_flow.inner_udp.src_port;
+                               udp->dgram_len =
+                       rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER);
+                       }
+               } else {
+                       udp->src_port = fdir_input->flow.udp4_flow.dst_port;
+                       udp->dst_port = fdir_input->flow.udp4_flow.src_port;
+                       udp->dgram_len =
+                               rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN);
+               }
        } else if (pctype == I40E_FILTER_PCTYPE_NONF_IPV4_TCP) {
                tcp = (struct tcp_hdr *)(raw_pkt + len);
                payload = (unsigned char *)tcp + sizeof(struct tcp_hdr);
@@ -1160,9 +1444,46 @@ i40e_flow_fdir_construct_pkt(struct i40e_pf *pf,
                 * need to be presented in a reversed order with respect
                 * to the expected received packets.
                 */
-               udp->src_port = fdir_input->flow.udp6_flow.dst_port;
-               udp->dst_port = fdir_input->flow.udp6_flow.src_port;
-               udp->dgram_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN);
+               if (fdir_input->flow_ext.tunnel_val != VXLAN) {
+                       if (fdir_input->flow_ext.iip_type ==
+                       I40E_FDIR_IPTYPE_IPV4) {
+                               udp->src_port =
+                       fdir_input->flow.mplsudp6_flow.inner6_udp.dst_port;
+                               udp->dst_port =
+                       fdir_input->flow.mplsudp6_flow.inner6_udp.src_port;
+                               udp->dgram_len =
+                       rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER);
+                       } else {
+                               udp->src_port =
+                       fdir_input->flow.mpls6udp6_flow.inner6_udp.dst_port;
+                               udp->dst_port =
+                       fdir_input->flow.mpls6udp6_flow.inner6_udp.src_port;
+                               udp->dgram_len =
+                       rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER);
+                       }
+               } else if (fdir_input->flow_ext.tunnel_val == VXLAN) {
+                       if (fdir_input->flow_ext.iip_type ==
+                       I40E_FDIR_IPTYPE_IPV4) {
+                               udp->src_port =
+                       fdir_input->flow.vxlanudp6_flow.inner6_udp.dst_port;
+                               udp->dst_port =
+                       fdir_input->flow.vxlanudp6_flow.inner6_udp.src_port;
+                               udp->dgram_len =
+                       rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER);
+                       } else {
+                               udp->src_port =
+                       fdir_input->flow.vxlan6udp6_flow.inner6_udp.dst_port;
+                               udp->dst_port =
+                       fdir_input->flow.vxlan6udp6_flow.inner6_udp.src_port;
+                               udp->dgram_len =
+                       rte_cpu_to_be_16(I40E_FDIR_UDP_DEFAULT_LEN_INNER);
+                       }
+               } else {
+                       udp->src_port = fdir_input->flow.udp6_flow.dst_port;
+                       udp->dst_port = fdir_input->flow.udp6_flow.src_port;
+                       udp->dgram_len =
+                               rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN);
+               }
        } else if (pctype == I40E_FILTER_PCTYPE_NONF_IPV6_TCP) {
                tcp = (struct tcp_hdr *)(raw_pkt + len);
                payload = (unsigned char *)tcp + sizeof(struct tcp_hdr);
@@ -1265,6 +1586,7 @@ i40e_flow_fdir_construct_pkt(struct i40e_pf *pf,
                                payload = (unsigned char *)gtp +
                                        sizeof(struct rte_flow_item_gtp);
                }
+
        } else {
                PMD_DRV_LOG(ERR, "unknown pctype %u.",
                            fdir_input->pctype);
@@ -1564,7 +1886,7 @@ i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev,
                pctype = filter->input.pctype;
        }
 
-       /* Check if there is the filter in SW list */
+               /* Check if there is the filter in SW list */
        memset(&check_filter, 0, sizeof(check_filter));
        i40e_fdir_filter_convert(filter, &check_filter);
        node = i40e_sw_fdir_filter_lookup(fdir_info, &check_filter.fdir.input);
diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c
index 3694df2..5b979ca 100644
--- a/drivers/net/i40e/i40e_flow.c
+++ b/drivers/net/i40e/i40e_flow.c
@@ -80,6 +80,12 @@ static int i40e_flow_parse_fdir_filter(struct rte_eth_dev 
*dev,
                                       const struct rte_flow_action actions[],
                                       struct rte_flow_error *error,
                                       union i40e_filter_t *filter);
+static int i40e_flow_parse_fdir_tunnel_filter(struct rte_eth_dev *dev,
+                                             const struct rte_flow_attr *attr,
+                                             const struct rte_flow_item 
pattern[],
+                                             const struct rte_flow_action 
actions[],
+                                             struct rte_flow_error *error,
+                                             union i40e_filter_t *filter);
 static int i40e_flow_parse_vxlan_filter(struct rte_eth_dev *dev,
                                        const struct rte_flow_attr *attr,
                                        const struct rte_flow_item pattern[],
@@ -136,6 +142,8 @@ const struct rte_flow_ops i40e_flow_ops = {
 static union i40e_filter_t cons_filter;
 static enum rte_filter_type cons_filter_type = RTE_ETH_FILTER_NONE;
 
+#define TUNNEL_FDIR_FUNCTION i40e_flow_parse_fdir_tunnel_filter
+
 /* Pattern matched ethertype filter */
 static enum rte_flow_item_type pattern_ethertype[] = {
        RTE_FLOW_ITEM_TYPE_ETH,
@@ -1543,6 +1551,50 @@ static enum rte_flow_item_type pattern_vxlan_4[] = {
        RTE_FLOW_ITEM_TYPE_END,
 };
 
+static enum rte_flow_item_type pattern_vxlan_5[] = { //IPv4+IPv4
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_VXLAN,
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_vxlan_6[] = { //IPv4+IPv6
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_VXLAN,
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_vxlan_7[] = { //IPv6+IPv4
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_VXLAN,
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_vxlan_8[] = { //IPv6+IPv6
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_VXLAN,
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+
 static enum rte_flow_item_type pattern_nvgre_1[] = {
        RTE_FLOW_ITEM_TYPE_ETH,
        RTE_FLOW_ITEM_TYPE_IPV4,
@@ -1609,6 +1661,96 @@ static enum rte_flow_item_type pattern_mpls_4[] = {
        RTE_FLOW_ITEM_TYPE_END,
 };
 
+//adding only for IPv4. adding MPLS flow match for inner packet
+
+static enum rte_flow_item_type pattern_mpls_5[] = { //IPv4+IPv4
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_MPLS,
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_mpls_6[] = { //IPv4 +IPv6
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_MPLS,
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_mpls_7[] = { //IPv6+IPv4
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_MPLS,
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_mpls_8[] = { //IPv6+IPv6
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_MPLS,
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_mpls_9[] = { //IPv4+IPv4
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_GRE,
+       RTE_FLOW_ITEM_TYPE_MPLS,
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_mpls_10[] = { //IPv4+IPv6
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_GRE,
+       RTE_FLOW_ITEM_TYPE_MPLS,
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_mpls_11[] = { //IPv6+IPv4
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_GRE,
+       RTE_FLOW_ITEM_TYPE_MPLS,
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+
+static enum rte_flow_item_type pattern_mpls_12[] = { //IPv6+IPv6
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_GRE,
+       RTE_FLOW_ITEM_TYPE_MPLS,
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+
 static enum rte_flow_item_type pattern_qinq_1[] = {
        RTE_FLOW_ITEM_TYPE_ETH,
        RTE_FLOW_ITEM_TYPE_VLAN,
@@ -1779,6 +1921,11 @@ static struct i40e_valid_pattern 
i40e_supported_patterns[] = {
        { pattern_vxlan_2, i40e_flow_parse_vxlan_filter },
        { pattern_vxlan_3, i40e_flow_parse_vxlan_filter },
        { pattern_vxlan_4, i40e_flow_parse_vxlan_filter },
+       /*VXLAN with inner header */
+       { pattern_vxlan_5, i40e_flow_parse_fdir_tunnel_filter },
+       { pattern_vxlan_6, i40e_flow_parse_fdir_tunnel_filter },
+       { pattern_vxlan_7, i40e_flow_parse_fdir_tunnel_filter },
+       { pattern_vxlan_8, i40e_flow_parse_fdir_tunnel_filter },
        /* NVGRE */
        { pattern_nvgre_1, i40e_flow_parse_nvgre_filter },
        { pattern_nvgre_2, i40e_flow_parse_nvgre_filter },
@@ -1789,6 +1936,15 @@ static struct i40e_valid_pattern 
i40e_supported_patterns[] = {
        { pattern_mpls_2, i40e_flow_parse_mpls_filter },
        { pattern_mpls_3, i40e_flow_parse_mpls_filter },
        { pattern_mpls_4, i40e_flow_parse_mpls_filter },
+       /* MPLS patterns with inner header */
+       { pattern_mpls_5, i40e_flow_parse_fdir_tunnel_filter },
+       { pattern_mpls_6, i40e_flow_parse_fdir_tunnel_filter },
+       { pattern_mpls_7, i40e_flow_parse_fdir_tunnel_filter },
+       { pattern_mpls_8, i40e_flow_parse_fdir_tunnel_filter },
+       { pattern_mpls_9, i40e_flow_parse_fdir_tunnel_filter },
+       { pattern_mpls_10, i40e_flow_parse_fdir_tunnel_filter },
+       { pattern_mpls_11, i40e_flow_parse_fdir_tunnel_filter },
+       { pattern_mpls_12, i40e_flow_parse_fdir_tunnel_filter },
        /* GTP-C & GTP-U */
        { pattern_fdir_ipv4_gtpc, i40e_flow_parse_gtp_filter },
        { pattern_fdir_ipv4_gtpu, i40e_flow_parse_gtp_filter },
@@ -2408,6 +2564,558 @@ i40e_flow_fdir_get_pctype_value(struct i40e_pf *pf,
        return I40E_FILTER_PCTYPE_INVALID;
 }
 
+
+static int
+i40e_flow_parse_fdir_tunnel_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_ipv4 *ipv4_spec, *ipv4_mask;
+       const struct rte_flow_item_mpls *mpls_spec, *mpls_mask;
+       const struct rte_flow_item_vxlan *vxlan_spec, *vxlan_mask;
+       const struct rte_flow_item_ipv6 *ipv6_spec, *ipv6_mask;
+       const struct rte_flow_item_udp *udp_spec, *udp_mask;
+       const struct rte_flow_item_gre *gre_spec, *gre_mask;
+       uint8_t pctype = 0;
+       uint64_t input_set = I40E_INSET_NONE;
+       enum rte_flow_item_type item_type;
+       enum rte_flow_item_type l3 = RTE_FLOW_ITEM_TYPE_END;
+       uint16_t frag_off;
+       bool outer_ip = true;
+       bool outer_udp = true;
+       int ret;
+       uint8_t  ipv6_addr_mask[16] = {
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+       uint8_t label_mask[3] = {0xFF, 0xFF, 0xF0};
+       uint8_t vni_mask[] = {0xFF, 0xFF, 0xFF};
+
+       filter->input.flow_ext.customized_pctype = false;
+       for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
+               if (item->last) {
+                       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;
+
+                       if (eth_spec && eth_mask) {
+                               if (!is_zero_ether_addr(&eth_mask->src) ||
+                                   !is_zero_ether_addr(&eth_mask->dst)) {
+                                       rte_flow_error_set(error, EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_ITEM,
+                                               item,
+                                               "Invalid MAC_addr mask.");
+                                       return -rte_errno;
+                               }
+                       }
+                       pctype = I40E_FILTER_PCTYPE_L2_PAYLOAD;
+                       break;
+
+               case RTE_FLOW_ITEM_TYPE_IPV4:
+                       l3 = RTE_FLOW_ITEM_TYPE_IPV4;
+                       ipv4_spec = item->spec;
+                       ipv4_mask = item->mask;
+
+                       if (ipv4_spec && ipv4_mask && outer_ip) {
+                               /* Check IPv4 mask and update input set */
+                               //for outer, we can take only dst IP
+
+                               if (ipv4_mask->hdr.version_ihl ||
+                                   ipv4_mask->hdr.total_length ||
+                                   ipv4_mask->hdr.packet_id ||
+                                   ipv4_mask->hdr.fragment_offset ||
+                                   ipv4_mask->hdr.src_addr ||
+                                   ipv4_mask->hdr.type_of_service ||
+                                   ipv4_mask->hdr.time_to_live ||
+                                   ipv4_mask->hdr.next_proto_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.dst_addr == UINT32_MAX)
+                                       input_set |= I40E_INSET_TUNNEL_IPV4_DST;
+
+                               
filter->input.flow.mplsudp4_flow.outer_udp.ip.dst_ip =
+                                       ipv4_spec->hdr.dst_addr;
+                               filter->input.flow_ext.iip_type =
+                                       I40E_FDIR_IPTYPE_IPV4;
+                       } else if (!ipv4_spec && !ipv4_mask && !outer_ip) {
+                                //no spec and mask for Inner IP
+                               rte_flow_error_set(error, EINVAL,
+                                                  RTE_FLOW_ERROR_TYPE_ITEM,
+                                                  item,
+                                                  "Invalid inner IPv4 mask.");
+                               return -rte_errno;
+
+                       } else if ((ipv4_spec || ipv4_mask) && !outer_ip) {
+                       //spec and mask for inner IP, set pctype and input_set
+                               pctype = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
+
+                               if (ipv4_mask->hdr.version_ihl ||
+                                   ipv4_mask->hdr.total_length ||
+                                   ipv4_mask->hdr.packet_id ||
+                                   ipv4_mask->hdr.fragment_offset ||
+                                   ipv4_mask->hdr.type_of_service ||
+                                   ipv4_mask->hdr.time_to_live ||
+                                   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.next_proto_id == UINT8_MAX)
+                                       input_set |= I40E_INSET_IPV4_PROTO;
+
+                                       /* Check if it is fragment. */
+                               frag_off = ipv4_spec->hdr.fragment_offset;
+                               frag_off = rte_be_to_cpu_16(frag_off);
+                               if (frag_off & IPV4_HDR_OFFSET_MASK ||
+                                   frag_off & IPV4_HDR_MF_FLAG)
+                                       pctype = I40E_FILTER_PCTYPE_FRAG_IPV4;
+
+                               if (filter->input.flow_ext.iip_type ==
+                                       I40E_FDIR_IPTYPE_IPV4 &&
+                               filter->input.flow_ext.tunnel_val != VXLAN) {
+                               //MPLS with outerIPv4
+                                       
filter->input.flow.mplsudp4_flow.inner_udp.ip.dst_ip =
+                                               ipv4_spec->hdr.dst_addr;
+                                       
filter->input.flow.mplsudp4_flow.inner_udp.ip.src_ip =
+                                               ipv4_spec->hdr.src_addr;
+                                       
filter->input.flow.mplsudp4_flow.inner_udp.ip.proto =
+                                               ipv4_spec->hdr.next_proto_id;
+                               } else if (filter->input.flow_ext.iip_type ==
+                                               I40E_FDIR_IPTYPE_IPV6 &&
+                               filter->input.flow_ext.tunnel_val != VXLAN) {
+                               // MPLS with outer IPv6
+                                       
filter->input.flow.mpls6udp4_flow.inner_udp.ip.dst_ip =
+                                               ipv4_spec->hdr.dst_addr;
+                                       
filter->input.flow.mpls6udp4_flow.inner_udp.ip.src_ip =
+                                               ipv4_spec->hdr.src_addr;
+                                       
filter->input.flow.mpls6udp4_flow.inner_udp.ip.proto =
+                                               ipv4_spec->hdr.next_proto_id;
+                               } else if (filter->input.flow_ext.iip_type ==
+                                               I40E_FDIR_IPTYPE_IPV4 &&
+                               filter->input.flow_ext.tunnel_val == VXLAN) {
+                                //VXLAN with outer IPv4
+                                       
filter->input.flow.vxlanudp4_flow.inner_udp.ip.dst_ip =
+                                               ipv4_spec->hdr.dst_addr;
+                                       
filter->input.flow.vxlanudp4_flow.inner_udp.ip.src_ip =
+                                               ipv4_spec->hdr.src_addr;
+                                       
filter->input.flow.vxlanudp4_flow.inner_udp.ip.proto =
+                                               ipv4_spec->hdr.next_proto_id;
+                               } else {
+                               // VXLAN with outer IPv6
+                                       
filter->input.flow.vxlan6udp4_flow.inner_udp.ip.dst_ip =
+                                               ipv4_spec->hdr.dst_addr;
+                                       
filter->input.flow.vxlan6udp4_flow.inner_udp.ip.src_ip =
+                                               ipv4_spec->hdr.src_addr;
+                                       
filter->input.flow.vxlan6udp4_flow.inner_udp.ip.proto =
+                                               ipv4_spec->hdr.next_proto_id;
+                               }
+                       }
+
+                       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;
+
+                       if (ipv6_spec && ipv6_mask && outer_ip) {
+               /* Check IPv6 mask and update input set, we take only dst IP */
+                               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.dst_addr,
+                                           ipv6_addr_mask,
+                                           RTE_DIM(ipv6_mask->hdr.dst_addr)))
+                                       input_set |= I40E_INSET_TUNNEL_IPV6_DST;
+
+                               /* Get filter info */
+
+                               
filter->input.flow.mpls6udp4_flow.outer6_udp.ip.proto =
+                                                       ipv6_spec->hdr.proto;
+                               
rte_memcpy(filter->input.flow.mpls6udp4_flow.outer6_udp.ip.dst_ip,
+                                               ipv6_spec->hdr.dst_addr, 16);
+                               filter->input.flow_ext.iip_type =
+                                               I40E_FDIR_IPTYPE_IPV6;
+
+                       } else if (!ipv6_spec && !ipv6_mask && !outer_ip) {
+                       //no spec,mask for inner IPv6
+                               rte_flow_error_set(error, EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_ITEM,
+                                                       item,
+                                               "Invalid inner IPv6 mask.");
+                               return -rte_errno;
+                       } else if ((ipv6_spec || ipv6_mask) && !outer_ip) {
+                       //spec,mask mentioned for inner IPv6
+                               pctype = I40E_FILTER_PCTYPE_NONF_IPV6_OTHER;
+                               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,
+                                           RTE_DIM(ipv6_mask->hdr.src_addr)))
+                                       input_set |= I40E_INSET_IPV6_SRC;
+                               if (!memcmp(ipv6_mask->hdr.dst_addr,
+                                           ipv6_addr_mask,
+                                           RTE_DIM(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 */
+                               if (filter->input.flow_ext.iip_type ==
+                                       I40E_FDIR_IPTYPE_IPV4 &&
+                               filter->input.flow_ext.tunnel_val != VXLAN) {
+                                       
filter->input.flow.mplsudp6_flow.inner6_udp.ip.proto =
+                                               ipv6_spec->hdr.proto;
+                                       
rte_memcpy(filter->input.flow.mplsudp6_flow.inner6_udp.ip.src_ip,
+                                               ipv6_spec->hdr.src_addr, 16);
+                                       
rte_memcpy(filter->input.flow.mplsudp6_flow.inner6_udp.ip.dst_ip,
+                                               ipv6_spec->hdr.dst_addr, 16);
+
+                               } else if (filter->input.flow_ext.iip_type ==
+                                       I40E_FDIR_IPTYPE_IPV6 &&
+                               filter->input.flow_ext.tunnel_val != VXLAN) {
+                                       
filter->input.flow.mpls6udp6_flow.inner6_udp.ip.proto =
+                                                       ipv6_spec->hdr.proto;
+                                       
rte_memcpy(filter->input.flow.mpls6udp6_flow.inner6_udp.ip.src_ip,
+                                               ipv6_spec->hdr.src_addr, 16);
+                                       
rte_memcpy(filter->input.flow.mpls6udp6_flow.inner6_udp.ip.dst_ip,
+                                               ipv6_spec->hdr.dst_addr, 16);
+
+                               } else if (filter->input.flow_ext.iip_type ==
+                                               I40E_FDIR_IPTYPE_IPV4 &&
+                               filter->input.flow_ext.tunnel_val == VXLAN) {
+                                       
filter->input.flow.vxlanudp6_flow.inner6_udp.ip.proto =
+                                               ipv6_spec->hdr.proto;
+                                       
rte_memcpy(filter->input.flow.vxlanudp6_flow.inner6_udp.ip.src_ip,
+                                               ipv6_spec->hdr.src_addr, 16);
+                                       
rte_memcpy(filter->input.flow.vxlanudp6_flow.inner6_udp.ip.dst_ip,
+                                               ipv6_spec->hdr.dst_addr, 16);
+
+                               } else {
+                                       
filter->input.flow.vxlan6udp6_flow.inner6_udp.ip.proto =
+                                               ipv6_spec->hdr.proto;
+                                       
rte_memcpy(filter->input.flow.vxlan6udp6_flow.inner6_udp.ip.src_ip,
+                                               ipv6_spec->hdr.src_addr, 16);
+                                       
rte_memcpy(filter->input.flow.vxlan6udp6_flow.inner6_udp.ip.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;
+                       }
+
+                       if (outer_ip)
+                               outer_ip = false;
+                       break;
+
+               case RTE_FLOW_ITEM_TYPE_GRE:
+                       gre_spec = item->spec;
+                       gre_mask = item->mask;
+                       if (gre_spec && gre_mask) {
+                               if (gre_mask->c_rsvd0_ver) {
+                                       rte_flow_error_set(error, EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_ITEM,
+                                               item,
+                                               "Invalid GRE mask");
+                                       return -rte_errno;
+                               }
+
+                               if (gre_mask->protocol == UINT16_MAX)
+                                       input_set |=
+                                       I40E_INSET_TUNNEL_DST_PORT;
+
+
+                               if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
+                                       
filter->input.flow.mplsgre4_flow.outer_gre.gre.protocol =
+                                               gre_spec->protocol;
+                               } else {
+                                       
filter->input.flow.mpls6gre4_flow.outer6_gre.gre.protocol =
+                                               gre_spec->protocol;
+                               }
+                       } else {
+                               rte_flow_error_set(error, EINVAL,
+                                                  RTE_FLOW_ERROR_TYPE_ITEM,
+                                                  item,
+                                                  "Invalid GRE mask");
+                               return -rte_errno;
+                       }
+                       outer_udp = false;
+                       filter->input.flow_ext.tunnel_val = MPLSOGRE;
+                       break;
+
+               case RTE_FLOW_ITEM_TYPE_UDP:
+                       udp_spec = item->spec;
+                       udp_mask = item->mask;
+
+                       if (udp_spec && udp_mask && outer_udp) {
+                               /* Check UDP mask and update input set */
+                               //for outer, we can take only dst port
+
+                               if (udp_mask->hdr.dgram_len ||
+                                       udp_mask->hdr.src_port ||
+                                       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.dst_port == UINT16_MAX)
+                                       input_set |= I40E_INSET_TUNNEL_DST_PORT;
+
+                               if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
+                               //outer UDP for outer IPv4
+                                       
filter->input.flow.mplsudp4_flow.outer_udp.dst_port =
+                                                       udp_spec->hdr.dst_port;
+                               } else {
+                                       
filter->input.flow.mpls6udp4_flow.outer6_udp.dst_port =
+                                                       udp_spec->hdr.dst_port;
+                               }
+                       } else if (!udp_spec && !udp_mask && !outer_udp) {
+                       //no spec and mask for Inner UDP
+                               rte_flow_error_set(error, EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_ITEM,
+                                               item,
+                                               "Invalid inner IPv4 mask.");
+                               return -rte_errno;
+
+                       } else if ((udp_spec || udp_mask) && !outer_udp) {
+                               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;
+                               /* Check UDP mask and update input set */
+                               //for inner, we can take dst port and src port
+
+                               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 (filter->input.flow_ext.tunnel_val !=
+                                               VXLAN) {
+                                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV4 &&
+                                       filter->input.flow_ext.iip_type ==
+                                       I40E_FDIR_IPTYPE_IPV4) {//both ipv4
+                                               
filter->input.flow.mplsudp4_flow.inner_udp.dst_port =
+                                                       udp_spec->hdr.dst_port;
+                                               
filter->input.flow.mplsudp4_flow.inner_udp.src_port =
+                                                       udp_spec->hdr.src_port;
+                                       } else if (l3 == 
RTE_FLOW_ITEM_TYPE_IPV4 &&
+                                       filter->input.flow_ext.iip_type ==
+                                               I40E_FDIR_IPTYPE_IPV6) {
+                                               
filter->input.flow.mpls6udp4_flow.inner_udp.dst_port =
+                                                       udp_spec->hdr.dst_port;
+                                               
filter->input.flow.mpls6udp4_flow.inner_udp.src_port =
+                                                       udp_spec->hdr.src_port;
+                                       } else if (l3 == 
RTE_FLOW_ITEM_TYPE_IPV6 &&
+                                       filter->input.flow_ext.iip_type ==
+                                               I40E_FDIR_IPTYPE_IPV4) {
+                                               
filter->input.flow.mplsudp6_flow.inner6_udp.dst_port =
+                                                       udp_spec->hdr.dst_port;
+                                               
filter->input.flow.mplsudp6_flow.inner6_udp.src_port =
+                                                       udp_spec->hdr.src_port;
+                                       } else {//both IPv6
+                                               
filter->input.flow.mpls6udp6_flow.inner6_udp.dst_port =
+                                                       udp_spec->hdr.dst_port;
+                                               
filter->input.flow.mpls6udp6_flow.inner6_udp.src_port =
+                                                       udp_spec->hdr.src_port;
+                                       }
+                               } else {
+                                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV4 &&
+                                       filter->input.flow_ext.iip_type ==
+                                       I40E_FDIR_IPTYPE_IPV4) {//both v4
+                                               
filter->input.flow.vxlanudp4_flow.inner_udp.dst_port =
+                                                       udp_spec->hdr.dst_port;
+                                               
filter->input.flow.vxlanudp4_flow.inner_udp.src_port =
+                                                       udp_spec->hdr.src_port;
+                                       } else if (l3 == 
RTE_FLOW_ITEM_TYPE_IPV4 &&
+                                       filter->input.flow_ext.iip_type ==
+                                       I40E_FDIR_IPTYPE_IPV6) 
{//innerv4,outerv6
+                                               
filter->input.flow.vxlan6udp4_flow.inner_udp.dst_port =
+                                                       udp_spec->hdr.dst_port;
+                                               
filter->input.flow.vxlan6udp4_flow.inner_udp.src_port =
+                                                       udp_spec->hdr.src_port;
+                                       } else if (l3 == 
RTE_FLOW_ITEM_TYPE_IPV6 &&
+                                       filter->input.flow_ext.iip_type ==
+                                       I40E_FDIR_IPTYPE_IPV4) 
{//outerv4,innerv6
+                                               
filter->input.flow.vxlanudp6_flow.inner6_udp.dst_port =
+                                                       udp_spec->hdr.dst_port;
+                                               
filter->input.flow.vxlanudp6_flow.inner6_udp.src_port =
+                                                       udp_spec->hdr.src_port;
+                                       } else { //both IPv6
+                                               
filter->input.flow.vxlan6udp6_flow.inner6_udp.dst_port =
+                                                       udp_spec->hdr.dst_port;
+                                               
filter->input.flow.vxlan6udp6_flow.inner6_udp.src_port =
+                                                       udp_spec->hdr.src_port;
+                                       }
+                               }
+                       }
+                       if (outer_udp)
+                               outer_udp = false;
+                       break;
+               case RTE_FLOW_ITEM_TYPE_MPLS:
+                       mpls_spec = item->spec;
+                       mpls_mask = item->mask;
+                       if (mpls_spec && mpls_mask) {
+                               if (memcmp(mpls_mask->label_tc_s,
+                                       label_mask, 3)) {
+                                       rte_flow_error_set(error, EINVAL,
+                                                  RTE_FLOW_ERROR_TYPE_ITEM,
+                                                  item,
+                                                  "Invalid MPLS label mask");
+                                       return -rte_errno;
+                               } else {
+                                       input_set |= I40E_INSET_TUNNEL_ID;
+                               }
+                               if (filter->input.flow_ext.iip_type ==
+                                               I40E_FDIR_IPTYPE_IPV4) {
+                                       
filter->input.flow.mplsudp4_flow.mpls.label_tc_s[0] =
+                                               mpls_spec->label_tc_s[0];
+                                       
filter->input.flow.mplsudp4_flow.mpls.label_tc_s[1] =
+                                               mpls_spec->label_tc_s[1];
+                                       
filter->input.flow.mplsudp4_flow.mpls.label_tc_s[2] =
+                                               mpls_spec->label_tc_s[2];
+
+                               } else {
+                                       
filter->input.flow.mpls6udp4_flow.mpls.label_tc_s[0] =
+                                               mpls_spec->label_tc_s[0];
+                                       
filter->input.flow.mpls6udp4_flow.mpls.label_tc_s[1] =
+                                               mpls_spec->label_tc_s[1];
+                                       
filter->input.flow.mpls6udp4_flow.mpls.label_tc_s[2] =
+                                               mpls_spec->label_tc_s[2];
+                               }
+                       }
+                       filter->input.flow_ext.tunnel = true;
+                       if (filter->input.flow_ext.tunnel_val !=
+                               MPLSOGRE) //it has not been set by GRE header
+                               filter->input.flow_ext.tunnel_val = MPLSOUDP;
+                       break;
+               case RTE_FLOW_ITEM_TYPE_VXLAN:
+                       vxlan_spec = item->spec;
+                       vxlan_mask = item->mask;
+                       /* Check if VXLAN item is used to describe protocol.
+                        * If yes, both spec and mask should be NULL.
+                        * If no, both spec and mask shouldn't be NULL.
+                        */
+                       if ((!vxlan_spec && !vxlan_mask)) {
+                               rte_flow_error_set(error, EINVAL,
+                                                  RTE_FLOW_ERROR_TYPE_ITEM,
+                                                  item,
+                                                  "Invalid VXLAN item");
+                               return -rte_errno;
+                       }
+
+                       /* Check if VNI is masked. */
+                       if (vxlan_spec && vxlan_mask) {
+                               if (memcmp(vxlan_mask->vni, vni_mask, 3)) {
+                                       rte_flow_error_set(error, EINVAL,
+                                                  RTE_FLOW_ERROR_TYPE_ITEM,
+                                                  item,
+                                                  "Invalid VXLAN mask");
+                                       return -rte_errno;
+                               } else {
+                                       input_set |= I40E_INSET_TUNNEL_ID;
+                               }
+
+                               if (filter->input.flow_ext.iip_type ==
+                                       I40E_FDIR_IPTYPE_IPV4) {
+                                       
filter->input.flow.vxlanudp4_flow.vxlan.vni[0] =
+                                                       vxlan_spec->vni[0];
+                                       
filter->input.flow.vxlanudp4_flow.vxlan.vni[1] =
+                                                       vxlan_spec->vni[1];
+                                       
filter->input.flow.vxlanudp4_flow.vxlan.vni[2] =
+                                                       vxlan_spec->vni[2];
+                               } else {
+                                       
filter->input.flow.vxlan6udp4_flow.vxlan.vni[0] =
+                                                       vxlan_spec->vni[0];
+                                       
filter->input.flow.vxlan6udp4_flow.vxlan.vni[1] =
+                                                       vxlan_spec->vni[1];
+                                       
filter->input.flow.vxlan6udp4_flow.vxlan.vni[2] =
+                                                       vxlan_spec->vni[2];
+                               }
+                       }
+                       filter->input.flow_ext.tunnel = true;
+                       filter->input.flow_ext.tunnel_val = VXLAN;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       /* If customized pctype is not used, set fdir configuration.*/
+               if (!filter->input.flow_ext.customized_pctype) {
+                       ret = i40e_flow_set_fdir_inset(pf, pctype, input_set);
+                       if (ret == -1) {
+                               rte_flow_error_set(error, EINVAL,
+                                          RTE_FLOW_ERROR_TYPE_ITEM, item,
+                          "Conflict with the first rule's input set.");
+                               return -rte_errno;
+                       } else if (ret == -EINVAL) {
+                               rte_flow_error_set(error, EINVAL,
+                                        RTE_FLOW_ERROR_TYPE_ITEM, item,
+                                          "Invalid pattern mask.");
+                               return -rte_errno;
+                       }
+               }
+               filter->input.pctype = pctype;
+       return 0;
+}
+
 /* 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
@@ -3011,7 +3719,7 @@ i40e_flow_parse_fdir_pattern(struct rte_eth_dev *dev,
                                           "Invalid pattern mask.");
                        return -rte_errno;
                }
-
+               filter->input.flow_ext.tunnel = false;
                /* Store flex mask to SW */
                ret = i40e_flow_store_flex_mask(pf, pctype, flex_mask);
                if (ret == -1) {
@@ -3079,6 +3787,9 @@ i40e_flow_parse_fdir_action(struct rte_eth_dev *dev,
        case RTE_FLOW_ACTION_TYPE_PASSTHRU:
                filter->action.behavior = I40E_FDIR_PASSTHRU;
                break;
+       case RTE_FLOW_ACTION_TYPE_RSS:
+               filter->action.behavior = I40E_FDIR_PASSTHRU;
+               break;
        default:
                rte_flow_error_set(error, EINVAL,
                                   RTE_FLOW_ERROR_TYPE_ACTION, act,
@@ -3120,6 +3831,57 @@ i40e_flow_parse_fdir_action(struct rte_eth_dev *dev,
 }
 
 static int
+i40e_flow_parse_fdir_tunnel_filter(struct rte_eth_dev *dev,
+                               const struct rte_flow_attr *attr,
+                               const struct rte_flow_item pattern[],
+                               const struct rte_flow_action actions[],
+                               struct rte_flow_error *error,
+                               union i40e_filter_t *filter)
+{
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct i40e_fdir_filter_conf *fdir_filter =
+                       &filter->fdir_filter;
+       int ret;
+
+       ret = i40e_flow_parse_fdir_tunnel_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;
+
+       ret = i40e_flow_parse_attr(attr, error);
+       if (ret)
+               return ret;
+
+       cons_filter_type = RTE_ETH_FILTER_FDIR;
+
+       if (dev->data->dev_conf.fdir_conf.mode !=
+                       RTE_FDIR_MODE_PERFECT) {
+               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 -rte_errno;
+               }
+               ret = i40e_fdir_configure(dev);
+               if (ret < 0) {
+                       rte_flow_error_set(error, ENOTSUP,
+                                          RTE_FLOW_ERROR_TYPE_HANDLE, NULL, 
"Failed to configure fdir");
+                       goto err;
+               }
+               dev->data->dev_conf.fdir_conf.mode = RTE_FDIR_MODE_PERFECT;
+       }
+       return 0;
+
+err:
+       i40e_fdir_teardown(pf);
+       return -rte_errno;
+}
+
+static int
 i40e_flow_parse_fdir_filter(struct rte_eth_dev *dev,
                            const struct rte_flow_attr *attr,
                            const struct rte_flow_item pattern[],
@@ -4558,6 +5320,7 @@ i40e_flow_validate(struct rte_eth_dev *dev,
        uint32_t item_num = 0; /* non-void item number of pattern*/
        uint32_t i = 0;
        bool flag = false;
+       bool rss = false;
        int ret = I40E_NOT_SUPPORTED;
 
        if (!pattern) {
@@ -4587,9 +5350,7 @@ i40e_flow_validate(struct rte_eth_dev *dev,
                i++;
 
        if ((actions + i)->type == RTE_FLOW_ACTION_TYPE_RSS) {
-               ret = i40e_parse_rss_filter(dev, attr, pattern,
-                                       actions, &cons_filter, error);
-               return ret;
+               rss = true;
        }
 
        i = 0;
@@ -4621,9 +5382,17 @@ i40e_flow_validate(struct rte_eth_dev *dev,
                        rte_free(items);
                        return -rte_errno;
                }
-               if (parse_filter)
-                       ret = parse_filter(dev, attr, items, actions,
+               if (parse_filter) {
+                       if (parse_filter != TUNNEL_FDIR_FUNCTION &&
+                                rss == true) {
+                               ret = i40e_parse_rss_filter(dev, attr, pattern,
+                                               actions, &cons_filter, error);
+                               return ret;
+                       } else {
+                               ret = parse_filter(dev, attr, items, actions,
                                           error, &cons_filter);
+                       }
+               }
                flag = true;
        } while ((ret < 0) && (i < RTE_DIM(i40e_supported_patterns)));
 
-- 
2.7.4

Reply via email to