Skip to content

Commit 7c1f081

Browse files
yuchungchengdavem330
authored andcommitted
tcp: undo initial congestion window on false SYN timeout
Linux implements RFC6298 and use an initial congestion window of 1 upon establishing the connection if the SYN packet is retransmitted 2 or more times. In cellular networks SYN timeouts are often spurious if the wireless radio was dormant or idle. Also some network path is longer than the default SYN timeout. Having a minimal cwnd on both cases are detrimental to TCP startup performance. This patch extends TCP undo feature (RFC3522 aka TCP Eifel) to detect spurious SYN timeout via TCP timestamps. Since tp->retrans_stamp records the initial SYN timestamp instead of first retransmission, we have to implement a different undo code additionally. The detection also must happen before tcp_ack() as retrans_stamp is reset when SYN is acknowledged. Note this patch covers both active regular and fast open. Signed-off-by: Yuchung Cheng <ycheng@google.com> Signed-off-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent bc9f38c commit 7c1f081

File tree

2 files changed

+17
-1
lines changed

2 files changed

+17
-1
lines changed

net/ipv4/tcp_input.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5748,6 +5748,21 @@ static void smc_check_reset_syn(struct tcp_sock *tp)
57485748
#endif
57495749
}
57505750

5751+
static void tcp_try_undo_spurious_syn(struct sock *sk)
5752+
{
5753+
struct tcp_sock *tp = tcp_sk(sk);
5754+
u32 syn_stamp;
5755+
5756+
/* undo_marker is set when SYN or SYNACK times out. The timeout is
5757+
* spurious if the ACK's timestamp option echo value matches the
5758+
* original SYN timestamp.
5759+
*/
5760+
syn_stamp = tp->retrans_stamp;
5761+
if (tp->undo_marker && syn_stamp && tp->rx_opt.saw_tstamp &&
5762+
syn_stamp == tp->rx_opt.rcv_tsecr)
5763+
tp->undo_marker = 0;
5764+
}
5765+
57515766
static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
57525767
const struct tcphdr *th)
57535768
{
@@ -5815,6 +5830,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
58155830
tcp_ecn_rcv_synack(tp, th);
58165831

58175832
tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);
5833+
tcp_try_undo_spurious_syn(sk);
58185834
tcp_ack(sk, skb, FLAG_SLOWPATH);
58195835

58205836
/* Ok.. it's good. Set up sequence numbers and

net/ipv4/tcp_metrics.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ void tcp_init_metrics(struct sock *sk)
517517
* initRTO, we only reset cwnd when more than 1 SYN/SYN-ACK
518518
* retransmission has occurred.
519519
*/
520-
if (tp->total_retrans > 1)
520+
if (tp->total_retrans > 1 && tp->undo_marker)
521521
tp->snd_cwnd = 1;
522522
else
523523
tp->snd_cwnd = tcp_init_cwnd(tp, dst);

0 commit comments

Comments
 (0)