Skip to content

Commit 843f4a5

Browse files
yuchungchengdavem330
authored andcommitted
tcp: use tcp_v4_send_synack on first SYN-ACK
To avoid large code duplication in IPv6, we need to first simplify the complicate SYN-ACK sending code in tcp_v4_conn_request(). To use tcp_v4(6)_send_synack() to send all SYN-ACKs, we need to initialize the mini socket's receive window before trying to create the child socket and/or building the SYN-ACK packet. So we move that initialization from tcp_make_synack() to tcp_v4_conn_request() as a new function tcp_openreq_init_req_rwin(). After this refactoring the SYN-ACK sending code is simpler and easier to implement Fast Open for IPv6. Signed-off-by: Yuchung Cheng <[email protected]> Signed-off-by: Daniel Lee <[email protected]> Signed-off-by: Jerry Chu <[email protected]> Acked-by: Neal Cardwell <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 89278c9 commit 843f4a5

File tree

5 files changed

+85
-105
lines changed

5 files changed

+85
-105
lines changed

include/net/tcp.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,9 @@ static inline void tcp_openreq_init(struct request_sock *req,
11141114
ireq->ir_num = ntohs(tcp_hdr(skb)->dest);
11151115
}
11161116

1117+
extern void tcp_openreq_init_rwin(struct request_sock *req,
1118+
struct sock *sk, struct dst_entry *dst);
1119+
11171120
void tcp_enter_memory_pressure(struct sock *sk);
11181121

11191122
static inline int keepalive_intvl_when(const struct tcp_sock *tp)
@@ -1323,13 +1326,10 @@ void tcp_free_fastopen_req(struct tcp_sock *tp);
13231326

13241327
extern struct tcp_fastopen_context __rcu *tcp_fastopen_ctx;
13251328
int tcp_fastopen_reset_cipher(void *key, unsigned int len);
1326-
int tcp_fastopen_create_child(struct sock *sk,
1327-
struct sk_buff *skb,
1328-
struct sk_buff *skb_synack,
1329-
struct request_sock *req);
1330-
bool tcp_fastopen_check(struct sock *sk, struct sk_buff *skb,
1331-
struct request_sock *req,
1332-
struct tcp_fastopen_cookie *foc);
1329+
bool tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
1330+
struct request_sock *req,
1331+
struct tcp_fastopen_cookie *foc,
1332+
struct dst_entry *dst);
13331333
void tcp_fastopen_init_key_once(bool publish);
13341334
#define TCP_FASTOPEN_KEY_LENGTH 16
13351335

net/ipv4/tcp_fastopen.c

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -95,34 +95,22 @@ void tcp_fastopen_cookie_gen(__be32 src, __be32 dst,
9595
rcu_read_unlock();
9696
}
9797

98-
int tcp_fastopen_create_child(struct sock *sk,
99-
struct sk_buff *skb,
100-
struct sk_buff *skb_synack,
101-
struct request_sock *req)
98+
static bool tcp_fastopen_create_child(struct sock *sk,
99+
struct sk_buff *skb,
100+
struct dst_entry *dst,
101+
struct request_sock *req)
102102
{
103103
struct tcp_sock *tp = tcp_sk(sk);
104104
struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
105-
const struct inet_request_sock *ireq = inet_rsk(req);
106105
struct sock *child;
107-
int err;
108106

109107
req->num_retrans = 0;
110108
req->num_timeout = 0;
111109
req->sk = NULL;
112110

113111
child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL);
114-
if (child == NULL) {
115-
NET_INC_STATS_BH(sock_net(sk),
116-
LINUX_MIB_TCPFASTOPENPASSIVEFAIL);
117-
kfree_skb(skb_synack);
118-
return -1;
119-
}
120-
err = ip_build_and_send_pkt(skb_synack, sk, ireq->ir_loc_addr,
121-
ireq->ir_rmt_addr, ireq->opt);
122-
err = net_xmit_eval(err);
123-
if (!err)
124-
tcp_rsk(req)->snt_synack = tcp_time_stamp;
125-
/* XXX (TFO) - is it ok to ignore error and continue? */
112+
if (child == NULL)
113+
return false;
126114

