LCOV - code coverage report
Current view: top level - mptcp/token.c (source / functions) Coverage Total Hit
Test: export Lines: 88.1 % 177 156
Test Date: 2024-10-18 11:08:02 Functions: 100.0 % 12 12
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 57.4 % 108 62

             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                 :        6350 :         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                 :        3458 :         struct mptcp_subflow_request_sock *req;
      58                 :        3458 :         struct hlist_nulls_node *pos;
      59                 :             : 
      60   [ +  -  +  -  :        3632 :         hlist_nulls_for_each_entry_rcu(req, pos, &t->req_chain, token_node)
                   -  + ]
      61   [ -  +  -  +  :        1186 :                 if (req->token == token)
                   -  - ]
      62                 :             :                         return req;
      63                 :             :         return NULL;
      64                 :             : }
      65                 :             : 
      66                 :             : /* called with bucket lock held */
      67                 :             : static struct mptcp_sock *
      68                 :        4792 : __token_lookup_msk(struct token_bucket *t, u32 token)
      69                 :             : {
      70                 :        4792 :         struct hlist_nulls_node *pos;
      71                 :        4792 :         struct sock *sk;
      72                 :             : 
      73         [ +  + ]:        4833 :         sk_nulls_for_each_rcu(sk, pos, &t->msk_chain)
      74   [ +  +  -  + ]:        2387 :                 if (mptcp_sk(sk)->token == token)
      75         [ -  + ]:        2346 :                         return mptcp_sk(sk);
      76                 :             :         return NULL;
      77                 :             : }
      78                 :             : 
      79                 :        2446 : static bool __token_bucket_busy(struct token_bucket *t, u32 token)
      80                 :             : {
      81   [ -  +  -  + ]:        4778 :         return !token || t->chain_len >= TOKEN_MAX_CHAIN_LEN ||
      82   [ +  -  -  +  :        4892 :                __token_lookup_req(t, token) || __token_lookup_msk(t, token);
                   -  + ]
      83                 :             : }
      84                 :             : 
      85                 :        1260 : 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                 :        1260 :         get_random_bytes(key, sizeof(u64));
      94                 :        1260 :         mptcp_crypto_key_sha(*key, token, idsn);
      95                 :        1260 : }
      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                 :             :  * Returns 0 on success.
     107                 :             :  */
     108                 :        1186 : int mptcp_token_new_request(struct request_sock *req)
     109                 :             : {
     110                 :        1186 :         struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
     111                 :        1186 :         struct token_bucket *bucket;
     112                 :        1186 :         u32 token;
     113                 :             : 
     114                 :        1186 :         mptcp_crypto_key_sha(subflow_req->local_key,
     115                 :             :                              &subflow_req->token,
     116                 :             :                              &subflow_req->idsn);
     117         [ -  + ]:        1186 :         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                 :        1186 :         token = subflow_req->token;
     122                 :        1186 :         bucket = token_bucket(token);
     123                 :        1186 :         spin_lock_bh(&bucket->lock);
     124         [ -  + ]:        1186 :         if (__token_bucket_busy(bucket, token)) {
     125                 :           0 :                 spin_unlock_bh(&bucket->lock);
     126                 :           0 :                 return -EBUSY;
     127                 :             :         }
     128                 :             : 
     129                 :        1186 :         hlist_nulls_add_head_rcu(&subflow_req->token_node, &bucket->req_chain);
     130                 :        1186 :         bucket->chain_len++;
     131                 :        1186 :         spin_unlock_bh(&bucket->lock);
     132                 :        1186 :         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                 :             :  * returns 0 on success.
     150                 :             :  */
     151                 :        1260 : int mptcp_token_new_connect(struct sock *ssk)
     152                 :             : {
     153         [ -  + ]:        1260 :         struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
     154         [ -  + ]:        1260 :         struct mptcp_sock *msk = mptcp_sk(subflow->conn);
     155                 :          54 :         int retries = MPTCP_TOKEN_MAX_RETRIES;
     156                 :             :         struct sock *sk = subflow->conn;
     157                 :          54 :         struct token_bucket *bucket;
     158                 :             : 
     159                 :        1260 : again:
     160                 :        1260 :         mptcp_crypto_key_gen_sha(&subflow->local_key, &subflow->token,
     161                 :             :                                  &subflow->idsn);
     162                 :             : 
     163                 :        1260 :         bucket = token_bucket(subflow->token);
     164                 :        1260 :         spin_lock_bh(&bucket->lock);
     165         [ -  + ]:        1260 :         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         [ -  + ]:        1260 :         pr_debug("ssk=%p, local_key=%llu, token=%u, idsn=%llu\n",
     173                 :             :                  ssk, subflow->local_key, subflow->token, subflow->idsn);
     174                 :             : 
     175                 :        1260 :         WRITE_ONCE(msk->token, subflow->token);
     176                 :        1260 :         __sk_nulls_add_node_rcu((struct sock *)msk, &bucket->msk_chain);
     177                 :        1260 :         bucket->chain_len++;
     178                 :        1260 :         spin_unlock_bh(&bucket->lock);
     179                 :        1260 :         sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
     180                 :        1260 :         return 0;
     181                 :             : }
     182                 :             : 
     183                 :             : /**
     184                 :             :  * mptcp_token_accept - replace a req sk with full sock in token hash
     185                 :             :  * @req: the request socket to be removed
     186                 :             :  * @msk: the just cloned socket linked to the new connection
     187                 :             :  *
     188                 :             :  * Called when a SYN packet creates a new logical connection, i.e.
     189                 :             :  * is not a join request.
     190                 :             :  */
     191                 :        1160 : void mptcp_token_accept(struct mptcp_subflow_request_sock *req,
     192                 :             :                         struct mptcp_sock *msk)
     193                 :             : {
     194                 :        1160 :         struct mptcp_subflow_request_sock *pos;
     195                 :        1160 :         struct sock *sk = (struct sock *)msk;
     196                 :        1160 :         struct token_bucket *bucket;
     197                 :             : 
     198                 :        1160 :         sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
     199                 :        1160 :         bucket = token_bucket(req->token);
     200                 :        1160 :         spin_lock_bh(&bucket->lock);
     201                 :             : 
     202                 :             :         /* pedantic lookup check for the moved token */
     203                 :        1160 :         pos = __token_lookup_req(bucket, req->token);
     204   [ -  +  +  - ]:        1160 :         if (!WARN_ON_ONCE(pos != req))
     205                 :        1160 :                 hlist_nulls_del_init_rcu(&req->token_node);
     206                 :        1160 :         __sk_nulls_add_node_rcu((struct sock *)msk, &bucket->msk_chain);
     207                 :        1160 :         spin_unlock_bh(&bucket->lock);
     208                 :        1160 : }
     209                 :             : 
     210                 :          28 : bool mptcp_token_exists(u32 token)
     211                 :             : {
     212                 :          28 :         struct hlist_nulls_node *pos;
     213                 :          28 :         struct token_bucket *bucket;
     214                 :          28 :         struct mptcp_sock *msk;
     215                 :          28 :         struct sock *sk;
     216                 :             : 
     217                 :          28 :         rcu_read_lock();
     218                 :          28 :         bucket = token_bucket(token);
     219                 :             : 
     220                 :          28 : again:
     221         [ -  + ]:          28 :         sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
     222         [ #  # ]:           0 :                 msk = mptcp_sk(sk);
     223         [ #  # ]:           0 :                 if (READ_ONCE(msk->token) == token)
     224                 :           0 :                         goto found;
     225                 :             :         }
     226         [ -  + ]:          28 :         if (get_nulls_value(pos) != (token & token_mask))
     227                 :           0 :                 goto again;
     228                 :             : 
     229                 :          28 :         rcu_read_unlock();
     230                 :          28 :         return false;
     231                 :           0 : found:
     232                 :           0 :         rcu_read_unlock();
     233                 :           0 :         return true;
     234                 :             : }
     235                 :             : 
     236                 :             : /**
     237                 :             :  * mptcp_token_get_sock - retrieve mptcp connection sock using its token
     238                 :             :  * @net: restrict to this namespace
     239                 :             :  * @token: token of the mptcp connection to retrieve
     240                 :             :  *
     241                 :             :  * This function returns the mptcp connection structure with the given token.
     242                 :             :  * A reference count on the mptcp socket returned is taken.
     243                 :             :  *
     244                 :             :  * returns NULL if no connection with the given token value exists.
     245                 :             :  */
     246                 :         674 : struct mptcp_sock *mptcp_token_get_sock(struct net *net, u32 token)
     247                 :             : {
     248                 :         674 :         struct hlist_nulls_node *pos;
     249                 :         674 :         struct token_bucket *bucket;
     250                 :         674 :         struct mptcp_sock *msk;
     251                 :         674 :         struct sock *sk;
     252                 :             : 
     253                 :         674 :         rcu_read_lock();
     254                 :         674 :         bucket = token_bucket(token);
     255                 :             : 
     256                 :             : again:
     257         [ +  + ]:         674 :         sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
     258         [ -  + ]:         660 :                 msk = mptcp_sk(sk);
     259   [ +  -  -  + ]:         969 :                 if (READ_ONCE(msk->token) != token ||
     260         [ -  + ]:          42 :                     !net_eq(sock_net(sk), net))
     261                 :           0 :                         continue;
     262                 :             : 
     263         [ +  + ]:         660 :                 if (!refcount_inc_not_zero(&sk->sk_refcnt))
     264                 :           2 :                         goto not_found;
     265                 :             : 
     266   [ +  -  -  + ]:         966 :                 if (READ_ONCE(msk->token) != token ||
     267         [ -  + ]:          42 :                     !net_eq(sock_net(sk), net)) {
     268                 :           0 :                         sock_put(sk);
     269                 :           0 :                         goto again;
     270                 :             :                 }
     271                 :         658 :                 goto found;
     272                 :             :         }
     273         [ -  + ]:          14 :         if (get_nulls_value(pos) != (token & token_mask))
     274                 :           0 :                 goto again;
     275                 :             : 
     276                 :          14 : not_found:
     277                 :             :         msk = NULL;
     278                 :             : 
     279                 :         674 : found:
     280                 :         674 :         rcu_read_unlock();
     281                 :         674 :         return msk;
     282                 :             : }
     283                 :             : EXPORT_SYMBOL_GPL(mptcp_token_get_sock);
     284                 :             : 
     285                 :             : /**
     286                 :             :  * mptcp_token_iter_next - iterate over the token container from given pos
     287                 :             :  * @net: namespace to be iterated
     288                 :             :  * @s_slot: start slot number
     289                 :             :  * @s_num: start number inside the given lock
     290                 :             :  *
     291                 :             :  * This function returns the first mptcp connection structure found inside the
     292                 :             :  * token container starting from the specified position, or NULL.
     293                 :             :  *
     294                 :             :  * On successful iteration, the iterator is moved to the next position and
     295                 :             :  * a reference to the returned socket is acquired.
     296                 :             :  */
     297                 :        5462 : struct mptcp_sock *mptcp_token_iter_next(const struct net *net, long *s_slot,
     298                 :             :                                          long *s_num)
     299                 :             : {
     300                 :        5462 :         struct mptcp_sock *ret = NULL;
     301                 :        5462 :         struct hlist_nulls_node *pos;
     302                 :        5462 :         int slot, num = 0;
     303                 :             : 
     304         [ +  + ]:     4564310 :         for (slot = *s_slot; slot <= token_mask; *s_num = 0, slot++) {
     305                 :     4561852 :                 struct token_bucket *bucket = &token_hash[slot];
     306                 :     4561852 :                 struct sock *sk;
     307                 :             : 
     308                 :     4561852 :                 num = 0;
     309                 :             : 
     310         [ +  + ]:     4561852 :                 if (hlist_nulls_empty(&bucket->msk_chain))
     311                 :     4554055 :                         continue;
     312                 :             : 
     313                 :        7797 :                 rcu_read_lock();
     314         [ +  + ]:       12844 :                 sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
     315                 :        8051 :                         ++num;
     316         [ +  + ]:        8051 :                         if (!net_eq(sock_net(sk), net))
     317                 :        1943 :                                 continue;
     318                 :             : 
     319         [ +  + ]:        6108 :                         if (num <= *s_num)
     320                 :        3104 :                                 continue;
     321                 :             : 
     322         [ -  + ]:        3004 :                         if (!refcount_inc_not_zero(&sk->sk_refcnt))
     323                 :           0 :                                 continue;
     324                 :             : 
     325         [ -  + ]:        3004 :                         if (!net_eq(sock_net(sk), net)) {
     326                 :           0 :                                 sock_put(sk);
     327                 :           0 :                                 continue;
     328                 :             :                         }
     329                 :             : 
     330         [ -  + ]:        3004 :                         ret = mptcp_sk(sk);
     331                 :        3004 :                         rcu_read_unlock();
     332                 :        3004 :                         goto out;
     333                 :             :                 }
     334                 :        4793 :                 rcu_read_unlock();
     335                 :             :         }
     336                 :             : 
     337                 :        2458 : out:
     338                 :        5462 :         *s_slot = slot;
     339                 :        5462 :         *s_num = num;
     340                 :        5462 :         return ret;
     341                 :             : }
     342                 :             : EXPORT_SYMBOL_GPL(mptcp_token_iter_next);
     343                 :             : 
     344                 :             : /**
     345                 :             :  * mptcp_token_destroy_request - remove mptcp connection/token
     346                 :             :  * @req: mptcp request socket dropping the token
     347                 :             :  *
     348                 :             :  * Remove the token associated to @req.
     349                 :             :  */
     350                 :        1812 : void mptcp_token_destroy_request(struct request_sock *req)
     351                 :             : {
     352                 :        1812 :         struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
     353                 :        1812 :         struct mptcp_subflow_request_sock *pos;
     354                 :        1812 :         struct token_bucket *bucket;
     355                 :             : 
     356         [ +  + ]:        1812 :         if (hlist_nulls_unhashed(&subflow_req->token_node))
     357                 :             :                 return;
     358                 :             : 
     359                 :          26 :         bucket = token_bucket(subflow_req->token);
     360                 :          26 :         spin_lock_bh(&bucket->lock);
     361                 :          26 :         pos = __token_lookup_req(bucket, subflow_req->token);
     362   [ -  +  +  - ]:          26 :         if (!WARN_ON_ONCE(pos != subflow_req)) {
     363                 :          26 :                 hlist_nulls_del_init_rcu(&pos->token_node);
     364                 :          26 :                 bucket->chain_len--;
     365                 :             :         }
     366                 :          26 :         spin_unlock_bh(&bucket->lock);
     367                 :             : }
     368                 :             : 
     369                 :             : /**
     370                 :             :  * mptcp_token_destroy - remove mptcp connection/token
     371                 :             :  * @msk: mptcp connection dropping the token
     372                 :             :  *
     373                 :             :  * Remove the token associated to @msk
     374                 :             :  */
     375                 :        3854 : void mptcp_token_destroy(struct mptcp_sock *msk)
     376                 :             : {
     377                 :        3854 :         struct sock *sk = (struct sock *)msk;
     378                 :        3854 :         struct token_bucket *bucket;
     379                 :        3854 :         struct mptcp_sock *pos;
     380                 :             : 
     381         [ +  + ]:        3854 :         if (sk_unhashed((struct sock *)msk))
     382                 :             :                 return;
     383                 :             : 
     384                 :        2346 :         sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
     385                 :        2346 :         bucket = token_bucket(msk->token);
     386                 :        2346 :         spin_lock_bh(&bucket->lock);
     387                 :        2346 :         pos = __token_lookup_msk(bucket, msk->token);
     388   [ -  +  +  - ]:        2346 :         if (!WARN_ON_ONCE(pos != msk)) {
     389         [ +  - ]:        2346 :                 __sk_nulls_del_node_init_rcu((struct sock *)pos);
     390                 :        2346 :                 bucket->chain_len--;
     391                 :             :         }
     392                 :        2346 :         spin_unlock_bh(&bucket->lock);
     393                 :        2346 :         WRITE_ONCE(msk->token, 0);
     394                 :             : }
     395                 :             : 
     396                 :           4 : void __init mptcp_token_init(void)
     397                 :             : {
     398                 :           4 :         int i;
     399                 :             : 
     400                 :           4 :         token_hash = alloc_large_system_hash("MPTCP token",
     401                 :             :                                              sizeof(struct token_bucket),
     402                 :             :                                              0,
     403                 :             :                                              20,/* one slot per 1MB of memory */
     404                 :             :                                              HASH_ZERO,
     405                 :             :                                              NULL,
     406                 :             :                                              &token_mask,
     407                 :             :                                              0,
     408                 :             :                                              64 * 1024);
     409         [ +  + ]:        8196 :         for (i = 0; i < token_mask + 1; ++i) {
     410                 :        8192 :                 INIT_HLIST_NULLS_HEAD(&token_hash[i].req_chain, i);
     411                 :        8192 :                 INIT_HLIST_NULLS_HEAD(&token_hash[i].msk_chain, i);
     412                 :        8192 :                 spin_lock_init(&token_hash[i].lock);
     413                 :             :         }
     414                 :           4 : }
     415                 :             : 
     416                 :             : #if IS_MODULE(CONFIG_MPTCP_KUNIT_TEST)
     417                 :             : EXPORT_SYMBOL_GPL(mptcp_token_new_request);
     418                 :             : EXPORT_SYMBOL_GPL(mptcp_token_new_connect);
     419                 :             : EXPORT_SYMBOL_GPL(mptcp_token_accept);
     420                 :             : EXPORT_SYMBOL_GPL(mptcp_token_destroy_request);
     421                 :             : EXPORT_SYMBOL_GPL(mptcp_token_destroy);
     422                 :             : #endif
        

Generated by: LCOV version 2.0-1