Skip to content

Commit 235174b

Browse files
Yan Zhaidavem330
authored andcommitted
udp: gso: do not drop small packets when PMTU reduces
Commit 4094871 ("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: 4094871 ("udp: only do GSO if # of segs > 1") Signed-off-by: Yan Zhai <[email protected]> Suggested-by: Willem de Bruijn <[email protected]> Reviewed-by: Willem de Bruijn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e0efe83 commit 235174b

File tree

3 files changed

+30
-4
lines changed

3 files changed

+30
-4
lines changed

net/ipv4/udp.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,9 +1141,9 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4,
11411141
const int hlen = skb_network_header_len(skb) +
11421142
sizeof(struct udphdr);
11431143

1144-
if (hlen + cork->gso_size > cork->fragsize) {
1144+
if (hlen + min(datalen, cork->gso_size) > cork->fragsize) {
11451145
kfree_skb(skb);
1146-
return -EINVAL;
1146+
return -EMSGSIZE;
11471147
}
11481148
if (datalen > cork->gso_size * UDP_MAX_SEGMENTS) {
11491149
kfree_skb(skb);

net/ipv6/udp.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,9 +1389,9 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6,
13891389
const int hlen = skb_network_header_len(skb) +
13901390
sizeof(struct udphdr);
13911391

1392-
if (hlen + cork->gso_size > cork->fragsize) {
1392+
if (hlen + min(datalen, cork->gso_size) > cork->fragsize) {
13931393
kfree_skb(skb);
1394-
return -EINVAL;
1394+
return -EMSGSIZE;
13951395
}
13961396
if (datalen > cork->gso_size * UDP_MAX_SEGMENTS) {
13971397
kfree_skb(skb);

tools/testing/selftests/net/udpgso.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,19 @@ struct testcase testcases_v4[] = {
102102
.gso_len = CONST_MSS_V4,
103103
.r_num_mss = 1,
104104
},
105+
{
106+
/* datalen <= MSS < gso_len: will fall back to no GSO */
107+
.tlen = CONST_MSS_V4,
108+
.gso_len = CONST_MSS_V4 + 1,
109+
.r_num_mss = 0,
110+
.r_len_last = CONST_MSS_V4,
111+
},
112+
{
113+
/* MSS < datalen < gso_len: fail */
114+
.tlen = CONST_MSS_V4 + 1,
115+
.gso_len = CONST_MSS_V4 + 2,
116+
.tfail = true,
117+
},
105118
{
106119
/* send a single MSS + 1B */
107120
.tlen = CONST_MSS_V4 + 1,
@@ -205,6 +218,19 @@ struct testcase testcases_v6[] = {
205218
.gso_len = CONST_MSS_V6,
206219
.r_num_mss = 1,
207220
},
221+
{
222+
/* datalen <= MSS < gso_len: will fall back to no GSO */
223+
.tlen = CONST_MSS_V6,
224+
.gso_len = CONST_MSS_V6 + 1,
225+
.r_num_mss = 0,
226+
.r_len_last = CONST_MSS_V6,
227+
},
228+
{
229+
/* MSS < datalen < gso_len: fail */
230+
.tlen = CONST_MSS_V6 + 1,
231+
.gso_len = CONST_MSS_V6 + 2,
232+
.tfail = true
233+
},
208234
{
209235
/* send a single MSS + 1B */
210236
.tlen = CONST_MSS_V6 + 1,

0 commit comments

Comments
 (0)