Implement comprehensive L2TPv2 support for Flow Director
-Flow pattern definitions for different L2TPv2 packet combinations
-FDIR filter parsing logic
-Flow type assignment for proper packet classification

Signed-off-by: Shaiq Wani <[email protected]>
Tested-by: Jiale Song <[email protected]>
---
 drivers/net/intel/ice/ice_fdir_filter.c  | 487 +++++++++++++++++++----
 drivers/net/intel/ice/ice_generic_flow.c | 177 ++++++++
 2 files changed, 587 insertions(+), 77 deletions(-)

diff --git a/drivers/net/intel/ice/ice_fdir_filter.c 
b/drivers/net/intel/ice/ice_fdir_filter.c
index 9dfe5c02cb..79c9dddae6 100644
--- a/drivers/net/intel/ice/ice_fdir_filter.c
+++ b/drivers/net/intel/ice/ice_fdir_filter.c
@@ -107,6 +107,31 @@
        ICE_INSET_IPV6_SRC | ICE_INSET_IPV6_DST | \
        ICE_INSET_NAT_T_ESP_SPI)
 
+#define ICE_FDIR_INSET_L2TPV2 (\
+       ICE_INSET_SMAC | ICE_INSET_DMAC | ICE_INSET_L2TPV2OIP_SESSION_ID)
+
+#define ICE_FDIR_INSET_L2TPV2_PPP_IPV4 (\
+       ICE_INSET_TUN_IPV4_SRC | ICE_INSET_TUN_IPV4_DST)
+
+#define ICE_FDIR_INSET_L2TPV2_PPP_IPV4_UDP (\
+       ICE_FDIR_INSET_L2TPV2_PPP_IPV4 | ICE_INSET_TUN_UDP_SRC_PORT | \
+       ICE_INSET_TUN_UDP_DST_PORT)
+
+#define ICE_FDIR_INSET_L2TPV2_PPP_IPV4_TCP (\
+       ICE_FDIR_INSET_L2TPV2_PPP_IPV4 | ICE_INSET_TUN_TCP_SRC_PORT | \
+       ICE_INSET_TUN_TCP_DST_PORT)
+
+#define ICE_FDIR_INSET_L2TPV2_PPP_IPV6 (\
+       ICE_INSET_TUN_IPV6_SRC | ICE_INSET_TUN_IPV6_DST)
+
+#define ICE_FDIR_INSET_L2TPV2_PPP_IPV6_UDP (\
+       ICE_FDIR_INSET_L2TPV2_PPP_IPV6 | ICE_INSET_TUN_UDP_SRC_PORT | \
+       ICE_INSET_TUN_UDP_DST_PORT)
+
+#define ICE_FDIR_INSET_L2TPV2_PPP_IPV6_TCP (\
+       ICE_FDIR_INSET_L2TPV2_PPP_IPV6 | ICE_INSET_TUN_TCP_SRC_PORT | \
+       ICE_INSET_TUN_TCP_DST_PORT)
+
 static struct ice_pattern_match_item ice_fdir_supported_pattern[] = {
        {pattern_raw,                                   ICE_INSET_NONE,         
        ICE_INSET_NONE,                 ICE_INSET_NONE},
        {pattern_ethertype,                             ICE_FDIR_INSET_ETH,     
        ICE_INSET_NONE,                 ICE_INSET_NONE},
@@ -132,10 +157,26 @@ static struct ice_pattern_match_item 
ice_fdir_supported_pattern[] = {
        {pattern_eth_ipv4_udp_vxlan_eth_ipv4_tcp,       
ICE_FDIR_INSET_ETH_IPV4_VXLAN,  ICE_FDIR_INSET_ETH_IPV4_TCP,    ICE_INSET_NONE},
        {pattern_eth_ipv4_udp_vxlan_eth_ipv4_sctp,      
ICE_FDIR_INSET_ETH_IPV4_VXLAN,  ICE_FDIR_INSET_ETH_IPV4_SCTP,   ICE_INSET_NONE},
        /* duplicated GTPU input set in 3rd column to align with shared code 
behavior. Ideally, only put GTPU field in 2nd column. */
-       {pattern_eth_ipv4_gtpu,                         
ICE_FDIR_INSET_IPV4_GTPU,       ICE_FDIR_INSET_IPV4_GTPU,       ICE_INSET_NONE},
-       {pattern_eth_ipv4_gtpu_eh,                      
ICE_FDIR_INSET_IPV4_GTPU_EH,    ICE_FDIR_INSET_IPV4_GTPU_EH,    ICE_INSET_NONE},
-       {pattern_eth_ipv6_gtpu,                         
ICE_FDIR_INSET_IPV6_GTPU,       ICE_FDIR_INSET_IPV6_GTPU,       ICE_INSET_NONE},
-       {pattern_eth_ipv6_gtpu_eh,                      
ICE_FDIR_INSET_IPV6_GTPU_EH,    ICE_FDIR_INSET_IPV6_GTPU_EH,    ICE_INSET_NONE},
+       {pattern_eth_ipv4_gtpu,                         
ICE_FDIR_INSET_IPV4_GTPU,       ICE_FDIR_INSET_IPV4_GTPU,               
ICE_INSET_NONE},
+       {pattern_eth_ipv4_gtpu_eh,                      
ICE_FDIR_INSET_IPV4_GTPU_EH,    ICE_FDIR_INSET_IPV4_GTPU_EH,            
ICE_INSET_NONE},
+       {pattern_eth_ipv6_gtpu,                         
ICE_FDIR_INSET_IPV6_GTPU,       ICE_FDIR_INSET_IPV6_GTPU,               
ICE_INSET_NONE},
+       {pattern_eth_ipv6_gtpu_eh,                      
ICE_FDIR_INSET_IPV6_GTPU_EH,    ICE_FDIR_INSET_IPV6_GTPU_EH,            
ICE_INSET_NONE},
+       {pattern_eth_ipv4_udp_l2tpv2,                   ICE_FDIR_INSET_L2TPV2,  
        ICE_INSET_NONE,                         ICE_INSET_NONE},
+       {pattern_eth_ipv4_udp_l2tpv2_ppp,               ICE_FDIR_INSET_L2TPV2,  
        ICE_INSET_NONE,                         ICE_INSET_NONE},
+       {pattern_eth_ipv6_udp_l2tpv2,                   ICE_FDIR_INSET_L2TPV2,  
        ICE_INSET_NONE,                         ICE_INSET_NONE},
+       {pattern_eth_ipv6_udp_l2tpv2_ppp,               ICE_FDIR_INSET_L2TPV2,  
        ICE_INSET_NONE,                         ICE_INSET_NONE},
+       {pattern_eth_ipv4_udp_l2tpv2_ppp_ipv4,          ICE_FDIR_INSET_L2TPV2,  
        ICE_FDIR_INSET_L2TPV2_PPP_IPV4,         ICE_INSET_NONE},
+       {pattern_eth_ipv4_udp_l2tpv2_ppp_ipv4_udp,      ICE_FDIR_INSET_L2TPV2,  
        ICE_FDIR_INSET_L2TPV2_PPP_IPV4_UDP,     ICE_INSET_NONE},
+       {pattern_eth_ipv4_udp_l2tpv2_ppp_ipv4_tcp,      ICE_FDIR_INSET_L2TPV2,  
        ICE_FDIR_INSET_L2TPV2_PPP_IPV4_TCP,     ICE_INSET_NONE},
+       {pattern_eth_ipv6_udp_l2tpv2_ppp_ipv4,          ICE_FDIR_INSET_L2TPV2,  
        ICE_FDIR_INSET_L2TPV2_PPP_IPV4,         ICE_INSET_NONE},
+       {pattern_eth_ipv6_udp_l2tpv2_ppp_ipv4_udp,      ICE_FDIR_INSET_L2TPV2,  
        ICE_FDIR_INSET_L2TPV2_PPP_IPV4_UDP,     ICE_INSET_NONE},
+       {pattern_eth_ipv6_udp_l2tpv2_ppp_ipv4_tcp,      ICE_FDIR_INSET_L2TPV2,  
        ICE_FDIR_INSET_L2TPV2_PPP_IPV4_TCP,     ICE_INSET_NONE},
+       {pattern_eth_ipv4_udp_l2tpv2_ppp_ipv6,          ICE_FDIR_INSET_L2TPV2,  
        ICE_FDIR_INSET_L2TPV2_PPP_IPV6,         ICE_INSET_NONE},
+       {pattern_eth_ipv4_udp_l2tpv2_ppp_ipv6_udp,      ICE_FDIR_INSET_L2TPV2,  
        ICE_FDIR_INSET_L2TPV2_PPP_IPV6_UDP,     ICE_INSET_NONE},
+       {pattern_eth_ipv4_udp_l2tpv2_ppp_ipv6_tcp,      ICE_FDIR_INSET_L2TPV2,  
        ICE_FDIR_INSET_L2TPV2_PPP_IPV6_TCP,     ICE_INSET_NONE},
+       {pattern_eth_ipv6_udp_l2tpv2_ppp_ipv6,          ICE_FDIR_INSET_L2TPV2,  
        ICE_FDIR_INSET_L2TPV2_PPP_IPV6,         ICE_INSET_NONE},
+       {pattern_eth_ipv6_udp_l2tpv2_ppp_ipv6_udp,      ICE_FDIR_INSET_L2TPV2,  
        ICE_FDIR_INSET_L2TPV2_PPP_IPV6_UDP,     ICE_INSET_NONE},
+       {pattern_eth_ipv6_udp_l2tpv2_ppp_ipv6_tcp,      ICE_FDIR_INSET_L2TPV2,  
        ICE_FDIR_INSET_L2TPV2_PPP_IPV6_TCP,     ICE_INSET_NONE},
 };
 
 static int
@@ -957,6 +998,7 @@ ice_fdir_input_set_parse(uint64_t inset, enum 
ice_flow_field *field)
                {ICE_INSET_VXLAN_VNI, ICE_FLOW_FIELD_IDX_VXLAN_VNI},
                {ICE_INSET_ESP_SPI, ICE_FLOW_FIELD_IDX_ESP_SPI},
                {ICE_INSET_NAT_T_ESP_SPI, ICE_FLOW_FIELD_IDX_NAT_T_ESP_SPI},
+               {ICE_INSET_L2TPV2OIP_SESSION_ID, 
ICE_FLOW_FIELD_IDX_L2TPV2_SESS_ID},
        };
 
        for (i = 0, j = 0; i < RTE_DIM(ice_inset_map); i++) {
@@ -1068,6 +1110,43 @@ ice_fdir_input_set_hdrs(enum ice_fltr_ptype flow, struct 
ice_flow_seg_info *seg)
                                  ICE_FLOW_SEG_HDR_IPV6 |
                                  ICE_FLOW_SEG_HDR_IPV_OTHER);
                break;
