Skip to content

Commit 2472186

Browse files
committed
Merge branch 'tcp-listener-fixes-and-improvement'
Eric Dumazet says: ==================== tcp: lockless listener fixes and improvement This fixes issues with TCP FastOpen vs lockless listeners, and SYNACK being attached to request sockets. Then, last patch brings performance improvement for syncookies generation and validation. Tested under a 4.3 Mpps SYNFLOOD attack, new perf profile looks like : 12.11% [kernel] [k] sha_transform 5.83% [kernel] [k] tcp_conn_request 4.59% [kernel] [k] __inet_lookup_listener 4.11% [kernel] [k] ipt_do_table 3.91% [kernel] [k] tcp_make_synack 3.05% [kernel] [k] fib_table_lookup 2.74% [kernel] [k] sock_wfree 2.66% [kernel] [k] memcpy_erms 2.12% [kernel] [k] tcp_v4_rcv ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 3e087ca + a1a5344 commit 2472186

File tree

11 files changed

+41
-36
lines changed

11 files changed

+41
-36
lines changed

include/linux/ipv6.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,9 @@ struct tcp6_timewait_sock {
264264
};
265265

266266
#if IS_ENABLED(CONFIG_IPV6)
267-
static inline struct ipv6_pinfo * inet6_sk(const struct sock *__sk)
267+
static inline struct ipv6_pinfo *inet6_sk(const struct sock *__sk)
268268
{
269-
return inet_sk(__sk)->pinet6;
269+
return sk_fullsock(__sk) ? inet_sk(__sk)->pinet6 : NULL;
270270
}
271271

272272
static inline struct raw6_sock *raw6_sk(const struct sock *sk)

include/net/inet_sock.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ static inline unsigned int __inet_ehashfn(const __be32 laddr,
245245
}
246246

247247
struct request_sock *inet_reqsk_alloc(const struct request_sock_ops *ops,
248-
struct sock *sk_listener);
248+
struct sock *sk_listener,
249+
bool attach_listener);
249250

