Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'single-mss-length-in-udp-gso_partial'

Gal Pressman says:

====================
Single MSS length in UDP GSO_PARTIAL

This series addresses an inconsistency in how UDP GSO_PARTIAL handles
the UDP header length field.

Currently, when GSO_PARTIAL segmentation is used, the UDP header length
contains the large MSS size, requiring drivers to manually adjust it
before transmitting. This is inconsistent with how tunnel GSO_PARTIAL
handles outer headers in UDP tunnels, where the length is set to the
single segment size.

This was originally suggested by Alexander Duyck back in 2018:
https://lore.kernel.org/netdev/CAKgT0UcdnUWgr3KQ=RnLKigokkiUuYefmL-ePpDvJOBNpKScFA@mail.gmail.com/

The first patch fixes the core UDP offload code to 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 proper template length
value for final segmentation.

The subsequent patches remove the now redundant UDP header length
adjustments from the mlx5e and aquantia drivers, as the core code now
handles this correctly.
I couldn't find any other drivers that support UDP GSO_PARTIAL; idpf
supports UDP segmentation, but it does not use GSO_PARTIAL.
====================

Link: https://patch.msgid.link/20260125121649.778086-1-gal@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+4 -22
-3
drivers/net/ethernet/aquantia/atlantic/aq_nic.c
··· 701 701 } else if (l4proto == IPPROTO_UDP) { 702 702 dx_buff->is_gso_udp = 1U; 703 703 dx_buff->len_l4 = sizeof(struct udphdr); 704 - /* UDP GSO Hardware does not replace packet length. */ 705 - udp_hdr(skb)->len = htons(dx_buff->mss + 706 - dx_buff->len_l4); 707 704 } else { 708 705 WARN_ONCE(true, "Bad GSO mode"); 709 706 goto exit;
-17
drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
··· 100 100 101 101 #endif /* CONFIG_GENEVE */ 102 102 103 - static inline void 104 - mlx5e_udp_gso_handle_tx_skb(struct sk_buff *skb) 105 - { 106 - int payload_len = skb_shinfo(skb)->gso_size + sizeof(struct udphdr); 107 - struct udphdr *udphdr; 108 - 109 - if (skb->encapsulation) 110 - udphdr = (struct udphdr *)skb_inner_transport_header(skb); 111 - else 112 - udphdr = udp_hdr(skb); 113 - 114 - udphdr->len = htons(payload_len); 115 - } 116 - 117 103 struct mlx5e_accel_tx_state { 118 104 #ifdef CONFIG_MLX5_EN_TLS 119 105 struct mlx5e_accel_tx_tls_state tls; ··· 117 131 struct sk_buff *skb, 118 132 struct mlx5e_accel_tx_state *state) 119 133 { 120 - if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) 121 - mlx5e_udp_gso_handle_tx_skb(skb); 122 - 123 134 #ifdef CONFIG_MLX5_EN_TLS 124 135 /* May send WQEs. */ 125 136 if (tls_is_skb_tx_device_offloaded(skb))
+4 -2
net/ipv4/udp_offload.c
··· 483 483 struct sock *sk = gso_skb->sk; 484 484 unsigned int sum_truesize = 0; 485 485 struct sk_buff *segs, *seg; 486 + __be16 newlen, msslen; 486 487 struct udphdr *uh; 487 488 unsigned int mss; 488 489 bool copy_dtor; 489 490 __sum16 check; 490 - __be16 newlen; 491 491 int ret = 0; 492 492 493 493 mss = skb_shinfo(gso_skb)->gso_size; ··· 555 555 return segs; 556 556 } 557 557 558 + msslen = htons(sizeof(*uh) + mss); 559 + 558 560 /* GSO partial and frag_list segmentation only requires splitting 559 561 * the frame into an MSS multiple and possibly a remainder, both 560 562 * cases return a GSO skb. So update the mss now. ··· 586 584 if (!seg->next) 587 585 break; 588 586 589 - uh->len = newlen; 587 + uh->len = msslen; 590 588 uh->check = check; 591 589 592 590 if (seg->ip_summed == CHECKSUM_PARTIAL)