Thread (6 messages) 6 messages, 3 authors, 9d ago

RE: [PATCH iwl-next v2 1/2] ice: fix TC flower filters matching more than the ip_proto key

flat view

From: Holda, Patryk <hidden>
Date: 2026-10-12 13:55:29
Also in: intel-wired-lan, lkml

quoted hunk ↗ jump to hunk
-----Original Message-----
From: Petr Oros <redacted>
Sent: Wednesday, September 16, 2026 4:41 PM
To: netdev@vger.kernel.org
Cc: Oros, Petr <redacted>; Loktionov, Aleksandr
[off-list ref]; Nguyen, Anthony L
[off-list ref]; Kitszel, Przemyslaw
[off-list ref]; Andrew Lunn [off-list ref];
David S. Miller [off-list ref]; Eric Dumazet
[off-list ref]; Jakub Kicinski [off-list ref]; Paolo Abeni
[off-list ref]; Kushwaha, Priyalee [off-list ref];
Kiran Patil [off-list ref]; Drewek, Wojciech
[off-list ref]; Michal Swiatkowski
[off-list ref]; Simon Horman [off-list ref];
intel-wired-lan@lists.osuosl.org; linux-kernel@vger.kernel.org
Subject: [PATCH iwl-next v2 1/2] ice: fix TC flower filters matching more than
the ip_proto key

ice_parse_cls_flower() stores the ip_proto key from the flow rule but never
programs a matching lookup unless the filter also matches on L4 ports or the
L2TPv3 session ID. A filter like:

  tc filter add dev $pf ingress protocol ip flower skip_sw \
      ip_proto udp action drop

is silently programmed into the hardware as a match on eth_type ipv4 alone
and drops every IPv4 packet, not just UDP.

Program the IP protocol match through the protocol field of the IPv4 header
lookup and the next header field of the IPv6 header lookup, the same lookups
that are already used for ToS and TTL. The OS default and comms DDP
packages provide no profile that extracts the IPv6 next header word, so the
IPv6 rule programming currently fails with "Required profiles not found" and
the filter falls back to software evaluation instead of over-matching, and the
offload starts working with a DDP package that can extract it. Note that the
lookup matches the next header byte of the base IPv6 header, so packets
carrying extension headers are not matched in hardware and fall back to
software evaluation, which under-matches only for skip_sw filters.

GTP tunnel and PPPoE filters rewrite the parsed ethertype, the IP header
lookups are not available there, so reject an unconsumed ip_proto for them
instead of silently widening the match. Filters where ip_proto is implied by an
L4 ports or L2TPv3 session ID lookup are not affected. Based on an earlier
unapplied patch from Michal Swiatkowski that implemented the IPv4 part [1].

Link: https://lore.kernel.org/intel-wired-lan/20240222123956.2393-3-
michal.swiatkowski@linux.intel.com/ [1]
Fixes: 0d08a441fb1a ("ice: ndo_setup_tc implementation for PF")
Reviewed-by: Aleksandr Loktionov <redacted>
Signed-off-by: Petr Oros <redacted>
---
v2:
- no code changes, collect Reviewed-by from Aleksandr Loktionov

v1: https://lore.kernel.org/all/20260910154824.3603687-2-
poros@redhat.com/
 drivers/net/ethernet/intel/ice/ice_tc_lib.c | 37 +++++++++++++++++++--
drivers/net/ethernet/intel/ice/ice_tc_lib.h |  1 +
 2 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.c
b/drivers/net/ethernet/intel/ice/ice_tc_lib.c
index d20357c0412731..fbd8cbad150a98 100644
--- a/drivers/net/ethernet/intel/ice/ice_tc_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.c
@@ -78,7 +78,8 @@ static int ice_tc_count_lkups(u32 flags, struct
ice_tc_flower_fltr *fltr)
 		     ICE_TC_FLWR_FIELD_DEST_IPV6 |
ICE_TC_FLWR_FIELD_SRC_IPV6))
 		lkups_cnt++;

-	if (flags & (ICE_TC_FLWR_FIELD_IP_TOS |
ICE_TC_FLWR_FIELD_IP_TTL))
+	if (flags & (ICE_TC_FLWR_FIELD_IP_TOS | ICE_TC_FLWR_FIELD_IP_TTL
|
+		     ICE_TC_FLWR_FIELD_IP_PROTO))
 		lkups_cnt++;

 	/* are L2TPv3 options specified? */