+       case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2:
+       case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_CONTROL:
+               ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_L2TPV2 |
+                                 ICE_FLOW_SEG_HDR_IPV6 |
+                                 ICE_FLOW_SEG_HDR_IPV_OTHER);
+               break;
+       case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP:
+       case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV4:
+       case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV4_TCP:
+       case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV4_UDP:
+       case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV6:
+       case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV6_TCP:
+       case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV6_UDP:
+               ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_L2TPV2 |
+                                 ICE_FLOW_SEG_HDR_PPP |
+                                 ICE_FLOW_SEG_HDR_IPV6 |
+                                 ICE_FLOW_SEG_HDR_IPV_OTHER);
+               break;
+       case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2:
+       case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_CONTROL:
+               ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_L2TPV2 |
+                                 ICE_FLOW_SEG_HDR_IPV4 |
+                                 ICE_FLOW_SEG_HDR_IPV_OTHER);
+               break;
+       case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP:
+       case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV4:
+       case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV4_TCP:
+       case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV4_UDP:
+       case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV6:
+       case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV6_TCP:
+       case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV6_UDP:
+               ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_L2TPV2 |
+                                 ICE_FLOW_SEG_HDR_PPP |
+                                 ICE_FLOW_SEG_HDR_IPV4 |
+                                 ICE_FLOW_SEG_HDR_IPV_OTHER);
+               break;
+
        default:
                PMD_DRV_LOG(ERR, "not supported filter type.");
                break;
