Commit 93d43e58 authored by David S. Miller's avatar David S. Miller

Merge branch 'mptcp-fix-MP_JOIN-failure-handling'

Paolo Abeni says:

====================
mptcp: fix MP_JOIN failure handling

Currently if we hit an MP_JOIN failure on the third ack, the child socket is
closed with reset, but the request socket is not deleted, causing weird
behaviors.

The main problem is that MPTCP's MP_JOIN code needs to plug it's own
'valid 3rd ack' checks and the current TCP callbacks do not allow that.

This series tries to address the above shortcoming introducing a new MPTCP
specific bit in a 'struct tcp_request_sock' hole, and leveraging that to allow
tcp_check_req releasing the request socket when needed.

The above allows cleaning-up a bit current MPTCP hooking in tcp_check_req().

An alternative solution, possibly cleaner but more invasive, would be
changing the 'bool *own_req' syn_recv_sock() argument into 'int *req_status'
and let MPTCP set it to 'REQ_DROP'.

v1 -> v2:
 - be more conservative about drop_req initialization

RFC -> v1:
 - move the drop_req bit inside tcp_request_sock (Eric)
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ca1c933b 729cd643
...@@ -120,6 +120,9 @@ struct tcp_request_sock { ...@@ -120,6 +120,9 @@ struct tcp_request_sock {
u64 snt_synack; /* first SYNACK sent time */ u64 snt_synack; /* first SYNACK sent time */
bool tfo_listener; bool tfo_listener;
bool is_mptcp; bool is_mptcp;
#if IS_ENABLED(CONFIG_MPTCP)
bool drop_req;
#endif
u32 txhash; u32 txhash;
u32 rcv_isn; u32 rcv_isn;
u32 snt_isn; u32 snt_isn;
......
...@@ -287,6 +287,14 @@ static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk) ...@@ -287,6 +287,14 @@ static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk)
void inet_csk_reqsk_queue_drop(struct sock *sk, struct request_sock *req); void inet_csk_reqsk_queue_drop(struct sock *sk, struct request_sock *req);
void inet_csk_reqsk_queue_drop_and_put(struct sock *sk, struct request_sock *req); void inet_csk_reqsk_queue_drop_and_put(struct sock *sk, struct request_sock *req);
static inline void inet_csk_prepare_for_destroy_sock(struct sock *sk)
{
/* The below has to be done to allow calling inet_csk_destroy_sock */
sock_set_flag(sk, SOCK_DEAD);
percpu_counter_inc(sk->sk_prot->orphan_count);
inet_sk(sk)->inet_num = 0;
}
void inet_csk_destroy_sock(struct sock *sk); void inet_csk_destroy_sock(struct sock *sk);
void inet_csk_prepare_forced_close(struct sock *sk); void inet_csk_prepare_forced_close(struct sock *sk);
......
...@@ -68,6 +68,11 @@ static inline bool rsk_is_mptcp(const struct request_sock *req) ...@@ -68,6 +68,11 @@ static inline bool rsk_is_mptcp(const struct request_sock *req)
return tcp_rsk(req)->is_mptcp; return tcp_rsk(req)->is_mptcp;
} }
static inline bool rsk_drop_req(const struct request_sock *req)
{
return tcp_rsk(req)->is_mptcp && tcp_rsk(req)->drop_req;
}
void mptcp_space(const struct sock *ssk, int *space, int *full_space); void mptcp_space(const struct sock *ssk, int *space, int *full_space);
bool mptcp_syn_options(struct sock *sk, const struct sk_buff *skb, bool mptcp_syn_options(struct sock *sk, const struct sk_buff *skb,
unsigned int *size, struct mptcp_out_options *opts); unsigned int *size, struct mptcp_out_options *opts);
...@@ -121,8 +126,6 @@ static inline bool mptcp_skb_can_collapse(const struct sk_buff *to, ...@@ -121,8 +126,6 @@ static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
skb_ext_find(from, SKB_EXT_MPTCP)); skb_ext_find(from, SKB_EXT_MPTCP));
} }
bool mptcp_sk_is_subflow(const struct sock *sk);
void mptcp_seq_show(struct seq_file *seq); void mptcp_seq_show(struct seq_file *seq);
#else #else
...@@ -140,6 +143,11 @@ static inline bool rsk_is_mptcp(const struct request_sock *req) ...@@ -140,6 +143,11 @@ static inline bool rsk_is_mptcp(const struct request_sock *req)
return false; return false;
} }
static inline bool rsk_drop_req(const struct request_sock *req)
{
return false;
}
static inline void mptcp_parse_option(const struct sk_buff *skb, static inline void mptcp_parse_option(const struct sk_buff *skb,
const unsigned char *ptr, int opsize, const unsigned char *ptr, int opsize,
struct tcp_options_received *opt_rx) struct tcp_options_received *opt_rx)
...@@ -190,11 +198,6 @@ static inline bool mptcp_skb_can_collapse(const struct sk_buff *to, ...@@ -190,11 +198,6 @@ static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
return true; return true;
} }
static inline bool mptcp_sk_is_subflow(const struct sock *sk)
{
return false;
}
static inline void mptcp_space(const struct sock *ssk, int *s, int *fs) { } static inline void mptcp_space(const struct sock *ssk, int *s, int *fs) { }
static inline void mptcp_seq_show(struct seq_file *seq) { } static inline void mptcp_seq_show(struct seq_file *seq) { }
#endif /* CONFIG_MPTCP */ #endif /* CONFIG_MPTCP */
......
...@@ -896,11 +896,7 @@ void inet_csk_prepare_forced_close(struct sock *sk) ...@@ -896,11 +896,7 @@ void inet_csk_prepare_forced_close(struct sock *sk)
/* sk_clone_lock locked the socket and set refcnt to 2 */ /* sk_clone_lock locked the socket and set refcnt to 2 */
bh_unlock_sock(sk); bh_unlock_sock(sk);
sock_put(sk); sock_put(sk);
inet_csk_prepare_for_destroy_sock(sk);
/* The below has to be done to allow calling inet_csk_destroy_sock */
sock_set_flag(sk, SOCK_DEAD);
percpu_counter_inc(sk->sk_prot->orphan_count);
inet_sk(sk)->inet_num = 0;
} }
EXPORT_SYMBOL(inet_csk_prepare_forced_close); EXPORT_SYMBOL(inet_csk_prepare_forced_close);
......
...@@ -774,7 +774,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, ...@@ -774,7 +774,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
if (!child) if (!child)
goto listen_overflow; goto listen_overflow;
if (own_req && sk_is_mptcp(child) && mptcp_sk_is_subflow(child)) { if (own_req && rsk_drop_req(req)) {
reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req); reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req);
inet_csk_reqsk_queue_drop_and_put(sk, req); inet_csk_reqsk_queue_drop_and_put(sk, req);
return child; return child;
......
...@@ -1638,13 +1638,6 @@ bool mptcp_finish_join(struct sock *sk) ...@@ -1638,13 +1638,6 @@ bool mptcp_finish_join(struct sock *sk)
return ret; return ret;
} }
bool mptcp_sk_is_subflow(const struct sock *sk)
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
return subflow->mp_join == 1;
}
static bool mptcp_memory_free(const struct sock *sk, int wake) static bool mptcp_memory_free(const struct sock *sk, int wake)
{ {
struct mptcp_sock *msk = mptcp_sk(sk); struct mptcp_sock *msk = mptcp_sk(sk);
......
...@@ -470,13 +470,15 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, ...@@ -470,13 +470,15 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
if (child && *own_req) { if (child && *own_req) {
struct mptcp_subflow_context *ctx = mptcp_subflow_ctx(child); struct mptcp_subflow_context *ctx = mptcp_subflow_ctx(child);
tcp_rsk(req)->drop_req = false;
/* we need to fallback on ctx allocation failure and on pre-reqs /* we need to fallback on ctx allocation failure and on pre-reqs
* checking above. In the latter scenario we additionally need * checking above. In the latter scenario we additionally need
* to reset the context to non MPTCP status. * to reset the context to non MPTCP status.
*/ */
if (!ctx || fallback) { if (!ctx || fallback) {
if (fallback_is_fatal) if (fallback_is_fatal)
goto close_child; goto dispose_child;
if (ctx) { if (ctx) {
subflow_ulp_fallback(child, ctx); subflow_ulp_fallback(child, ctx);
...@@ -505,13 +507,14 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, ...@@ -505,13 +507,14 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
owner = mptcp_token_get_sock(ctx->token); owner = mptcp_token_get_sock(ctx->token);
if (!owner) if (!owner)
goto close_child; goto dispose_child;
ctx->conn = (struct sock *)owner; ctx->conn = (struct sock *)owner;
if (!mptcp_finish_join(child)) if (!mptcp_finish_join(child))
goto close_child; goto dispose_child;
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKRX); SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKRX);
tcp_rsk(req)->drop_req = true;
} }
} }
...@@ -528,11 +531,14 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, ...@@ -528,11 +531,14 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
!mptcp_subflow_ctx(child)->conn)); !mptcp_subflow_ctx(child)->conn));
return child; return child;
close_child: dispose_child:
tcp_rsk(req)->drop_req = true;
tcp_send_active_reset(child, GFP_ATOMIC); tcp_send_active_reset(child, GFP_ATOMIC);
inet_csk_prepare_forced_close(child); inet_csk_prepare_for_destroy_sock(child);
tcp_done(child); tcp_done(child);
return NULL;
/* The last child reference will be released by the caller */
return child;
} }
static struct inet_connection_sock_af_ops subflow_specific; static struct inet_connection_sock_af_ops subflow_specific;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment