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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
93d43e5868
@ -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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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)
|
|||||||
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,
|
|||||||
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)
|
|||||||
/* 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,
|
|||||||
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)
|
|||||||
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 @@ create_child:
|
|||||||
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 @@ create_child:
|
|||||||
|
|
||||||
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 @@ out:
|
|||||||
!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;
|
||||||
|
Loading…
Reference in New Issue
Block a user