@@ -552,7 +553,8 @@ ice_tc_fill_rules(struct ice_hw *hw, u32 flags,
 	}

 	if (headers->l2_key.n_proto == htons(ETH_P_IP) &&
-	    (flags & (ICE_TC_FLWR_FIELD_IP_TOS |
ICE_TC_FLWR_FIELD_IP_TTL))) {
+	    (flags & (ICE_TC_FLWR_FIELD_IP_TOS | ICE_TC_FLWR_FIELD_IP_TTL
|
+		      ICE_TC_FLWR_FIELD_IP_PROTO))) {
 		list[i].type = ice_proto_type_from_ipv4(inner);

 		if (flags & ICE_TC_FLWR_FIELD_IP_TOS) { @@ -567,11
+569,19 @@ ice_tc_fill_rules(struct ice_hw *hw, u32 flags,
 				headers->l3_mask.ttl;
 		}

+		if (flags & ICE_TC_FLWR_FIELD_IP_PROTO) {
+			list[i].h_u.ipv4_hdr.protocol =
+				headers->l3_key.ip_proto;
+			list[i].m_u.ipv4_hdr.protocol =
+				headers->l3_mask.ip_proto;
+		}
+
 		i++;
 	}

 	if (headers->l2_key.n_proto == htons(ETH_P_IPV6) &&
-	    (flags & (ICE_TC_FLWR_FIELD_IP_TOS |
ICE_TC_FLWR_FIELD_IP_TTL))) {
+	    (flags & (ICE_TC_FLWR_FIELD_IP_TOS | ICE_TC_FLWR_FIELD_IP_TTL
|
+		      ICE_TC_FLWR_FIELD_IP_PROTO))) {
 		struct ice_ipv6_hdr *hdr_h, *hdr_m;

 		hdr_h = &list[i].h_u.ipv6_hdr;
@@ -592,6 +602,11 @@ ice_tc_fill_rules(struct ice_hw *hw, u32 flags,
 			hdr_m->hop_limit = headers->l3_mask.ttl;
 		}

+		if (flags & ICE_TC_FLWR_FIELD_IP_PROTO) {
+			hdr_h->next_hdr = headers->l3_key.ip_proto;
+			hdr_m->next_hdr = headers->l3_mask.ip_proto;
+		}
+
 		i++;
 	}
@@ -1737,6 +1752,9 @@ ice_parse_cls_flower(struct net_device *filter_dev,
struct ice_vsi *vsi,
 		headers->l2_key.n_proto = cpu_to_be16(n_proto_key);
 		headers->l2_mask.n_proto = cpu_to_be16(n_proto_mask);
 		headers->l3_key.ip_proto = match.key->ip_proto;
+		headers->l3_mask.ip_proto = match.mask->ip_proto;
+		if (match.mask->ip_proto)
+			fltr->flags |= ICE_TC_FLWR_FIELD_IP_PROTO;
 	}

 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
@@ -1910,6 +1928,19 @@ ice_parse_cls_flower(struct net_device
*filter_dev, struct ice_vsi *vsi,
 		}
 	}

+	if (fltr->flags & (ICE_TC_FLWR_FIELD_DEST_L4_PORT |
+			   ICE_TC_FLWR_FIELD_SRC_L4_PORT |
+			   ICE_TC_FLWR_FIELD_L2TPV3_SESSID))
+		fltr->flags &= ~ICE_TC_FLWR_FIELD_IP_PROTO;
+
+	if ((fltr->flags & ICE_TC_FLWR_FIELD_IP_PROTO) &&
+	    headers->l2_key.n_proto != htons(ETH_P_IP) &&
+	    headers->l2_key.n_proto != htons(ETH_P_IPV6)) {
+		NL_SET_ERR_MSG_MOD(fltr->extack,
+				   "IP protocol match is not supported with
GTP or PPPoE");
+		return -EOPNOTSUPP;
+	}
+
 	/* Ingress filter on representor results in an egress filter in HW
 	 * and vice versa
 	 */
diff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.h
b/drivers/net/ethernet/intel/ice/ice_tc_lib.h
index 8a3ab2f22af9ba..752af65e70b7bf 100644
--- a/drivers/net/ethernet/intel/ice/ice_tc_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.h
@@ -38,6 +38,7 @@
 #define ICE_TC_FLWR_FIELD_CVLAN_PRIO		BIT(28)
 #define ICE_TC_FLWR_FIELD_VLAN_TPID		BIT(29)
 #define ICE_TC_FLWR_FIELD_PFCP_OPTS		BIT(30)
+#define ICE_TC_FLWR_FIELD_IP_PROTO		BIT(31)

 #define ICE_TC_FLOWER_MASK_32   0xFFFFFFFF

--
2.55.0
Tested-by: Patryk Holda <redacted> 

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help