127115
spin_lock(&queue->fastopenq->lock);
128116
queue->fastopenq->qlen++;
@@ -167,28 +155,24 @@ int tcp_fastopen_create_child(struct sock *sk,
167155
/* Queue the data carried in the SYN packet. We need to first
168156
* bump skb's refcnt because the caller will attempt to free it.
169157
*
170-
* XXX (TFO) - we honor a zero-payload TFO request for now.
171-
* (Any reason not to?)
158+
* XXX (TFO) - we honor a zero-payload TFO request for now,
159+
* (any reason not to?) but no need to queue the skb since
160+
* there is no data. How about SYN+FIN?
172161
*/
173-
if (TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq + 1) {
174-
/* Don't queue the skb if there is no payload in SYN.
175-
* XXX (TFO) - How about SYN+FIN?
176-
*/
177-
tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
178-
} else {
162+
if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq + 1) {
179163
skb = skb_get(skb);
180164
skb_dst_drop(skb);
181165
__skb_pull(skb, tcp_hdr(skb)->doff * 4);
182166
skb_set_owner_r(skb, child);
183167
__skb_queue_tail(&child->sk_receive_queue, skb);
184-
tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
185168
tp->syn_data_acked = 1;
186169
}
170+
tcp_rsk(req)->rcv_nxt = tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
187171
sk->sk_data_ready(sk);
188172
bh_unlock_sock(child);
189173
sock_put(child);
190174
WARN_ON(req->sk == NULL);
191-
return 0;
175+
return true;
192176
}
193177
EXPORT_SYMBOL(tcp_fastopen_create_child);
194178

@@ -232,9 +216,10 @@ static bool tcp_fastopen_queue_check(struct sock *sk)
232216
* may be updated and return the client in the SYN-ACK later. E.g., Fast Open
233217
* cookie request (foc->len == 0).
234218
*/
235-
bool tcp_fastopen_check(struct sock *sk, struct sk_buff *skb,
236-
struct request_sock *req,
237-
struct tcp_fastopen_cookie *foc)
219+
bool tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
220+
struct request_sock *req,
221+
struct tcp_fastopen_cookie *foc,
222+
struct dst_entry *dst)
238223
{
239224
struct tcp_fastopen_cookie valid_foc = { .len = -1 };
240225
bool syn_data = TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq + 1;
@@ -255,11 +240,21 @@ bool tcp_fastopen_check(struct sock *sk, struct sk_buff *skb,
255240
if (foc->len == TCP_FASTOPEN_COOKIE_SIZE &&
256241
foc->len == valid_foc.len &&
257242
!memcmp(foc->val, valid_foc.val, foc->len)) {
243+
/* Cookie is valid. Create a (full) child socket to accept
244+
* the data in SYN before returning a SYN-ACK to ack the
245+
* data. If we fail to create the socket, fall back and
246+
* ack the ISN only but includes the same cookie.
247+
*
248+
* Note: Data-less SYN with valid cookie is allowed to send
249+
* data in SYN_RECV state.
250+
*/
258251
fastopen:
259-
tcp_rsk(req)->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
260-
foc->len = -1;
261-
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPFASTOPENPASSIVE);
262-
return true;
252+
if (tcp_fastopen_create_child(sk, skb, dst, req)) {
253+
foc->len = -1;
254+
NET_INC_STATS_BH(sock_net(sk),
255+
LINUX_MIB_TCPFASTOPENPASSIVE);
256+
return true;
257+
}
263258
}
264259

265260
NET_INC_STATS_BH(sock_net(sk), foc->len ?
@@ -268,4 +263,4 @@ bool tcp_fastopen_check(struct sock *sk, struct sk_buff *skb,
268263
*foc = valid_foc;
269264
return false;
270265
}
271-
EXPORT_SYMBOL(tcp_fastopen_check);
266+
EXPORT_SYMBOL(tcp_try_fastopen);

net/ipv4/tcp_ipv4.c

Lines changed: 16 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,8 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
822822
*/
823823
static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
824824
struct request_sock *req,
825-
u16 queue_mapping)
825+
u16 queue_mapping,
826+
struct tcp_fastopen_cookie *foc)
826827
{
827828
const struct inet_request_sock *ireq = inet_rsk(req);
828829
struct flowi4 fl4;
@@ -833,7 +834,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
833834
if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL)
834835
return -1;
835836

