net/mptcp/token.c

Source file repositories/reference/linux-study-clean/net/mptcp/token.c

File Facts

System
Linux kernel
Corpus path
net/mptcp/token.c
Extension
.c
Size
11339 bytes
Lines
425
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

struct token_bucket {
	spinlock_t		lock;
	int			chain_len;
	struct hlist_nulls_head	req_chain;
	struct hlist_nulls_head	msk_chain;
};

static struct token_bucket *token_hash __read_mostly;
static unsigned int token_mask __read_mostly;

static struct token_bucket *token_bucket(u32 token)
{
	return &token_hash[token & token_mask];
}

/* called with bucket lock held */
static struct mptcp_subflow_request_sock *
__token_lookup_req(struct token_bucket *t, u32 token)
{
	struct mptcp_subflow_request_sock *req;
	struct hlist_nulls_node *pos;

	hlist_nulls_for_each_entry_rcu(req, pos, &t->req_chain, token_node)
		if (req->token == token)
			return req;
	return NULL;
}

/* called with bucket lock held */
static struct mptcp_sock *
__token_lookup_msk(struct token_bucket *t, u32 token)
{
	struct hlist_nulls_node *pos;
	struct sock *sk;

	sk_nulls_for_each_rcu(sk, pos, &t->msk_chain)
		if (mptcp_sk(sk)->token == token)
			return mptcp_sk(sk);
	return NULL;
}

static bool __token_bucket_busy(struct token_bucket *t, u32 token)
{
	return !token || t->chain_len >= TOKEN_MAX_CHAIN_LEN ||
	       __token_lookup_req(t, token) || __token_lookup_msk(t, token);
}

static void mptcp_crypto_key_gen_sha(u64 *key, u32 *token, u64 *idsn)
{
	/* we might consider a faster version that computes the key as a
	 * hash of some information available in the MPTCP socket. Use
	 * random data at the moment, as it's probably the safest option
	 * in case multiple sockets are opened in different namespaces at
	 * the same time.
	 */
	get_random_bytes(key, sizeof(u64));
	mptcp_crypto_key_sha(*key, token, idsn);
}

/**
 * mptcp_token_new_request - create new key/idsn/token for subflow_request
 * @req: the request socket
 *
 * This function is called when a new mptcp connection is coming in.
 *
 * It creates a unique token to identify the new mptcp connection,
 * a secret local key and the initial data sequence number (idsn).
 *
 * Return: 0 on success.
 */
int mptcp_token_new_request(struct request_sock *req)
{
	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
	struct token_bucket *bucket;
	u32 token;

	mptcp_crypto_key_sha(subflow_req->local_key,
			     &subflow_req->token,
			     &subflow_req->idsn);
	pr_debug("req=%p local_key=%llu, token=%u, idsn=%llu\n",
		 req, subflow_req->local_key, subflow_req->token,
		 subflow_req->idsn);

	token = subflow_req->token;
	bucket = token_bucket(token);
	spin_lock_bh(&bucket->lock);
	if (__token_bucket_busy(bucket, token)) {
		spin_unlock_bh(&bucket->lock);
		return -EBUSY;
	}

Annotation

Implementation Notes