From b10b446ce7ad912559e3af523aaa9f5f34a18c2e Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Sun, 25 Jan 2026 14:16:47 +0200 Subject: [PATCH 1/3] udp: gso: Use single MSS length in UDP header for GSO_PARTIAL In GSO_PARTIAL segmentation, set the UDP length field to the single segment size (gso_size + UDP header) instead of the large MSS size. This provides hardware with a template length value for final segmentation, similar to how tunnel GSO_PARTIAL handles outer headers in UDP tunnels. This will remove the need to manually adjust the UDP header length in the drivers, as can be seen in subsequent patches. This was suggested by Alex in 2018: https://lore.kernel.org/netdev/CAKgT0UcdnUWgr3KQ=RnLKigokkiUuYefmL-ePpDvJOBNpKScFA@mail.gmail.com/ Reviewed-by: Dragos Tatulea Signed-off-by: Gal Pressman Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20260125121649.778086-2-gal@nvidia.com Signed-off-by: Jakub Kicinski --- net/ipv4/udp_offload.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 19d0b5b09ffa..89e0b48b60ae 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -483,11 +483,11 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, struct sock *sk = gso_skb->sk; unsigned int sum_truesize = 0; struct sk_buff *segs, *seg; + __be16 newlen, msslen; struct udphdr *uh; unsigned int mss; bool copy_dtor; __sum16 check; - __be16 newlen; int ret = 0; mss = skb_shinfo(gso_skb)->gso_size; @@ -555,6 +555,8 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, return segs; } + msslen = htons(sizeof(*uh) + mss); + /* GSO partial and frag_list segmentation only requires splitting * the frame into an MSS multiple and possibly a remainder, both * cases return a GSO skb. So update the mss now. @@ -584,7 +586,7 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, if (!seg->next) break; - uh->len = newlen; + uh->len = msslen; uh->check = check; if (seg->ip_summed == CHECKSUM_PARTIAL) From 8d2eda97f464d3fdbc8cfe469b78d2e7ab3792ff Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Sun, 25 Jan 2026 14:16:48 +0200 Subject: [PATCH 2/3] net/mlx5e: Remove redundant UDP length adjustment with GSO_PARTIAL GSO_PARTIAL now takes care of updating the UDP header length, mlx5e_udp_gso_handle_tx_skb() is redundant, remove it. Reviewed-by: Dragos Tatulea Signed-off-by: Gal Pressman Reviewed-by: Tariq Toukan Link: https://patch.msgid.link/20260125121649.778086-3-gal@nvidia.com Signed-off-by: Jakub Kicinski --- .../mellanox/mlx5/core/en_accel/en_accel.h | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h index 8bef99e8367e..b526b3898c22 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h @@ -100,20 +100,6 @@ static inline bool mlx5_geneve_tx_allowed(struct mlx5_core_dev *mdev) #endif /* CONFIG_GENEVE */ -static inline void -mlx5e_udp_gso_handle_tx_skb(struct sk_buff *skb) -{ - int payload_len = skb_shinfo(skb)->gso_size + sizeof(struct udphdr); - struct udphdr *udphdr; - - if (skb->encapsulation) - udphdr = (struct udphdr *)skb_inner_transport_header(skb); - else - udphdr = udp_hdr(skb); - - udphdr->len = htons(payload_len); -} - struct mlx5e_accel_tx_state { #ifdef CONFIG_MLX5_EN_TLS struct mlx5e_accel_tx_tls_state tls; @@ -131,9 +117,6 @@ static inline bool mlx5e_accel_tx_begin(struct net_device *dev, struct sk_buff *skb, struct mlx5e_accel_tx_state *state) { - if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) - mlx5e_udp_gso_handle_tx_skb(skb); - #ifdef CONFIG_MLX5_EN_TLS /* May send WQEs. */ if (tls_is_skb_tx_device_offloaded(skb)) From 5b4015ad833c7636a1e43eeb4047d0813fffe3f7 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Sun, 25 Jan 2026 14:16:49 +0200 Subject: [PATCH 3/3] net: aquantia: Remove redundant UDP length adjustment with GSO_PARTIAL GSO_PARTIAL now takes care of updating the UDP header length, remove the redundant assignment in aq_nic_map_skb(). Reviewed-by: Dragos Tatulea Signed-off-by: Gal Pressman Link: https://patch.msgid.link/20260125121649.778086-4-gal@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index b24eaa5283fa..ef9447810071 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -701,9 +701,6 @@ unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb, } else if (l4proto == IPPROTO_UDP) { dx_buff->is_gso_udp = 1U; dx_buff->len_l4 = sizeof(struct udphdr); - /* UDP GSO Hardware does not replace packet length. */ - udp_hdr(skb)->len = htons(dx_buff->mss + - dx_buff->len_l4); } else { WARN_ONCE(true, "Bad GSO mode"); goto exit;