diff options
| author | Jerry Chu <hkchu@google.com> | 2012-08-31 08:29:11 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2012-08-31 20:02:18 -0400 |
| commit | 1046716368979dee857a2b8a91c4a8833f21b9cb (patch) | |
| tree | fdda70278e6fa56c27d242fb1a0ec9b7e3e81d38 | |
| parent | 2a35cfa591ac63f17815c2d9432b799e37527980 (diff) | |
tcp: TCP Fast Open Server - header & support functions
This patch adds all the necessary data structure and support
functions to implement TFO server side. It also documents a number
of flags for the sysctl_tcp_fastopen knob, and adds a few Linux
extension MIBs.
In addition, it includes the following:
1. a new TCP_FASTOPEN socket option an application must call to
supply a max backlog allowed in order to enable TFO on its listener.
2. A number of key data structures:
"fastopen_rsk" in tcp_sock - for a big socket to access its
request_sock for retransmission and ack processing purpose. It is
non-NULL iff 3WHS not completed.
"fastopenq" in request_sock_queue - points to a per Fast Open
listener data structure "fastopen_queue" to keep track of qlen (# of
outstanding Fast Open requests) and max_qlen, among other things.
"listener" in tcp_request_sock - to point to the original listener
for book-keeping purpose, i.e., to maintain qlen against max_qlen
as part of defense against IP spoofing attack.
3. various data structure and functions, many in tcp_fastopen.c, to
support server side Fast Open cookie operations, including
/proc/sys/net/ipv4/tcp_fastopen_key to allow manual rekeying.
Signed-off-by: H.K. Jerry Chu <hkchu@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
Cc: Neal Cardwell <ncardwell@google.com>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Tom Herbert <therbert@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | Documentation/networking/ip-sysctl.txt | 29 | ||||
| -rw-r--r-- | include/linux/snmp.h | 4 | ||||
| -rw-r--r-- | include/linux/tcp.h | 45 | ||||
| -rw-r--r-- | include/net/request_sock.h | 36 | ||||
| -rw-r--r-- | include/net/tcp.h | 46 | ||||
| -rw-r--r-- | net/ipv4/proc.c | 4 | ||||
| -rw-r--r-- | net/ipv4/sysctl_net_ipv4.c | 45 | ||||
| -rw-r--r-- | net/ipv4/tcp_fastopen.c | 83 | ||||
| -rw-r--r-- | net/ipv4/tcp_input.c | 4 |
9 files changed, 276 insertions, 20 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index d64e53124b8c..c7fc10724948 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt | |||
| @@ -467,16 +467,31 @@ tcp_syncookies - BOOLEAN | |||
| 467 | tcp_fastopen - INTEGER | 467 | tcp_fastopen - INTEGER |
| 468 | Enable TCP Fast Open feature (draft-ietf-tcpm-fastopen) to send data | 468 | Enable TCP Fast Open feature (draft-ietf-tcpm-fastopen) to send data |
| 469 | in the opening SYN packet. To use this feature, the client application | 469 | in the opening SYN packet. To use this feature, the client application |
| 470 | must not use connect(). Instead, it should use sendmsg() or sendto() | 470 | must use sendmsg() or sendto() with MSG_FASTOPEN flag rather than |
| 471 | with MSG_FASTOPEN flag which performs a TCP handshake automatically. | 471 | connect() to perform a TCP handshake automatically. |
| 472 | 472 | ||
| 473 | The values (bitmap) are: | 473 | The values (bitmap) are |
| 474 | 1: Enables sending data in the opening SYN on the client | 474 | 1: Enables sending data in the opening SYN on the client. |
| 475 | 5: Enables sending data in the opening SYN on the client regardless | 475 | 2: Enables TCP Fast Open on the server side, i.e., allowing data in |
| 476 | of cookie availability. | 476 | a SYN packet to be accepted and passed to the application before |
| 477 | 3-way hand shake finishes. | ||
| 478 | 4: Send data in the opening SYN regardless of cookie availability and | ||
| 479 | without a cookie option. | ||
| 480 | 0x100: Accept SYN data w/o validating the cookie. | ||
| 481 | 0x200: Accept data-in-SYN w/o any cookie option present. | ||
| 482 | 0x400/0x800: Enable Fast Open on all listeners regardless of the | ||
| 483 | TCP_FASTOPEN socket option. The two different flags designate two | ||
| 484 | different ways of setting max_qlen without the TCP_FASTOPEN socket | ||
| 485 | option. | ||
| 477 | 486 | ||
| 478 | Default: 0 | 487 | Default: 0 |
| 479 | 488 | ||
| 489 | Note that the client & server side Fast Open flags (1 and 2 | ||
| 490 | respectively) must be also enabled before the rest of flags can take | ||
| 491 | effect. | ||
| 492 | |||
| 493 | See include/net/tcp.h and the code for more details. | ||
| 494 | |||
| 480 | tcp_syn_retries - INTEGER | 495 | tcp_syn_retries - INTEGER |
| 481 | Number of times initial SYNs for an active TCP connection attempt | 496 | Number of times initial SYNs for an active TCP connection attempt |
| 482 | will be retransmitted. Should not be higher than 255. Default value | 497 | will be retransmitted. Should not be higher than 255. Default value |
diff --git a/include/linux/snmp.h b/include/linux/snmp.h index ad6e3a6bf9fb..fdfba235f9f1 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h | |||
| @@ -241,6 +241,10 @@ enum | |||
| 241 | LINUX_MIB_TCPCHALLENGEACK, /* TCPChallengeACK */ | 241 | LINUX_MIB_TCPCHALLENGEACK, /* TCPChallengeACK */ |
| 242 | LINUX_MIB_TCPSYNCHALLENGE, /* TCPSYNChallenge */ | 242 | LINUX_MIB_TCPSYNCHALLENGE, /* TCPSYNChallenge */ |
| 243 | LINUX_MIB_TCPFASTOPENACTIVE, /* TCPFastOpenActive */ | 243 | LINUX_MIB_TCPFASTOPENACTIVE, /* TCPFastOpenActive */ |
| 244 | LINUX_MIB_TCPFASTOPENPASSIVE, /* TCPFastOpenPassive*/ | ||
| 245 | LINUX_MIB_TCPFASTOPENPASSIVEFAIL, /* TCPFastOpenPassiveFail */ | ||
| 246 | LINUX_MIB_TCPFASTOPENLISTENOVERFLOW, /* TCPFastOpenListenOverflow */ | ||
| 247 | LINUX_MIB_TCPFASTOPENCOOKIEREQD, /* TCPFastOpenCookieReqd */ | ||
| 244 | __LINUX_MIB_MAX | 248 | __LINUX_MIB_MAX |
| 245 | }; | 249 | }; |
| 246 | 250 | ||
diff --git a/include/linux/tcp.h b/include/linux/tcp.h index eb125a4c30b3..ae46df590629 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h | |||
| @@ -110,6 +110,7 @@ enum { | |||
| 110 | #define TCP_REPAIR_QUEUE 20 | 110 | #define TCP_REPAIR_QUEUE 20 |
| 111 | #define TCP_QUEUE_SEQ 21 | 111 | #define TCP_QUEUE_SEQ 21 |
| 112 | #define TCP_REPAIR_OPTIONS 22 | 112 | #define TCP_REPAIR_OPTIONS 22 |
| 113 | #define TCP_FASTOPEN 23 /* Enable FastOpen on listeners */ | ||
| 113 | 114 | ||
| 114 | struct tcp_repair_opt { | 115 | struct tcp_repair_opt { |
| 115 | __u32 opt_code; | 116 | __u32 opt_code; |
| @@ -246,6 +247,7 @@ static inline unsigned int tcp_optlen(const struct sk_buff *skb) | |||
| 246 | /* TCP Fast Open */ | 247 | /* TCP Fast Open */ |
| 247 | #define TCP_FASTOPEN_COOKIE_MIN 4 /* Min Fast Open Cookie size in bytes */ | 248 | #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 | #define TCP_FASTOPEN_COOKIE_MAX 16 /* Max Fast Open Cookie size in bytes */ |
| 250 | #define TCP_FASTOPEN_COOKIE_SIZE 8 /* the size employed by this impl. */ | ||
| 249 | 251 | ||
| 250 | /* TCP Fast Open Cookie as stored in memory */ | 252 | /* TCP Fast Open Cookie as stored in memory */ |
| 251 | struct tcp_fastopen_cookie { | 253 | struct tcp_fastopen_cookie { |
| @@ -312,9 +314,14 @@ struct tcp_request_sock { | |||
| 312 | /* Only used by TCP MD5 Signature so far. */ | 314 | /* Only used by TCP MD5 Signature so far. */ |
| 313 | const struct tcp_request_sock_ops *af_specific; | 315 | const struct tcp_request_sock_ops *af_specific; |
| 314 | #endif | 316 | #endif |
| 317 | struct sock *listener; /* needed for TFO */ | ||
| 315 | u32 rcv_isn; | 318 | u32 rcv_isn; |
| 316 | u32 snt_isn; | 319 | u32 snt_isn; |
| 317 | u32 snt_synack; /* synack sent time */ | 320 | u32 snt_synack; /* synack sent time */ |
| 321 | u32 rcv_nxt; /* the ack # by SYNACK. For | ||
| 322 | * FastOpen it's the seq# | ||
| 323 | * after data-in-SYN. | ||
| 324 | */ | ||
| 318 | }; | 325 | }; |
| 319 | 326 | ||
| 320 | static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) | 327 | static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) |
| @@ -505,14 +512,18 @@ struct tcp_sock { | |||
| 505 | struct tcp_md5sig_info __rcu *md5sig_info; | 512 | struct tcp_md5sig_info __rcu *md5sig_info; |
| 506 | #endif | 513 | #endif |
| 507 | 514 | ||
| 508 | /* TCP fastopen related information */ | ||
| 509 | struct tcp_fastopen_request *fastopen_req; | ||
| 510 | |||
| 511 | /* When the cookie options are generated and exchanged, then this | 515 | /* When the cookie options are generated and exchanged, then this |
| 512 | * object holds a reference to them (cookie_values->kref). Also | 516 | * object holds a reference to them (cookie_values->kref). Also |
| 513 | * contains related tcp_cookie_transactions fields. | 517 | * contains related tcp_cookie_transactions fields. |
| 514 | */ | 518 | */ |
| 515 | struct tcp_cookie_values *cookie_values; | 519 | struct tcp_cookie_values *cookie_values; |
| 520 | |||
| 521 | /* TCP fastopen related information */ | ||
| 522 | struct tcp_fastopen_request *fastopen_req; | ||
| 523 | /* fastopen_rsk points to request_sock that resulted in this big | ||
| 524 | * socket. Used to retransmit SYNACKs etc. | ||
| 525 | */ | ||
| 526 | struct request_sock *fastopen_rsk; | ||
| 516 | }; | 527 | }; |
| 517 | 528 | ||
| 518 | enum tsq_flags { | 529 | enum tsq_flags { |
| @@ -552,6 +563,34 @@ static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) | |||
| 552 | return (struct tcp_timewait_sock *)sk; | 563 | return (struct tcp_timewait_sock *)sk; |
| 553 | } | 564 | } |
| 554 | 565 | ||
| 566 | static inline bool tcp_passive_fastopen(const struct sock *sk) | ||
| 567 | { | ||
| 568 | return (sk->sk_state == TCP_SYN_RECV && | ||
| 569 | tcp_sk(sk)->fastopen_rsk != NULL); | ||
| 570 | } | ||
| 571 | |||
| 572 | static inline bool fastopen_cookie_present(struct tcp_fastopen_cookie *foc) | ||
| 573 | { | ||
| 574 | return foc->len != -1; | ||
| 575 | } | ||
| 576 | |||
| 577 | static inline int fastopen_init_queue(struct sock *sk, int backlog) | ||
| 578 | { | ||
| 579 | struct request_sock_queue *queue = | ||
| 580 | &inet_csk(sk)->icsk_accept_queue; | ||
| 581 | |||
| 582 | if (queue->fastopenq == NULL) { | ||
| 583 | queue->fastopenq = kzalloc( | ||
| 584 | sizeof(struct fastopen_queue), | ||
| 585 | sk->sk_allocation); | ||
| 586 | if (queue->fastopenq == NULL) | ||
| 587 | return -ENOMEM; | ||
| 588 | spin_lock_init(&queue->fastopenq->lock); | ||
| 589 | } | ||
| 590 | queue->fastopenq->max_qlen = backlog; | ||
| 591 | return 0; | ||
| 592 | } | ||
| 593 | |||
| 555 | #endif /* __KERNEL__ */ | 594 | #endif /* __KERNEL__ */ |
| 556 | 595 | ||
| 557 | #endif /* _LINUX_TCP_H */ | 596 | #endif /* _LINUX_TCP_H */ |
diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 4c0766e201e3..c3cdd6c9f448 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h | |||
| @@ -106,6 +106,34 @@ struct listen_sock { | |||
| 106 | struct request_sock *syn_table[0]; | 106 | struct request_sock *syn_table[0]; |
| 107 | }; | 107 | }; |
| 108 | 108 | ||
| 109 | /* | ||
| 110 | * For a TCP Fast Open listener - | ||
| 111 | * lock - protects the access to all the reqsk, which is co-owned by | ||
| 112 | * the listener and the child socket. | ||