836-
skb = tcp_make_synack(sk, dst, req, NULL);
837+
skb = tcp_make_synack(sk, dst, req, foc);
837838

838839
if (skb) {
839840
__tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr);
@@ -852,7 +853,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
852853

853854
static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req)
854855
{
855-
int res = tcp_v4_send_synack(sk, NULL, req, 0);
856+
int res = tcp_v4_send_synack(sk, NULL, req, 0, NULL);
856857

857858
if (!res) {
858859
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
@@ -1270,11 +1271,10 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
12701271
__be32 saddr = ip_hdr(skb)->saddr;
12711272
__be32 daddr = ip_hdr(skb)->daddr;
12721273
__u32 isn = TCP_SKB_CB(skb)->when;
1273-
bool want_cookie = false;
1274+
bool want_cookie = false, fastopen;
12741275
struct flowi4 fl4;
12751276
struct tcp_fastopen_cookie foc = { .len = -1 };
1276-
struct sk_buff *skb_synack;
1277-
int do_fastopen;
1277+
int err;
12781278

12791279
/* Never answer to SYNs send to broadcast or multicast */
12801280
if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
@@ -1373,49 +1373,24 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
13731373

13741374
isn = tcp_v4_init_sequence(skb);
13751375
}
1376-
tcp_rsk(req)->snt_isn = isn;
1377-
1378-
if (dst == NULL) {
1379-
dst = inet_csk_route_req(sk, &fl4, req);
1380-
if (dst == NULL)
1381-
goto drop_and_free;
1382-
}
1383-
do_fastopen = !want_cookie &&
1384-
tcp_fastopen_check(sk, skb, req, &foc);
1385-
1386-
/* We don't call tcp_v4_send_synack() directly because we need
1387-
* to make sure a child socket can be created successfully before
1388-
* sending back synack!
1389-
*
1390-
* XXX (TFO) - Ideally one would simply call tcp_v4_send_synack()
1391-
* (or better yet, call tcp_send_synack() in the child context
1392-
* directly, but will have to fix bunch of other code first)
1393-
* after syn_recv_sock() except one will need to first fix the
1394-
* latter to remove its dependency on the current implementation
1395-
* of tcp_v4_send_synack()->tcp_select_initial_window().
1396-
*/
1397-
skb_synack = tcp_make_synack(sk, dst, req, &foc);
1398-
1399-
if (skb_synack) {
1400-
__tcp_v4_send_check(skb_synack, ireq->ir_loc_addr, ireq->ir_rmt_addr);
1401-
skb_set_queue_mapping(skb_synack, skb_get_queue_mapping(skb));
1402-
} else
1376+
if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL)
14031377
goto drop_and_free;
14041378

