summaryrefslogtreecommitdiff
path: root/net/ipv4
diff options
context:
space:
mode:
authorYan Zhai <yan@cloudflare.com>2025-01-31 00:31:39 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-02-17 10:05:00 +0100
commit83ebf741aa648bec9a7dabb11553e436f3aa5a1e (patch)
tree3c45ec6292dcad79a03aee76b7d57e5aaa5633e6 /net/ipv4
parentb55dfd7bac2490ab29929f3dbb7f47725b43f805 (diff)
downloadlinux-83ebf741aa648bec9a7dabb11553e436f3aa5a1e.tar.gz
linux-83ebf741aa648bec9a7dabb11553e436f3aa5a1e.tar.bz2
linux-83ebf741aa648bec9a7dabb11553e436f3aa5a1e.zip
udp: gso: do not drop small packets when PMTU reduces
[ Upstream commit 235174b2bed88501fda689c113c55737f99332d8 ] Commit 4094871db1d6 ("udp: only do GSO if # of segs > 1") avoided GSO for small packets. But the kernel currently dismisses GSO requests only after checking MTU/PMTU on gso_size. This means any packets, regardless of their payload sizes, could be dropped when PMTU becomes smaller than requested gso_size. We encountered this issue in production and it caused a reliability problem that new QUIC connection cannot be established before PMTU cache expired, while non GSO sockets still worked fine at the same time. Ideally, do not check any GSO related constraints when payload size is smaller than requested gso_size, and return EMSGSIZE instead of EINVAL on MTU/PMTU check failure to be more specific on the error cause. Fixes: 4094871db1d6 ("udp: only do GSO if # of segs > 1") Signed-off-by: Yan Zhai <yan@cloudflare.com> Suggested-by: Willem de Bruijn <willemdebruijn.kernel@gmail.com> Reviewed-by: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/udp.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index d2eeb6fc49b3..8da74dc63061 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -985,9 +985,9 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4,
const int hlen = skb_network_header_len(skb) +
sizeof(struct udphdr);
- if (hlen + cork->gso_size > cork->fragsize) {
+ if (hlen + min(datalen, cork->gso_size) > cork->fragsize) {
kfree_skb(skb);
- return -EINVAL;
+ return -EMSGSIZE;
}
if (datalen > cork->gso_size * UDP_MAX_SEGMENTS) {
kfree_skb(skb);