Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /* Multipath TCP token management
3 : : * Copyright (c) 2017 - 2019, Intel Corporation.
4 : : *
5 : : * Note: This code is based on mptcp_ctrl.c from multipath-tcp.org,
6 : : * authored by:
7 : : *
8 : : * Sébastien Barré <sebastien.barre@uclouvain.be>
9 : : * Christoph Paasch <christoph.paasch@uclouvain.be>
10 : : * Jaakko Korkeaniemi <jaakko.korkeaniemi@aalto.fi>
11 : : * Gregory Detal <gregory.detal@uclouvain.be>
12 : : * Fabien Duchêne <fabien.duchene@uclouvain.be>
13 : : * Andreas Seelinger <Andreas.Seelinger@rwth-aachen.de>
14 : : * Lavkesh Lahngir <lavkesh51@gmail.com>
15 : : * Andreas Ripke <ripke@neclab.eu>
16 : : * Vlad Dogaru <vlad.dogaru@intel.com>
17 : : * Octavian Purdila <octavian.purdila@intel.com>
18 : : * John Ronan <jronan@tssg.org>
19 : : * Catalin Nicutar <catalin.nicutar@gmail.com>
20 : : * Brandon Heller <brandonh@stanford.edu>
21 : : */
22 : :
23 : : #define pr_fmt(fmt) "MPTCP: " fmt
24 : :
25 : : #include <linux/kernel.h>
26 : : #include <linux/module.h>
27 : : #include <linux/memblock.h>
28 : : #include <linux/ip.h>
29 : : #include <linux/tcp.h>
30 : : #include <net/sock.h>
31 : : #include <net/inet_common.h>
32 : : #include <net/protocol.h>
33 : : #include <net/mptcp.h>
34 : : #include "protocol.h"
35 : :
36 : : #define TOKEN_MAX_CHAIN_LEN 4
37 : :
38 : : struct token_bucket {
39 : : spinlock_t lock;
40 : : int chain_len;
41 : : struct hlist_nulls_head req_chain;
42 : : struct hlist_nulls_head msk_chain;
43 : : };
44 : :
45 : : static struct token_bucket *token_hash __read_mostly;
46 : : static unsigned int token_mask __read_mostly;
47 : :
48 : 0 : static struct token_bucket *token_bucket(u32 token)
49 : : {
50 : 7096 : return &token_hash[token & token_mask];
51 : : }
52 : :
53 : : /* called with bucket lock held */
54 : : static struct mptcp_subflow_request_sock *
55 : 0 : __token_lookup_req(struct token_bucket *t, u32 token)
56 : : {
57 : 4139 : struct mptcp_subflow_request_sock *req;
58 : 4139 : struct hlist_nulls_node *pos;
59 : :
60 [ - - - + ]: 5095 : hlist_nulls_for_each_entry_rcu(req, pos, &t->req_chain, token_node)
61 [ - - - - ]: 1684 : if (req->token == token)
62 : : return req;
63 : : return NULL;
64 : : }
65 : :
66 : : /* called with bucket lock held */
67 : : static struct mptcp_sock *
68 : 6724 : __token_lookup_msk(struct token_bucket *t, u32 token)
69 : : {
70 : 6724 : struct hlist_nulls_node *pos;
71 : 6724 : struct sock *sk;
72 : :
73 [ + ]: 6747 : sk_nulls_for_each_rcu(sk, pos, &t->msk_chain)
74 [ + - + ]: 3336 : if (mptcp_sk(sk)->token == token)
75 [ + ]: 3313 : return mptcp_sk(sk);
76 : : return NULL;
77 : : }
78 : :
79 : 3411 : static bool __token_bucket_busy(struct token_bucket *t, u32 token)
80 : : {
81 [ + - ][ + ]: 6756 : return !token || t->chain_len >= TOKEN_MAX_CHAIN_LEN ||
82 [ - - ]: 6822 : __token_lookup_req(t, token) || __token_lookup_msk(t, token);
[ - - - ]
83 : : }
84 : :
85 : 1733 : static void mptcp_crypto_key_gen_sha(u64 *key, u32 *token, u64 *idsn)
86 : : {
87 : : /* we might consider a faster version that computes the key as a
88 : : * hash of some information available in the MPTCP socket. Use
89 : : * random data at the moment, as it's probably the safest option
90 : : * in case multiple sockets are opened in different namespaces at
91 : : * the same time.
92 : : */
93 : 1733 : get_random_bytes(key, sizeof(u64));
94 : 1733 : mptcp_crypto_key_sha(*key, token, idsn);
95 : 1733 : }
96 : :
97 : : /**
98 : : * mptcp_token_new_request - create new key/idsn/token for subflow_request
99 : : * @req: the request socket
100 : : *
101 : : * This function is called when a new mptcp connection is coming in.
102 : : *
103 : : * It creates a unique token to identify the new mptcp connection,
104 : : * a secret local key and the initial data sequence number (idsn).
105 : : *
106 : : * Return: 0 on success.
107 : : */
108 : 1678 : int mptcp_token_new_request(struct request_sock *req)
109 : : {
110 : 1678 : struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
111 : 1678 : struct token_bucket *bucket;
112 : 1678 : u32 token;
113 : :
114 : 1678 : mptcp_crypto_key_sha(subflow_req->local_key,
115 : : &subflow_req->token,
116 : : &subflow_req->idsn);
117 [ - - ]: 1678 : pr_debug("req=%p local_key=%llu, token=%u, idsn=%llu\n",
118 : : req, subflow_req->local_key, subflow_req->token,
119 : : subflow_req->idsn);
120 : :
121 : 1678 : token = subflow_req->token;
122 : 1678 : bucket = token_bucket(token);
123 : 1678 : spin_lock_bh(&bucket->lock);
124 [ + ]: 1678 : if (__token_bucket_busy(bucket, token)) {
125 : 0 : spin_unlock_bh(&bucket->lock);
126 : 0 : return -EBUSY;
127 : : }
128 : :
129 : 1678 : hlist_nulls_add_head_rcu(&subflow_req->token_node, &bucket->req_chain);
130 : 1678 : bucket->chain_len++;
131 : 1678 : spin_unlock_bh(&bucket->lock);
132 : 1678 : return 0;
133 : : }
134 : :
135 : : /**
136 : : * mptcp_token_new_connect - create new key/idsn/token for subflow
137 : : * @ssk: the socket that will initiate a connection
138 : : *
139 : : * This function is called when a new outgoing mptcp connection is
140 : : * initiated.
141 : : *
142 : : * It creates a unique token to identify the new mptcp connection,
143 : : * a secret local key and the initial data sequence number (idsn).
144 : : *
145 : : * On success, the mptcp connection can be found again using
146 : : * the computed token at a later time, this is needed to process
147 : : * join requests.
148 : : *
149 : : * Return: 0 on success.
150 : : */
151 : 1733 : int mptcp_token_new_connect(struct sock *ssk)
152 : : {
153 [ + ]: 1733 : struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
154 [ + ]: 1733 : struct mptcp_sock *msk = mptcp_sk(subflow->conn);
155 : 30 : int retries = MPTCP_TOKEN_MAX_RETRIES;
156 : : struct sock *sk = subflow->conn;
157 : 30 : struct token_bucket *bucket;
158 : :
159 : 1733 : again:
160 : 1733 : mptcp_crypto_key_gen_sha(&subflow->local_key, &subflow->token,
161 : : &subflow->idsn);
162 : :
163 : 1733 : bucket = token_bucket(subflow->token);
164 : 1733 : spin_lock_bh(&bucket->lock);
165 [ + ]: 1733 : if (__token_bucket_busy(bucket, subflow->token)) {
166 : 0 : spin_unlock_bh(&bucket->lock);
167 [ # ][ # ]: 0 : if (!--retries)
168 : : return -EBUSY;
169 : 0 : goto again;
170 : : }
171 : :
172 [ - - ]: 1733 : pr_debug("ssk=%p, local_key=%llu, token=%u, idsn=%llu\n",
173 : : ssk, subflow->local_key, subflow->token, subflow->idsn);
174 : :
175 : 1733 : WRITE_ONCE(msk->token, subflow->token);
176 : 1733 : __sk_nulls_add_node_rcu((struct sock *)msk, &bucket->msk_chain);
177 : 1733 : bucket->chain_len++;
178 : 1733 : spin_unlock_bh(&bucket->lock);
179 : 1733 : sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
180 : 1733 : return 0;
181 : : }
182 : :
183 : : /**
184 : : * mptcp_token_move_request - move request token ownership to a clone
185 : : * @req: original request socket
186 : : * @new_req: cloned request socket
187 : : *
188 : : * Move the token hash entry from the original request to its clone.
189 : : */
190 : 12 : void mptcp_token_move_request(struct request_sock *req,
191 : : struct request_sock *new_req)
192 : : {
193 : 12 : struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
194 : 12 : struct mptcp_subflow_request_sock *new_subflow_req;
195 : 12 : struct mptcp_subflow_request_sock *pos;
196 : 12 : struct token_bucket *bucket;
197 : :
198 : 12 : new_subflow_req = mptcp_subflow_rsk(new_req);
199 : :
200 [ + ]: 12 : if (hlist_nulls_unhashed_lockless(&subflow_req->token_node)) {
201 : 6 : mptcp_token_init_request(new_req);
202 : 6 : return;
203 : : }
204 : :
205 : 6 : bucket = token_bucket(subflow_req->token);
206 : 6 : spin_lock_bh(&bucket->lock);
207 [ + ]: 6 : if (hlist_nulls_unhashed(&subflow_req->token_node)) {
208 : 0 : mptcp_token_init_request(new_req);
209 : : } else {
210 : 6 : pos = __token_lookup_req(bucket, subflow_req->token);
211 [ - ]: 6 : if (pos == subflow_req)
212 : 6 : hlist_nulls_replace_init_rcu(&subflow_req->token_node,
213 : : &new_subflow_req->token_node);
214 : : else
215 : 0 : mptcp_token_init_request(new_req);
216 : : }
217 : 6 : spin_unlock_bh(&bucket->lock);
218 : : }
219 : :
220 : : /**
221 : : * mptcp_token_accept - replace a req sk with full sock in token hash
222 : : * @req: the request socket to be removed
223 : : * @msk: the just cloned socket linked to the new connection
224 : : *
225 : : * Called when a SYN packet creates a new logical connection, i.e.
226 : : * is not a join request.
227 : : *
228 : : * Return: true on success.
229 : : */
230 : 1646 : bool mptcp_token_accept(struct mptcp_subflow_request_sock *req,
231 : : struct mptcp_sock *msk)
232 : : {
233 : 1646 : struct mptcp_subflow_request_sock *pos;
234 : 1646 : struct sock *sk = (struct sock *)msk;
235 : 1646 : struct token_bucket *bucket;
236 : 1646 : bool ret = false;
237 : :
238 : 1646 : bucket = token_bucket(req->token);
239 : 1646 : spin_lock_bh(&bucket->lock);
240 [ + ]: 1646 : if (hlist_nulls_unhashed(&req->token_node))
241 : 0 : goto unlock;
242 : :
243 : 1646 : pos = __token_lookup_req(bucket, req->token);
244 [ + ]: 1646 : if (pos != req)
245 : 0 : goto unlock;
246 : :
247 : 1646 : hlist_nulls_del_init_rcu(&req->token_node);
248 : 1646 : __sk_nulls_add_node_rcu((struct sock *)msk, &bucket->msk_chain);
249 : : ret = true;
250 : :
251 : 1646 : unlock:
252 : 1646 : spin_unlock_bh(&bucket->lock);
253 [ - ][ - ]: 1646 : if (ret)
254 : 1646 : sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
255 : :
256 : 1646 : return ret;
257 : : }
258 : :
259 : 52 : bool mptcp_token_exists(u32 token)
260 : : {
261 : 52 : struct hlist_nulls_node *pos;
262 : 52 : struct token_bucket *bucket;
263 : 52 : struct mptcp_sock *msk;
264 : 52 : struct sock *sk;
265 : :
266 : 52 : rcu_read_lock();
267 : 52 : bucket = token_bucket(token);
268 : :
269 : 52 : again:
270 [ + ][ + ]: 52 : sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
271 [ # # ][ # # ]: 0 : msk = mptcp_sk(sk);
272 [ # ][ # ]: 0 : if (READ_ONCE(msk->token) == token)
273 : 0 : goto found;
274 : : }
275 [ + ][ + ]: 52 : if (get_nulls_value(pos) != (token & token_mask))
276 : 0 : goto again;
277 : :
278 : 52 : rcu_read_unlock();
279 : 52 : return false;
280 : 0 : found:
281 : 0 : rcu_read_unlock();
282 : 0 : return true;
283 : : }
284 : :
285 : : /**
286 : : * mptcp_token_get_sock - retrieve mptcp connection sock using its token
287 : : * @net: restrict to this namespace
288 : : * @token: token of the mptcp connection to retrieve
289 : : *
290 : : * This function returns the mptcp connection structure with the given token.
291 : : * A reference count on the mptcp socket returned is taken.
292 : : *
293 : : * Return: NULL if no connection with the given token value exists.
294 : : */
295 : 814 : struct mptcp_sock *mptcp_token_get_sock(struct net *net, u32 token)
296 : : {
297 : 814 : struct hlist_nulls_node *pos;
298 : 814 : struct token_bucket *bucket;
299 : 814 : struct mptcp_sock *msk;
300 : 814 : struct sock *sk;
301 : :
302 : 814 : rcu_read_lock();
303 : 814 : bucket = token_bucket(token);
304 : :
305 : : again:
306 [ + ][ + ]: 814 : sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
307 [ - + ][ - + ]: 800 : msk = mptcp_sk(sk);
308 [ - + ][ - + ]: 1197 : if (READ_ONCE(msk->token) != token ||
[ - ][ - ]
309 [ + ][ + ]: 6 : !net_eq(sock_net(sk), net))
310 : 0 : continue;
311 : :
312 [ + ][ + ]: 800 : if (!refcount_inc_not_zero(&sk->sk_refcnt))
313 : 2 : goto not_found;
314 : :
315 [ - + ][ - + ]: 1194 : if (READ_ONCE(msk->token) != token ||
[ - ][ - ]
316 [ + ][ + ]: 6 : !net_eq(sock_net(sk), net)) {
317 : 0 : sock_put(sk);
318 : 0 : goto again;
319 : : }
320 : 798 : goto found;
321 : : }
322 [ + ][ + ]: 14 : if (get_nulls_value(pos) != (token & token_mask))
323 : 0 : goto again;
324 : :
325 : 14 : not_found:
326 : : msk = NULL;
327 : :
328 : 814 : found:
329 : 814 : rcu_read_unlock();
330 : 814 : return msk;
331 : : }
332 : : EXPORT_SYMBOL_GPL(mptcp_token_get_sock);
333 : :
334 : : /**
335 : : * mptcp_token_iter_next - iterate over the token container from given pos
336 : : * @net: namespace to be iterated
337 : : * @s_slot: start slot number
338 : : * @s_num: start number inside the given lock
339 : : *
340 : : * Description:
341 : : * On successful iteration, the iterator is moved to the next position and a
342 : : * reference to the returned socket is acquired.
343 : : *
344 : : * Return:
345 : : * The first mptcp connection structure found inside the token container
346 : : * starting from the specified position, or NULL.
347 : : */
348 : 5964 : struct mptcp_sock *mptcp_token_iter_next(const struct net *net, long *s_slot,
349 : : long *s_num)
350 : : {
351 : 5964 : struct mptcp_sock *ret = NULL;
352 : 5964 : struct hlist_nulls_node *pos;
353 : 5964 : int slot, num = 0;
354 : :
355 [ + ][ + ]: 18839372 : for (slot = *s_slot; slot <= token_mask; *s_num = 0, slot++) {
356 : 18836757 : struct token_bucket *bucket = &token_hash[slot];
357 : 18836757 : struct sock *sk;
358 : :
359 : 18836757 : num = 0;
360 : :
361 [ + ]: 18836757 : if (hlist_nulls_empty(&bucket->msk_chain))
362 : 18825326 : continue;
363 : :
364 : 11431 : rcu_read_lock();
365 [ + ][ + ]: 19667 : sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
366 : 11585 : ++num;
367 [ + + ][ + + ]: 11585 : if (!net_eq(sock_net(sk), net))
368 : 4837 : continue;
369 : :
370 [ + ][ + ]: 6748 : if (num <= *s_num)
371 : 3399 : continue;
372 : :
373 [ + ][ + ]: 3349 : if (!refcount_inc_not_zero(&sk->sk_refcnt))
374 : 0 : continue;
375 : :
376 [ + ][ + ]: 3349 : if (!net_eq(sock_net(sk), net)) {
377 : 0 : sock_put(sk);
378 : 0 : continue;
379 : : }
380 : :
381 [ + ][ + ]: 3349 : ret = mptcp_sk(sk);
382 : 3349 : rcu_read_unlock();
383 : 3349 : goto out;
384 : : }
385 : 8082 : rcu_read_unlock();
386 : : }
387 : :
388 : 2615 : out:
389 : 5964 : *s_slot = slot;
390 : 5964 : *s_num = num;
391 : 5964 : return ret;
392 : : }
393 : : EXPORT_SYMBOL_GPL(mptcp_token_iter_next);
394 : :
395 : : /**
396 : : * mptcp_token_destroy_request - remove mptcp connection/token
397 : : * @req: mptcp request socket dropping the token
398 : : *
399 : : * Remove the token associated to @req.
400 : : */
401 : 2556 : void mptcp_token_destroy_request(struct request_sock *req)
402 : : {
403 : 2556 : struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
404 : 2556 : struct mptcp_subflow_request_sock *pos;
405 : 2556 : struct token_bucket *bucket;
406 : :
407 [ + ]: 2556 : if (hlist_nulls_unhashed_lockless(&subflow_req->token_node))
408 : : return;
409 : :
410 : 32 : bucket = token_bucket(subflow_req->token);
411 : 32 : spin_lock_bh(&bucket->lock);
412 [ + ]: 32 : if (hlist_nulls_unhashed(&subflow_req->token_node))
413 : 0 : goto unlock;
414 : :
415 : 32 : pos = __token_lookup_req(bucket, subflow_req->token);
416 [ + ]: 32 : if (pos == subflow_req) {
417 : 32 : hlist_nulls_del_init_rcu(&pos->token_node);
418 : 32 : bucket->chain_len--;
419 : : }
420 : :
421 : 0 : unlock:
422 : 32 : spin_unlock_bh(&bucket->lock);
423 : : }
424 : :
425 : : /**
426 : : * mptcp_token_destroy - remove mptcp connection/token
427 : : * @msk: mptcp connection dropping the token
428 : : *
429 : : * Remove the token associated to @msk
430 : : */
431 : 5412 : void mptcp_token_destroy(struct mptcp_sock *msk)
432 : : {
433 : 5412 : struct sock *sk = (struct sock *)msk;
434 : 5412 : struct token_bucket *bucket;
435 : 5412 : struct mptcp_sock *pos;
436 : :
437 [ + ][ + ]: 5412 : if (sk_unhashed((struct sock *)msk))
438 : : return;
439 : :
440 : 3313 : sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
441 : 3313 : bucket = token_bucket(msk->token);
442 : 3313 : spin_lock_bh(&bucket->lock);
443 : 3313 : pos = __token_lookup_msk(bucket, msk->token);
444 [ + - ][ + - ]: 3313 : if (!WARN_ON_ONCE(pos != msk)) {
445 [ - ][ - ]: 3313 : __sk_nulls_del_node_init_rcu((struct sock *)pos);
446 : 3313 : bucket->chain_len--;
447 : : }
448 : 3313 : spin_unlock_bh(&bucket->lock);
449 : 3313 : WRITE_ONCE(msk->token, 0);
450 : : }
451 : :
452 : 6 : void __init mptcp_token_init(void)
453 : : {
454 : 6 : int i;
455 : :
456 : 6 : token_hash = alloc_large_system_hash("MPTCP token",
457 : : sizeof(struct token_bucket),
458 : : 0,
459 : : 20,/* one slot per 1MB of memory */
460 : : HASH_ZERO,
461 : : NULL,
462 : : &token_mask,
463 : : 0,
464 : : 64 * 1024);
465 [ + ][ + ]: 49158 : for (i = 0; i < token_mask + 1; ++i) {
466 : 49152 : INIT_HLIST_NULLS_HEAD(&token_hash[i].req_chain, i);
467 : 49152 : INIT_HLIST_NULLS_HEAD(&token_hash[i].msk_chain, i);
468 : 49152 : spin_lock_init(&token_hash[i].lock);
469 : : }
470 : 6 : }
471 : :
472 : : #if IS_MODULE(CONFIG_MPTCP_KUNIT_TEST)
473 : : EXPORT_SYMBOL_GPL(mptcp_token_new_request);
474 : : EXPORT_SYMBOL_GPL(mptcp_token_new_connect);
475 : : EXPORT_SYMBOL_GPL(mptcp_token_accept);
476 : : EXPORT_SYMBOL_GPL(mptcp_token_destroy_request);
477 : : EXPORT_SYMBOL_GPL(mptcp_token_destroy);
478 : : #endif
|