@@ -1170,7 +1249,10 @@ ice_fdir_uninit(struct ice_adapter *ad)
 static int
 ice_fdir_is_tunnel_profile(enum ice_fdir_tunnel_type tunnel_type)
 {
-       if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_VXLAN)
+       if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_VXLAN ||
+           tunnel_type == ICE_FDIR_TUNNEL_TYPE_L2TPV2 ||
+           tunnel_type == ICE_FDIR_TUNNEL_TYPE_GTPU ||
+           tunnel_type == ICE_FDIR_TUNNEL_TYPE_GTPU_EH)
                return 1;
        else
                return 0;
@@ -1239,6 +1321,9 @@ ice_fdir_extract_fltr_key(struct ice_fdir_fltr_pattern 
*key,
        rte_memcpy(&key->gtpu_data, &input->gtpu_data, sizeof(key->gtpu_data));
        rte_memcpy(&key->gtpu_mask, &input->gtpu_mask, sizeof(key->gtpu_mask));
 
+       rte_memcpy(&key->l2tpv2_data, &input->l2tpv2_data, 
sizeof(key->l2tpv2_data));
+       rte_memcpy(&key->l2tpv2_mask, &input->l2tpv2_mask, 
sizeof(key->l2tpv2_mask));
+
        key->tunnel_type = filter->tunnel_type;
 }
 
@@ -1797,16 +1882,22 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter 
*ad,
        const struct rte_flow_item_gtp *gtp_spec, *gtp_mask;
        const struct rte_flow_item_gtp_psc *gtp_psc_spec, *gtp_psc_mask;
        const struct rte_flow_item_esp *esp_spec, *esp_mask;
+       const struct rte_flow_item_l2tpv2 *l2tpv2_spec, *l2tpv2_mask;
+       const struct rte_flow_item_ppp *ppp_spec, *ppp_mask;
        uint64_t input_set_i = ICE_INSET_NONE; /* only for tunnel inner */
        uint64_t input_set_o = ICE_INSET_NONE; /* non-tunnel and tunnel outer */
        uint64_t *input_set;
        uint8_t flow_type = ICE_FLTR_PTYPE_NONF_NONE;
+       enum rte_flow_item_type inner_l3 = RTE_FLOW_ITEM_TYPE_END;
+       enum rte_flow_item_type inner_l4 = RTE_FLOW_ITEM_TYPE_END;
+       enum rte_flow_item_type current_l3 = RTE_FLOW_ITEM_TYPE_END;
+       bool ppp_present = false;
        uint8_t  ipv6_addr_mask[16] = {
                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        };
        uint32_t vtc_flow_cpu;
-       uint16_t ether_type;
+       uint16_t ether_type = 0, flags_version = 0;
        enum rte_flow_item_type next_type;
        bool is_outer = true;
        struct ice_fdir_extra *p_ext_data;
@@ -1994,22 +2085,30 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter 
*ad,
                                   &eth_spec->hdr.ether_type, 
sizeof(eth_spec->hdr.ether_type));
                        break;
                case RTE_FLOW_ITEM_TYPE_IPV4:
-                       flow_type = ICE_FLTR_PTYPE_NONF_IPV4_OTHER;
-                       l3 = RTE_FLOW_ITEM_TYPE_IPV4;
+                       /* Only set flow_type for outer IPv4, track inner L3 
for tunnels */
+                       if (is_outer || !tunnel_type) {
+                               flow_type = ICE_FLTR_PTYPE_NONF_IPV4_OTHER;
+                               l3 = RTE_FLOW_ITEM_TYPE_IPV4;
+                               current_l3 = RTE_FLOW_ITEM_TYPE_IPV4;
+                       } else {
+                               inner_l3 = RTE_FLOW_ITEM_TYPE_IPV4;
+                               current_l3 = RTE_FLOW_ITEM_TYPE_IPV4;
+                       }
+
                        ipv4_spec = item->spec;
                        ipv4_last = item->last;
                        ipv4_mask = item->mask;
                        p_v4 = (tunnel_type && is_outer) ?
