aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Lee <Longinus00@gmail.com>2015-04-06 17:37:27 -0400
committerDavid S. Miller <davem@davemloft.net>2015-04-07 18:36:39 -0400
commit2646c831c00c5d22aa72b79d24069c1b412cda7c (patch)
treef6e61181b9dc10969a0501fc1e3a8af5be021dfe
parent7f9b838b71eb78a27de27a12ca5de8542fac3115 (diff)
tcp: RFC7413 option support for Fast Open client
Fast Open has been using an experimental option with a magic number (RFC6994). This patch makes the client by default use the RFC7413 option (34) to get and send Fast Open cookies. This patch makes the client solicit cookies from a given server first with the RFC7413 option. If that fails to elicit a cookie, then it tries the RFC6994 experimental option. If that also fails, it uses the RFC7413 option on all subsequent connect attempts. If the server returns a Fast Open cookie then the client caches the form of the option that successfully elicited a cookie, and uses that form on later connects when it presents that cookie. The idea is to gradually obsolete the use of experimental options as the servers and clients upgrade, while keeping the interoperability meanwhile. Signed-off-by: Daniel Lee <Longinus00@gmail.com> Signed-off-by: Yuchung Cheng <ycheng@google.com> Signed-off-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/tcp.h1
-rw-r--r--include/net/tcp.h3
-rw-r--r--net/ipv4/tcp_input.c29
-rw-r--r--net/ipv4/tcp_metrics.c13
-rw-r--r--net/ipv4/tcp_output.c6
-rw-r--r--net/ipv4/tcp_timer.c2
6 files changed, 39 insertions, 15 deletions
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index a48d00318683..0caa3a2d4106 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -189,6 +189,7 @@ struct tcp_sock {
189 u8 do_early_retrans:1,/* Enable RFC5827 early-retransmit */ 189 u8 do_early_retrans:1,/* Enable RFC5827 early-retransmit */
190 syn_data:1, /* SYN includes data */ 190 syn_data:1, /* SYN includes data */
191 syn_fastopen:1, /* SYN includes Fast Open option */ 191 syn_fastopen:1, /* SYN includes Fast Open option */
192 syn_fastopen_exp:1,/* SYN includes Fast Open exp. option */
192 syn_data_acked:1,/* data in SYN is acked by SYN-ACK */ 193 syn_data_acked:1,/* data in SYN is acked by SYN-ACK */
193 is_cwnd_limited:1;/* forward progress limited by snd_cwnd? */ 194 is_cwnd_limited:1;/* forward progress limited by snd_cwnd? */
194 u32 tlp_high_seq; /* snd_nxt at the time of TLP retransmit. */ 195 u32 tlp_high_seq; /* snd_nxt at the time of TLP retransmit. */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 7292c3c575bc..9598871485ce 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1339,7 +1339,8 @@ void tcp_fastopen_cache_get(struct sock *sk, u16 *mss,
1339 struct tcp_fastopen_cookie *cookie, int *syn_loss, 1339 struct tcp_fastopen_cookie *cookie, int *syn_loss,
1340 unsigned long *last_syn_loss); 1340 unsigned long *last_syn_loss);
1341void tcp_fastopen_cache_set(struct sock *sk, u16 mss, 1341void tcp_fastopen_cache_set(struct sock *sk, u16 mss,
1342 struct tcp_fastopen_cookie *cookie, bool syn_lost); 1342 struct tcp_fastopen_cookie *cookie, bool syn_lost,
1343 u16 try_exp);
1343struct tcp_fastopen_request { 1344struct tcp_fastopen_request {
1344 /* Fast Open cookie. Size 0 means a cookie request */ 1345 /* Fast Open cookie. Size 0 means a cookie request */
1345 struct tcp_fastopen_cookie cookie; 1346 struct tcp_fastopen_cookie cookie;
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
29struct tcp_fastopen_metrics { 29struct 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
723void tcp_fastopen_cache_set(struct sock *sk, u16 mss, 728void 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);