aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYuchung Cheng <ycheng@google.com>2012-07-19 02:43:05 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-19 13:55:36 -0400
commit2100c8d2d9db23c0a09901a782bb4e3b21bee298 (patch)
treefd5842c540bf77c3fa546797c1c8e94f054cc86c
parent4cce66cdd14aa5006a011505865d932adb49f600 (diff)
net-tcp: Fast Open base
This patch impelements the common code for both the client and server. 1. TCP Fast Open option processing. Since Fast Open does not have an option number assigned by IANA yet, it shares the experiment option code 254 by implementing draft-ietf-tcpm-experimental-options with a 16 bits magic number 0xF989. This enables global experiments without clashing the scarce(2) experimental options available for TCP. When the draft status becomes standard (maybe), the client should switch to the new option number assigned while the server supports both numbers for transistion. 2. The new sysctl tcp_fastopen 3. A place holder init function Signed-off-by: Yuchung Cheng <ycheng@google.com> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/tcp.h10
-rw-r--r--include/net/tcp.h9
-rw-r--r--net/ipv4/Makefile2
-rw-r--r--net/ipv4/syncookies.c2
-rw-r--r--net/ipv4/sysctl_net_ipv4.c7
-rw-r--r--net/ipv4/tcp_fastopen.c11
-rw-r--r--net/ipv4/tcp_input.c26
-rw-r--r--net/ipv4/tcp_ipv4.c2
-rw-r--r--net/ipv4/tcp_minisocks.c4
-rw-r--r--net/ipv4/tcp_output.c25
-rw-r--r--net/ipv6/syncookies.c2
-rw-r--r--net/ipv6/tcp_ipv6.c2
12 files changed, 86 insertions, 16 deletions
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 1888169e07c7..12948f543839 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -243,6 +243,16 @@ static inline unsigned int tcp_optlen(const struct sk_buff *skb)
243 return (tcp_hdr(skb)->doff - 5) * 4; 243 return (tcp_hdr(skb)->doff - 5) * 4;
244} 244}
245 245
246/* TCP Fast Open */
247#define TCP_FASTOPEN_COOKIE_MIN 4 /* Min Fast Open Cookie size in bytes */
248#define TCP_FASTOPEN_COOKIE_MAX 16 /* Max Fast Open Cookie size in bytes */
249
250/* TCP Fast Open Cookie as stored in memory */
251struct tcp_fastopen_cookie {
252 s8 len;
253 u8 val[TCP_FASTOPEN_COOKIE_MAX];
254};
255
246/* This defines a selective acknowledgement block. */ 256/* This defines a selective acknowledgement block. */
247struct tcp_sack_block_wire { 257struct tcp_sack_block_wire {
248 __be32 start_seq; 258 __be32 start_seq;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 85c5090bfe25..5aed3718fde8 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -170,6 +170,11 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
170#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ 170#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */
171#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ 171#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */
172#define TCPOPT_COOKIE 253 /* Cookie extension (experimental) */ 172#define TCPOPT_COOKIE 253 /* Cookie extension (experimental) */
173#define TCPOPT_EXP 254 /* Experimental */
174/* Magic number to be after the option value for sharing TCP
175 * experimental options. See draft-ietf-tcpm-experimental-options-00.txt
176 */
177#define TCPOPT_FASTOPEN_MAGIC 0xF989
173 178
174/* 179/*
175 * TCP option lengths 180 * TCP option lengths
@@ -180,6 +185,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
180#define TCPOLEN_SACK_PERM 2 185#define TCPOLEN_SACK_PERM 2
181#define TCPOLEN_TIMESTAMP 10 186#define TCPOLEN_TIMESTAMP 10
182#define TCPOLEN_MD5SIG 18 187#define TCPOLEN_MD5SIG 18
188#define TCPOLEN_EXP_FASTOPEN_BASE 4
183#define TCPOLEN_COOKIE_BASE 2 /* Cookie-less header extension */ 189#define TCPOLEN_COOKIE_BASE 2 /* Cookie-less header extension */
184#define TCPOLEN_COOKIE_PAIR 3 /* Cookie pair header extension */ 190#define TCPOLEN_COOKIE_PAIR 3 /* Cookie pair header extension */
185#define TCPOLEN_COOKIE_MIN (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MIN) 191#define TCPOLEN_COOKIE_MIN (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MIN)
@@ -222,6 +228,7 @@ extern int sysctl_tcp_retries1;
222extern int sysctl_tcp_retries2; 228extern int sysctl_tcp_retries2;
223extern int sysctl_tcp_orphan_retries; 229extern int sysctl_tcp_orphan_retries;
224extern int sysctl_tcp_syncookies; 230extern int sysctl_tcp_syncookies;
231extern int sysctl_tcp_fastopen;
225extern int sysctl_tcp_retrans_collapse; 232extern int sysctl_tcp_retrans_collapse;
226extern int sysctl_tcp_stdurg; 233extern int sysctl_tcp_stdurg;
227extern int sysctl_tcp_rfc1337; 234extern int sysctl_tcp_rfc1337;
@@ -418,7 +425,7 @@ extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
418 size_t len, int nonblock, int flags, int *addr_len); 425 size_t len, int nonblock, int flags, int *addr_len);
419extern void tcp_parse_options(const struct sk_buff *skb, 426extern void tcp_parse_options(const struct sk_buff *skb,
420 struct tcp_options_received *opt_rx, const u8 **hvpp, 427 struct tcp_options_received *opt_rx, const u8 **hvpp,
421 int estab); 428 int estab, struct tcp_fastopen_cookie *foc);
422extern const u8 *tcp_parse_md5sig_option(const struct tcphdr *th); 429extern const u8 *tcp_parse_md5sig_option(const struct tcphdr *th);
423 430
424/* 431/*
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index a677d804e53e..ae2ccf2890e4 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -7,7 +7,7 @@ obj-y := route.o inetpeer.o protocol.o \
7 ip_output.o ip_sockglue.o inet_hashtables.o \ 7 ip_output.o ip_sockglue.o inet_hashtables.o \
8 inet_timewait_sock.o inet_connection_sock.o \ 8 inet_timewait_sock.o inet_connection_sock.o \
9 tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ 9 tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \
10 tcp_minisocks.o tcp_cong.o tcp_metrics.o \ 10 tcp_minisocks.o tcp_cong.o tcp_metrics.o tcp_fastopen.o \
11 datagram.o raw.o udp.o udplite.o \ 11 datagram.o raw.o udp.o udplite.o \
12 arp.o icmp.o devinet.o af_inet.o igmp.o \ 12 arp.o icmp.o devinet.o af_inet.o igmp.o \
13 fib_frontend.o fib_semantics.o fib_trie.o \ 13 fib_frontend.o fib_semantics.o fib_trie.o \
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index eab2a7fb15d1..650e1528e1e6 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -293,7 +293,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
293 293
294 /* check for timestamp cookie support */ 294 /* check for timestamp cookie support */
295 memset(&tcp_opt, 0, sizeof(tcp_opt)); 295 memset(&tcp_opt, 0, sizeof(tcp_opt));
296 tcp_parse_options(skb, &tcp_opt, &hash_location, 0); 296 tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL);
297 297
298 if (!cookie_check_timestamp(&tcp_opt, &ecn_ok)) 298 if (!cookie_check_timestamp(&tcp_opt, &ecn_ok))
299 goto out; 299 goto out;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 3f6a1e762e9c..5840c3255721 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -367,6 +367,13 @@ static struct ctl_table ipv4_table[] = {
367 }, 367 },
368#endif 368#endif
369 { 369 {
370 .procname = "tcp_fastopen",
371 .data = &sysctl_tcp_fastopen,
372 .maxlen = sizeof(int),
373 .mode = 0644,
374 .proc_handler = proc_dointvec,
375 },
376 {
370 .procname = "tcp_tw_recycle", 377 .procname = "tcp_tw_recycle",
371 .data = &tcp_death_row.sysctl_tw_recycle, 378 .data = &tcp_death_row.sysctl_tw_recycle,
372 .maxlen = sizeof(int), 379 .maxlen = sizeof(int),
diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c
new file mode 100644
index 000000000000..a7f729c409d7
--- /dev/null
+++ b/net/ipv4/tcp_fastopen.c
@@ -0,0 +1,11 @@
1#include <linux/init.h>
2#include <linux/kernel.h>
3
4int sysctl_tcp_fastopen;
5
6static int __init tcp_fastopen_init(void)
7{
8 return 0;
9}
10
11late_initcall(tcp_fastopen_init);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index fdd49f1b7a52..a06bb8959e7e 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3732,7 +3732,8 @@ old_ack:
3732 * the fast version below fails. 3732 * the fast version below fails.
3733 */ 3733 */
3734void tcp_parse_options(const struct sk_buff *skb, struct tcp_options_received *opt_rx, 3734void tcp_parse_options(const struct sk_buff *skb, struct tcp_options_received *opt_rx,
3735 const u8 **hvpp, int estab) 3735 const u8 **hvpp, int estab,
3736 struct tcp_fastopen_cookie *foc)
3736{ 3737{
3737 const unsigned char *ptr; 3738 const unsigned char *ptr;
3738 const struct tcphdr *th = tcp_hdr(skb); 3739 const struct tcphdr *th = tcp_hdr(skb);
@@ -3839,8 +3840,25 @@ void tcp_parse_options(const struct sk_buff *skb, struct tcp_options_received *o
3839 break; 3840 break;
3840 } 3841 }
3841 break; 3842 break;
3842 }
3843 3843
3844 case TCPOPT_EXP:
3845 /* Fast Open option shares code 254 using a
3846 * 16 bits magic number. It's valid only in
3847 * SYN or SYN-ACK with an even size.
3848 */
3849 if (opsize < TCPOLEN_EXP_FASTOPEN_BASE ||
3850 get_unaligned_be16(ptr) != TCPOPT_FASTOPEN_MAGIC ||
3851 foc == NULL || !th->syn || (opsize & 1))
3852 break;
3853 foc->len = opsize - TCPOLEN_EXP_FASTOPEN_BASE;
3854 if (foc->len >= TCP_FASTOPEN_COOKIE_MIN &&
3855 foc->len <= TCP_FASTOPEN_COOKIE_MAX)
3856 memcpy(foc->val, ptr + 2, foc->len);
3857 else if (foc->len != 0)
3858 foc->len = -1;
3859 break;
3860
3861 }
3844 ptr += opsize-2; 3862 ptr += opsize-2;
3845 length -= opsize; 3863 length -= opsize;
3846 } 3864 }
@@ -3882,7 +3900,7 @@ static bool tcp_fast_parse_options(const struct sk_buff *skb,
3882 if (tcp_parse_aligned_timestamp(tp, th)) 3900 if (tcp_parse_aligned_timestamp(tp, th))
3883 return true; 3901 return true;
3884 } 3902 }
3885 tcp_parse_options(skb, &tp->rx_opt, hvpp, 1); 3903 tcp_parse_options(skb, &tp->rx_opt, hvpp, 1, NULL);
3886 return true; 3904 return true;
3887} 3905}
3888 3906
@@ -5637,7 +5655,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
5637 struct tcp_cookie_values *cvp = tp->cookie_values; 5655 struct tcp_cookie_values *cvp = tp->cookie_values;
5638 int saved_clamp = tp->rx_opt.mss_clamp; 5656 int saved_clamp = tp->rx_opt.mss_clamp;
5639 5657
5640 tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0); 5658 tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0, NULL);
5641 5659
5642 if (th->ack) { 5660 if (th->ack) {
5643 /* rfc793: 5661 /* rfc793:
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index d7d2fa50f07f..01aa77a97020 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1307,7 +1307,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
1307 tcp_clear_options(&tmp_opt); 1307 tcp_clear_options(&tmp_opt);
1308 tmp_opt.mss_clamp = TCP_MSS_DEFAULT; 1308 tmp_opt.mss_clamp = TCP_MSS_DEFAULT;
1309 tmp_opt.user_mss = tp->rx_opt.user_mss; 1309 tmp_opt.user_mss = tp->rx_opt.user_mss;
1310 tcp_parse_options(skb, &tmp_opt, &hash_location, 0); 1310 tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL);
1311 1311
1312 if (tmp_opt.cookie_plus > 0 && 1312 if (tmp_opt.cookie_plus > 0 &&
1313 tmp_opt.saw_tstamp && 1313 tmp_opt.saw_tstamp &&
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index c66f2ede160e..5912ac3fd240 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -97,7 +97,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
97 97
98 tmp_opt.saw_tstamp = 0; 98 tmp_opt.saw_tstamp = 0;
99 if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) { 99 if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) {
100 tcp_parse_options(skb, &tmp_opt, &hash_location, 0); 100 tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL);
101 101
102 if (tmp_opt.saw_tstamp) { 102 if (tmp_opt.saw_tstamp) {
103 tmp_opt.ts_recent = tcptw->tw_ts_recent; 103 tmp_opt.ts_recent = tcptw->tw_ts_recent;
@@ -534,7 +534,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
534 534
535 tmp_opt.saw_tstamp = 0; 535 tmp_opt.saw_tstamp = 0;
536 if (th->doff > (sizeof(struct tcphdr)>>2)) { 536 if (th->doff > (sizeof(struct tcphdr)>>2)) {
537 tcp_parse_options(skb, &tmp_opt, &hash_location, 0); 537 tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL);
538 538
539 if (tmp_opt.saw_tstamp) { 539 if (tmp_opt.saw_tstamp) {
540 tmp_opt.ts_recent = req->ts_recent; 540 tmp_opt.ts_recent = req->ts_recent;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 15a7c7bc3e58..4849be76ccd6 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -385,15 +385,17 @@ static inline bool tcp_urg_mode(const struct tcp_sock *tp)
385#define OPTION_MD5 (1 << 2) 385#define OPTION_MD5 (1 << 2)
386#define OPTION_WSCALE (1 << 3) 386#define OPTION_WSCALE (1 << 3)
387#define OPTION_COOKIE_EXTENSION (1 << 4) 387#define OPTION_COOKIE_EXTENSION (1 << 4)
388#define OPTION_FAST_OPEN_COOKIE (1 << 8)
388 389
389struct tcp_out_options { 390struct tcp_out_options {
390 u8 options; /* bit field of OPTION_* */ 391 u16 options; /* bit field of OPTION_* */
392 u16 mss; /* 0 to disable */
391 u8 ws; /* window scale, 0 to disable */ 393 u8 ws; /* window scale, 0 to disable */
392 u8 num_sack_blocks; /* number of SACK blocks to include */ 394 u8 num_sack_blocks; /* number of SACK blocks to include */
393 u8 hash_size; /* bytes in hash_location */ 395 u8 hash_size; /* bytes in hash_location */
394 u16 mss; /* 0 to disable */
395 __u32 tsval, tsecr; /* need to include OPTION_TS */
396 __u8 *hash_location; /* temporary pointer, overloaded */ 396 __u8 *hash_location; /* temporary pointer, overloaded */
397 __u32 tsval, tsecr; /* need to include OPTION_TS */
398 struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */
397}; 399};
398 400
399/* The sysctl int routines are generic, so check consistency here. 401/* The sysctl int routines are generic, so check consistency here.
@@ -442,7 +444,7 @@ static u8 tcp_cookie_size_check(u8 desired)
442static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, 444static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
443 struct tcp_out_options *opts) 445 struct tcp_out_options *opts)
444{ 446{
445 u8 options = opts->options; /* mungable copy */ 447 u16 options = opts->options; /* mungable copy */
446 448
447 /* Having both authentication and cookies for security is redundant, 449 /* Having both authentication and cookies for security is redundant,
448 * and there's certainly not enough room. Instead, the cookie-less 450 * and there's certainly not enough room. Instead, the cookie-less
@@ -564,6 +566,21 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
564 566
565 tp->rx_opt.dsack = 0; 567 tp->rx_opt.dsack = 0;
566 } 568 }
569
570 if (unlikely(OPTION_FAST_OPEN_COOKIE & options)) {
571 struct tcp_fastopen_cookie *foc = opts->fastopen_cookie;
572
573 *ptr++ = htonl((TCPOPT_EXP << 24) |
574 ((TCPOLEN_EXP_FASTOPEN_BASE + foc->len) << 16) |
575 TCPOPT_FASTOPEN_MAGIC);
576
577 memcpy(ptr, foc->val, foc->len);
578 if ((foc->len & 3) == 2) {
579 u8 *align = ((u8 *)ptr) + foc->len;
580 align[0] = align[1] = TCPOPT_NOP;
581 }
582 ptr += (foc->len + 3) >> 2;
583 }
567} 584}
568 585
569/* Compute TCP options for SYN packets. This is not the final 586/* Compute TCP options for SYN packets. This is not the final
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 7bf3cc427c28..bb46061c813a 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -177,7 +177,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
177 177
178 /* check for timestamp cookie support */ 178 /* check for timestamp cookie support */
179 memset(&tcp_opt, 0, sizeof(tcp_opt)); 179 memset(&tcp_opt, 0, sizeof(tcp_opt));
180 tcp_parse_options(skb, &tcp_opt, &hash_location, 0); 180 tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL);
181 181
182 if (!cookie_check_timestamp(&tcp_opt, &ecn_ok)) 182 if (!cookie_check_timestamp(&tcp_opt, &ecn_ok))
183 goto out; 183 goto out;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index c9dabdd832d7..0302ec3fecfc 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1033,7 +1033,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1033 tcp_clear_options(&tmp_opt); 1033 tcp_clear_options(&tmp_opt);
1034 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); 1034 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
1035 tmp_opt.user_mss = tp->rx_opt.user_mss; 1035 tmp_opt.user_mss = tp->rx_opt.user_mss;
1036 tcp_parse_options(skb, &tmp_opt, &hash_location, 0); 1036 tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL);
1037 1037
1038 if (tmp_opt.cookie_plus > 0 && 1038 if (tmp_opt.cookie_plus > 0 &&
1039 tmp_opt.saw_tstamp && 1039 tmp_opt.saw_tstamp &&