-                              &filter->input.ip_outer.v4 :
-                              &filter->input.ip.v4;
+                                       &filter->input.ip_outer.v4 :
+                                       &filter->input.ip.v4;
 
                        if (!(ipv4_spec && ipv4_mask))
                                break;
 
                        /* Check IPv4 mask and update input set */
                        if (ipv4_mask->hdr.version_ihl ||
-                           ipv4_mask->hdr.total_length ||
-                           ipv4_mask->hdr.hdr_checksum) {
+                               ipv4_mask->hdr.total_length ||
+                               ipv4_mask->hdr.hdr_checksum) {
                                rte_flow_error_set(error, EINVAL,
                                                   RTE_FLOW_ERROR_TYPE_ITEM,
                                                   item,
@@ -2041,10 +2140,18 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter 
*ad,
                                ipv4_mask->hdr.dst_addr != UINT32_MAX)
                                return -rte_errno;
 
-                       if (ipv4_mask->hdr.dst_addr == UINT32_MAX)
-                               *input_set |= ICE_INSET_IPV4_DST;
-                       if (ipv4_mask->hdr.src_addr == UINT32_MAX)
-                               *input_set |= ICE_INSET_IPV4_SRC;
+                       if (ipv4_mask->hdr.dst_addr == UINT32_MAX) {
+                               if (tunnel_type && !is_outer && tunnel_type == 
ICE_FDIR_TUNNEL_TYPE_L2TPV2)
+                                       *input_set |= ICE_INSET_TUN_IPV4_DST;
+                               else
+                                       *input_set |= ICE_INSET_IPV4_DST;
+                       }
+                       if (ipv4_mask->hdr.src_addr == UINT32_MAX) {
+                               if (tunnel_type && !is_outer && tunnel_type == 
ICE_FDIR_TUNNEL_TYPE_L2TPV2)
+                                       *input_set |= ICE_INSET_TUN_IPV4_SRC;
+                               else
+                                       *input_set |= ICE_INSET_IPV4_SRC;
+                       }
                        if (ipv4_mask->hdr.time_to_live == UINT8_MAX)
                                *input_set |= ICE_INSET_IPV4_TTL;
                        if (ipv4_mask->hdr.next_proto_id == UINT8_MAX)
@@ -2085,48 +2192,62 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter 
*ad,
 
                        break;
                case RTE_FLOW_ITEM_TYPE_IPV6:
-                       flow_type = ICE_FLTR_PTYPE_NONF_IPV6_OTHER;
-                       l3 = RTE_FLOW_ITEM_TYPE_IPV6;
+                       if (is_outer || !tunnel_type) {
+                               flow_type = ICE_FLTR_PTYPE_NONF_IPV6_OTHER;
+                               l3 = RTE_FLOW_ITEM_TYPE_IPV6;
+                               current_l3 = RTE_FLOW_ITEM_TYPE_IPV6;
+                       } else {
+                               inner_l3 = RTE_FLOW_ITEM_TYPE_IPV6;
+                               current_l3 = RTE_FLOW_ITEM_TYPE_IPV6;
+                       }
+
                        ipv6_spec = item->spec;
                        ipv6_mask = item->mask;
                        p_v6 = (tunnel_type && is_outer) ?
                               &filter->input.ip_outer.v6 :
                               &filter->input.ip.v6;
 
-                       if (!(ipv6_spec && ipv6_mask))
-                               break;
+               if (!(ipv6_spec && ipv6_mask))
+                       break;
 
-                       /* 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;
-                       }
+               /* 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)))
+               if (!memcmp(&ipv6_mask->hdr.src_addr, ipv6_addr_mask,
+                           sizeof(ipv6_mask->hdr.src_addr))) {
+                       if (tunnel_type && !is_outer && tunnel_type == 
ICE_FDIR_TUNNEL_TYPE_L2TPV2)
+                               *input_set |= ICE_INSET_TUN_IPV6_SRC;
+                       else
                                *input_set |= ICE_INSET_IPV6_SRC;
-                       if (!memcmp(&ipv6_mask->hdr.dst_addr, ipv6_addr_mask,
-                                   sizeof(ipv6_mask->hdr.dst_addr)))
+               }
+               if (!memcmp(&ipv6_mask->hdr.dst_addr, ipv6_addr_mask,
+                           sizeof(ipv6_mask->hdr.dst_addr))) {
+                       if (tunnel_type && !is_outer && tunnel_type == 
ICE_FDIR_TUNNEL_TYPE_L2TPV2)
+                               *input_set |= ICE_INSET_TUN_IPV6_DST;
+                       else
                                *input_set |= ICE_INSET_IPV6_DST;
-
-                       if ((ipv6_mask->hdr.vtc_flow &
-                            rte_cpu_to_be_32(ICE_IPV6_TC_MASK))
-                           == rte_cpu_to_be_32(ICE_IPV6_TC_MASK))
-                               *input_set |= ICE_INSET_IPV6_TC;
-                       if (ipv6_mask->hdr.proto == UINT8_MAX)
-                               *input_set |= ICE_INSET_IPV6_NEXT_HDR;
-                       if (ipv6_mask->hdr.hop_limits == UINT8_MAX)
-                               *input_set |= ICE_INSET_IPV6_HOP_LIMIT;
-
-                       rte_memcpy(&p_v6->dst_ip, &ipv6_spec->hdr.dst_addr, 16);
-                       rte_memcpy(&p_v6->src_ip, &ipv6_spec->hdr.src_addr, 16);
-                       vtc_flow_cpu = 
rte_be_to_cpu_32(ipv6_spec->hdr.vtc_flow);
-                       p_v6->tc = (uint8_t)(vtc_flow_cpu >> 
ICE_FDIR_IPV6_TC_OFFSET);
-                       p_v6->proto = ipv6_spec->hdr.proto;
-                       p_v6->hlim = ipv6_spec->hdr.hop_limits;
+               }
+               if ((ipv6_mask->hdr.vtc_flow &
+                    rte_cpu_to_be_32(ICE_IPV6_TC_MASK)) ==
+                   rte_cpu_to_be_32(ICE_IPV6_TC_MASK))
+                       *input_set |= ICE_INSET_IPV6_TC;
+               if (ipv6_mask->hdr.proto == UINT8_MAX)
+                       *input_set |= ICE_INSET_IPV6_NEXT_HDR;
+               if (ipv6_mask->hdr.hop_limits == UINT8_MAX)
+                       *input_set |= ICE_INSET_IPV6_HOP_LIMIT;
+
+               rte_memcpy(&p_v6->dst_ip, &ipv6_spec->hdr.dst_addr, 16);
+               rte_memcpy(&p_v6->src_ip, &ipv6_spec->hdr.src_addr, 16);
+               vtc_flow_cpu = rte_be_to_cpu_32(ipv6_spec->hdr.vtc_flow);
+               p_v6->tc = (uint8_t)(vtc_flow_cpu >> ICE_FDIR_IPV6_TC_OFFSET);
+               p_v6->proto = ipv6_spec->hdr.proto;
+               p_v6->hlim = ipv6_spec->hdr.hop_limits;
                        break;
                case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
                        l3 = RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT;
@@ -2160,10 +2281,16 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter 
*ad,
                        break;
 
                case RTE_FLOW_ITEM_TYPE_TCP:
-                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
-                               flow_type = ICE_FLTR_PTYPE_NONF_IPV4_TCP;
-                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
-                               flow_type = ICE_FLTR_PTYPE_NONF_IPV6_TCP;
+                       if (!is_outer && tunnel_type) {
+                               /* For inner TCP in tunnels, track inner_l4 */
+                               inner_l4 = RTE_FLOW_ITEM_TYPE_TCP;
+                       } else {
+                               /* For outer TCP, update flow_type normally */
+                               if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV4_TCP;
+                               if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV6_TCP;
+                       }
 
                        tcp_spec = item->spec;
                        tcp_mask = item->mask;
