Commit a9782a6f2bbd for kernel
commit a9782a6f2bbd0c444689725a710d8b21eab61bc5
Author: Kuniyuki Iwashima <kuniyu@google.com>
Date: Wed Nov 11 02:03:00 2026 +0000
tcp: Pass req->rsk_listener to inet_csk_reqsk_queue_drop() in tcp_check_req().
When connection migration happens in tcp_v[46]_rcv(), a new
listener is passed to tcp_check_req().
When either of the following is true,
* the new listener queue is full and
net.ipv4.tcp_abort_on_overflow is set
* the packet has RST or (not stripped) SYN
tcp_check_req() sends RST and calls inet_csk_reqsk_queue_drop().
Here, the new listener is passed, and its qlen is decremented
wrongly while reqsk is tied to the old listener.
Once qlen underflows, inet_csk_reqsk_queue_is_full() always
return true, and the new listener stops serving.
Without the patch, this script times out while waiting for SYN+ACK
since the new listener drops SYN, but with the patch, 3WHS completes.
0 `sysctl -q net.ipv4.tcp_migrate_req=1`
+0 `sysctl -q net.ipv4.tcp_syncookies=0`
+0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEPORT, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 4
+0 setsockopt(4, SOL_SOCKET, SO_REUSEPORT, [1], 4) = 0
+0 bind(4, ..., ...) = 0
+0 listen(4, 128) = 0
+0 < S 0:0(0) win 32792 <mss 1000>
+0 > S. 0:0(0) ack 1 <...>
+0 listen(3, 128) = 0
+0 close(4) = 0
+.01 < R 1:1(0) win 0
+0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 5
+0 listen(5, 1) = 0
+.01 < S 0:0(0) win 32792 <mss 1000>
+0 > S. 0:0(0) ack 1 <...>
+0 < . 1:1(0) ack 1 win 32792
+0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
+0 accept(3, ..., ...) = 6
Let's pass req->rsk_listener instead.
Fixes: d4f2c86b2b7e ("tcp: Migrate TCP_NEW_SYN_RECV requests at receiving the final ACK.")
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20261111020304.1532064-2-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 0ddfd5af6e58..a05bb02e204c 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -974,7 +974,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
tcp_reset(sk, skb);
}
if (!fastopen) {
- bool unlinked = inet_csk_reqsk_queue_drop(sk, req);
+ bool unlinked = inet_csk_reqsk_queue_drop(req->rsk_listener, req);
if (unlinked)
__NET_INC_STATS(sock_net(sk), LINUX_MIB_EMBRYONICRSTS);