Thread (27 messages) flat view 27 messages, 2 authors, 3d ago

Re: [PATCH net-next 02/15] ice: always do GCS if hardware supports it

From: Jakub Kicinski <kuba@kernel.org>
Date: 2026-08-11 00:35:15

This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
---
ice: always do GCS if hardware supports it

This replaces the NETIF_F_HW_CSUM test in ice_tx_csum() with a new
per-Tx-ring flag, ICE_TX_RING_FLAGS_GCS, which is set in
ice_vsi_alloc_rings() whenever ICE_F_GCS is supported.  The E830 generic
checksum (GCS) context descriptor is therefore emitted based on hardware
capability instead of the netdev feature bit.  There are no Link: tags in
the commit header.
quoted hunk ↗ jump to hunk
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 8cdc4fda89e97..fc9d4e0fa7558 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -1415,6 +1415,10 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi)
 			set_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, ring->flags);
 		else
 			set_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG1, ring->flags);
+
+		if (ice_is_feature_supported(pf, ICE_F_GCS))
+			set_bit(ICE_TX_RING_FLAGS_GCS, ring->flags);
+
 		WRITE_ONCE(vsi->tx_rings[i], ring);
 	}
[Severity: Medium]

The changelog says "There is no need to check for NETIF_HW_CSUM."  Was
that check really redundant?  In ice_set_netdev_features() the bit is
added to hw_features only, and that happens after netdev->features has
already been assigned:

	netdev->features |= netdev->hw_features;
	...
	/* Mutual exclusivity for TSO and GCS is enforced by the set features
	 * ndo callback.
	 */
	if (ice_is_feature_supported(pf, ICE_F_GCS))
		netdev->hw_features |= NETIF_F_HW_CSUM;

So NETIF_F_HW_CSUM was advertised as changeable but was off by default,
which makes the removed test the actual on/off switch for the GCS branch
rather than a redundant condition.

Since ICE_TX_RING_FLAGS_GCS is set here for every Tx ring whenever
ICE_F_GCS is supported (set for every ICE_MAC_E830 PF in
ice_init_feature_support(), and never cleared, and never resynchronized
from ndo_set_features), do GCS context descriptors now get emitted while
TSO is simultaneously enabled on the same netdev?  That is the
combination ice_set_features() still refuses at this commit:

	/* Due to E830 hardware limitations, TSO (NETIF_F_ALL_TSO) with GCS
	 * (NETIF_F_HW_CSUM) is not supported.
	 */
	if (ice_is_feature_supported(pf, ICE_F_GCS) &&
	    ((features & NETIF_F_HW_CSUM) && (features & NETIF_F_ALL_TSO))) {
		...
		return -EIO;

commit 905d1a220e8d ("ice: Add E830 checksum offload support") states the
limitation at feature granularity: inner packet header modification is
not supported and MSS is limited to 1023 bytes when both GCS and TSO are
enabled.

If that limitation is device or configuration level, does a default E830
port (MTU 1500, TSO on) now run in the unsupported mode after this patch?
If it is per-packet only, then the -EIO check and the comment claiming the
ndo callback enforces exclusivity are stale, and could be retired in this
same change with that reasoning recorded.

For completeness: the follow-up patch "ice: use NETIF_F_HW_CSUM instead of
IP/IPV6" removes the -EIO check and the stale comment and moves
NETIF_F_HW_CSUM into csumo_features, but GCS being active with TSO enabled
persists to the end of the series.

Two effects not mentioned in the changelog: every checksummed packet now
also consumes a Tx context descriptor, and at this commit
tx-checksum-ip-generic no longer controls GCS at all, since clearing it
leaves NETIF_F_IP_CSUM/NETIF_F_IPV6_CSUM set and CHECKSUM_PARTIAL skbs
still take the GCS branch.  Could the changelog mention both?
quoted hunk ↗ jump to hunk
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index 31303ab5be175..477c86d8c53bc 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -1739,7 +1739,7 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
 	l3_len = l4.hdr - ip.hdr;
 	offset |= (l3_len / 4) << ICE_TX_DESC_LEN_IPLEN_S;
 
-	if ((tx_ring->netdev->features & NETIF_F_HW_CSUM) &&
+	if (test_bit(ICE_TX_RING_FLAGS_GCS, tx_ring->flags) &&
 	    !(first->tx_flags & ICE_TX_FLAGS_TSO) &&
 	    !skb_csum_is_sctp(skb)) {
 		/* Set GCS */
[Severity: High]

This is a pre-existing issue and was not introduced by this patch, but
making the GCS branch the default widens the exposure of a missing bounds
check in the block right below this hunk in ice_tx_csum():

	u16 csum_start = (skb->csum_start - skb->mac_header) / 2;
	u16 csum_offset = skb->csum_offset / 2;
	u16 gcs_params;

	gcs_params = FIELD_PREP(ICE_TX_GCS_DESC_START_M, csum_start) |
		     FIELD_PREP(ICE_TX_GCS_DESC_OFFSET_M, csum_offset) |
		     FIELD_PREP(ICE_TX_GCS_DESC_TYPE_M,
				ICE_TX_GCS_DESC_CSUM_PSH);

In ice_lan_tx_rx.h these fields are narrow:

	#define ICE_TX_GCS_DESC_START_M		GENMASK(7, 0)
	#define ICE_TX_GCS_DESC_OFFSET_M	GENMASK(11, 8)

Both are in 2-byte units, so only csum_start up to 510 bytes past the MAC
header and csum_offset up to 30 can be expressed.  FIELD_PREP rejects only
out-of-range compile-time constants, so larger runtime values are silently
masked and the descriptor is still committed:

		off->cd_qw1 |= ICE_TX_DESC_DTYPE_CTX;
		off->cd_gcs_params = gcs_params;
		off->td_offset |= offset;
		off->td_cmd |= cmd;
		return 1;

There is no range check, no fall back to the legacy L4T checksum path and
no skb_checksum_help() call.  Can the device then compute the sum over the
wrong span and write the two result bytes over payload, leaving the real
checksum field holding the pseudo-header partial sum?

Are these offsets trustworthy at this point?  skb_partial_csum_set()
bounds them only by skb_headlen():

net/core/skbuff.c:skb_partial_csum_set() {
	...
	if (unlikely(csum_start >= U16_MAX || csum_end > skb_headlen(skb))) {
	...
}

so a tun/tap guest using virtio_net_hdr, or an AF_PACKET sender with
CAP_NET_RAW, can pick csum_start beyond 510 or csum_offset beyond 30, and
skb_csum_hwoffload_help() returns 0 without fixing anything up once
NETIF_F_HW_CSUM is advertised.  Long IPv6 extension header chains and
MPLS/tunnel stacks can also push csum_start past 510.

Would it make sense to validate csum_start and csum_offset against the
descriptor field widths here and fall through to the legacy checksum path
when they do not fit?

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