Commit 88a95781 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

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: default avatarJakub Kicinski <kuba@kernel.org>
parents d64f761d 5b4015ad
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -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;
+0 −17
Original line number Diff line number Diff line
@@ -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))
+4 −2
Original line number Diff line number Diff line
@@ -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)