@@ -2194,28 +2321,42 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter 
*ad,
                                tcp_mask->hdr.dst_port != UINT16_MAX)
                                return -rte_errno;
 
-                       if (tcp_mask->hdr.src_port == UINT16_MAX)
-                               *input_set |= ICE_INSET_TCP_SRC_PORT;
-                       if (tcp_mask->hdr.dst_port == UINT16_MAX)
-                               *input_set |= ICE_INSET_TCP_DST_PORT;
+                       if (tcp_mask->hdr.src_port == UINT16_MAX) {
+                               if (tunnel_type && !is_outer && tunnel_type == 
ICE_FDIR_TUNNEL_TYPE_L2TPV2)
+                                       *input_set |= 
ICE_INSET_TUN_TCP_SRC_PORT;
+                               else
+                                       *input_set |= ICE_INSET_TCP_SRC_PORT;
+                       }
+                       if (tcp_mask->hdr.dst_port == UINT16_MAX) {
+                               if (tunnel_type && !is_outer && tunnel_type == 
ICE_FDIR_TUNNEL_TYPE_L2TPV2)
+                                       *input_set |= 
ICE_INSET_TUN_TCP_DST_PORT;
+                               else
+                                       *input_set |= ICE_INSET_TCP_DST_PORT;
+                       }
 
                        /* Get filter info */
-                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
+                       if (current_l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
                                assert(p_v4);
                                p_v4->dst_port = tcp_spec->hdr.dst_port;
                                p_v4->src_port = tcp_spec->hdr.src_port;
-                       } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) {
+                       } else if (current_l3 == RTE_FLOW_ITEM_TYPE_IPV6) {
                                assert(p_v6);
                                p_v6->dst_port = tcp_spec->hdr.dst_port;
                                p_v6->src_port = tcp_spec->hdr.src_port;
                        }
                        break;
                case RTE_FLOW_ITEM_TYPE_UDP:
-                       l4 = RTE_FLOW_ITEM_TYPE_UDP;
-                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
-                               flow_type = ICE_FLTR_PTYPE_NONF_IPV4_UDP;
-                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
-                               flow_type = ICE_FLTR_PTYPE_NONF_IPV6_UDP;
+                       if (!is_outer && tunnel_type) {
+                               /* For inner UDP in tunnels, track inner_l4 */
+                               inner_l4 = RTE_FLOW_ITEM_TYPE_UDP;
+                       } else {
+                               /* For outer UDP, update flow_type normally */
+                               l4 = RTE_FLOW_ITEM_TYPE_UDP;
+                               if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV4_UDP;
+                               if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV6_UDP;
+                       }
 
                        udp_spec = item->spec;
                        udp_mask = item->mask;
@@ -2241,27 +2382,41 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter 
*ad,
                                udp_mask->hdr.dst_port != UINT16_MAX)
                                return -rte_errno;
 
-                       if (udp_mask->hdr.src_port == UINT16_MAX)
-                               *input_set |= ICE_INSET_UDP_SRC_PORT;
-                       if (udp_mask->hdr.dst_port == UINT16_MAX)
-                               *input_set |= ICE_INSET_UDP_DST_PORT;
+                       if (udp_mask->hdr.src_port == UINT16_MAX) {
+                               if (tunnel_type && !is_outer && tunnel_type == 
ICE_FDIR_TUNNEL_TYPE_L2TPV2)
+                                       *input_set |= 
ICE_INSET_TUN_UDP_SRC_PORT;
+                               else
+                                       *input_set |= ICE_INSET_UDP_SRC_PORT;
+                       }
+                       if (udp_mask->hdr.dst_port == UINT16_MAX) {
+                               if (tunnel_type && !is_outer && tunnel_type == 
ICE_FDIR_TUNNEL_TYPE_L2TPV2)
+                                       *input_set |= 
ICE_INSET_TUN_UDP_DST_PORT;
+                               else
+                                       *input_set |= ICE_INSET_UDP_DST_PORT;
+                       }
 
                        /* Get filter info */
-                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
+                       if (current_l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
                                assert(p_v4);
                                p_v4->dst_port = udp_spec->hdr.dst_port;
                                p_v4->src_port = udp_spec->hdr.src_port;
-                       } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) {
+                       } else if (current_l3 == RTE_FLOW_ITEM_TYPE_IPV6) {
                                assert(p_v6);
                                p_v6->src_port = udp_spec->hdr.src_port;
                                p_v6->dst_port = udp_spec->hdr.dst_port;
                        }
                        break;
                case RTE_FLOW_ITEM_TYPE_SCTP:
-                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
-                               flow_type = ICE_FLTR_PTYPE_NONF_IPV4_SCTP;
-                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
-                               flow_type = ICE_FLTR_PTYPE_NONF_IPV6_SCTP;
+                       if (!is_outer && tunnel_type) {
+                               /* For inner SCTP in tunnels, track inner_l4 */
+                               inner_l4 = RTE_FLOW_ITEM_TYPE_SCTP;
+                       } else {
+                               /* For outer SCTP, update flow_type normally */
+                               if (l3 == RTE_FLOW_ITEM_TYPE_IPV4)
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV4_SCTP;
+                               if (l3 == RTE_FLOW_ITEM_TYPE_IPV6)
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV6_SCTP;
+                       }
 
                        sctp_spec = item->spec;
                        sctp_mask = item->mask;
@@ -2292,11 +2447,11 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter 
*ad,
                                *input_set |= ICE_INSET_SCTP_DST_PORT;
 
                        /* Get filter info */
