From patchwork Thu Sep 24 14:35:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Westphal X-Patchwork-Id: 1370698 X-Patchwork-Delegate: matthieu.baerts@tessares.net Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.01.org (client-ip=2001:19d0:306:5::1; helo=ml01.01.org; envelope-from=mptcp-bounces@lists.01.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=strlen.de Received: from ml01.01.org (ml01.01.org [IPv6:2001:19d0:306:5::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BxyJ928RCz9sTh for ; Fri, 25 Sep 2020 00:35:20 +1000 (AEST) Received: from ml01.vlan13.01.org (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 00BD3152ADCB4; Thu, 24 Sep 2020 07:35:18 -0700 (PDT) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=2a0a:51c0:0:12e:520::1; helo=chamillionaire.breakpoint.cc; envelope-from=fw@breakpoint.cc; receiver= Received: from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc [IPv6:2a0a:51c0:0:12e:520::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id A4D77152ADCAF for ; Thu, 24 Sep 2020 07:35:17 -0700 (PDT) Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.92) (envelope-from ) id 1kLSL6-0007Ek-6I; Thu, 24 Sep 2020 16:35:16 +0200 From: Florian Westphal To: Cc: Florian Westphal Date: Thu, 24 Sep 2020 16:35:02 +0200 Message-Id: <20200924143505.27641-2-fw@strlen.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200924143505.27641-1-fw@strlen.de> References: <20200924143505.27641-1-fw@strlen.de> MIME-Version: 1.0 Message-ID-Hash: XS7LDKNX2SQVEJIRHOBAIBA553QP46WH X-Message-ID-Hash: XS7LDKNX2SQVEJIRHOBAIBA553QP46WH X-MailFrom: fw@breakpoint.cc X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.1.1 Precedence: list Subject: [MPTCP] [RFC PATCH 1/4] net: tcp: drop unused function argument from mptcp_incoming_options List-Id: Discussions regarding MPTCP upstreaming Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: Since commit cfde141ea3faa30e ("mptcp: move option parsing into mptcp_incoming_options()"), the 3rd function argument is no longer used. Signed-off-by: Florian Westphal Reviewed-by: Mat Martineau --- include/net/mptcp.h | 6 ++---- net/ipv4/tcp_input.c | 4 ++-- net/mptcp/options.c | 3 +-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/include/net/mptcp.h b/include/net/mptcp.h index a7fc486e1035..6e706d838e4e 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -86,8 +86,7 @@ bool mptcp_synack_options(const struct request_sock *req, unsigned int *size, bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, unsigned int *size, unsigned int remaining, struct mptcp_out_options *opts); -void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb, - struct tcp_options_received *opt_rx); +void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb); void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts); @@ -199,8 +198,7 @@ static inline bool mptcp_established_options(struct sock *sk, } static inline void mptcp_incoming_options(struct sock *sk, - struct sk_buff *skb, - struct tcp_options_received *opt_rx) + struct sk_buff *skb) { } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 50834e7f958e..8afa4af30fdc 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4908,7 +4908,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) int eaten; if (sk_is_mptcp(sk)) - mptcp_incoming_options(sk, skb, &tp->rx_opt); + mptcp_incoming_options(sk, skb); if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) { __kfree_skb(skb); @@ -6487,7 +6487,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) case TCP_LAST_ACK: if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { if (sk_is_mptcp(sk)) - mptcp_incoming_options(sk, skb, &tp->rx_opt); + mptcp_incoming_options(sk, skb); break; } fallthrough; diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 14a290fae767..411fd4a41796 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -859,8 +859,7 @@ static bool add_addr_hmac_valid(struct mptcp_sock *msk, return hmac == mp_opt->ahmac; } -void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb, - struct tcp_options_received *opt_rx) +void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); struct mptcp_sock *msk = mptcp_sk(subflow->conn); From patchwork Thu Sep 24 14:35:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Westphal X-Patchwork-Id: 1370700 X-Patchwork-Delegate: fw@strlen.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.01.org (client-ip=198.145.21.10; helo=ml01.01.org; envelope-from=mptcp-bounces@lists.01.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=strlen.de Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BxyJG1dQRz9sTg for ; Fri, 25 Sep 2020 00:35:26 +1000 (AEST) Received: from ml01.vlan13.01.org (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 0CD44152ADCB6; Thu, 24 Sep 2020 07:35:24 -0700 (PDT) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=2a0a:51c0:0:12e:520::1; helo=chamillionaire.breakpoint.cc; envelope-from=fw@breakpoint.cc; receiver= Received: from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc [IPv6:2a0a:51c0:0:12e:520::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id C8F9F152ADCB0 for ; Thu, 24 Sep 2020 07:35:21 -0700 (PDT) Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.92) (envelope-from ) id 1kLSLA-0007Es-Bj; Thu, 24 Sep 2020 16:35:20 +0200 From: Florian Westphal To: Cc: Florian Westphal Date: Thu, 24 Sep 2020 16:35:03 +0200 Message-Id: <20200924143505.27641-3-fw@strlen.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200924143505.27641-1-fw@strlen.de> References: <20200924143505.27641-1-fw@strlen.de> MIME-Version: 1.0 Message-ID-Hash: XJYLIOLXA54SINNRTE6P3MMXVAQLV6ZU X-Message-ID-Hash: XJYLIOLXA54SINNRTE6P3MMXVAQLV6ZU X-MailFrom: fw@breakpoint.cc X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.1.1 Precedence: list Subject: [MPTCP] [RFC PATCH 2/4] tcp: move selected mptcp helpers to tcp.h/mptcp.h List-Id: Discussions regarding MPTCP upstreaming Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: Will be needed to fill in the MPTCP reset option from tcp_ipv4/ipv6.c. It would make more sense to place mptcp_option() in mptcp.h, but TCPOPT_MPTCP is defined in tcp.h, and mptcp.h is included from tcp.h, not the other way around. Placing the helper in mptcp.h thus results in a build failure because TCPOPT_MPTCP is not defined. Signed-off-by: Florian Westphal --- include/net/mptcp.h | 10 ++++++++++ include/net/tcp.h | 5 +++++ net/mptcp/protocol.h | 11 ----------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/include/net/mptcp.h b/include/net/mptcp.h index 6e706d838e4e..5f5062580e0e 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -68,6 +68,11 @@ static inline bool sk_is_mptcp(const struct sock *sk) return tcp_sk(sk)->is_mptcp; } +static inline struct mptcp_ext *mptcp_get_ext(struct sk_buff *skb) +{ + return (struct mptcp_ext *)skb_ext_find(skb, SKB_EXT_MPTCP); +} + static inline bool rsk_is_mptcp(const struct request_sock *req) { return tcp_rsk(req)->is_mptcp; @@ -153,6 +158,11 @@ static inline void mptcp_init(void) { } +static inline struct mptcp_ext *mptcp_get_ext(struct sk_buff *skb) +{ + return NULL; +} + static inline bool sk_is_mptcp(const struct sock *sk) { return false; diff --git a/include/net/tcp.h b/include/net/tcp.h index 852f0d71dd40..ea8c134802e8 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -2406,4 +2406,9 @@ static inline u64 tcp_transmit_time(const struct sock *sk) return 0; } +static inline __be32 mptcp_option(u8 subopt, u8 len, u8 nib, u8 field) +{ + return htonl((TCPOPT_MPTCP << 24) | (len << 16) | (subopt << 12) | + ((nib & 0xF) << 8) | field); +} #endif /* _TCP_H */ diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 7cfe52aeb2b8..e8c873c66182 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -130,12 +130,6 @@ struct mptcp_options_received { u16 port; }; -static inline __be32 mptcp_option(u8 subopt, u8 len, u8 nib, u8 field) -{ - return htonl((TCPOPT_MPTCP << 24) | (len << 16) | (subopt << 12) | - ((nib & 0xF) << 8) | field); -} - struct mptcp_addr_info { sa_family_t family; __be16 port; @@ -486,11 +480,6 @@ void mptcp_pm_nl_rm_addr_received(struct mptcp_sock *msk); void mptcp_pm_nl_rm_subflow_received(struct mptcp_sock *msk, u8 rm_id); int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc); -static inline struct mptcp_ext *mptcp_get_ext(struct sk_buff *skb) -{ - return (struct mptcp_ext *)skb_ext_find(skb, SKB_EXT_MPTCP); -} - static inline bool before64(__u64 seq1, __u64 seq2) { return (__s64)(seq1 - seq2) < 0; From patchwork Thu Sep 24 14:35:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Westphal X-Patchwork-Id: 1370701 X-Patchwork-Delegate: fw@strlen.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.01.org (client-ip=198.145.21.10; helo=ml01.01.org; envelope-from=mptcp-bounces@lists.01.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=strlen.de Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BxyJK6D26z9sTl for ; Fri, 25 Sep 2020 00:35:29 +1000 (AEST) Received: from ml01.vlan13.01.org (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 28DC3152ADCB4; Thu, 24 Sep 2020 07:35:28 -0700 (PDT) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=2a0a:51c0:0:12e:520::1; helo=chamillionaire.breakpoint.cc; envelope-from=fw@breakpoint.cc; receiver= Received: from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc [IPv6:2a0a:51c0:0:12e:520::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 022BB152ADCB1 for ; Thu, 24 Sep 2020 07:35:26 -0700 (PDT) Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.92) (envelope-from ) id 1kLSLE-0007F5-Ho; Thu, 24 Sep 2020 16:35:24 +0200 From: Florian Westphal To: Cc: Florian Westphal Date: Thu, 24 Sep 2020 16:35:04 +0200 Message-Id: <20200924143505.27641-4-fw@strlen.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200924143505.27641-1-fw@strlen.de> References: <20200924143505.27641-1-fw@strlen.de> MIME-Version: 1.0 Message-ID-Hash: C2LYY5PHIFPY5H7BA2FEXIZPCX2DJWE5 X-Message-ID-Hash: C2LYY5PHIFPY5H7BA2FEXIZPCX2DJWE5 X-MailFrom: fw@breakpoint.cc X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.1.1 Precedence: list Subject: [MPTCP] [RFC PATCH 3/4] mptcp: add mptcp reset option support List-Id: Discussions regarding MPTCP upstreaming Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: Reset option data taht is received will be stored in the mptcp skb extension structure so it can be consumed by e.g. path management. When a subflow gets closed, the desired error code is stored in the subflow context structure. When the close happens before a suitable tcp socket has been created (for example, when HMAC fails validation), its possible to attach the mptcp skb extension and store the reset reason code there. Signed-off-by: Florian Westphal --- include/net/mptcp.h | 6 ++++-- include/net/tcp.h | 3 +++ net/ipv4/tcp_ipv4.c | 21 ++++++++++++++++++++- net/ipv6/tcp_ipv6.c | 19 +++++++++++++++++++ net/mptcp/options.c | 37 +++++++++++++++++++++++++++++++++++++ net/mptcp/protocol.c | 12 +++++++++--- net/mptcp/protocol.h | 18 ++++++++++++++++++ net/mptcp/subflow.c | 27 ++++++++++++++++++++++++--- 8 files changed, 134 insertions(+), 9 deletions(-) diff --git a/include/net/mptcp.h b/include/net/mptcp.h index 5f5062580e0e..2fc556946ef6 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -30,8 +30,8 @@ struct mptcp_ext { ack64:1, mpc_map:1, frozen:1, - __unused:1; - /* one byte hole */ + reset_transient:1; + u8 reset_reason:4; }; struct mptcp_out_options { @@ -50,6 +50,8 @@ struct mptcp_out_options { u8 rm_id; u8 join_id; u8 backup; + u8 reset_reason:4; + u8 reset_transient:1; u32 nonce; u64 thmac; u32 token; diff --git a/include/net/tcp.h b/include/net/tcp.h index ea8c134802e8..a981b5d60112 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -193,6 +193,8 @@ void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOPT_FASTOPEN_MAGIC 0xF989 #define TCPOPT_SMC_MAGIC 0xE2D4C3D9 +/* MPTCP suboptions used in TCP */ +#define MPTCPOPT_TCPRST 8 /* * TCP option lengths */ @@ -216,6 +218,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOLEN_MD5SIG_ALIGNED 20 #define TCPOLEN_MSS_ALIGNED 4 #define TCPOLEN_EXP_SMC_BASE_ALIGNED 8 +#define TCPOLEN_MPTCP_TCPRST 4 /* Flags in tp->nonagle */ #define TCP_NAGLE_OFF 1 /* Nagle's algo is disabled */ diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index ace48b2790ff..b4bc04586d73 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -660,9 +660,11 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) const struct tcphdr *th = tcp_hdr(skb); struct { struct tcphdr th; + __be32 opt[(TCPOLEN_MPTCP_TCPRST >> 2) #ifdef CONFIG_TCP_MD5SIG - __be32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)]; + + (TCPOLEN_MD5SIG_ALIGNED >> 2) #endif + ]; } rep; struct ip_reply_arg arg; #ifdef CONFIG_TCP_MD5SIG @@ -770,6 +772,23 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) ip_hdr(skb)->daddr, &rep.th); } #endif + /* Can't co-exist with TCPMD5, hence check rep.opt[0] */ + if (sk && sk_fullsock(sk) && sk_is_mptcp(sk) && rep.opt[0] == 0) { + const struct mptcp_ext *ext = mptcp_get_ext(skb); + u8 flags = 0, reason = 0; + + if (ext) { + flags = ext->reset_transient; + reason = ext->reset_reason; + } + + rep.opt[0] = mptcp_option(MPTCPOPT_TCPRST, TCPOLEN_MPTCP_TCPRST, + flags, reason); + + arg.iov[0].iov_len += TCPOLEN_MPTCP_TCPRST; + rep.th.doff = arg.iov[0].iov_len / 4; + } + arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, ip_hdr(skb)->saddr, /* XXX */ arg.iov[0].iov_len, IPPROTO_TCP, 0); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8db59f4e5f13..e8c2b68ec4f9 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -868,6 +868,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 struct net *net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev); struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(struct tcphdr); + bool mptcp_reset = false; struct dst_entry *dst; __be32 *topt; __u32 mark = 0; @@ -879,6 +880,11 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 tot_len += TCPOLEN_MD5SIG_ALIGNED; #endif + if (rst && sk && sk_fullsock(sk) && sk_is_mptcp(sk) && !key) { + tot_len += TCPOLEN_MPTCP_TCPRST; + mptcp_reset = true; + } + buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, GFP_ATOMIC); if (!buff) @@ -909,6 +915,19 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 *topt++ = htonl(tsecr); } + if (mptcp_reset) { + const struct mptcp_ext *ext = mptcp_get_ext(skb); + u8 flags = 0, reason = 0; + + if (ext) { + flags = ext->reset_transient; + reason = ext->reset_reason; + } + + *topt++ = mptcp_option(MPTCPOPT_TCPRST, TCPOLEN_MPTCP_TCPRST, + flags, reason); + } + #ifdef CONFIG_TCP_MD5SIG if (key) { *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 411fd4a41796..1eb395dfaa50 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -280,7 +280,17 @@ static void mptcp_parse_option(const struct sk_buff *skb, mp_opt->rm_id = *ptr++; pr_debug("RM_ADDR: id=%d", mp_opt->rm_id); break; + case MPTCPOPT_TCPRST: + if (opsize != TCPOLEN_MPTCP_TCPRST) + break; + if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) + break; + mp_opt->reset = 1; + flags = *ptr++; + mp_opt->reset_transient = flags & MPTCP_TCPRST_TRANSIENT; + mp_opt->reset_reason = *ptr; + break; default: break; } @@ -299,6 +309,7 @@ void mptcp_get_options(const struct sk_buff *skb, mp_opt->add_addr = 0; mp_opt->rm_addr = 0; mp_opt->dss = 0; + mp_opt->reset = 0; length = (th->doff * 4) - sizeof(struct tcphdr); ptr = (const unsigned char *)(th + 1); @@ -477,6 +488,22 @@ static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow, } } +static noinline void mptcp_established_options_rst(struct sock *sk, struct sk_buff *skb, + unsigned int *size, + unsigned int remaining, + struct mptcp_out_options *opts) +{ + const struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); + + if (remaining < TCPOLEN_MPTCP_TCPRST) + return; + + *size = TCPOLEN_MPTCP_TCPRST; + opts->suboptions |= OPTION_MPTCP_TCPRST; + opts->reset_transient = subflow->reset_transient; + opts->reset_reason = subflow->reset_reason; +} + static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb, unsigned int *size, unsigned int remaining, @@ -535,6 +562,10 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb, dss_size += ack_size; *size = ALIGN(dss_size, 4); + + if (unlikely(skb && (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST))) + mptcp_established_options_rst(sk, skb, size, remaining, opts); + return true; } @@ -1065,6 +1096,12 @@ void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts) ptr += 5; } + if (OPTION_MPTCP_TCPRST & opts->suboptions) + *ptr++ = mptcp_option(MPTCPOPT_TCPRST, + TCPOLEN_MPTCP_TCPRST, + opts->reset_transient, + opts->reset_reason); + if (opts->ext_copy.use_ack || opts->ext_copy.use_map) { struct mptcp_ext *mpext = &opts->ext_copy; u8 len = TCPOLEN_MPTCP_DSS_BASE; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 6677461efc85..c4f510f4c556 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2402,14 +2402,18 @@ bool mptcp_finish_join(struct sock *sk) pr_debug("msk=%p, subflow=%p", msk, subflow); /* mptcp socket already closing? */ - if (!mptcp_is_fully_established(parent)) + if (!mptcp_is_fully_established(parent)) { + subflow->reset_reason = MPTCP_TCPRST_EMPTCP; return false; + } if (!msk->pm.server_side) return true; - if (!mptcp_pm_allow_new_subflow(msk)) + if (!mptcp_pm_allow_new_subflow(msk)) { + subflow->reset_reason = MPTCP_TCPRST_EPROHIBIT; return false; + } /* active connections are already on conn_list, and we can't acquire * msk lock here. @@ -2421,8 +2425,10 @@ bool mptcp_finish_join(struct sock *sk) if (ret && !WARN_ON_ONCE(!list_empty(&subflow->node))) list_add_tail(&subflow->node, &msk->join_list); spin_unlock_bh(&msk->join_list_lock); - if (!ret) + if (!ret) { + subflow->reset_reason = MPTCP_TCPRST_EPROHIBIT; return false; + } /* attach to msk socket only after we are sure he will deal with us * at close time diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index e8c873c66182..8ed09af586f0 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -23,6 +23,7 @@ #define OPTION_MPTCP_ADD_ADDR BIT(6) #define OPTION_MPTCP_ADD_ADDR6 BIT(7) #define OPTION_MPTCP_RM_ADDR BIT(8) +#define OPTION_MPTCP_TCPRST BIT(9) /* MPTCP option subtypes */ #define MPTCPOPT_MP_CAPABLE 0 @@ -84,6 +85,18 @@ #define MPTCP_ADDR_IPVERSION_4 4 #define MPTCP_ADDR_IPVERSION_6 6 +/* MPTCP TCPRST flags */ +#define MPTCP_TCPRST_TRANSIENT BIT(0) + +/* MPTCP TCPRST reason codes */ +#define MPTCP_TCPRST_EUNSPEC 0 +#define MPTCP_TCPRST_EMPTCP 1 +#define MPTCP_TCPRST_ERESOURCE 2 +#define MPTCP_TCPRST_EPROHIBIT 3 +#define MPTCP_TCPRST_EWQ2BIG 4 +#define MPTCP_TCPRST_EBADPERF 5 +#define MPTCP_TCPRST_EMIDDLEBOX 6 + /* MPTCP socket flags */ #define MPTCP_DATA_READY 0 #define MPTCP_SEND_SPACE 1 @@ -100,6 +113,7 @@ struct mptcp_options_received { u16 data_len; u16 mp_capable : 1, mp_join : 1, + reset : 1, dss : 1, add_addr : 1, rm_addr : 1, @@ -120,6 +134,8 @@ struct mptcp_options_received { __unused:2; u8 addr_id; u8 rm_id; + u8 reset_reason:4; + u8 reset_transient:1; union { struct in_addr addr; #if IS_ENABLED(CONFIG_MPTCP_IPV6) @@ -314,6 +330,8 @@ struct mptcp_subflow_context { u8 hmac[MPTCPOPT_HMAC_LEN]; u8 local_id; u8 remote_id; + u8 reset_transient:1; + u8 reset_reason:4; struct sock *tcp_sock; /* tcp sk backpointer */ struct sock *conn; /* parent mptcp_sock */ diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 07b07be3e307..f3a493324777 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -312,8 +312,10 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) } else if (subflow->request_join) { u8 hmac[SHA256_DIGEST_SIZE]; - if (!mp_opt.mp_join) + if (!mp_opt.mp_join) { + subflow->reset_reason = MPTCP_TCPRST_EMPTCP; goto do_reset; + } subflow->thmac = mp_opt.thmac; subflow->remote_nonce = mp_opt.nonce; @@ -322,6 +324,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) if (!subflow_thmac_valid(subflow)) { MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKMAC); + subflow->reset_reason = MPTCP_TCPRST_EMPTCP; goto do_reset; } @@ -343,6 +346,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) return; do_reset: + subflow->reset_transient = 0; tcp_send_active_reset(sk, GFP_ATOMIC); tcp_done(sk); } @@ -493,6 +497,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, struct mptcp_options_received mp_opt; bool fallback, fallback_is_fatal; struct sock *new_msk = NULL; + struct mptcp_ext *mpext; struct sock *child; pr_debug("listener=%p, req=%p, conn=%p", listener, req, listener->conn); @@ -553,8 +558,15 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, * to reset the context to non MPTCP status. */ if (!ctx || fallback) { - if (fallback_is_fatal) + if (fallback_is_fatal) { + mpext = skb_ext_add(skb, SKB_EXT_MPTCP); + if (mpext) { + memset(mpext, 0, sizeof(*mpext)); + mpext->reset_reason = MPTCP_TCPRST_EMPTCP; + } + goto dispose_child; + } subflow_drop_ctx(child); goto out; @@ -584,8 +596,15 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, struct mptcp_sock *owner; owner = subflow_req->msk; - if (!owner) + if (!owner) { + mpext = skb_ext_add(skb, SKB_EXT_MPTCP); + if (mpext) { + memset(mpext, 0, sizeof(*mpext)); + mpext->reset_reason = MPTCP_TCPRST_EPROHIBIT; + } + goto dispose_child; + } /* move the msk reference ownership to the subflow */ subflow_req->msk = NULL; @@ -911,6 +930,8 @@ static bool subflow_check_data_avail(struct sock *ssk) smp_wmb(); ssk->sk_error_report(ssk); tcp_set_state(ssk, TCP_CLOSE); + subflow->reset_transient = 0; + subflow->reset_reason = MPTCP_TCPRST_EMPTCP; tcp_send_active_reset(ssk, GFP_ATOMIC); subflow->data_avail = 0; return false; From patchwork Thu Sep 24 14:35:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Westphal X-Patchwork-Id: 1370702 X-Patchwork-Delegate: fw@strlen.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.01.org (client-ip=2001:19d0:306:5::1; helo=ml01.01.org; envelope-from=mptcp-bounces@lists.01.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=strlen.de Received: from ml01.01.org (ml01.01.org [IPv6:2001:19d0:306:5::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BxyJP6Zqgz9sTl for ; Fri, 25 Sep 2020 00:35:33 +1000 (AEST) Received: from ml01.vlan13.01.org (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 396BD152ADCB9; Thu, 24 Sep 2020 07:35:32 -0700 (PDT) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=2a0a:51c0:0:12e:520::1; helo=chamillionaire.breakpoint.cc; envelope-from=fw@breakpoint.cc; receiver= Received: from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc [IPv6:2a0a:51c0:0:12e:520::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 28B24152ADCB2 for ; Thu, 24 Sep 2020 07:35:30 -0700 (PDT) Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.92) (envelope-from ) id 1kLSLI-0007FH-MC; Thu, 24 Sep 2020 16:35:28 +0200 From: Florian Westphal To: Cc: Florian Westphal Date: Thu, 24 Sep 2020 16:35:05 +0200 Message-Id: <20200924143505.27641-5-fw@strlen.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200924143505.27641-1-fw@strlen.de> References: <20200924143505.27641-1-fw@strlen.de> MIME-Version: 1.0 Message-ID-Hash: 3DYOZ5K3KRKQEAHIYQAN272PRNU6D674 X-Message-ID-Hash: 3DYOZ5K3KRKQEAHIYQAN272PRNU6D674 X-MailFrom: fw@breakpoint.cc X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.1.1 Precedence: list Subject: [MPTCP] [RFC PATCH 4/4] tcp: parse tcp options contained in reset packets List-Id: Discussions regarding MPTCP upstreaming Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: This will be used to handle MPTCP_TCPRST suboption. It allows an MPTCP receiver to learn more information when a subflow is re-set. The MPTCP_TCPRST option gives an error code (protocol error, path too slow, middlebox interference detected, and so on). This allows an MPTCP receiver to make a decision to reopen the subflow at a later time, or even completely disable the path. Signed-off-by: Florian Westphal --- include/net/tcp.h | 2 +- net/ipv4/tcp_input.c | 13 ++++++++----- net/ipv4/tcp_minisocks.c | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index a981b5d60112..92eee154e2a3 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -609,7 +609,7 @@ void tcp_skb_collapse_tstamp(struct sk_buff *skb, /* tcp_input.c */ void tcp_rearm_rto(struct sock *sk); void tcp_synack_rtt_meas(struct sock *sk, struct request_sock *req); -void tcp_reset(struct sock *sk); +void tcp_reset(struct sock *sk, struct sk_buff *skb); void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb); void tcp_fin(struct sock *sk); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 8afa4af30fdc..0a10ba1df1a0 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4206,10 +4206,13 @@ static inline bool tcp_sequence(const struct tcp_sock *tp, u32 seq, u32 end_seq) } /* When we get a reset we do this. */ -void tcp_reset(struct sock *sk) +void tcp_reset(struct sock *sk, struct sk_buff *skb) { trace_tcp_receive_reset(sk); + if (sk_is_mptcp(sk)) + mptcp_incoming_options(sk, skb); + /* We want the right error as BSD sees it (and indeed as we do). */ switch (sk->sk_state) { case TCP_SYN_SENT: @@ -5590,7 +5593,7 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, &tp->last_oow_ack_time)) tcp_send_dupack(sk, skb); } else if (tcp_reset_check(sk, skb)) { - tcp_reset(sk); + tcp_reset(sk, skb); } goto discard; } @@ -5626,7 +5629,7 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, } if (rst_seq_match) - tcp_reset(sk); + tcp_reset(sk, skb); else { /* Disable TFO if RST is out-of-order * and no data has been received @@ -6059,7 +6062,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, */ if (th->rst) { - tcp_reset(sk); + tcp_reset(sk, skb); goto discard; } @@ -6501,7 +6504,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA); - tcp_reset(sk); + tcp_reset(sk, skb); return 1; } } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 56c306e3cd2f..12f2495f98df 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -802,7 +802,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, req->rsk_ops->send_reset(sk, skb); } else if (fastopen) { /* received a valid RST pkt */ reqsk_fastopen_remove(sk, req, true); - tcp_reset(sk); + tcp_reset(sk, skb); } if (!fastopen) { inet_csk_reqsk_queue_drop(sk, req);