udp: gso: do not drop small packets when PMTU reduces
Subsystems (4)
PATCH v3 1/1 udp: gso: do not drop small packets when PMTU reduces
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.
---v2->v3: simplify the code; adding two test casesv1->v2: add a missing MTU check when fall back to no GSO mode; Fixed up commit message to be more precise.
v2: https://lore.kernel.org/netdev/[email protected]/T/#u
v1: https://lore.kernel.org/all/Z5cgWh%[email protected]/
--- net/ipv4/udp.c | 4 ++-- net/ipv6/udp.c | 4 ++-- tools/testing/selftests/net/udpgso.c | 26 ++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-)
net/ipv4/udp.c +2 -2
@@ -1141,9 +1141,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);
net/ipv6/udp.c +2 -2
@@ -1389,9 +1389,9 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6,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);
tools/testing/selftests/net/udpgso.c +26 -0
@@ -102,6 +102,19 @@ struct testcase testcases_v4[] = { .gso_len = CONST_MSS_V4, .r_num_mss = 1, }, + { + /* datalen <= MSS < gso_len: will fall back to no GSO */ + .tlen = CONST_MSS_V4, + .gso_len = CONST_MSS_V4 + 1, + .r_num_mss = 0, + .r_len_last = CONST_MSS_V4, + }, + { + /* MSS < datalen < gso_len: fail */ + .tlen = CONST_MSS_V4 + 1, + .gso_len = CONST_MSS_V4 + 2, + .tfail = true, + }, { /* send a single MSS + 1B */ .tlen = CONST_MSS_V4 + 1,
@@ -205,6 +218,19 @@ struct testcase testcases_v6[] = { .gso_len = CONST_MSS_V6, .r_num_mss = 1, }, + { + /* datalen <= MSS < gso_len: will fall back to no GSO */ + .tlen = CONST_MSS_V6, + .gso_len = CONST_MSS_V6 + 1, + .r_num_mss = 0, + .r_len_last = CONST_MSS_V6, + }, + { + /* MSS < datalen < gso_len: fail */ + .tlen = CONST_MSS_V6 + 1, + .gso_len = CONST_MSS_V6 + 2, + .tfail = true + }, { /* send a single MSS + 1B */ .tlen = CONST_MSS_V6 + 1,
Signature · 1 line
2.30.2
Quoted 9 lines · Yan Zhai
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 ongso_size. This means any packets, regardless of their payload sizes, could be dropped when PMTU becomes smaller than requestedgso_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.
Quoted 7 lines
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 <[email protected]>Suggested-by Willem de Bruijn <[email protected]>
This patch was applied to netdev/net.git (main) by David S. Miller <[email protected]>:
Hello:
This patch was applied to netdev/net.git (main)
by David S. Miller <[email protected]>:
Quoted 10 lines · On Fri, 31 Jan 2025 00:31:39 -0800 you wrote:
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 ongso_size. This means any packets, regardless of their payload sizes, could be dropped when PMTU becomes smaller than requestedgso_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.[...]
Here is the summary with links:
- [v3,net] udp: gso: do not drop small packets when PMTU reduces
https://git.kernel.org/netdev/net/c/235174b2bed8
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html