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 /include | |
| 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>
Diffstat (limited to 'include')
| -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 |
4 files changed, 121 insertions, 10 deletions
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. | ||
| 113 | * qlen - pending TFO requests (still in TCP_SYN_RECV). | ||
| 114 | * max_qlen - max TFO reqs allowed before TFO is disabled. | ||
| 115 | * | ||
| 116 | * XXX (TFO) - ideally these fields can be made as part of "listen_sock" | ||
| 117 | * structure above. But there is some implementation difficulty due to | ||
| 118 | * listen_sock being part of request_sock_queue hence will be freed when | ||
| 119 | * a listener is stopped. But TFO related fields may continue to be | ||
| 120 | * accessed even after a listener is closed, until its sk_refcnt drops | ||
| 121 | * to 0 implying no more outstanding TFO reqs. One solution is to keep | ||
| 122 | * listen_opt around until sk_refcnt drops to 0. But there is some other | ||
| 123 | * complexity that needs to be resolved. E.g., a listener can be disabled | ||
| 124 | * temporarily through shutdown()->tcp_disconnect(), and re-enabled later. | ||
| 125 | */ | ||
| 126 | struct fastopen_queue { | ||
| 127 | struct request_sock *rskq_rst_head; /* Keep track of past TFO */ | ||
| 128 | struct request_sock *rskq_rst_tail; /* requests that caused RST. | ||
| 129 | * This is part of the defense | ||
| 130 | * against spoofing attack. | ||
| 131 | */ | ||
| 132 | spinlock_t lock; | ||
| 133 | int qlen; /* # of pending (TCP_SYN_RECV) reqs */ | ||
| 134 | int max_qlen; /* != 0 iff TFO is currently enabled */ | ||
| 135 | }; | ||
| 136 | |||
| 109 | /** struct request_sock_queue - queue of request_socks | 137 | /** struct request_sock_queue - queue of request_socks |
| 110 | * | 138 | * |
| 111 | * @rskq_accept_head - FIFO head of established children | 139 | * @rskq_accept_head - FIFO head of established children |
| @@ -129,6 +157,12 @@ struct request_sock_queue { | |||
| 129 | u8 rskq_defer_accept; | 157 | u8 rskq_defer_accept; |
| 130 | /* 3 bytes hole, try to pack */ | 158 | /* 3 bytes hole, try to pack */ |
| 131 | struct listen_sock *listen_opt; | 159 | struct listen_sock *listen_opt; |
| 160 | struct fastopen_queue *fastopenq; /* This is non-NULL iff TFO has been | ||
| 161 | * enabled on this listener. Check | ||
| 162 | * max_qlen != 0 in fastopen_queue | ||
| 163 | * to determine if TFO is enabled | ||
| 164 | * right at this moment. | ||
| 165 | */ | ||
| 132 | }; | 166 | }; |
| 133 | 167 | ||
| 134 | extern int reqsk_queue_alloc(struct request_sock_queue *queue, | 168 | extern int reqsk_queue_alloc(struct request_sock_queue *queue, |
| @@ -136,6 +170,8 @@ extern int reqsk_queue_alloc(struct request_sock_queue *queue, | |||
| 136 | 170 | ||
| 137 | extern void __reqsk_queue_destroy(struct request_sock_queue *queue); | 171 | extern void __reqsk_queue_destroy(struct request_sock_queue *queue); |
| 138 | extern void reqsk_queue_destroy(struct request_sock_queue *queue); | 172 | extern void reqsk_queue_destroy(struct request_sock_queue *queue); |
| 173 | extern void reqsk_fastopen_remove(struct sock *sk, | ||
| 174 | |||