-                       if (l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
+                       if (current_l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
                                assert(p_v4);
                                p_v4->dst_port = sctp_spec->hdr.dst_port;
                                p_v4->src_port = sctp_spec->hdr.src_port;
-                       } else if (l3 == RTE_FLOW_ITEM_TYPE_IPV6) {
+                       } else if (current_l3 == RTE_FLOW_ITEM_TYPE_IPV6) {
                                assert(p_v6);
                                p_v6->dst_port = sctp_spec->hdr.dst_port;
                                p_v6->src_port = sctp_spec->hdr.src_port;
@@ -2399,6 +2554,114 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter 
*ad,
                                filter->input.ip.v6.sec_parm_idx =
                                        esp_spec->hdr.spi;
                        break;
+               case RTE_FLOW_ITEM_TYPE_L2TPV2:
+
+                       l2tpv2_spec = item->spec;
+                       l2tpv2_mask = item->mask;
+
+                       if (l2tpv2_spec && l2tpv2_mask) {
+                               flags_version =
+                                       
rte_be_to_cpu_16(l2tpv2_spec->hdr.common.flags_version);
+                               if ((flags_version == 
RTE_L2TPV2_MSG_TYPE_CONTROL &&
+                                    l2tpv2_mask->hdr.type3.session_id == 
UINT16_MAX) ||
+                                   (flags_version == RTE_L2TPV2_MSG_TYPE_DATA 
&&
+                                    l2tpv2_mask->hdr.type7.session_id == 
UINT16_MAX) ||
+                                   (flags_version == 
RTE_L2TPV2_MSG_TYPE_DATA_L &&
+                                    l2tpv2_mask->hdr.type6.session_id == 
UINT16_MAX) ||
+                                   (flags_version == 
RTE_L2TPV2_MSG_TYPE_DATA_S &&
+                                    l2tpv2_mask->hdr.type5.session_id == 
UINT16_MAX) ||
+                                   (flags_version == 
RTE_L2TPV2_MSG_TYPE_DATA_O &&
+                                    l2tpv2_mask->hdr.type4.session_id == 
UINT16_MAX) ||
+                                   (flags_version == 
RTE_L2TPV2_MSG_TYPE_DATA_L_S &&
+                                    l2tpv2_mask->hdr.type3.session_id == 
UINT16_MAX) ||
+                                   (flags_version == 
RTE_L2TPV2_MSG_TYPE_DATA_L_O &&
+                                    l2tpv2_mask->hdr.type2.session_id == 
UINT16_MAX) ||
+                                   (flags_version == 
RTE_L2TPV2_MSG_TYPE_DATA_S_O &&
+                                    l2tpv2_mask->hdr.type1.session_id == 
UINT16_MAX) ||
+                                   (flags_version == 
RTE_L2TPV2_MSG_TYPE_DATA_L_S_O &&
+                                    l2tpv2_mask->hdr.type0.session_id == 
UINT16_MAX)) {
+                                       input_set_o |= 
ICE_INSET_L2TPV2OIP_SESSION_ID;
+                               }
+                       }
+
+                       tunnel_type = ICE_FDIR_TUNNEL_TYPE_L2TPV2;
+
+                       struct ice_fdir_l2tpv2 l2tpv2_be;
+                       memset(&l2tpv2_be, 0, sizeof(l2tpv2_be));
+
+                       if (flags_version == RTE_L2TPV2_MSG_TYPE_CONTROL) {
+                               l2tpv2_be.length = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type3.length);
+                               l2tpv2_be.tunnel_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type3.tunnel_id);
+                               l2tpv2_be.session_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type3.session_id);
+                               l2tpv2_be.ns = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type3.ns);
+                               l2tpv2_be.nr = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type3.nr);
+                       } else if (flags_version == RTE_L2TPV2_MSG_TYPE_DATA) {
+                               l2tpv2_be.tunnel_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type7.tunnel_id);
+                               l2tpv2_be.session_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type7.session_id);
+                       } else if (flags_version == RTE_L2TPV2_MSG_TYPE_DATA_L) 
{
+                               l2tpv2_be.length = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type6.length);
+                               l2tpv2_be.tunnel_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type6.tunnel_id);
+                               l2tpv2_be.session_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type6.session_id);
+                       } else if (flags_version == RTE_L2TPV2_MSG_TYPE_DATA_S) 
{
+                               l2tpv2_be.tunnel_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type5.tunnel_id);
+                               l2tpv2_be.session_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type5.session_id);
+                               l2tpv2_be.ns = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type5.ns);
+                               l2tpv2_be.nr = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type5.nr);
+                       } else if (flags_version == RTE_L2TPV2_MSG_TYPE_DATA_O) 
{
+                               l2tpv2_be.tunnel_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type4.tunnel_id);
+                               l2tpv2_be.session_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type4.session_id);
+                               l2tpv2_be.offset_size = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type4.offset_size);
+                       } else if (flags_version == 
RTE_L2TPV2_MSG_TYPE_DATA_L_S) {
+                               l2tpv2_be.length = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type3.length);
+                               l2tpv2_be.tunnel_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type3.tunnel_id);
+                               l2tpv2_be.session_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type3.session_id);
+                               l2tpv2_be.ns = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type3.ns);
+                               l2tpv2_be.nr = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type3.nr);
+                       } else if (flags_version == 
RTE_L2TPV2_MSG_TYPE_DATA_L_O) {
+                               l2tpv2_be.length = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type2.length);
+                               l2tpv2_be.tunnel_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type2.tunnel_id);
+                               l2tpv2_be.session_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type2.session_id);
+                               l2tpv2_be.offset_size = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type2.offset_size);
+                       } else if (flags_version == 
RTE_L2TPV2_MSG_TYPE_DATA_S_O) {
+                               l2tpv2_be.tunnel_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type1.tunnel_id);
+                               l2tpv2_be.session_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type1.session_id);
+                               l2tpv2_be.ns = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type1.ns);
+                               l2tpv2_be.nr = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type1.nr);
+                               l2tpv2_be.offset_size = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type1.offset_size);
+                       } else if (flags_version == 
RTE_L2TPV2_MSG_TYPE_DATA_L_S_O) {
+                               l2tpv2_be.length = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type0.length);
+                               l2tpv2_be.tunnel_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type0.tunnel_id);
+                               l2tpv2_be.session_id = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type0.session_id);
+                               l2tpv2_be.ns = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type0.ns);
+                               l2tpv2_be.nr = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type0.nr);
+                               l2tpv2_be.offset_size = 
rte_cpu_to_be_16(l2tpv2_spec->hdr.type0.offset_size);
+                       }
+
+                       /* Copy converted values to filter */
+                       filter->input.l2tpv2_data.flags_version = 
rte_cpu_to_be_16(flags_version);
+                       filter->input.l2tpv2_data.length = l2tpv2_be.length;
+                       filter->input.l2tpv2_data.tunnel_id = 
l2tpv2_be.tunnel_id;
+                       filter->input.l2tpv2_data.session_id = 
l2tpv2_be.session_id;
+                       filter->input.l2tpv2_data.ns = l2tpv2_be.ns;
+                       filter->input.l2tpv2_data.nr = l2tpv2_be.nr;
+                       filter->input.l2tpv2_data.offset_size = 
l2tpv2_be.offset_size;
+                       break;
+               case RTE_FLOW_ITEM_TYPE_PPP:
+                       ppp_spec = item->spec;
+                       ppp_mask = item->mask;
+
+                       /* PPP marks transition from outer to inner in L2TPv2 
tunnels */
+                       if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_L2TPV2) {
+                               is_outer = false;
+                               ppp_present = true;
+                       }
+
+                       if (ppp_spec && ppp_mask) {
+                               filter->input.ppp_data.addr = 
ppp_spec->hdr.addr;
+                               filter->input.ppp_data.ctrl = 
ppp_spec->hdr.ctrl;
+                               filter->input.ppp_data.proto_id = 
ppp_spec->hdr.proto_id;
+                       }
+                       break;
                default:
                        rte_flow_error_set(error, EINVAL,
                                           RTE_FLOW_ERROR_TYPE_ITEM,
@@ -2432,12 +2695,82 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter 
*ad,
        else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_VXLAN &&
                flow_type == ICE_FLTR_PTYPE_NONF_IPV4_OTHER)
                flow_type = ICE_FLTR_PTYPE_NONF_IPV4_UDP_VXLAN_IPV4_OTHER;
