Skip to content

Commit

Permalink
mptcp: explicitly track the fully established status
Browse files Browse the repository at this point in the history
Currently accepted msk sockets become established only after
accept() returns the new sk to user-space.

As MP_JOIN request are refused as per RFC spec on non fully
established socket, the above causes mp_join self-tests
instabilities.

This change lets the msk entering the established status
as soon as it receives the 3rd ack and propagates the first
subflow fully established status on the msk socket.

Finally we can change the subflow acceptance condition to
take in account both the sock state and the msk fully
established flag.

Reviewed-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Tested-by: Christoph Paasch <cpaasch@apple.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Paolo Abeni authored and davem330 committed Jul 23, 2020
1 parent 0235d07 commit b93df08
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 9 deletions.
5 changes: 2 additions & 3 deletions net/mptcp/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,7 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *sk,
* additional ack.
*/
subflow->fully_established = 1;
WRITE_ONCE(msk->fully_established, true);
goto fully_established;
}

Expand All @@ -724,9 +725,7 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *sk,

if (unlikely(!READ_ONCE(msk->pm.server_side)))
pr_warn_once("bogus mpc option on established client sk");
subflow->fully_established = 1;
subflow->remote_key = mp_opt->sndr_key;
subflow->can_ack = 1;
mptcp_subflow_fully_established(subflow, mp_opt);

fully_established:
if (likely(subflow->pm_notified))
Expand Down
4 changes: 2 additions & 2 deletions net/mptcp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,7 @@ struct sock *mptcp_sk_clone(const struct sock *sk,
msk->local_key = subflow_req->local_key;
msk->token = subflow_req->token;
msk->subflow = NULL;
WRITE_ONCE(msk->fully_established, false);

msk->write_seq = subflow_req->idsn + 1;
atomic64_set(&msk->snd_una, msk->write_seq);
Expand Down Expand Up @@ -1605,7 +1606,6 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
newsk = new_mptcp_sock;
mptcp_copy_inaddrs(newsk, ssk);
list_add(&subflow->node, &msk->conn_list);
inet_sk_state_store(newsk, TCP_ESTABLISHED);

mptcp_rcv_space_init(msk, ssk);
bh_unlock_sock(new_mptcp_sock);
Expand Down Expand Up @@ -1855,7 +1855,7 @@ bool mptcp_finish_join(struct sock *sk)
pr_debug("msk=%p, subflow=%p", msk, subflow);

/* mptcp socket already closing? */
if (inet_sk_state_load(parent) != TCP_ESTABLISHED)
if (!mptcp_is_fully_established(parent))
return false;

if (!msk->pm.server_side)
Expand Down
8 changes: 8 additions & 0 deletions net/mptcp/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ struct mptcp_sock {
u32 token;
unsigned long flags;
bool can_ack;
bool fully_established;
spinlock_t join_list_lock;
struct work_struct work;
struct list_head conn_list;
Expand Down Expand Up @@ -342,6 +343,8 @@ mptcp_subflow_get_mapped_dsn(const struct mptcp_subflow_context *subflow)
}

int mptcp_is_enabled(struct net *net);
void mptcp_subflow_fully_established(struct mptcp_subflow_context *subflow,
struct mptcp_options_received *mp_opt);
bool mptcp_subflow_data_available(struct sock *sk);
void __init mptcp_subflow_init(void);

Expand Down Expand Up @@ -373,6 +376,11 @@ void mptcp_get_options(const struct sk_buff *skb,
struct mptcp_options_received *mp_opt);

void mptcp_finish_connect(struct sock *sk);
static inline bool mptcp_is_fully_established(struct sock *sk)
{
return inet_sk_state_load(sk) == TCP_ESTABLISHED &&
READ_ONCE(mptcp_sk(sk)->fully_established);
}
void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk);
void mptcp_data_ready(struct sock *sk, struct sock *ssk);
bool mptcp_finish_join(struct sock *sk);
Expand Down
23 changes: 19 additions & 4 deletions net/mptcp/subflow.c
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,17 @@ static void subflow_drop_ctx(struct sock *ssk)
kfree_rcu(ctx, rcu);
}

void mptcp_subflow_fully_established(struct mptcp_subflow_context *subflow,
struct mptcp_options_received *mp_opt)
{
struct mptcp_sock *msk = mptcp_sk(subflow->conn);

subflow->remote_key = mp_opt->sndr_key;
subflow->fully_established = 1;
subflow->can_ack = 1;
WRITE_ONCE(msk->fully_established, true);
}

static struct sock *subflow_syn_recv_sock(const struct sock *sk,
struct sk_buff *skb,
struct request_sock *req,
Expand Down Expand Up @@ -466,6 +477,11 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
}

if (ctx->mp_capable) {
/* this can't race with mptcp_close(), as the msk is
* not yet exposted to user-space
*/
inet_sk_state_store((void *)new_msk, TCP_ESTABLISHED);

/* new mpc subflow takes ownership of the newly
* created mptcp socket
*/
Expand All @@ -478,9 +494,8 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
/* with OoO packets we can reach here without ingress
* mpc option
*/
ctx->remote_key = mp_opt.sndr_key;
ctx->fully_established = mp_opt.mp_capable;
ctx->can_ack = mp_opt.mp_capable;
if (mp_opt.mp_capable)
mptcp_subflow_fully_established(ctx, &mp_opt);
} else if (ctx->mp_join) {
struct mptcp_sock *owner;

Expand Down Expand Up @@ -967,7 +982,7 @@ int __mptcp_subflow_connect(struct sock *sk, int ifindex,
int addrlen;
int err;

if (sk->sk_state != TCP_ESTABLISHED)
if (!mptcp_is_fully_established(sk))
return -ENOTCONN;

err = mptcp_subflow_create_socket(sk, &sf);
Expand Down

0 comments on commit b93df08

Please sign in to comment.