diff options
author | Neal Cardwell <ncardwell@google.com> | 2012-09-22 00:18:55 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-09-22 15:47:10 -0400 |
commit | 016818d076871c4ee34db1e8d74dc17ac1de626a (patch) | |
tree | 60d0f20afb0937f61b5fc4611e53a2ac411a0646 | |
parent | 623df484a777f3c00c1ea3d6a7565b8d8ac688a1 (diff) |
tcp: TCP Fast Open Server - take SYNACK RTT after completing 3WHS
When taking SYNACK RTT samples for servers using TCP Fast Open, fix
the code to ensure that we only call tcp_valid_rtt_meas() after we
receive the ACK that completes the 3-way handshake.
Previously we were always taking an RTT sample in
tcp_v4_syn_recv_sock(). However, for TCP Fast Open connections
tcp_v4_conn_req_fastopen() calls tcp_v4_syn_recv_sock() at the time we
receive the SYN. So for TFO we must wait until tcp_rcv_state_process()
to take the RTT sample.
To fix this, we wait until after TFO calls tcp_v4_syn_recv_sock()
before we set the snt_synack timestamp, since tcp_synack_rtt_meas()
already ensures that we only take a SYNACK RTT sample if snt_synack is
non-zero. To be careful, we only take a snt_synack timestamp when
a SYNACK transmit or retransmit succeeds.
Signed-off-by: Neal Cardwell <ncardwell@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/tcp.h | 1 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 1 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 12 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 2 |
4 files changed, 12 insertions, 4 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h index a718d0e3d8e7..6feeccd83dd7 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -1125,6 +1125,7 @@ static inline void tcp_openreq_init(struct request_sock *req, | |||
1125 | req->cookie_ts = 0; | 1125 | req->cookie_ts = 0; |
1126 | tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq; | 1126 | tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq; |
1127 | tcp_rsk(req)->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; | 1127 | tcp_rsk(req)->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; |
1128 | tcp_rsk(req)->snt_synack = 0; | ||
1128 | req->mss = rx_opt->mss_clamp; | 1129 | req->mss = rx_opt->mss_clamp; |
1129 | req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0; | 1130 | req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0; |
1130 | ireq->tstamp_ok = rx_opt->tstamp_ok; | 1131 | ireq->tstamp_ok = rx_opt->tstamp_ok; |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e2bec815ff23..bb326684495b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -5983,6 +5983,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
5983 | * need req so release it. | 5983 | * need req so release it. |
5984 | */ | 5984 | */ |
5985 | if (req) { | 5985 | if (req) { |
5986 | tcp_synack_rtt_meas(sk, req); | ||
5986 | reqsk_fastopen_remove(sk, req, false); | 5987 | reqsk_fastopen_remove(sk, req, false); |
5987 | } else { | 5988 | } else { |
5988 | /* Make sure socket is routed, for | 5989 | /* Make sure socket is routed, for |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1e66f7fb4fe6..0a7e020f16b5 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -868,6 +868,8 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, | |||
868 | ireq->rmt_addr, | 868 | ireq->rmt_addr, |
869 | ireq->opt); | 869 | ireq->opt); |
870 | err = net_xmit_eval(err); | 870 | err = net_xmit_eval(err); |
871 | if (!tcp_rsk(req)->snt_synack && !err) | ||
872 | tcp_rsk(req)->snt_synack = tcp_time_stamp; | ||
871 | } | 873 | } |
872 | 874 | ||
873 | return err; | 875 | return err; |
@@ -1382,6 +1384,7 @@ static int tcp_v4_conn_req_fastopen(struct sock *sk, | |||
1382 | struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; | 1384 | struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; |
1383 | const struct inet_request_sock *ireq = inet_rsk(req); | 1385 | const struct inet_request_sock *ireq = inet_rsk(req); |
1384 | struct sock *child; | 1386 | struct sock *child; |
1387 | int err; | ||
1385 | 1388 | ||
1386 | req->retrans = 0; | 1389 | req->retrans = 0; |
1387 | req->sk = NULL; | 1390 | req->sk = NULL; |
@@ -1393,8 +1396,11 @@ static int tcp_v4_conn_req_fastopen(struct sock *sk, | |||
1393 | kfree_skb(skb_synack); | 1396 | kfree_skb(skb_synack); |
1394 | return -1; | 1397 | return -1; |
1395 | } | 1398 | } |
1396 | ip_build_and_send_pkt(skb_synack, sk, ireq->loc_addr, | 1399 | err = ip_build_and_send_pkt(skb_synack, sk, ireq->loc_addr, |
1397 | ireq->rmt_addr, ireq->opt); | 1400 | ireq->rmt_addr, ireq->opt); |
1401 | err = net_xmit_eval(err); | ||
1402 | if (!err) | ||
1403 | tcp_rsk(req)->snt_synack = tcp_time_stamp; | ||
1398 | /* XXX (TFO) - is it ok to ignore error and continue? */ | 1404 | /* XXX (TFO) - is it ok to ignore error and continue? */ |
1399 | 1405 | ||
1400 | spin_lock(&queue->fastopenq->lock); | 1406 | spin_lock(&queue->fastopenq->lock); |
@@ -1612,7 +1618,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1612 | isn = tcp_v4_init_sequence(skb); | 1618 | isn = tcp_v4_init_sequence(skb); |
1613 | } | 1619 | } |
1614 | tcp_rsk(req)->snt_isn = isn; | 1620 | tcp_rsk(req)->snt_isn = isn; |
1615 | tcp_rsk(req)->snt_synack = tcp_time_stamp; | ||
1616 | 1621 | ||
1617 | if (dst == NULL) { | 1622 | if (dst == NULL) { |
1618 | dst = inet_csk_route_req(sk, &fl4, req); | 1623 | dst = inet_csk_route_req(sk, &fl4, req); |
@@ -1650,6 +1655,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1650 | if (err || want_cookie) | 1655 | if (err || want_cookie) |
1651 | goto drop_and_free; | 1656 | goto drop_and_free; |
1652 | 1657 | ||
1658 | tcp_rsk(req)->snt_synack = tcp_time_stamp; | ||
1653 | tcp_rsk(req)->listener = NULL; | 1659 | tcp_rsk(req)->listener = NULL; |
1654 | /* Add the request_sock to the SYN table */ | 1660 | /* Add the request_sock to the SYN table */ |
1655 | inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | 1661 | inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index cfeeeb7fcf54..d6212d6bc8d8 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -1169,7 +1169,6 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1169 | } | 1169 | } |
1170 | have_isn: | 1170 | have_isn: |
1171 | tcp_rsk(req)->snt_isn = isn; | 1171 | tcp_rsk(req)->snt_isn = isn; |
1172 | tcp_rsk(req)->snt_synack = tcp_time_stamp; | ||
1173 | 1172 | ||
1174 | if (security_inet_conn_request(sk, skb, req)) | 1173 | if (security_inet_conn_request(sk, skb, req)) |
1175 | goto drop_and_release; | 1174 | goto drop_and_release; |
@@ -1180,6 +1179,7 @@ have_isn: | |||
1180 | want_cookie) | 1179 | want_cookie) |
1181 | goto drop_and_free; | 1180 | goto drop_and_free; |
1182 | 1181 | ||
1182 | tcp_rsk(req)->snt_synack = tcp_time_stamp; | ||
1183 | tcp_rsk(req)->listener = NULL; | 1183 | tcp_rsk(req)->listener = NULL; |
1184 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | 1184 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); |
1185 | return 0; | 1185 | return 0; |