aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_metrics.c
diff options
context:
space:
mode:
authorYuchung Cheng <ycheng@google.com>2012-07-19 02:43:10 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-19 14:02:03 -0400
commitaab4874355679c70f93993cf3b3fd74643b9ac33 (patch)
tree677d3faf161e39f9de18b5956e24cd746e73d996 /net/ipv4/tcp_metrics.c
parentcf60af03ca4e71134206809ea892e49b92a88896 (diff)
net-tcp: Fast Open client - detecting SYN-data drops
On paths with firewalls dropping SYN with data or experimental TCP options, Fast Open connections will have experience SYN timeout and bad performance. The solution is to track such incidents in the cookie cache and disables Fast Open temporarily. Since only the original SYN includes data and/or Fast Open option, the SYN-ACK has some tell-tale sign (tcp_rcv_fastopen_synack()) to detect such drops. If a path has recurring Fast Open SYN drops, Fast Open is disabled for 2^(recurring_losses) minutes starting from four minutes up to roughly one and half day. sendmsg with MSG_FASTOPEN flag will succeed but it behaves as connect() then write(). Signed-off-by: Yuchung Cheng <ycheng@google.com> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_metrics.c')
-rw-r--r--net/ipv4/tcp_metrics.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c
index d02ff3777785..99779ae44f64 100644
--- a/net/ipv4/tcp_metrics.c
+++ b/net/ipv4/tcp_metrics.c
@@ -32,6 +32,8 @@ enum tcp_metric_index {
32 32
33struct tcp_fastopen_metrics { 33struct tcp_fastopen_metrics {
34 u16 mss; 34 u16 mss;
35 u16 syn_loss:10; /* Recurring Fast Open SYN losses */
36 unsigned long last_syn_loss; /* Last Fast Open SYN loss */
35 struct tcp_fastopen_cookie cookie; 37 struct tcp_fastopen_cookie cookie;
36}; 38};
37 39
@@ -125,6 +127,7 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm, struct dst_entry *dst)
125 tm->tcpm_ts = 0; 127 tm->tcpm_ts = 0;
126 tm->tcpm_ts_stamp = 0; 128 tm->tcpm_ts_stamp = 0;
127 tm->tcpm_fastopen.mss = 0; 129 tm->tcpm_fastopen.mss = 0;
130 tm->tcpm_fastopen.syn_loss = 0;
128 tm->tcpm_fastopen.cookie.len = 0; 131 tm->tcpm_fastopen.cookie.len = 0;
129} 132}
130 133
@@ -644,7 +647,8 @@ bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw)
644static DEFINE_SEQLOCK(fastopen_seqlock); 647static DEFINE_SEQLOCK(fastopen_seqlock);
645 648
646void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, 649void tcp_fastopen_cache_get(struct sock *sk, u16 *mss,
647 struct tcp_fastopen_cookie *cookie) 650 struct tcp_fastopen_cookie *cookie,
651 int *syn_loss, unsigned long *last_syn_loss)
648{ 652{
649 struct tcp_metrics_block *tm; 653 struct tcp_metrics_block *tm;
650 654
@@ -659,14 +663,15 @@ void tcp_fastopen_cache_get(struct sock *sk, u16 *mss,
659 if (tfom->mss) 663 if (tfom->mss)
660 *mss = tfom->mss; 664 *mss = tfom->mss;
661 *cookie = tfom->cookie; 665 *cookie = tfom->cookie;
666 *syn_loss = tfom->syn_loss;
667 *last_syn_loss = *syn_loss ? tfom->last_syn_loss : 0;
662 } while (read_seqretry(&fastopen_seqlock, seq)); 668 } while (read_seqretry(&fastopen_seqlock, seq));
663 } 669 }
664 rcu_read_unlock(); 670 rcu_read_unlock();
665} 671}
666 672
667
668void tcp_fastopen_cache_set(struct sock *sk, u16 mss, 673void tcp_fastopen_cache_set(struct sock *sk, u16 mss,
669 struct tcp_fastopen_cookie *cookie) 674 struct tcp_fastopen_cookie *cookie, bool syn_lost)
670{ 675{
671 struct tcp_metrics_block *tm; 676 struct tcp_metrics_block *tm;
672 677
@@ -679,6 +684,11 @@ void tcp_fastopen_cache_set(struct sock *sk, u16 mss,
679 tfom->mss = mss; 684 tfom->mss = mss;
680 if (cookie->len > 0) 685 if (cookie->len > 0)
681 tfom->cookie = *cookie; 686 tfom->cookie = *cookie;
687 if (syn_lost) {
688 ++tfom->syn_loss;
689 tfom->last_syn_loss = jiffies;
690 } else
691 tfom->syn_loss = 0;
682 write_sequnlock_bh(&fastopen_seqlock); 692 write_sequnlock_bh(&fastopen_seqlock);
683 } 693 }
684 rcu_read_unlock(); 694 rcu_read_unlock();