[PATCH net v5 8/8] net/mlx5e: psp: tso: replace only the length in checksum seed

From: Todd Freed

Date: Tue Nov 10 2026 - 19:21:07 EST


for psp tcp with tso,

- __tcp_transmit_skb() -> tcp_v6_send_check() or tcp_v4_send_check()
computes the checksum seed using the addresses on the socket and the
total length, then

- mlx5e_psp_handle_tx_skb() recomputes the checksum seed using
addresses from the packet's l3 header, and the length of one segment

the length difference is expected by the device. however, the difference
in addresses is incorrect in cases where the l3 header daddr is an
intermediate hop, for example,

- ipv4 source route option (IP_OPTIONS with lsrr or ssrr)
- ipv6 IPV6_RTHDR header (conceptually ; ipv6 extension headers are not
properly supported on this path yet)

in these cases every segment of the tso packet to go out with a bad tcp
checksum

the fix is to replace only the length in the seed which tcp had already
computed. this is also what tcp_gso_segment() does.

tested on connectx-7, with a psp tcp socket whose ipv4 loose source
route's first hop isn't the final destination, and the peer checking
tcp checksums in software.

Fixes: e5a1861a298e ("net/mlx5e: Implement PSP Tx data path")
Acked-by: Daniel Zahka <daniel.zahka@xxxxxxxxx>
Signed-off-by: Todd Freed <toddfreed@xxxxxxxx>
---
.../mellanox/mlx5/core/en_accel/psp_rxtx.c | 21 ++++++++-----------
1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c
index 348fd7a96261..d9c2742b3c24 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c
@@ -177,18 +177,15 @@ bool mlx5e_psp_handle_tx_skb(struct net_device *netdev,
return false;
}
if (skb_is_gso(skb)) {
- int len = skb_shinfo(skb)->gso_size + inner_tcp_hdrlen(skb);
- struct tcphdr *th = inner_tcp_hdr(skb);
-
- if (skb->protocol == htons(ETH_P_IP)) {
- const struct iphdr *ip = ip_hdr(skb);
-
- th->check = ~tcp_v4_check(len, ip->saddr, ip->daddr, 0);
- } else {
- const struct ipv6hdr *ip6 = ipv6_hdr(skb);
-
- th->check = ~tcp_v6_check(len, &ip6->saddr, &ip6->daddr, 0);
- }
+ u32 seg_len = skb_shinfo(skb)->gso_size + inner_tcp_hdrlen(skb);
+ u32 len = skb->len - skb_inner_transport_offset(skb);
+
+ /* update just the length component of the checksum seed
+ * tcp computed the seed with the total length, but mlx5
+ * devices are expecting the segment length
+ */
+ inet_proto_csum_replace4(&inner_tcp_hdr(skb)->check, skb,
+ htonl(len), htonl(seg_len), true);
}

return true;
--
2.53.0-Meta