+       else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_L2TPV2 &&
+               flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP &&
+               flags_version != RTE_L2TPV2_MSG_TYPE_CONTROL &&
+               !ppp_present)
+               flow_type = ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2;
+       else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_L2TPV2 &&
+               flow_type == ICE_FLTR_PTYPE_NONF_IPV6_UDP &&
+               flags_version != RTE_L2TPV2_MSG_TYPE_CONTROL &&
+               !ppp_present)
+               flow_type = ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2;
+       else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_L2TPV2 &&
+               flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP &&
+               flags_version == RTE_L2TPV2_MSG_TYPE_CONTROL &&
+               !ppp_present)
+               flow_type = ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_CONTROL;
+       else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_L2TPV2 &&
+               flow_type == ICE_FLTR_PTYPE_NONF_IPV6_UDP &&
+               flags_version == RTE_L2TPV2_MSG_TYPE_CONTROL &&
+               !ppp_present)
+               flow_type = ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_CONTROL;
+       /* Handle L2TPV2 with PPP and inner protocols */
+       else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_L2TPV2 &&
+               ppp_present &&
+               inner_l3 != RTE_FLOW_ITEM_TYPE_END) {
+               /* L2TPV2 with inner IPv4/IPv6 */
+               if (flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP) {
+                       /* Outer IPv4 + inner protocol */
+                       if (inner_l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
+                               if (inner_l4 == RTE_FLOW_ITEM_TYPE_TCP)
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV4_TCP;
+                               else if (inner_l4 == RTE_FLOW_ITEM_TYPE_UDP)
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV4_UDP;
+                               else
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV4;
+                       } else if (inner_l3 == RTE_FLOW_ITEM_TYPE_IPV6) {
+                               if (inner_l4 == RTE_FLOW_ITEM_TYPE_TCP)
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV6_TCP;
+                               else if (inner_l4 == RTE_FLOW_ITEM_TYPE_UDP)
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV6_UDP;
+                               else
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV6;
+                       }
+               } else if (flow_type == ICE_FLTR_PTYPE_NONF_IPV6_UDP) {
+                       /* Outer IPv6 + inner protocol */
+                       if (inner_l3 == RTE_FLOW_ITEM_TYPE_IPV4) {
+                               if (inner_l4 == RTE_FLOW_ITEM_TYPE_TCP)
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV4_TCP;
+                               else if (inner_l4 == RTE_FLOW_ITEM_TYPE_UDP)
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV4_UDP;
+                               else
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV4;
+                       } else if (inner_l3 == RTE_FLOW_ITEM_TYPE_IPV6) {
+                               if (inner_l4 == RTE_FLOW_ITEM_TYPE_TCP)
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV6_TCP;
+                               else if (inner_l4 == RTE_FLOW_ITEM_TYPE_UDP)
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV6_UDP;
+                               else
+                                       flow_type = 
ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV6;
+                       }
+               }
+       } else if (tunnel_type == ICE_FDIR_TUNNEL_TYPE_L2TPV2 && ppp_present &&
+               inner_l3 == RTE_FLOW_ITEM_TYPE_END) {
+               /* Handle L2TPV2 with PPP but no inner protocol specified */
+               if (flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP)
+                       flow_type = ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP;
+               else if (flow_type == ICE_FLTR_PTYPE_NONF_IPV6_UDP)
+                       flow_type = ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP;
+       }
 
        filter->tunnel_type = tunnel_type;
        filter->input.flow_type = flow_type;
        filter->input_set_o = input_set_o;
        filter->input_set_i = input_set_i;
 
+
+
        return 0;
 }
 
