diff options
-rw-r--r-- | include/net/tcp.h | 6 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 10 | ||||
-rw-r--r-- | net/ipv4/tcp_metrics.c | 16 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 13 |
4 files changed, 37 insertions, 8 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h index c0258100d70c..e07878d246aa 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -409,9 +409,11 @@ extern bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst, | |||
409 | extern bool tcp_remember_stamp(struct sock *sk); | 409 | extern bool tcp_remember_stamp(struct sock *sk); |
410 | extern bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw); | 410 | extern bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw); |
411 | extern void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, | 411 | extern void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, |
412 | struct tcp_fastopen_cookie *cookie); | 412 | struct tcp_fastopen_cookie *cookie, |
413 | int *syn_loss, unsigned long *last_syn_loss); | ||
413 | extern void tcp_fastopen_cache_set(struct sock *sk, u16 mss, | 414 | extern void tcp_fastopen_cache_set(struct sock *sk, u16 mss, |
414 | struct tcp_fastopen_cookie *cookie); | 415 | struct tcp_fastopen_cookie *cookie, |
416 | bool syn_lost); | ||
415 | extern void tcp_fetch_timewait_stamp(struct sock *sk, struct dst_entry *dst); | 417 | extern void tcp_fetch_timewait_stamp(struct sock *sk, struct dst_entry *dst); |
416 | extern void tcp_disable_fack(struct tcp_sock *tp); | 418 | extern void tcp_disable_fack(struct tcp_sock *tp); |
417 | extern void tcp_close(struct sock *sk, long timeout); | 419 | extern void tcp_close(struct sock *sk, long timeout); |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 38b6a811edfc..c49a4fc175bd 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -5652,6 +5652,7 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, | |||
5652 | struct tcp_sock *tp = tcp_sk(sk); | 5652 | struct tcp_sock *tp = tcp_sk(sk); |
5653 | struct sk_buff *data = tcp_write_queue_head(sk); | 5653 | struct sk_buff *data = tcp_write_queue_head(sk); |
5654 | u16 mss = tp->rx_opt.mss_clamp; | 5654 | u16 mss = tp->rx_opt.mss_clamp; |
5655 | bool syn_drop; | ||
5655 | 5656 | ||
5656 | if (mss == tp->rx_opt.user_mss) { | 5657 | if (mss == tp->rx_opt.user_mss) { |
5657 | struct tcp_options_received opt; | 5658 | struct tcp_options_received opt; |
@@ -5664,7 +5665,14 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, | |||
5664 | mss = opt.mss_clamp; | 5665 | mss = opt.mss_clamp; |
5665 | } | 5666 | } |
5666 | 5667 | ||
5667 | tcp_fastopen_cache_set(sk, mss, cookie); | 5668 | /* The SYN-ACK neither has cookie nor acknowledges the data. Presumably |
5669 | * the remote receives only the retransmitted (regular) SYNs: either | ||
5670 | * the original SYN-data or the corresponding SYN-ACK is lost. | ||
5671 | */ | ||
5672 | syn_drop = (cookie->len <= 0 && data && | ||
5673 | inet_csk(sk)->icsk_retransmits); | ||
5674 | |||
5675 | tcp_fastopen_cache_set(sk, mss, cookie, syn_drop); | ||
5668 | 5676 | ||
5669 | if (data) { /* Retransmit unacked data in SYN */ | 5677 | if (data) { /* Retransmit unacked data in SYN */ |
5670 | tcp_retransmit_skb(sk, data); | 5678 | tcp_retransmit_skb(sk, data); |
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 | ||
33 | struct tcp_fastopen_metrics { | 33 | struct 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) | |||
644 | static DEFINE_SEQLOCK(fastopen_seqlock); | 647 | static DEFINE_SEQLOCK(fastopen_seqlock); |
645 | 648 | ||
646 | void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, | 649 | void 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 | |||
668 | void tcp_fastopen_cache_set(struct sock *sk, u16 mss, | 673 | void 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(); |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 88693281da4c..c5cfd5ec3184 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -2860,10 +2860,19 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) | |||
2860 | { | 2860 | { |
2861 | struct tcp_sock *tp = tcp_sk(sk); | 2861 | struct tcp_sock *tp = tcp_sk(sk); |
2862 | struct tcp_fastopen_request *fo = tp->fastopen_req; | 2862 | struct tcp_fastopen_request *fo = tp->fastopen_req; |
2863 | int space, i, err = 0, iovlen = fo->data->msg_iovlen; | 2863 | int syn_loss = 0, space, i, err = 0, iovlen = fo->data->msg_iovlen; |
2864 | struct sk_buff *syn_data = NULL, *data; | 2864 | struct sk_buff *syn_data = NULL, *data; |
2865 | unsigned long last_syn_loss = 0; | ||
2866 | |||
2867 | tcp_fastopen_cache_get(sk, &tp->rx_opt.mss_clamp, &fo->cookie, | ||
2868 | &syn_loss, &last_syn_loss); | ||
2869 | /* Recurring FO SYN losses: revert to regular handshake temporarily */ | ||
2870 | if (syn_loss > 1 && | ||
2871 | time_before(jiffies, last_syn_loss + (60*HZ << syn_loss))) { | ||
2872 | fo->cookie.len = -1; | ||
2873 | goto fallback; | ||
2874 | } | ||
2865 | 2875 | ||
2866 | tcp_fastopen_cache_get(sk, &tp->rx_opt.mss_clamp, &fo->cookie); | ||
2867 | if (fo->cookie.len <= 0) | 2876 | if (fo->cookie.len <= 0) |
2868 | goto fallback; | 2877 | goto fallback; |
2869 | 2878 | ||