aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_timer.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2017-05-23 15:38:35 -0400
committerDavid S. Miller <davem@davemloft.net>2017-05-24 16:29:57 -0400
commitce682ef6e3e019f98cafbdc7058668e0ea8f4a13 (patch)
tree771905210d14b2a9fdecfb27c4f2f4f8ecbb2743 /net/ipv4/tcp_timer.c
parent64dba236a15770af1e07f90f23a54789c9f9a3ba (diff)
tcp: fix TCP_SYNCNT flakes
After the mentioned commit, some of our packetdrill tests became flaky. TCP_SYNCNT socket option can limit the number of SYN retransmits. retransmits_timed_out() has to compare times computations based on local_clock() while timers are based on jiffies. With NTP adjustments and roundings we can observe 999 ms delay for 1000 ms timers. We end up sending one extra SYN packet. Gimmick added in commit 6fa12c850314 ("Revert Backoff [v3]: Calculate TCP's connection close threshold as a time value") makes no real sense for TCP_SYN_SENT sockets where no RTO backoff can happen at all. Lets use a simpler logic for TCP_SYN_SENT sockets and remove @syn_set parameter from retransmits_timed_out() Fixes: 9a568de4818d ("tcp: switch TCP TS option (RFC 7323) to 1ms clock") Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: Yuchung Cheng <ycheng@google.com> Acked-by: Soheil Hassas Yeganeh <soheil@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_timer.c')
-rw-r--r--net/ipv4/tcp_timer.c26
1 files changed, 11 insertions, 15 deletions
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index c4a35ba7f8ed..c0feeeef962a 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -139,21 +139,17 @@ static void tcp_mtu_probing(struct inet_connection_sock *icsk, struct sock *sk)
139 * @timeout: A custom timeout value. 139 * @timeout: A custom timeout value.
140 * If set to 0 the default timeout is calculated and used. 140 * If set to 0 the default timeout is calculated and used.
141 * Using TCP_RTO_MIN and the number of unsuccessful retransmits. 141 * Using TCP_RTO_MIN and the number of unsuccessful retransmits.
142 * @syn_set: true if the SYN Bit was set.
143 * 142 *
144 * The default "timeout" value this function can calculate and use 143 * The default "timeout" value this function can calculate and use
145 * is equivalent to the timeout of a TCP Connection 144 * is equivalent to the timeout of a TCP Connection
146 * after "boundary" unsuccessful, exponentially backed-off 145 * after "boundary" unsuccessful, exponentially backed-off
147 * retransmissions with an initial RTO of TCP_RTO_MIN or TCP_TIMEOUT_INIT if 146 * retransmissions with an initial RTO of TCP_RTO_MIN.
148 * syn_set flag is set.
149 *
150 */ 147 */
151static bool retransmits_timed_out(struct sock *sk, 148static bool retransmits_timed_out(struct sock *sk,
152 unsigned int boundary, 149 unsigned int boundary,
153 unsigned int timeout, 150 unsigned int timeout)
154 bool syn_set)
155{ 151{
156 unsigned int rto_base = syn_set ? TCP_TIMEOUT_INIT : TCP_RTO_MIN; 152 const unsigned int rto_base = TCP_RTO_MIN;
157 unsigned int linear_backoff_thresh, start_ts; 153 unsigned int linear_backoff_thresh, start_ts;
158 154
159 if (!inet_csk(sk)->icsk_retransmits) 155 if (!inet_csk(sk)->icsk_retransmits)
@@ -181,8 +177,8 @@ static int tcp_write_timeout(struct sock *sk)
181 struct inet_connection_sock *icsk = inet_csk(sk); 177 struct inet_connection_sock *icsk = inet_csk(sk);
182 struct tcp_sock *tp = tcp_sk(sk); 178 struct tcp_sock *tp = tcp_sk(sk);
183 struct net *net = sock_net(sk); 179 struct net *net = sock_net(sk);
180 bool expired, do_reset;
184 int retry_until; 181 int retry_until;
185 bool do_reset, syn_set = false;
186 182
187 if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { 183 if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
188 if (icsk->icsk_retransmits) { 184 if (icsk->icsk_retransmits) {
@@ -196,9 +192,9 @@ static int tcp_write_timeout(struct sock *sk)
196 sk_rethink_txhash(sk); 192 sk_rethink_txhash(sk);
197 } 193 }
198 retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries; 194 retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries;
199 syn_set = true; 195 expired = icsk->icsk_retransmits >= retry_until;
200 } else { 196 } else {
201 if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1, 0, 0)) { 197 if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1, 0)) {
202 /* Some middle-boxes may black-hole Fast Open _after_ 198 /* Some middle-boxes may black-hole Fast Open _after_
203 * the handshake. Therefore we conservatively disable 199 * the handshake. Therefore we conservatively disable
204 * Fast Open on this path on recurring timeouts after 200 * Fast Open on this path on recurring timeouts after
@@ -224,15 +220,15 @@ static int tcp_write_timeout(struct sock *sk)
224 220
225 retry_until = tcp_orphan_retries(sk, alive); 221 retry_until = tcp_orphan_retries(sk, alive);
226 do_reset = alive || 222 do_reset = alive ||
227 !retransmits_timed_out(sk, retry_until, 0, 0); 223 !retransmits_timed_out(sk, retry_until, 0);
228 224
229 if (tcp_out_of_resources(sk, do_reset)) 225 if (tcp_out_of_resources(sk, do_reset))
230 return 1; 226 return 1;
231 } 227 }
228 expired = retransmits_timed_out(sk, retry_until,
229 icsk->icsk_user_timeout);
232 } 230 }
233 231 if (expired) {
234 if (retransmits_timed_out(sk, retry_until,
235 syn_set ? 0 : icsk->icsk_user_timeout, syn_set)) {
236 /* Has it gone just too far? */ 232 /* Has it gone just too far? */
237 tcp_write_err(sk); 233 tcp_write_err(sk);
238 return 1; 234 return 1;
@@ -540,7 +536,7 @@ out_reset_timer:
540 icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); 536 icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
541 } 537 }
542 inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX); 538 inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
543 if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1 + 1, 0, 0)) 539 if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1 + 1, 0))
544 __sk_dst_reset(sk); 540 __sk_dst_reset(sk);
545 541
546out:; 542out:;