@@ -2476,8 +2809,8 @@ ice_fdir_parse(struct ice_adapter *ad,
        input_set = raw ? ~input_set : input_set;
 
        if (!input_set || filter->input_set_o &
-           ~(item->input_set_mask_o | ICE_INSET_ETHERTYPE) ||
-           filter->input_set_i & ~item->input_set_mask_i) {
+               ~(item->input_set_mask_o | ICE_INSET_ETHERTYPE) ||
+               filter->input_set_i & ~item->input_set_mask_i) {
                rte_flow_error_set(error, EINVAL,
                                   RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
                                   pattern,
diff --git a/drivers/net/intel/ice/ice_generic_flow.c 
b/drivers/net/intel/ice/ice_generic_flow.c
index 4049157eab..644958cccf 100644
--- a/drivers/net/intel/ice/ice_generic_flow.c
+++ b/drivers/net/intel/ice/ice_generic_flow.c
@@ -1794,6 +1794,166 @@ enum rte_flow_item_type pattern_eth_ipv6_pfcp[] = {
        RTE_FLOW_ITEM_TYPE_PFCP,
        RTE_FLOW_ITEM_TYPE_END,
 };
+enum rte_flow_item_type pattern_eth_ipv4_l2tpv2[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv6_l2tpv2[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv4_udp_l2tpv2[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv4_udp_l2tpv2_ppp[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_PPP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv6_udp_l2tpv2[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv6_udp_l2tpv2_ppp[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_PPP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+/* PPPoL2TPv2oUDP */
+enum rte_flow_item_type pattern_eth_ipv4_udp_l2tpv2_ppp_ipv4[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_PPP,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv4_udp_l2tpv2_ppp_ipv4_udp[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_PPP,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv4_udp_l2tpv2_ppp_ipv4_tcp[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_PPP,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_TCP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv6_udp_l2tpv2_ppp_ipv4[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_PPP,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv6_udp_l2tpv2_ppp_ipv4_udp[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_PPP,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv6_udp_l2tpv2_ppp_ipv4_tcp[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_PPP,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_TCP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv4_udp_l2tpv2_ppp_ipv6[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_PPP,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv4_udp_l2tpv2_ppp_ipv6_udp[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_PPP,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv4_udp_l2tpv2_ppp_ipv6_tcp[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV4,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_PPP,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_TCP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv6_udp_l2tpv2_ppp_ipv6[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_PPP,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv6_udp_l2tpv2_ppp_ipv6_udp[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_PPP,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+enum rte_flow_item_type pattern_eth_ipv6_udp_l2tpv2_ppp_ipv6_tcp[] = {
+       RTE_FLOW_ITEM_TYPE_ETH,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_UDP,
+       RTE_FLOW_ITEM_TYPE_L2TPV2,
+       RTE_FLOW_ITEM_TYPE_PPP,
+       RTE_FLOW_ITEM_TYPE_IPV6,
+       RTE_FLOW_ITEM_TYPE_TCP,
+       RTE_FLOW_ITEM_TYPE_END,
+};
+
 
 typedef bool (*parse_engine_t)(struct ice_adapter *ad,
                               struct rte_flow *flow,
@@ -2021,6 +2181,23 @@ static struct ice_ptype_match ice_ptype_map[] = {
        {pattern_eth_ipv4_udp_esp,                      ICE_MAC_IPV4_NAT_T_ESP},
        {pattern_eth_ipv4_ah,                           ICE_MAC_IPV4_AH},
        {pattern_eth_ipv4_l2tp,                         ICE_MAC_IPV4_L2TPV3},
+       {pattern_eth_ipv4_udp_l2tpv2,           ICE_MAC_IPV4_L2TPV2},
+       {pattern_eth_ipv4_udp_l2tpv2_ppp,               ICE_MAC_IPV4_L2TPV2},
+       {pattern_eth_ipv4_udp_l2tpv2_ppp_ipv4,          ICE_MAC_IPV4_L2TPV2},
+       {pattern_eth_ipv4_udp_l2tpv2_ppp_ipv4_udp,      ICE_MAC_IPV4_L2TPV2},
+       {pattern_eth_ipv4_udp_l2tpv2_ppp_ipv4_tcp,      ICE_MAC_IPV4_L2TPV2},
+       {pattern_eth_ipv4_udp_l2tpv2_ppp_ipv6,          ICE_MAC_IPV4_L2TPV2},
+       {pattern_eth_ipv4_udp_l2tpv2_ppp_ipv6_udp,      ICE_MAC_IPV4_L2TPV2},
+       {pattern_eth_ipv4_udp_l2tpv2_ppp_ipv6_tcp,      ICE_MAC_IPV4_L2TPV2},
+       {pattern_eth_ipv6_udp_l2tpv2,           ICE_MAC_IPV6_L2TPV2},
+       {pattern_eth_ipv6_udp_l2tpv2_ppp,               ICE_MAC_IPV6_L2TPV2},
+       {pattern_eth_ipv6_udp_l2tpv2_ppp_ipv4,          ICE_MAC_IPV6_L2TPV2},
+       {pattern_eth_ipv6_udp_l2tpv2_ppp_ipv4_udp,      ICE_MAC_IPV6_L2TPV2},
+       {pattern_eth_ipv6_udp_l2tpv2_ppp_ipv4_tcp,      ICE_MAC_IPV6_L2TPV2},
+       {pattern_eth_ipv6_udp_l2tpv2_ppp_ipv6,          ICE_MAC_IPV6_L2TPV2},
+       {pattern_eth_ipv6_udp_l2tpv2_ppp_ipv6_udp,      ICE_MAC_IPV6_L2TPV2},
+       {pattern_eth_ipv6_udp_l2tpv2_ppp_ipv6_tcp,      ICE_MAC_IPV6_L2TPV2},
+
        {pattern_eth_ipv4_pfcp,                         
ICE_MAC_IPV4_PFCP_SESSION},
        {pattern_eth_ipv6,                              ICE_PTYPE_IPV6_PAY},
        {pattern_eth_ipv6_udp,                          ICE_PTYPE_IPV6_UDP_PAY},
-- 
2.34.1


Reply via email to