aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
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 /net/ipv4
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>
Diffstat (limited to 'net/ipv4')
-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
8 files changed, 66 insertions, 13 deletions
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