diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/tcp_input.c | 29 | ||||
-rw-r--r-- | net/ipv4/tcp_metrics.c | 13 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 6 | ||||
-rw-r--r-- | net/ipv4/tcp_timer.c | 2 |
4 files changed, 36 insertions, 14 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 24f1630b2afb..031cf72cd05c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -5378,8 +5378,8 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, | |||
5378 | { | 5378 | { |
5379 | struct tcp_sock *tp = tcp_sk(sk); | 5379 | struct tcp_sock *tp = tcp_sk(sk); |
5380 | struct sk_buff *data = tp->syn_data ? tcp_write_queue_head(sk) : NULL; | 5380 | struct sk_buff *data = tp->syn_data ? tcp_write_queue_head(sk) : NULL; |
5381 | u16 mss = tp->rx_opt.mss_clamp; | 5381 | u16 mss = tp->rx_opt.mss_clamp, try_exp = 0; |
5382 | bool syn_drop; | 5382 | bool syn_drop = false; |
5383 | 5383 | ||
5384 | if (mss == tp->rx_opt.user_mss) { | 5384 | if (mss == tp->rx_opt.user_mss) { |
5385 | struct tcp_options_received opt; | 5385 | struct tcp_options_received opt; |
@@ -5391,16 +5391,25 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, | |||
5391 | mss = opt.mss_clamp; | 5391 | mss = opt.mss_clamp; |
5392 | } | 5392 | } |
5393 | 5393 | ||
5394 | if (!tp->syn_fastopen) /* Ignore an unsolicited cookie */ | 5394 | if (!tp->syn_fastopen) { |
5395 | /* Ignore an unsolicited cookie */ | ||
5395 | cookie->len = -1; | 5396 | cookie->len = -1; |
5397 | } else if (tp->total_retrans) { | ||
5398 | /* SYN timed out and the SYN-ACK neither has a cookie nor | ||
5399 | * acknowledges data. Presumably the remote received only | ||
5400 | * the retransmitted (regular) SYNs: either the original | ||
5401 | * SYN-data or the corresponding SYN-ACK was dropped. | ||
5402 | */ | ||
5403 | syn_drop = (cookie->len < 0 && data); | ||
5404 | } else if (cookie->len < 0 && !tp->syn_data) { | ||
5405 | /* We requested a cookie but didn't get it. If we did not use | ||
5406 | * the (old) exp opt format then try so next time (try_exp=1). | ||
5407 | * Otherwise we go back to use the RFC7413 opt (try_exp=2). | ||
5408 | */ | ||
5409 | try_exp = tp->syn_fastopen_exp ? 2 : 1; | ||
5410 | } | ||
5396 | 5411 | ||
5397 | /* The SYN-ACK neither has cookie nor acknowledges the data. Presumably | 5412 | tcp_fastopen_cache_set(sk, mss, cookie, syn_drop, try_exp); |
5398 | * the remote receives only the retransmitted (regular) SYNs: either | ||
5399 | * the original SYN-data or the corresponding SYN-ACK is lost. | ||
5400 | */ | ||
5401 | syn_drop = (cookie->len <= 0 && data && tp->total_retrans); | ||
5402 | |||
5403 | tcp_fastopen_cache_set(sk, mss, cookie, syn_drop); | ||
5404 | 5413 | ||
5405 | if (data) { /* Retransmit unacked data in SYN */ | 5414 | if (data) { /* Retransmit unacked data in SYN */ |
5406 | tcp_for_write_queue_from(data, sk) { | 5415 | tcp_for_write_queue_from(data, sk) { |
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 78ecc4a01712..a51d63a43e33 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c | |||
@@ -28,7 +28,8 @@ static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *s | |||
28 | 28 | ||
29 | struct tcp_fastopen_metrics { | 29 | struct tcp_fastopen_metrics { |
30 | u16 mss; | 30 | u16 mss; |
31 | u16 syn_loss:10; /* Recurring Fast Open SYN losses */ | 31 | u16 syn_loss:10, /* Recurring Fast Open SYN losses */ |
32 | try_exp:2; /* Request w/ exp. option (once) */ | ||
32 | unsigned long last_syn_loss; /* Last Fast Open SYN loss */ | 33 | unsigned long last_syn_loss; /* Last Fast Open SYN loss */ |
33 | struct tcp_fastopen_cookie cookie; | 34 | struct tcp_fastopen_cookie cookie; |
34 | }; | 35 | }; |
@@ -131,6 +132,8 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm, | |||
131 | if (fastopen_clear) { | 132 | if (fastopen_clear) { |
132 | tm->tcpm_fastopen.mss = 0; | 133 | tm->tcpm_fastopen.mss = 0; |
133 | tm->tcpm_fastopen.syn_loss = 0; | 134 | tm->tcpm_fastopen.syn_loss = 0; |
135 | tm->tcpm_fastopen.try_exp = 0; | ||
136 | tm->tcpm_fastopen.cookie.exp = false; | ||
134 | tm->tcpm_fastopen.cookie.len = 0; | 137 | tm->tcpm_fastopen.cookie.len = 0; |
135 | } | 138 | } |
136 | } | 139 | } |
@@ -713,6 +716,8 @@ void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, | |||
713 | if (tfom->mss) | 716 | if (tfom->mss) |
714 | *mss = tfom->mss; | 717 | *mss = tfom->mss; |
715 | *cookie = tfom->cookie; | 718 | *cookie = tfom->cookie; |
719 | if (cookie->len <= 0 && tfom->try_exp == 1) | ||
720 | cookie->exp = true; | ||
716 | *syn_loss = tfom->syn_loss; | 721 | *syn_loss = tfom->syn_loss; |
717 | *last_syn_loss = *syn_loss ? tfom->last_syn_loss : 0; | 722 | *last_syn_loss = *syn_loss ? tfom->last_syn_loss : 0; |
718 | } while (read_seqretry(&fastopen_seqlock, seq)); | 723 | } while (read_seqretry(&fastopen_seqlock, seq)); |
@@ -721,7 +726,8 @@ void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, | |||
721 | } | 726 | } |
722 | 727 | ||
723 | void tcp_fastopen_cache_set(struct sock *sk, u16 mss, | 728 | void tcp_fastopen_cache_set(struct sock *sk, u16 mss, |
724 | struct tcp_fastopen_cookie *cookie, bool syn_lost) | 729 | struct tcp_fastopen_cookie *cookie, bool syn_lost, |
730 | u16 try_exp) | ||
725 | { | 731 | { |
726 | struct dst_entry *dst = __sk_dst_get(sk); | 732 | struct dst_entry *dst = __sk_dst_get(sk); |
727 | struct tcp_metrics_block *tm; | 733 | struct tcp_metrics_block *tm; |
@@ -738,6 +744,9 @@ void tcp_fastopen_cache_set(struct sock *sk, u16 mss, | |||
738 | tfom->mss = mss; | 744 | tfom->mss = mss; |
739 | if (cookie && cookie->len > 0) | 745 | if (cookie && cookie->len > 0) |
740 | tfom->cookie = *cookie; | 746 | tfom->cookie = *cookie; |
747 | else if (try_exp > tfom->try_exp && | ||
748 | tfom->cookie.len <= 0 && !tfom->cookie.exp) | ||
749 | tfom->try_exp = try_exp; | ||
741 | if (syn_lost) { | 750 | if (syn_lost) { |
742 | ++tfom->syn_loss; | 751 | ++tfom->syn_loss; |
743 | tfom->last_syn_loss = jiffies; | 752 | tfom->last_syn_loss = jiffies; |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 464bd8c5de69..e662d85d1635 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -592,13 +592,17 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb, | |||
592 | } | 592 | } |
593 | 593 | ||
594 | if (fastopen && fastopen->cookie.len >= 0) { | 594 | if (fastopen && fastopen->cookie.len >= 0) { |
595 | u32 need = TCPOLEN_EXP_FASTOPEN_BASE + fastopen->cookie.len; | 595 | u32 need = fastopen->cookie.len; |
596 | |||
597 | need += fastopen->cookie.exp ? TCPOLEN_EXP_FASTOPEN_BASE : | ||
598 | TCPOLEN_FASTOPEN_BASE; | ||
596 | need = (need + 3) & ~3U; /* Align to 32 bits */ | 599 | need = (need + 3) & ~3U; /* Align to 32 bits */ |
597 | if (remaining >= need) { | 600 | if (remaining >= need) { |
598 | opts->options |= OPTION_FAST_OPEN_COOKIE; | 601 | opts->options |= OPTION_FAST_OPEN_COOKIE; |
599 | opts->fastopen_cookie = &fastopen->cookie; | 602 | opts->fastopen_cookie = &fastopen->cookie; |
600 | remaining -= need; | 603 | remaining -= need; |
601 | tp->syn_fastopen = 1; | 604 | tp->syn_fastopen = 1; |
605 | tp->syn_fastopen_exp = fastopen->cookie.exp ? 1 : 0; | ||
602 | } | 606 | } |
603 | } | 607 | } |
604 | 608 | ||
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 2568fd282873..8c65dc147d8b 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c | |||
@@ -167,7 +167,7 @@ static int tcp_write_timeout(struct sock *sk) | |||
167 | if (icsk->icsk_retransmits) { | 167 | if (icsk->icsk_retransmits) { |
168 | dst_negative_advice(sk); | 168 | dst_negative_advice(sk); |
169 | if (tp->syn_fastopen || tp->syn_data) | 169 | if (tp->syn_fastopen || tp->syn_data) |
170 | tcp_fastopen_cache_set(sk, 0, NULL, true); | 170 | tcp_fastopen_cache_set(sk, 0, NULL, true, 0); |
171 | if (tp->syn_data) | 171 | if (tp->syn_data) |
172 | NET_INC_STATS_BH(sock_net(sk), | 172 | NET_INC_STATS_BH(sock_net(sk), |
173 | LINUX_MIB_TCPFASTOPENACTIVEFAIL); | 173 | LINUX_MIB_TCPFASTOPENACTIVEFAIL); |