]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
udp: gso: do not drop small packets when PMTU reduces
authorYan Zhai <yan@cloudflare.com>
Fri, 31 Jan 2025 08:31:39 +0000 (00:31 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 3 Feb 2025 10:13:27 +0000 (10:13 +0000)
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>
net/ipv4/udp.c
net/ipv6/udp.c
tools/testing/selftests/net/udpgso.c

index c472c9a57cf68880a277603b4a771152c6f79ff6..a9bb9ce5438eaa9f9ceede1e4ac080dc6ab74588 100644 (file)
@@ -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);
index 6671daa67f4fab28f847bd4d8475ef752a63f05d..c6ea438b5c7588edd2971997f21382c26446a45c 100644 (file)
@@ -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);
index 3f2fca02fec53f52beaddb43ea4255bca24b79b8..36ff28af4b19059204728d13c0155c5a5cc84bba 100644 (file)
@@ -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,