1405-
if (likely(!do_fastopen)) {
1406-
int err;
1407-
err = ip_build_and_send_pkt(skb_synack, sk, ireq->ir_loc_addr,
1408-
ireq->ir_rmt_addr, ireq->opt);
1409-
err = net_xmit_eval(err);
1379+
tcp_rsk(req)->snt_isn = isn;
1380+
tcp_rsk(req)->snt_synack = tcp_time_stamp;
1381+
tcp_openreq_init_rwin(req, sk, dst);
1382+
fastopen = !want_cookie &&
1383+
tcp_try_fastopen(sk, skb, req, &foc, dst);
1384+
err = tcp_v4_send_synack(sk, dst, req,
1385+
skb_get_queue_mapping(skb), &foc);
1386+
if (!fastopen) {
14101387
if (err || want_cookie)
14111388
goto drop_and_free;
14121389

14131390
tcp_rsk(req)->snt_synack = tcp_time_stamp;
14141391
tcp_rsk(req)->listener = NULL;
1415-
/* Add the request_sock to the SYN table */
14161392
inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
1417-
} else if (tcp_fastopen_create_child(sk, skb, skb_synack, req))
1418-
goto drop_and_release;
1393+
}
14191394

14201395
return 0;
14211396

net/ipv4/tcp_minisocks.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,37 @@ void tcp_twsk_destructor(struct sock *sk)
362362
}
363363
EXPORT_SYMBOL_GPL(tcp_twsk_destructor);
364364

365+
void tcp_openreq_init_rwin(struct request_sock *req,
366+
struct sock *sk, struct dst_entry *dst)
367+
{
368+
struct inet_request_sock *ireq = inet_rsk(req);
369+
struct tcp_sock *tp = tcp_sk(sk);
370+
__u8 rcv_wscale;
371+
int mss = dst_metric_advmss(dst);
372+
373+
if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < mss)
374+
mss = tp->rx_opt.user_mss;
375+
376+
/* Set this up on the first call only */
377+
req->window_clamp = tp->window_clamp ? : dst_metric(dst, RTAX_WINDOW);
378+
379+
/* limit the window selection if the user enforce a smaller rx buffer */
380+
if (sk->sk_userlocks & SOCK_RCVBUF_LOCK &&
381+
(req->window_clamp > tcp_full_space(sk) || req->window_clamp == 0))
382+
req->window_clamp = tcp_full_space(sk);
383+
384+
/* tcp_full_space because it is guaranteed to be the first packet */
385+
tcp_select_initial_window(tcp_full_space(sk),
386+
mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0),
387+
&req->rcv_wnd,
388+
&req->window_clamp,
389+
ireq->wscale_ok,
390+
&rcv_wscale,
391+
dst_metric(dst, RTAX_INITRWND));
392+
ireq->rcv_wscale = rcv_wscale;
393+
}
394+
EXPORT_SYMBOL(tcp_openreq_init_rwin);
395+
365396
static inline void TCP_ECN_openreq_child(struct tcp_sock *tp,
366397
struct request_sock *req)
367398
{

net/ipv4/tcp_output.c

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2803,27 +2803,6 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
28032803
if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < mss)
28042804
mss = tp->rx_opt.user_mss;
28052805

2806-
if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */
2807-
__u8 rcv_wscale;
2808-
/* Set this up on the first call only */
2809-
req->window_clamp = tp->window_clamp ? : dst_metric(dst, RTAX_WINDOW);
2810-
2811-
/* limit the window selection if the user enforce a smaller rx buffer */
2812-
if (sk->sk_userlocks & SOCK_RCVBUF_LOCK &&
2813-
(req->window_clamp > tcp_full_space(sk) || req->window_clamp == 0))
2814-
req->window_clamp = tcp_full_space(sk);
2815-
2816-
/* tcp_full_space because it is guaranteed to be the first packet */
2817-
tcp_select_initial_window(tcp_full_space(sk),
2818-
mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0),
2819-
&req->rcv_wnd,
2820-
&req->window_clamp,
2821-
ireq->wscale_ok,
2822-
&rcv_wscale,
2823-
dst_metric(dst, RTAX_INITRWND));
2824-
ireq->rcv_wscale = rcv_wscale;
2825-
}
2826-
28272806
memset(&opts, 0, sizeof(opts));
28282807
#ifdef CONFIG_SYN_COOKIES
28292808
if (unlikely(req->cookie_ts))

0 commit comments

Comments
 (0)