Skip to content

Commit

Permalink
mptcp: refactor token container.
Browse files Browse the repository at this point in the history
Replace the radix tree with an hash table allocated
at boot time. The radix tree has some short coming:
a single lock is contented by all the mptcp operation,
the lookup currently use such lock, and traversing
all the items would require lock, too.

With hash table instead we trade a little memory to
address all the above - a per bucket lock is used.

To hash the MPTCP sockets, we re-use the msk' sk_node
entry: the MPTCP sockets are never hashed by the stack.
Replace the existing hash proto callbacks with dummy
implementation, annotating the above constraint.

Additionally refactor the token creation to code to:

- limit the number of consecutive attempts to a fixed
maximum. Hitting an hash bucket with long chain is
considered a failed attempt

- accept() no longer can fail to to token management.

- if token creation fails at connect() time, we do
fallback to TCP (before the connection was closed)

Signed-off-by: Paolo Abeni <pabeni@redhat.com>
  • Loading branch information
Paolo Abeni authored and jenkins-tessares committed Jun 5, 2020
1 parent eb65a6b commit 962c918
Show file tree
Hide file tree
Showing 4 changed files with 233 additions and 108 deletions.
39 changes: 21 additions & 18 deletions net/mptcp/protocol.c
Expand Up @@ -1448,20 +1448,6 @@ struct sock *mptcp_sk_clone(const struct sock *sk,
msk->token = subflow_req->token;
msk->subflow = NULL;

if (unlikely(mptcp_token_new_accept(subflow_req->token, nsk))) {
nsk->sk_state = TCP_CLOSE;
bh_unlock_sock(nsk);

/* we can't call into mptcp_close() here - possible BH context
* free the sock directly.
* sk_clone_lock() sets nsk refcnt to two, hence call sk_free()
* too.
*/
sk_common_release(nsk);
sk_free(nsk);
return NULL;
}

msk->write_seq = subflow_req->idsn + 1;
atomic64_set(&msk->snd_una, msk->write_seq);
if (mp_opt->mp_capable) {
Expand Down Expand Up @@ -1547,7 +1533,7 @@ static void mptcp_destroy(struct sock *sk)
{
struct mptcp_sock *msk = mptcp_sk(sk);

mptcp_token_destroy(msk->token);
mptcp_token_destroy(msk);
if (msk->cached_ext)
__skb_ext_put(msk->cached_ext);

Expand Down Expand Up @@ -1636,6 +1622,20 @@ static void mptcp_release_cb(struct sock *sk)
}
}

static int mptcp_hash(struct sock *sk)
{
/* should never be called,
* we hash the TCP subflows not the master socket
*/
WARN_ON_ONCE(1);
return 0;
}

static void mptcp_unhash(struct sock *sk)
{
/* called from sk_common_release(), but nothing to do here */
}

static int mptcp_get_port(struct sock *sk, unsigned short snum)
{
struct mptcp_sock *msk = mptcp_sk(sk);
Expand Down Expand Up @@ -1679,7 +1679,6 @@ void mptcp_finish_connect(struct sock *ssk)
*/
WRITE_ONCE(msk->remote_key, subflow->remote_key);
WRITE_ONCE(msk->local_key, subflow->local_key);
WRITE_ONCE(msk->token, subflow->token);
WRITE_ONCE(msk->write_seq, subflow->idsn + 1);
WRITE_ONCE(msk->ack_seq, ack_seq);
WRITE_ONCE(msk->can_ack, 1);
Expand Down Expand Up @@ -1761,8 +1760,8 @@ static struct proto mptcp_prot = {
.sendmsg = mptcp_sendmsg,
.recvmsg = mptcp_recvmsg,
.release_cb = mptcp_release_cb,
.hash = inet_hash,
.unhash = inet_unhash,
.hash = mptcp_hash,
.unhash = mptcp_unhash,
.get_port = mptcp_get_port,
.sockets_allocated = &mptcp_sockets_allocated,
.memory_allocated = &tcp_memory_allocated,
Expand All @@ -1771,6 +1770,7 @@ static struct proto mptcp_prot = {
.sysctl_wmem_offset = offsetof(struct net, ipv4.sysctl_tcp_wmem),
.sysctl_mem = sysctl_tcp_mem,
.obj_size = sizeof(struct mptcp_sock),
.slab_flags = SLAB_TYPESAFE_BY_RCU,
.no_autobind = true,
};

Expand Down Expand Up @@ -1812,6 +1812,7 @@ static int mptcp_stream_connect(struct socket *sock, struct sockaddr *uaddr,
goto do_connect;
}

mptcp_token_destroy(msk);
ssock = __mptcp_socket_create(msk, TCP_SYN_SENT);
if (IS_ERR(ssock)) {
err = PTR_ERR(ssock);
Expand Down Expand Up @@ -1888,6 +1889,7 @@ static int mptcp_listen(struct socket *sock, int backlog)
pr_debug("msk=%p", msk);

lock_sock(sock->sk);
mptcp_token_destroy(msk);
ssock = __mptcp_socket_create(msk, TCP_LISTEN);
if (IS_ERR(ssock)) {
err = PTR_ERR(ssock);
Expand Down Expand Up @@ -2086,6 +2088,7 @@ void __init mptcp_proto_init(void)

mptcp_subflow_init();
mptcp_pm_init();
mptcp_token_init();

if (proto_register(&mptcp_prot, 1) != 0)
panic("Failed to register MPTCP proto.\n");
Expand Down
14 changes: 11 additions & 3 deletions net/mptcp/protocol.h
Expand Up @@ -254,6 +254,7 @@ struct mptcp_subflow_request_sock {
u64 thmac;
u32 local_nonce;
u32 remote_nonce;
struct hlist_nulls_node token_node;
};

static inline struct mptcp_subflow_request_sock *
Expand Down Expand Up @@ -381,12 +382,19 @@ bool mptcp_finish_join(struct sock *sk);
void mptcp_data_acked(struct sock *sk);
void mptcp_subflow_eof(struct sock *sk);

void __init mptcp_token_init(void);
static inline void mptcp_token_init_request(struct request_sock *req)
{
mptcp_subflow_rsk(req)->token_node.pprev = NULL;
}

int mptcp_token_new_request(struct request_sock *req);
void mptcp_token_destroy_request(u32 token);
void mptcp_token_destroy_request(struct request_sock *req);
int mptcp_token_new_connect(struct sock *sk);
int mptcp_token_new_accept(u32 token, struct sock *conn);
void mptcp_token_accept(struct mptcp_subflow_request_sock *r,
struct mptcp_sock *msk);
struct mptcp_sock *mptcp_token_get_sock(u32 token);
void mptcp_token_destroy(u32 token);
void mptcp_token_destroy(struct mptcp_sock *msk);

void mptcp_crypto_key_sha(u64 key, u32 *token, u64 *idsn);
static inline void mptcp_crypto_key_gen_sha(u64 *key, u32 *token, u64 *idsn)
Expand Down
17 changes: 9 additions & 8 deletions net/mptcp/subflow.c
Expand Up @@ -32,11 +32,14 @@ static void SUBFLOW_REQ_INC_STATS(struct request_sock *req,
static int subflow_rebuild_header(struct sock *sk)
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
int local_id, err = 0;
int local_id;

if (subflow->request_mptcp && !subflow->token) {
if (subflow->request_mptcp && sk_unhashed(subflow->conn)) {
pr_debug("subflow=%p", sk);
err = mptcp_token_new_connect(sk);
if (mptcp_token_new_connect(sk)) {
subflow->mp_capable = 0;
goto out;
}
} else if (subflow->request_join && !subflow->local_nonce) {
struct mptcp_sock *msk = (struct mptcp_sock *)subflow->conn;

Expand All @@ -57,9 +60,6 @@ static int subflow_rebuild_header(struct sock *sk)
}

out:
if (err)
return err;

return subflow->icsk_af_ops->rebuild_header(sk);
}

Expand All @@ -69,8 +69,7 @@ static void subflow_req_destructor(struct request_sock *req)

pr_debug("subflow_req=%p", subflow_req);

if (subflow_req->mp_capable)
mptcp_token_destroy_request(subflow_req->token);
mptcp_token_destroy_request(req);
tcp_request_sock_ops.destructor(req);
}

Expand Down Expand Up @@ -133,6 +132,7 @@ static void subflow_init_req(struct request_sock *req,

subflow_req->mp_capable = 0;
subflow_req->mp_join = 0;
mptcp_token_init_request(req);

#ifdef CONFIG_TCP_MD5SIG
/* no MPTCP if MD5SIG is enabled on this socket or we may run out of
Expand Down Expand Up @@ -509,6 +509,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
*/
new_msk->sk_destruct = mptcp_sock_destruct;
mptcp_pm_new_connection(mptcp_sk(new_msk), 1);
mptcp_token_accept(subflow_req, mptcp_sk(new_msk));
ctx->conn = new_msk;
new_msk = NULL;

Expand Down

0 comments on commit 962c918

Please sign in to comment.