250251
static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
251252
{

include/net/ip.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,12 +323,15 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
323323

324324
static inline unsigned int ip_skb_dst_mtu(const struct sk_buff *skb)
325325
{
326-
if (!skb->sk || ip_sk_use_pmtu(skb->sk)) {
326+
struct sock *sk = skb->sk;
327+
328+
if (!sk || !sk_fullsock(sk) || ip_sk_use_pmtu(sk)) {
327329
bool forwarding = IPCB(skb)->flags & IPSKB_FORWARDED;
330+
328331
return ip_dst_mtu_maybe_forward(skb_dst(skb), forwarding);
329-
} else {
330-
return min(skb_dst(skb)->dev->mtu, IP_MAX_MTU);
331332
}
333+
334+
return min(skb_dst(skb)->dev->mtu, IP_MAX_MTU);
332335
}
333336

334337
u32 ip_idents_reserve(u32 hash, int segs);

include/net/request_sock.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,18 +80,24 @@ static inline struct sock *req_to_sk(struct request_sock *req)
8080
}
8181

8282
static inline struct request_sock *
83-
reqsk_alloc(const struct request_sock_ops *ops, struct sock *sk_listener)
83+
reqsk_alloc(const struct request_sock_ops *ops, struct sock *sk_listener,
84+
bool attach_listener)
8485
{
8586
struct request_sock *req;
8687

8788
req = kmem_cache_alloc(ops->slab, GFP_ATOMIC | __GFP_NOWARN);
8889

8990
if (req) {
9091
req->rsk_ops = ops;
91-
sock_hold(sk_listener);
92-
req->rsk_listener = sk_listener;
92+
if (attach_listener) {
93+
sock_hold(sk_listener);
94+
req->rsk_listener = sk_listener;
95+
} else {
96+
req->rsk_listener = NULL;
97+
}
9398
req_to_sk(req)->sk_prot = sk_listener->sk_prot;
9499
sk_node_init(&req_to_sk(req)->sk_node);
100+
sk_tx_queue_clear(req_to_sk(req));
95101
req->saved_syn = NULL;
96102
/* Following is temporary. It is coupled with debugging
97103
* helpers in reqsk_put() & reqsk_free()

net/core/dev.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2974,6 +2974,7 @@ static u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb)
29742974
new_index = skb_tx_hash(dev, skb);
29752975

29762976
if (queue_index != new_index && sk &&
2977+
sk_fullsock(sk) &&
29772978
rcu_access_pointer(sk->sk_dst_cache))
29782979
sk_tx_queue_set(sk, new_index);
29792980

net/dccp/ipv4.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
595595
if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
596596
goto drop;
597597

598-
req = inet_reqsk_alloc(&dccp_request_sock_ops, sk);
598+
req = inet_reqsk_alloc(&dccp_request_sock_ops, sk, true);
599599
if (req == NULL)
600600
goto drop;
601601

net/dccp/ipv6.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
319319
if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
320320
goto drop;
321321

322-
req = inet_reqsk_alloc(&dccp6_request_sock_ops, sk);
322+
req = inet_reqsk_alloc(&dccp6_request_sock_ops, sk, true);
323323
if (req == NULL)
324324
goto drop;
325325

net/ipv4/syncookies.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
326326
goto out;
327327

328328
ret = NULL;
329-
req = inet_reqsk_alloc(&tcp_request_sock_ops, sk); /* for safety */
329+
req = inet_reqsk_alloc(&tcp_request_sock_ops, sk, false); /* for safety */
330330
if (!req)
331331
goto out;
332332

net/ipv4/tcp_fastopen.c

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,6 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk,
168168
TCP_TIMEOUT_INIT, TCP_RTO_MAX);
169169

170170
atomic_set(&req->rsk_refcnt, 2);
171-
/* Add the child socket directly into the accept queue */
172-
inet_csk_reqsk_queue_add(sk, req, child);
173171

174172
/* Now finish processing the fastopen child socket. */
175173
inet_csk(child)->icsk_af_ops->rebuild_header(child);
@@ -178,25 +176,18 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk,
178176
tcp_init_metrics(child);
179177
tcp_init_buffer_space(child);
180178

181-
/* Queue the data carried in the SYN packet. We need to first
182-
* bump skb's refcnt because the caller will attempt to free it.
183-
* Note that IPv6 might also have used skb_get() trick
184-
* in tcp_v6_conn_request() to keep this SYN around (treq->pktopts)
185-
* So we need to eventually get a clone of the packet,
186-
* before inserting it in sk_receive_queue.
179+
/* Queue the data carried in the SYN packet.
180+
* We used to play tricky games with skb_get().
181+
* With lockless listener, it is a dead end.
182+
* Do not think about it.
187183
*
188184
* XXX (TFO) - we honor a zero-payload TFO request for now,
189185
* (any reason not to?) but no need to queue the skb since
190186
* there is no data. How about SYN+FIN?
191187
*/
192188
end_seq = TCP_SKB_CB(skb)->end_seq;
193189
if (end_seq != TCP_SKB_CB(skb)->seq + 1) {
194-
struct sk_buff *skb2;
195-
196-
if (unlikely(skb_shared(skb)))
197-
skb2 = skb_clone(skb, GFP_ATOMIC);
198-
else
199-
skb2 = skb_get(skb);
190+
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
200191

201192
if (likely(skb2)) {
202193
skb_dst_drop(skb2);
@@ -214,12 +205,9 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk,
214205
}
215206
}
216207
tcp_rsk(req)->rcv_nxt = tp->rcv_nxt = end_seq;
217-
sk->sk_data_ready(sk);
218-
bh_unlock_sock(child);
219-
/* Note: sock_put(child) will be done by tcp_conn_request()
220-
* after SYNACK packet is sent.
208+
/* tcp_conn_request() is sending the SYNACK,
209+
* and queues the child into listener accept queue.
221210
*/
222-
WARN_ON(!req->sk);
223211
return child;
224212
}
225213

net/ipv4/tcp_input.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6042,9 +6042,11 @@ static void tcp_openreq_init(struct request_sock *req,
60426042
}
60436043

60446044
struct request_sock *inet_reqsk_alloc(const struct request_sock_ops *ops,
6045-
struct sock *sk_listener)
6045+
struct sock *sk_listener,
6046+
bool attach_listener)
60466047
{
6047-
struct request_sock *req = reqsk_alloc(ops, sk_listener);
6048+
struct request_sock *req = reqsk_alloc(ops, sk_listener,
6049+
attach_listener);
60486050

60496051
if (req) {
60506052
struct inet_request_sock *ireq = inet_rsk(req);
@@ -6143,7 +6145,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
61436145
goto drop;
61446146
}
61456147

6146-
req = inet_reqsk_alloc(rsk_ops, sk);
6148+
req = inet_reqsk_alloc(rsk_ops, sk, !want_cookie);
61476149
if (!req)
61486150
goto drop;
61496151

@@ -6229,12 +6231,16 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
62296231
tcp_rsk(req)->txhash = net_tx_rndhash();
62306232
tcp_openreq_init_rwin(req, sk, dst);
62316233
if (!want_cookie) {
6232-
fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst);
62336234
tcp_reqsk_record_syn(sk, req, skb);
6235+
fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst);
62346236
}
62356237
if (fastopen_sk) {
62366238
af_ops->send_synack(fastopen_sk, dst, &fl, req,
62376239
skb_get_queue_mapping(skb), &foc, false);
6240+
/* Add the child socket directly into the accept queue */
6241+
inet_csk_reqsk_queue_add(sk, req, fastopen_sk);
6242+
sk->sk_data_ready(sk);
6243+
bh_unlock_sock(fastopen_sk);
62386244
sock_put(fastopen_sk);
62396245
} else {
62406246
tcp_rsk(req)->tfo_listener = false;

net/ipv6/syncookies.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
170170
goto out;
171171

172172
ret = NULL;
173-
req = inet_reqsk_alloc(&tcp6_request_sock_ops, sk);
173+
req = inet_reqsk_alloc(&tcp6_request_sock_ops, sk, false);
174174
if (!req)
175175
goto out;
176176

0 commit comments

Comments
 (0)