mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
Merge branch 'tcp-clean-up-syn-ack-rto-code-and-apply-max-rto'
Kuniyuki Iwashima says: ==================== tcp: Clean up SYN+ACK RTO code and apply max RTO. Patch 1 - 4 are misc cleanup. Patch 5 applies max RTO to non-TFO SYN+ACK. Patch 6 adds a test for max RTO of SYN+ACK. ==================== Link: https://patch.msgid.link/20251106003357.273403-1-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -267,8 +267,7 @@ struct dst_entry *inet_csk_route_child_sock(const struct sock *sk,
|
||||
struct sock *inet_csk_reqsk_queue_add(struct sock *sk,
|
||||
struct request_sock *req,
|
||||
struct sock *child);
|
||||
bool inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
|
||||
unsigned long timeout);
|
||||
bool inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req);
|
||||
struct sock *inet_csk_complete_hashdance(struct sock *sk, struct sock *child,
|
||||
struct request_sock *req,
|
||||
bool own_req);
|
||||
@@ -291,14 +290,6 @@ static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk)
|
||||
bool inet_csk_reqsk_queue_drop(struct sock *sk, struct request_sock *req);
|
||||
void inet_csk_reqsk_queue_drop_and_put(struct sock *sk, struct request_sock *req);
|
||||
|
||||
static inline unsigned long
|
||||
reqsk_timeout(struct request_sock *req, unsigned long max_timeout)
|
||||
{
|
||||
u64 timeout = (u64)req->timeout << req->num_timeout;
|
||||
|
||||
return (unsigned long)min_t(u64, timeout, max_timeout);
|
||||
}
|
||||
|
||||
void inet_csk_destroy_sock(struct sock *sk);
|
||||
void inet_csk_prepare_for_destroy_sock(struct sock *sk);
|
||||
void inet_csk_prepare_forced_close(struct sock *sk);
|
||||
|
||||
@@ -36,7 +36,6 @@ struct request_sock_ops {
|
||||
struct sk_buff *skb,
|
||||
enum sk_rst_reason reason);
|
||||
void (*destructor)(struct request_sock *req);
|
||||
void (*syn_ack_timeout)(const struct request_sock *req);
|
||||
};
|
||||
|
||||
struct saved_syn {
|
||||
|
||||
@@ -841,6 +841,14 @@ static inline u32 __tcp_set_rto(const struct tcp_sock *tp)
|
||||
return usecs_to_jiffies((tp->srtt_us >> 3) + tp->rttvar_us);
|
||||
}
|
||||
|
||||
static inline unsigned long tcp_reqsk_timeout(struct request_sock *req)
|
||||
{
|
||||
u64 timeout = (u64)req->timeout << req->num_timeout;
|
||||
|
||||
return (unsigned long)min_t(u64, timeout,
|
||||
tcp_rto_max(req->rsk_listener));
|
||||
}
|
||||
|
||||
u32 tcp_delack_max(const struct sock *sk);
|
||||
|
||||
/* Compute the actual rto_min value */
|
||||
|
||||
@@ -885,7 +885,6 @@ reqsk_alloc_noprof(const struct request_sock_ops *ops, struct sock *sk_listener,
|
||||
sk_tx_queue_clear(req_to_sk(req));
|
||||
req->saved_syn = NULL;
|
||||
req->syncookie = 0;
|
||||
req->timeout = 0;
|
||||
req->num_timeout = 0;
|
||||
req->num_retrans = 0;
|
||||
req->sk = NULL;
|
||||
@@ -913,7 +912,6 @@ struct request_sock *inet_reqsk_alloc(const struct request_sock_ops *ops,
|
||||
ireq->ireq_state = TCP_NEW_SYN_RECV;
|
||||
write_pnet(&ireq->ireq_net, sock_net(sk_listener));
|
||||
ireq->ireq_family = sk_listener->sk_family;
|
||||
req->timeout = TCP_TIMEOUT_INIT;
|
||||
}
|
||||
|
||||
return req;
|
||||
@@ -1096,16 +1094,18 @@ static void reqsk_timer_handler(struct timer_list *t)
|
||||
young <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
syn_ack_recalc(req, max_syn_ack_retries, READ_ONCE(queue->rskq_defer_accept),
|
||||
&expire, &resend);
|
||||
req->rsk_ops->syn_ack_timeout(req);
|
||||
tcp_syn_ack_timeout(req);
|
||||
|
||||
if (!expire &&
|
||||
(!resend ||
|
||||
!tcp_rtx_synack(sk_listener, req) ||
|
||||
inet_rsk(req)->acked)) {
|
||||
if (req->num_timeout++ == 0)
|
||||
atomic_dec(&queue->young);
|
||||
mod_timer(&req->rsk_timer, jiffies + reqsk_timeout(req, TCP_RTO_MAX));
|
||||
mod_timer(&req->rsk_timer, jiffies + tcp_reqsk_timeout(req));
|
||||
|
||||
if (!nreq)
|
||||
return;
|
||||
@@ -1142,8 +1142,7 @@ drop:
|
||||
reqsk_put(oreq);
|
||||
}
|
||||
|
||||
static bool reqsk_queue_hash_req(struct request_sock *req,
|
||||
unsigned long timeout)
|
||||
static bool reqsk_queue_hash_req(struct request_sock *req)
|
||||
{
|
||||
bool found_dup_sk = false;
|
||||
|
||||
@@ -1151,8 +1150,9 @@ static bool reqsk_queue_hash_req(struct request_sock *req,
|
||||
return false;
|
||||
|
||||
/* The timer needs to be setup after a successful insertion. */
|
||||
req->timeout = tcp_timeout_init((struct sock *)req);
|
||||
timer_setup(&req->rsk_timer, reqsk_timer_handler, TIMER_PINNED);
|
||||
mod_timer(&req->rsk_timer, jiffies + timeout);
|
||||
mod_timer(&req->rsk_timer, jiffies + req->timeout);
|
||||
|
||||
/* before letting lookups find us, make sure all req fields
|
||||
* are committed to memory and refcnt initialized.
|
||||
@@ -1162,10 +1162,9 @@ static bool reqsk_queue_hash_req(struct request_sock *req,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
|
||||
unsigned long timeout)
|
||||
bool inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req)
|
||||
{
|
||||
if (!reqsk_queue_hash_req(req, timeout))
|
||||
if (!reqsk_queue_hash_req(req))
|
||||
return false;
|
||||
|
||||
inet_csk_reqsk_queue_added(sk);
|
||||
|
||||
@@ -7531,15 +7531,11 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
|
||||
sock_put(fastopen_sk);
|
||||
} else {
|
||||
tcp_rsk(req)->tfo_listener = false;
|
||||
if (!want_cookie) {
|
||||
req->timeout = tcp_timeout_init((struct sock *)req);
|
||||
if (unlikely(!inet_csk_reqsk_queue_hash_add(sk, req,
|
||||
req->timeout))) {
|
||||
reqsk_free(req);
|
||||
dst_release(dst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!want_cookie &&
|
||||
unlikely(!inet_csk_reqsk_queue_hash_add(sk, req))) {
|
||||
reqsk_free(req);
|
||||
dst_release(dst);
|
||||
return 0;
|
||||
}
|
||||
af_ops->send_synack(sk, dst, &fl, req, &foc,
|
||||
!want_cookie ? TCP_SYNACK_NORMAL :
|
||||
|
||||
@@ -1660,7 +1660,6 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = {
|
||||
.send_ack = tcp_v4_reqsk_send_ack,
|
||||
.destructor = tcp_v4_reqsk_destructor,
|
||||
.send_reset = tcp_v4_send_reset,
|
||||
.syn_ack_timeout = tcp_syn_ack_timeout,
|
||||
};
|
||||
|
||||
const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = {
|
||||
|
||||
@@ -714,7 +714,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
|
||||
* it can be estimated (approximately)
|
||||
* from another data.
|
||||
*/
|
||||
tmp_opt.ts_recent_stamp = ktime_get_seconds() - reqsk_timeout(req, TCP_RTO_MAX) / HZ;
|
||||
tmp_opt.ts_recent_stamp = ktime_get_seconds() -
|
||||
tcp_reqsk_timeout(req) / HZ;
|
||||
paws_reject = tcp_paws_reject(&tmp_opt, th->rst);
|
||||
}
|
||||
}
|
||||
@@ -753,7 +754,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
|
||||
!tcp_rtx_synack(sk, req)) {
|
||||
unsigned long expires = jiffies;
|
||||
|
||||
expires += reqsk_timeout(req, TCP_RTO_MAX);
|
||||
expires += tcp_reqsk_timeout(req);
|
||||
if (!fastopen)
|
||||
mod_timer_pending(&req->rsk_timer, expires);
|
||||
else
|
||||
|
||||
@@ -458,7 +458,7 @@ static void tcp_fastopen_synack_timer(struct sock *sk, struct request_sock *req)
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
int max_retries;
|
||||
|
||||
req->rsk_ops->syn_ack_timeout(req);
|
||||
tcp_syn_ack_timeout(req);
|
||||
|
||||
/* Add one more retry for fastopen.
|
||||
* Paired with WRITE_ONCE() in tcp_sock_set_syncnt()
|
||||
@@ -752,7 +752,6 @@ void tcp_syn_ack_timeout(const struct request_sock *req)
|
||||
|
||||
__NET_INC_STATS(net, LINUX_MIB_TCPTIMEOUTS);
|
||||
}
|
||||
EXPORT_IPV6_MOD(tcp_syn_ack_timeout);
|
||||
|
||||
void tcp_reset_keepalive_timer(struct sock *sk, unsigned long len)
|
||||
{
|
||||
|
||||
@@ -796,7 +796,6 @@ struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
|
||||
.send_ack = tcp_v6_reqsk_send_ack,
|
||||
.destructor = tcp_v6_reqsk_destructor,
|
||||
.send_reset = tcp_v6_send_reset,
|
||||
.syn_ack_timeout = tcp_syn_ack_timeout,
|
||||
};
|
||||
|
||||
const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Test SYN+ACK RTX with 1s RTO.
|
||||
//
|
||||
`./defaults.sh
|
||||
./set_sysctls.py /proc/sys/net/ipv4/tcp_rto_max_ms=1000`
|
||||
|
||||
//
|
||||
// Test 1: TFO SYN+ACK
|
||||
//
|
||||
0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 3
|
||||
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
|
||||
+0 bind(3, ..., ...) = 0
|
||||
+0 listen(3, 1) = 0
|
||||
+0 setsockopt(3, SOL_TCP, TCP_FASTOPEN, [1], 4) = 0
|
||||
|
||||
+0 < S 0:10(10) win 1000 <mss 1460,sackOK,nop,nop,FO TFO_COOKIE,nop,nop>
|
||||
+0 > S. 0:0(0) ack 11 <mss 1460,nop,nop,sackOK>
|
||||
|
||||
// RTO must be capped to 1s
|
||||
+1 > S. 0:0(0) ack 11 <mss 1460,nop,nop,sackOK>
|
||||
+1 > S. 0:0(0) ack 11 <mss 1460,nop,nop,sackOK>
|
||||
+1 > S. 0:0(0) ack 11 <mss 1460,nop,nop,sackOK>
|
||||
|
||||
+0 < . 11:11(0) ack 1 win 1000 <mss 1460,nop,nop,sackOK>
|
||||
+0 accept(3, ..., ...) = 4
|
||||
+0 %{ assert (tcpi_options & TCPI_OPT_SYN_DATA) != 0, tcpi_options }%
|
||||
|
||||
+0 close(4) = 0
|
||||
+0 close(3) = 0
|
||||
|
||||
|
||||
//
|
||||
// Test 2: non-TFO SYN+ACK
|
||||
//
|
||||
+0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 3
|
||||
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
|
||||
+0 bind(3, ..., ...) = 0
|
||||
+0 listen(3, 1) = 0
|
||||
|
||||
+0 < S 0:0(0) win 1000 <mss 1460,sackOK,nop,nop>
|
||||
+0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK>
|
||||
|
||||
// RTO must be capped to 1s
|
||||
+1 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK>
|
||||
+1 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK>
|
||||
+1 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK>
|
||||
|
||||
+0 < . 1:1(0) ack 1 win 1000 <mss 1460,nop,nop,sackOK>
|
||||
+0 accept(3, ..., ...) = 4
|
||||
+0 %{ assert (tcpi_options & TCPI_OPT_SYN_DATA) == 0, tcpi_options }%
|
||||
|
||||
+0 close(4) = 0
|
||||
+0 close(3) = 0
|
||||
Reference in New Issue
Block a user