Skip to content

Commit 168a8f5

Browse files
hkchudavem330
authored andcommitted
tcp: TCP Fast Open Server - main code path
This patch adds the main processing path to complete the TFO server patches. A TFO request (i.e., SYN+data packet with a TFO cookie option) first gets processed in tcp_v4_conn_request(). If it passes the various TFO checks by tcp_fastopen_check(), a child socket will be created right away to be accepted by applications, rather than waiting for the 3WHS to finish. In additon to the use of TFO cookie, a simple max_qlen based scheme is put in place to fend off spoofed TFO attack. When a valid ACK comes back to tcp_rcv_state_process(), it will cause the state of the child socket to switch from either TCP_SYN_RECV to TCP_ESTABLISHED, or TCP_FIN_WAIT1 to TCP_FIN_WAIT2. At this time retransmission will resume for any unack'ed (data, FIN,...) segments. 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>
1 parent 8336886 commit 168a8f5

File tree

2 files changed

+309
-27
lines changed

2 files changed

+309
-27
lines changed

net/ipv4/tcp_input.c

+58-13
Original file line numberDiff line numberDiff line change
@@ -3127,6 +3127,12 @@ void tcp_rearm_rto(struct sock *sk)
31273127
{
31283128
struct tcp_sock *tp = tcp_sk(sk);
31293129

3130+
/* If the retrans timer is currently being used by Fast Open
3131+
* for SYN-ACK retrans purpose, stay put.
3132+
*/
3133+
if (tp->fastopen_rsk)
3134+
return;
3135+
31303136
if (!tp->packets_out) {
31313137
inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
31323138
} else {
@@ -5895,7 +5901,9 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
58955901
tcp_send_synack(sk);
58965902
#if 0
58975903
/* Note, we could accept data and URG from this segment.
5898-
* There are no obstacles to make this.
5904+
* There are no obstacles to make this (except that we must
5905+
* either change tcp_recvmsg() to prevent it from returning data
5906+
* before 3WHS completes per RFC793, or employ TCP Fast Open).
58995907
*
59005908
* However, if we ignore data in ACKless segments sometimes,
59015909
* we have no reasons to accept it sometimes.
@@ -5935,6 +5943,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
59355943
{
59365944
struct tcp_sock *tp = tcp_sk(sk);
59375945
struct inet_connection_sock *icsk = inet_csk(sk);
5946+
struct request_sock *req;
59385947
int queued = 0;
59395948

59405949
tp->rx_opt.saw_tstamp = 0;
@@ -5990,7 +5999,14 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
59905999
return 0;
59916000
}
59926001

5993-
if (!tcp_validate_incoming(sk, skb, th, 0))
6002+
req = tp->fastopen_rsk;
6003+
if (req != NULL) {
6004+
BUG_ON(sk->sk_state != TCP_SYN_RECV &&
6005+
sk->sk_state != TCP_FIN_WAIT1);
6006+
6007+
if (tcp_check_req(sk, skb, req, NULL, true) == NULL)
6008+
goto discard;
6009+
} else if (!tcp_validate_incoming(sk, skb, th, 0))
59946010
return 0;
59956011

59966012
/* step 5: check the ACK field */
@@ -6000,7 +6016,22 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
60006016
switch (sk->sk_state) {
60016017
case TCP_SYN_RECV:
60026018
if (acceptable) {
6003-
tp->copied_seq = tp->rcv_nxt;
6019+
/* Once we leave TCP_SYN_RECV, we no longer
6020+
* need req so release it.
6021+
*/
6022+
if (req) {
6023+
reqsk_fastopen_remove(sk, req, false);
6024+
} else {
6025+
/* Make sure socket is routed, for
6026+
* correct metrics.
6027+
*/
6028+
icsk->icsk_af_ops->rebuild_header(sk);
6029+
tcp_init_congestion_control(sk);
6030+
6031+
tcp_mtup_init(sk);
6032+
tcp_init_buffer_space(sk);
6033+
tp->copied_seq = tp->rcv_nxt;
6034+
}
60046035
smp_mb();
60056036
tcp_set_state(sk, TCP_ESTABLISHED);
60066037
sk->sk_state_change(sk);
@@ -6022,30 +6053,44 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
60226053
if (tp->rx_opt.tstamp_ok)
60236054
tp->advmss -= TCPOLEN_TSTAMP_ALIGNED;
60246055

6025-
/* Make sure socket is routed, for
6026-
* correct metrics.
6027-
*/
6028-
icsk->icsk_af_ops->rebuild_header(sk);
6029-
6030-
tcp_init_metrics(sk);
6031-
6032-
tcp_init_congestion_control(sk);
6056+
if (req) {
6057+
/* Re-arm the timer because data may
6058+
* have been sent out. This is similar
6059+
* to the regular data transmission case
6060+
* when new data has just been ack'ed.
6061+
*
6062+
* (TFO) - we could try to be more
6063+
* aggressive and retranmitting any data
6064+
* sooner based on when they were sent
6065+
* out.
6066+
*/
6067+
tcp_rearm_rto(sk);
6068+
} else
6069+
tcp_init_metrics(sk);
60336070

60346071
/* Prevent spurious tcp_cwnd_restart() on
60356072
* first data packet.
60366073
*/
60376074
tp->lsndtime = tcp_time_stamp;
60386075

6039-
tcp_mtup_init(sk);
60406076
tcp_initialize_rcv_mss(sk);
6041-
tcp_init_buffer_space(sk);
60426077
tcp_fast_path_on(tp);
60436078
} else {
60446079
return 1;
60456080
}
60466081
break;
60476082

60486083
case TCP_FIN_WAIT1:
6084+
/* If we enter the TCP_FIN_WAIT1 state and we are a
6085+
* Fast Open socket and this is the first acceptable
6086+
* ACK we have received, this would have acknowledged
6087+
* our SYNACK so stop the SYNACK timer.
6088+
*/
6089+
if (acceptable && req != NULL) {
6090+
/* We no longer need the request sock. */
6091+
reqsk_fastopen_remove(sk, req, false);
6092+
tcp_rearm_rto(sk);
6093+
}
60496094
if (tp->snd_una == tp->write_seq) {
60506095
struct dst_entry *dst;
60516096

0 commit comments

Comments
 (0)