[PATCH 3/7] net/ice: fix L2TPv2 inner segment header setup

Shaiq Wani shaiq.wani at intel.com
Mon Apr 27 04:31:11 CEST 2026


ice_fdir_input_set_hdrs() sets identical headers on both outer and
inner segments and groups all PPP variants into a single fall-through,
so the HW cannot distinguish inner IPv4 from IPv6 or TCP from UDP.

Add a seg_idx parameter and expand each L2TPv2/PPP ptype into its own
case with per-segment header selection.  Also ensure the inner segment
headers are always programmed even when no inner fields are extracted,
so ptype-only narrowing works correctly.

Fixes: 733640dae75e ("net/ice: support L2TPv2 flow pattern matching")
Signed-off-by: Shaiq Wani <shaiq.wani at intel.com>
---
 drivers/net/intel/ice/ice_fdir_filter.c | 160 +++++++++++++++++++++---
 1 file changed, 145 insertions(+), 15 deletions(-)

diff --git a/drivers/net/intel/ice/ice_fdir_filter.c b/drivers/net/intel/ice/ice_fdir_filter.c
index 5ee9edc442..a0cddaeaef 100644
--- a/drivers/net/intel/ice/ice_fdir_filter.c
+++ b/drivers/net/intel/ice/ice_fdir_filter.c
@@ -1022,7 +1022,8 @@ ice_fdir_input_set_parse(uint64_t inset, enum ice_flow_field *field)
 }
 
 static void
-ice_fdir_input_set_hdrs(enum ice_fltr_ptype flow, struct ice_flow_seg_info *seg)
+ice_fdir_input_set_hdrs(enum ice_fltr_ptype flow, struct ice_flow_seg_info *seg,
+		       int seg_idx)
 {
 	switch (flow) {
 	case ICE_FLTR_PTYPE_NONF_IPV4_UDP:
@@ -1130,16 +1131,77 @@ ice_fdir_input_set_hdrs(enum ice_fltr_ptype flow, struct ice_flow_seg_info *seg)
 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
 		break;
 	case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP:
+		if (seg_idx == 0)
+			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);
+		else
+			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV_OTHER);
+		break;
 	case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV4:
-	case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV4_TCP:
+		if (seg_idx == 0)
+			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);
+		else
+			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4 |
+					  ICE_FLOW_SEG_HDR_IPV_OTHER);
+		break;
 	case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV4_UDP:
+		if (seg_idx == 0)
+			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);
+		else
+			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP |
+					  ICE_FLOW_SEG_HDR_IPV4 |
+					  ICE_FLOW_SEG_HDR_IPV_OTHER);
+		break;
+	case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV4_TCP:
+		if (seg_idx == 0)
+			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);
+		else
+			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_TCP |
+					  ICE_FLOW_SEG_HDR_IPV4 |
+					  ICE_FLOW_SEG_HDR_IPV_OTHER);
+		break;
 	case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV6:
-	case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV6_TCP:
+		if (seg_idx == 0)
+			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);
+		else
+			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6 |
+					  ICE_FLOW_SEG_HDR_IPV_OTHER);
+		break;
 	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);
+		if (seg_idx == 0)
+			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);
+		else
+			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP |
+					  ICE_FLOW_SEG_HDR_IPV6 |
+					  ICE_FLOW_SEG_HDR_IPV_OTHER);
+		break;
+	case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP_IPV6_TCP:
+		if (seg_idx == 0)
+			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);
+		else
+			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_TCP |
+					  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:
@@ -1148,16 +1210,77 @@ ice_fdir_input_set_hdrs(enum ice_fltr_ptype flow, struct ice_flow_seg_info *seg)
 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
 		break;
 	case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP:
+		if (seg_idx == 0)
+			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);
+		else
+			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV_OTHER);
+		break;
 	case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV4:
-	case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV4_TCP:
+		if (seg_idx == 0)
+			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);
+		else
+			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4 |
+					  ICE_FLOW_SEG_HDR_IPV_OTHER);
+		break;
 	case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV4_UDP:
+		if (seg_idx == 0)
+			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);
+		else
+			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP |
+					  ICE_FLOW_SEG_HDR_IPV4 |
+					  ICE_FLOW_SEG_HDR_IPV_OTHER);
+		break;
+	case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV4_TCP:
+		if (seg_idx == 0)
+			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);
+		else
+			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_TCP |
+					  ICE_FLOW_SEG_HDR_IPV4 |
+					  ICE_FLOW_SEG_HDR_IPV_OTHER);
+		break;
 	case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV6:
-	case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV6_TCP:
+		if (seg_idx == 0)
+			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);
+		else
+			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6 |
+					  ICE_FLOW_SEG_HDR_IPV_OTHER);
+		break;
 	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);
+		if (seg_idx == 0)
+			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);
+		else
+			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP |
+					  ICE_FLOW_SEG_HDR_IPV6 |
+					  ICE_FLOW_SEG_HDR_IPV_OTHER);
+		break;
+	case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP_IPV6_TCP:
+		if (seg_idx == 0)
+			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);
+		else
+			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_TCP |
+					  ICE_FLOW_SEG_HDR_IPV6 |
+					  ICE_FLOW_SEG_HDR_IPV_OTHER);
 		break;
 
 	default:
@@ -1192,15 +1315,22 @@ ice_fdir_input_set_conf(struct ice_pf *pf, enum ice_fltr_ptype flow,
 	for (k = 0; k <= ICE_FD_HW_SEG_TUN; k++) {
 		seg = &seg_tun[k];
 		input_set = (k == ICE_FD_HW_SEG_TUN) ? inner_input_set : outer_input_set;
-		if (input_set == 0)
+		if (input_set == 0) {
+			/* For tunnel inner segment, always set headers for
+			 * correct ptype narrowing even if no fields extracted.
+			 */
+			if (k == ICE_FD_HW_SEG_TUN &&
+			    ice_fdir_is_tunnel_profile(ttype))
+				ice_fdir_input_set_hdrs(flow, seg, k);
 			continue;
+		}
 
 		for (i = 0; i < ICE_FLOW_FIELD_IDX_MAX; i++)
 			field[i] = ICE_FLOW_FIELD_IDX_MAX;
 
 		ice_fdir_input_set_parse(input_set, field);
 
-		ice_fdir_input_set_hdrs(flow, seg);
+		ice_fdir_input_set_hdrs(flow, seg, k);
 
 		for (i = 0; field[i] != ICE_FLOW_FIELD_IDX_MAX; i++) {
 			ice_flow_set_fld(seg, field[i],
-- 
2.43.0



More information about the dev mailing list