From nobody Fri Nov 22 07:25:22 2024 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C8AE4185B6A for ; Mon, 2 Sep 2024 09:09:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725268160; cv=none; b=s8o0lxCY+Qy82I2M0PjJCZfHITC6D3loMcBbSfgkJyObixkXk5Q3JKFrMWeKmmCoUp1aOYEFrsjFxCbTHFbFXp3S6HuldsGYPlPOuuive5PhZw/yP0Ser49ewGPtmA7qRbAqXk5lSRkP9kxlSe3PO/6n1iIQY2fUwYaYS04V1aU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725268160; c=relaxed/simple; bh=jdg4u2VORfaDlWnAsdaHvp7lNBz21LXVrp23fsRFvrg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Oi8mYD+hNWJawanya9TS6TY/Qr2+n7gdfLa5KzeU23GrIsAOqWqgSGTq+8oH9JZ1nV9mu3uN0jrXLAuX7utezozp54OTgoFASAHpPVwCl0AL/KjaNgTXr2tJAhcjGmL1LYQyRFu91J1KkjM3btRiDgIysQjuz9SHaYOFS1j8IaI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XNTYdnBS; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="XNTYdnBS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1A385C4CEC2; Mon, 2 Sep 2024 09:09:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725268160; bh=jdg4u2VORfaDlWnAsdaHvp7lNBz21LXVrp23fsRFvrg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=XNTYdnBSrjeI+gNv+a5GJE6i3BpsS1OVNd113lCrTNZAF9WvLtlP6GJoA7Q8H2NH8 yw1HpymGtVUFDOKJKSTL1oICq7kXuQuhsLr8mPNaxZPeNU0uTiD80HuN99hhOvWUFY qYLYUkYSC/VhY20i6vgQb5Yu0zbjkkVFSJS6Axnuqtz4uqQ2jSPBDxlMU9P/zj47QY cpoj1km0pFqrxh8PH4V16JV+rwXqFdPhnKUFAyVVvMw0NTrT8elIoQM4T4n33R8HPR Qe7OAMzESkpx1akVwAaRFfuxMWIbZYaW9DCNk9w36Myi1uWWnO5z/nl1Vo9/+qzKt8 8Lh9+CIzoGUVw== From: "Matthieu Baerts (NGI0)" Date: Mon, 02 Sep 2024 11:09:08 +0200 Subject: [PATCH mptcp-next 1/3] mptcp: export mptcp_subflow_early_fallback() Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20240902-mptcp-fallback-x-mpc-v1-1-86d9170ddff7@kernel.org> References: <20240902-mptcp-fallback-x-mpc-v1-0-86d9170ddff7@kernel.org> In-Reply-To: <20240902-mptcp-fallback-x-mpc-v1-0-86d9170ddff7@kernel.org> To: mptcp@lists.linux.dev Cc: "Matthieu Baerts (NGI0)" X-Mailer: b4 0.14.1 X-Developer-Signature: v=1; a=openpgp-sha256; l=1568; i=matttbe@kernel.org; h=from:subject:message-id; bh=jdg4u2VORfaDlWnAsdaHvp7lNBz21LXVrp23fsRFvrg=; b=owEBbQKS/ZANAwAIAfa3gk9CaaBzAcsmYgBm1YC+hD3RBKs6KtnkvIzQFq9JKzN3uIAOHIC5I RpueEbejamJAjMEAAEIAB0WIQToy4X3aHcFem4n93r2t4JPQmmgcwUCZtWAvgAKCRD2t4JPQmmg c8vOEADW59Vvz1vst3YvMssrLYrp7aFXT4OFkZvhmyeVuf9F+vFrrv/Bwj5rcnepG3ouLDOKvPy GOOlIzWbZERhVpmRvU+8BtYxA1fP6dCO+dsUZLG/O316P5+eaBq7XJrtHtP2xZRDRBMmJSDjyKM /fy3OjD0G2Mzs+8iK/9qrEbDJNzigU4gLMYC1o0UbZfiZSqX7yTIr8fKLZCkgFmrVATZAGS4k2A B3CwGltz0H7zaAt3Y75e/Tuyc4fiKzCSVgBzmXhZtlxqr4BxIAWxs4XCGnNBnEge3ndzkVLewQV pcZ040Ek+FNyQflGIgSA9sT7cvnbxIodL0g2xbwibcY4DM167av3gMDrtEOSr736y/mqlgaeug5 uUrISM3EfvL6ja1qzTvUGieqa8bVZRrOCqGfqA7K+VNMrJj0MVtYOkip6DT2P6jzVIzdNujSjG0 MY9jVXZ06/xOLQjFkCNKWogzP11E509MoKx7XG4smyJ+jfndetMUThAJuVmWoWJrJljCOpaESyE S49LYguthT6nvCMdTHmFPUQ3oSNJwMtEq6VJQNIYpogQI1dX6L5UmrPlxon5vtIlSLmX9OtIT7W w0p1s/avDWWdgHt8wtf2HOwkNzH8RgZjid69jogKNpFMIWnFE1Y095ltXii+Wkco6DfEbx7Pay5 Pwag8WhK++iaM0Q== X-Developer-Key: i=matttbe@kernel.org; a=openpgp; fpr=E8CB85F76877057A6E27F77AF6B7824F4269A073 This helper will be used outside protocol.h in the following commit. While at it, also add a 'pr_fallback()' debug print, to help identifying fallbacks. Signed-off-by: Matthieu Baerts (NGI0) --- net/mptcp/protocol.c | 7 ------- net/mptcp/protocol.h | 8 ++++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 7ef59e17d03a..a32f79db235a 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3717,13 +3717,6 @@ static int mptcp_ioctl(struct sock *sk, int cmd, int= *karg) return 0; } =20 -static void mptcp_subflow_early_fallback(struct mptcp_sock *msk, - struct mptcp_subflow_context *subflow) -{ - subflow->request_mptcp =3D 0; - __mptcp_do_fallback(msk); -} - static int mptcp_connect(struct sock *sk, struct sockaddr *uaddr, int addr= _len) { struct mptcp_subflow_context *subflow; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index d25d2dac88a5..633a9bc7a0e7 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -1220,6 +1220,14 @@ static inline void mptcp_do_fallback(struct sock *ss= k) =20 #define pr_fallback(a) pr_debug("%s:fallback to TCP (msk=3D%p)\n", __func_= _, a) =20 +static inline void mptcp_subflow_early_fallback(struct mptcp_sock *msk, + struct mptcp_subflow_context *subflow) +{ + pr_fallback(msk); + subflow->request_mptcp =3D 0; + __mptcp_do_fallback(msk); +} + static inline bool mptcp_check_infinite_map(struct sk_buff *skb) { struct mptcp_ext *mpext; --=20 2.45.2 From nobody Fri Nov 22 07:25:22 2024 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 38903187357 for ; Mon, 2 Sep 2024 09:09:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725268162; cv=none; b=fRPtnX64iZJhmkeAt7u1r4RzgxBX/QgahcJeTZwl7rLOO50A9tEoBogIgzpSnK9Gj3y7m8xCyJexIBupEcKDkjoi31GoNExHTUrauPNV0aF9zh7SAzvGEnJqWVoaa7eyxkOKeNqSPlcoqclJsyJkf7hUZMUdYXsBRJNYs93ZfIY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725268162; c=relaxed/simple; bh=rjEniUY9LS7YomeFWzdX/evdWHB/tnFmR/a7VtVogJE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=poeGtAAlW9WuoUrP8MDyeKiJG53wbRGQkGvuILI9p29lJ0kzQeR61M05ZV6nbeCJcC6yAveryIqoDWlu5lprryVLAEndUHzosJ+omQ0so91C30qLWsYSFvTaoOl/3Oz+eHZY8enNa+4Oi4S/m5xWDuLvyIac8Vp0/+VidgMZ49Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=DsaoKxtj; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="DsaoKxtj" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1B81BC4CECB; Mon, 2 Sep 2024 09:09:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725268161; bh=rjEniUY9LS7YomeFWzdX/evdWHB/tnFmR/a7VtVogJE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=DsaoKxtjYTOoCYxWamyIlspaEtBXChSk2nJPOM6PeBe+BDkEgU3Uw0VwJeEND10dK lqhFHUoMTa6m6kUbhRRnAIG3FLXeZqzYqgj0KK0X/8aZyu9ltvfR7cjnQZ5tPDbnYM xv1vj9yhuN732sY7kdJ/ycu9plDMEqr25Ho+ZIVOG1YkK8mIeCk70ILySMwDGKVQfU CjYJxYeYqmJiYG0eFZNBxBLmgQqHsnwLfN6oeIFsOcI9SRLpPsET9vxiy1erjlCvAI H0R6VLITcJGnAqXfZIDc4+r7+KoOaL2XjMWVRncdS9pPkDmuav1tqbhNgZuR/Vjrk0 VGdoy6VZpSIXw== From: "Matthieu Baerts (NGI0)" Date: Mon, 02 Sep 2024 11:09:09 +0200 Subject: [PATCH mptcp-next 2/3] mptcp: fallback to TCP after SYN+MPC drops Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20240902-mptcp-fallback-x-mpc-v1-2-86d9170ddff7@kernel.org> References: <20240902-mptcp-fallback-x-mpc-v1-0-86d9170ddff7@kernel.org> In-Reply-To: <20240902-mptcp-fallback-x-mpc-v1-0-86d9170ddff7@kernel.org> To: mptcp@lists.linux.dev Cc: "Matthieu Baerts (NGI0)" X-Mailer: b4 0.14.1 X-Developer-Signature: v=1; a=openpgp-sha256; l=4433; i=matttbe@kernel.org; h=from:subject:message-id; bh=rjEniUY9LS7YomeFWzdX/evdWHB/tnFmR/a7VtVogJE=; b=owEBbQKS/ZANAwAIAfa3gk9CaaBzAcsmYgBm1YC+gj2ZqqsM+Nrl+z/57rpKRPXraX/BYVqF/ ejYUoEkAAqJAjMEAAEIAB0WIQToy4X3aHcFem4n93r2t4JPQmmgcwUCZtWAvgAKCRD2t4JPQmmg c62fEADa+12gqocSDc06XaU1E8XI5R578ehPmj4VvSPHxh64nbEbPnP6JjAPPhzBez2/Zmbeqm4 s9Dqa5ljoRw3qualVyF9al+H3Vp0/qA+FfBfQJpQLYcu7vJeyOeijUtG9vGqsaNDFty1rWLNjpG n0aLGMBjt6OjM2DDB5k3bCzgzAc6cYPbbL+OEpgOicvYsumrio+b+/YKDaigvXjs3v91psYF71R CVs1RMOIMQpNaOK9oV4n9DEvkEkUAf8ssS6K+zg5V8qgRLOoMQ4eI/1IiHgO29AjXfiynMkjcQN ziijJwruR0SkWQbPiqyx3+gntLM8WSiNjgvEkO89YyGpEgPwPar7ZuQAwFnBvlXUzW7mc0lGKj9 snUxg3LWQ/MqSA/o0UnQ78dht51cl3wZ1d3uBuOC9sVLHeMNpcTNpcw9tpDXgErACdBl82xkND3 ERHjlCdk4ZDuSZp9uliAelAXFk3Xdle+kWUuHpSWSMTwyusN6ipCbfDijRUYYVNkA5Kn74LIluO 14E4Xe6GAWrN5D/fDBFARPm3alppGpqOP22Obvk4VwccrHLXDGuzdx9kgsnr4y+0SlXEm9+gBJY LxcRUb3NQM/0K9lEKPmGmOh4Q0VVw1b8DQ2joearS6XZHu9aXD6PZElPLAQr40Sb1ZhzTdfwzxD UAa/eKWq6JPxQmA== X-Developer-Key: i=matttbe@kernel.org; a=openpgp; fpr=E8CB85F76877057A6E27F77AF6B7824F4269A073 Some middleboxes might be nasty with MPTCP, and decide to drop packets with MPTCP options, instead of just dropping the MPTCP options (or letting them pass...). In this case, it sounds better to fallback to "plain" TCP, and try again. Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/477 Signed-off-by: Matthieu Baerts (NGI0) --- include/net/mptcp.h | 4 ++++ net/ipv4/tcp_timer.c | 1 + net/mptcp/ctrl.c | 20 ++++++++++++++++++++ net/mptcp/mib.c | 1 + net/mptcp/mib.h | 1 + 5 files changed, 27 insertions(+) diff --git a/include/net/mptcp.h b/include/net/mptcp.h index 0bc4ab03f487..814b5f2e3ed5 100644 --- a/include/net/mptcp.h +++ b/include/net/mptcp.h @@ -223,6 +223,8 @@ static inline __be32 mptcp_reset_option(const struct sk= _buff *skb) =20 return htonl(0u); } + +void mptcp_active_detect_blackhole(struct sock *sk, bool expired); #else =20 static inline void mptcp_init(void) @@ -307,6 +309,8 @@ static inline struct request_sock *mptcp_subflow_reqsk_= alloc(const struct reques } =20 static inline __be32 mptcp_reset_option(const struct sk_buff *skb) { retu= rn htonl(0u); } + +static inline void mptcp_active_detect_blackhole(struct sock *sk, bool exp= ired) { } #endif /* CONFIG_MPTCP */ =20 #if IS_ENABLED(CONFIG_MPTCP_IPV6) diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 86169127e4d1..79064580c8c0 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -282,6 +282,7 @@ static int tcp_write_timeout(struct sock *sk) expired =3D retransmits_timed_out(sk, retry_until, READ_ONCE(icsk->icsk_user_timeout)); tcp_fastopen_active_detect_blackhole(sk, expired); + mptcp_active_detect_blackhole(sk, expired); =20 if (BPF_SOCK_OPS_TEST_FLAG(tp, BPF_SOCK_OPS_RTO_CB_FLAG)) tcp_call_bpf_3arg(sk, BPF_SOCK_OPS_RTO_CB, diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c index 99382c317ebb..0b23e3c5e8ff 100644 --- a/net/mptcp/ctrl.c +++ b/net/mptcp/ctrl.c @@ -12,6 +12,7 @@ #include =20 #include "protocol.h" +#include "mib.h" =20 #define MPTCP_SYSCTL_PATH "net/mptcp" =20 @@ -277,6 +278,25 @@ static void mptcp_pernet_del_table(struct mptcp_pernet= *pernet) {} =20 #endif /* CONFIG_SYSCTL */ =20 +/* Check the number of retransmissions, and fallback to TCP if needed */ +void mptcp_active_detect_blackhole(struct sock *ssk, bool expired) +{ + struct mptcp_subflow_context *subflow; + u32 timeouts; + + if (!sk_is_mptcp(ssk)) + return; + + timeouts =3D inet_csk(ssk)->icsk_retransmits; + subflow =3D mptcp_subflow_ctx(ssk); + + if (subflow->request_mptcp && ssk->sk_state =3D=3D TCP_SYN_SENT && + (timeouts =3D=3D 2 || (timeouts < 2 && expired))) { + MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_MPCAPABLEACTIVEDROP); + mptcp_subflow_early_fallback(mptcp_sk(subflow->conn), subflow); + } +} + static int __net_init mptcp_net_init(struct net *net) { struct mptcp_pernet *pernet =3D mptcp_get_pernet(net); diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c index ec0d461cb921..d70a3e2bfad6 100644 --- a/net/mptcp/mib.c +++ b/net/mptcp/mib.c @@ -15,6 +15,7 @@ static const struct snmp_mib mptcp_snmp_list[] =3D { SNMP_MIB_ITEM("MPCapableACKRX", MPTCP_MIB_MPCAPABLEPASSIVEACK), SNMP_MIB_ITEM("MPCapableFallbackACK", MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK), SNMP_MIB_ITEM("MPCapableFallbackSYNACK", MPTCP_MIB_MPCAPABLEACTIVEFALLBAC= K), + SNMP_MIB_ITEM("MPCapableSYNTXDrop", MPTCP_MIB_MPCAPABLEACTIVEDROP), SNMP_MIB_ITEM("MPFallbackTokenInit", MPTCP_MIB_TOKENFALLBACKINIT), SNMP_MIB_ITEM("MPTCPRetrans", MPTCP_MIB_RETRANSSEGS), SNMP_MIB_ITEM("MPJoinNoTokenFound", MPTCP_MIB_JOINNOTOKEN), diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h index d68136f93dac..062775700b63 100644 --- a/net/mptcp/mib.h +++ b/net/mptcp/mib.h @@ -10,6 +10,7 @@ enum linux_mptcp_mib_field { MPTCP_MIB_MPCAPABLEPASSIVEACK, /* Received third ACK with MP_CAPABLE */ MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK,/* Server-side fallback during 3-way h= andshake */ MPTCP_MIB_MPCAPABLEACTIVEFALLBACK, /* Client-side fallback during 3-way h= andshake */ + MPTCP_MIB_MPCAPABLEACTIVEDROP, /* Client-side fallback due to a MPC drop = */ MPTCP_MIB_TOKENFALLBACKINIT, /* Could not init/allocate token */ MPTCP_MIB_RETRANSSEGS, /* Segments retransmitted at the MPTCP-level */ MPTCP_MIB_JOINNOTOKEN, /* Received MP_JOIN but the token was not found */ --=20 2.45.2 From nobody Fri Nov 22 07:25:22 2024 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 58FE9185B6A for ; Mon, 2 Sep 2024 09:09:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725268163; cv=none; b=Bwbj/9lEc/zX3LQulkL0WTKQwxRQLn61ln599BVmf//ML3ueGk2T1IEd72QOdL6EZ9TCkqDDvt8PgZcuJtEObCud4dX+FfS3avjtih8Vr2riuBoG1ZjcrySqWV9dPMOAJIPZjpV/EivPRcT2y02ymVEhpKD4CzOqCSL4+SZvBqI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725268163; c=relaxed/simple; bh=75M/B2Raljs92TuJB4xKJ3XI2BTsyB/PvjkYM8Zo728=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=gktHja17WG5Bph0ek5HgdAAZN1H5UEEfpJeLbFZJyavopLmJGifW7NAkN6cxHlHveMh0gYQglKDJFqXMKJaHoeJvHJkxJHmVzlLmLzJW/G2908EUcziEoxI3nVe6DERr176+EvRzXNfMnpcceyvNch7AZ43h0watUsdqXpLQ/P4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FKU1cEie; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FKU1cEie" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1EB3BC4CEC8; Mon, 2 Sep 2024 09:09:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725268162; bh=75M/B2Raljs92TuJB4xKJ3XI2BTsyB/PvjkYM8Zo728=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=FKU1cEieF0qR7lOttx5ngyjZikGWyaYauT0rWTPozb31Nh5dKvoFY2nms81KejFmP ZMgcsVrPUrB29ce1SJOXj+0E/ZVFtr+PNZhmaDKu23CwTu8c9OGfF6h9TpUJkrX6NS Ekp0LGDzrcrCFF1fMrkN0bQ3gX+dz+QQpIlo96+a2Cv084f0WOorjmVntfdASbR2BB hPzP1fHcf8BXDME5jEjPxL9Li55q5Q7K53SUTtQy0cOU4NoMmiFkVXYrpgYFy1BgM4 1a6yIDMp4CJ5KKcRzcLV0KE5heLz4L55SlW3VyQIg+wC48DBky4RTy+zSietH9cTfL kO7ZOuZdlYrnQ== From: "Matthieu Baerts (NGI0)" Date: Mon, 02 Sep 2024 11:09:10 +0200 Subject: [PATCH mptcp-next 3/3] mptcp: disable active MPTCP in case of blackhole Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20240902-mptcp-fallback-x-mpc-v1-3-86d9170ddff7@kernel.org> References: <20240902-mptcp-fallback-x-mpc-v1-0-86d9170ddff7@kernel.org> In-Reply-To: <20240902-mptcp-fallback-x-mpc-v1-0-86d9170ddff7@kernel.org> To: mptcp@lists.linux.dev Cc: "Matthieu Baerts (NGI0)" X-Mailer: b4 0.14.1 X-Developer-Signature: v=1; a=openpgp-sha256; l=13632; i=matttbe@kernel.org; h=from:subject:message-id; bh=75M/B2Raljs92TuJB4xKJ3XI2BTsyB/PvjkYM8Zo728=; b=owEBbQKS/ZANAwAIAfa3gk9CaaBzAcsmYgBm1YC+KBwwUfiLfckb0fA65yJ/lydm9iV1bAATz 7h8dMTBpdyJAjMEAAEIAB0WIQToy4X3aHcFem4n93r2t4JPQmmgcwUCZtWAvgAKCRD2t4JPQmmg c5ynD/9gnXscMDAzia9AlwnbcfqiMrjy93fDEdo8zLfJ05CncbblCcl/NCURP89fFdTXJkcRT6f OjMd8MRNqM3QJhpz2KzRAEcgcJx8r38Rc427kI1SaNNMo0mPFmwAEXgP26JylqqutlVOYl1fKU3 bcd19ffkQ1YJTqn6ciUHx5E8/H3AhTc/Y4w5Wf6GYbKYLOcAMtrdf6LKt5eREl027nxcnydiQUC J3w5cPheOaYZJ2rMA/JVp4B5Q17UFi4xIKpqL8a/k49HSBXzytXbQaWOTS0d7hK6O6xSrb/FSDS JPQAyoX8pRvTryp1nUTWQdl10dx2LP4LjvaSL78lWqKpLQHn7cYWbQsf7oMo9MwU3Jks9lew0Br 1LjF8n1W5+zkfZBHHwkq4IOG2WKjcPicwCnXAsaMFNbqkFF0BsBhleczFlC5MbSwdOm/0VyGHdk CJQMXEQM7mzidg1635E6CODVuMzVYT5xOvrRe9ev+k5FssFGXWHDXH3upLxmEI73yAv3pZsdKfz x/weWympdQcpKGP6z77XrcJwTp4i+QNTZZ+XOWPvkngfQUxY77unlLRmEQVOJWOILcCDHE06tQ4 EYnh5ceIDu4gZqbfrUDRFgb76Mxcr9TB6WZ9p/iXk49/h9se6PY2Nw5Ojiac9UhV7pK029JQcrt v0KqKxkLqEbDvEA== X-Developer-Key: i=matttbe@kernel.org; a=openpgp; fpr=E8CB85F76877057A6E27F77AF6B7824F4269A073 An MPTCP firewall blackhole can be detected if the following SYN retransmission after a fallback to "plain" TCP is accepted. In case of blackhole, a similar technique to the one used by TFO is used: MPTCP can be disabled for a certain period of time, 1h by default. This time period will grow exponentially when more blackhole issues get detected right after MPTCP is re-enabled and will reset to the initial value when the blackhole issue goes away. The blackhole period can be modified thanks to a new sysctl knob: blackhole_timeout. Two new MIB counters help understanding what's happening: - 'Blackhole', incremented when a blackhole has been detected. - 'MPCapableSYNTXDisabled', incremented when an MPTCP connection directly falls back to TCP during the blackhole period. Because the technique is similar to the one used by TFO, an important part of the new code is similar to what was can find in tcp_fastopen.c, with some adaptations to the MPTCP case. Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/57 Signed-off-by: Matthieu Baerts (NGI0) --- Documentation/networking/mptcp-sysctl.rst | 11 +++ net/mptcp/ctrl.c | 121 ++++++++++++++++++++++++++= +++- net/mptcp/mib.c | 2 + net/mptcp/mib.h | 2 + net/mptcp/protocol.c | 11 ++- net/mptcp/protocol.h | 8 +- net/mptcp/subflow.c | 4 + 7 files changed, 151 insertions(+), 8 deletions(-) diff --git a/Documentation/networking/mptcp-sysctl.rst b/Documentation/netw= orking/mptcp-sysctl.rst index fd514bba8c43..95598c21fc8e 100644 --- a/Documentation/networking/mptcp-sysctl.rst +++ b/Documentation/networking/mptcp-sysctl.rst @@ -34,6 +34,17 @@ available_schedulers - STRING Shows the available schedulers choices that are registered. More packet schedulers may be available, but not loaded. =20 +blackhole_timeout - INTEGER (seconds) + Initial time period in second to disable MPTCP on active MPTCP sockets + when a MPTCP firewall blackhole issue happens. This time period will + grow exponentially when more blackhole issues get detected right after + MPTCP is re-enabled and will reset to the initial value when the + blackhole issue goes away. + + 0 to disable the blackhole detection. + + Default: 3600 + checksum_enabled - BOOLEAN Control whether DSS checksum can be enabled. =20 diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c index 0b23e3c5e8ff..38d8121331d4 100644 --- a/net/mptcp/ctrl.c +++ b/net/mptcp/ctrl.c @@ -28,8 +28,11 @@ struct mptcp_pernet { #endif =20 unsigned int add_addr_timeout; + unsigned int blackhole_timeout; unsigned int close_timeout; unsigned int stale_loss_cnt; + atomic_t active_disable_times; + unsigned long active_disable_stamp; u8 mptcp_enabled; u8 checksum_enabled; u8 allow_join_initial_addr_port; @@ -88,6 +91,8 @@ static void mptcp_pernet_set_defaults(struct mptcp_pernet= *pernet) { pernet->mptcp_enabled =3D 1; pernet->add_addr_timeout =3D TCP_RTO_MAX; + pernet->blackhole_timeout =3D 3600; + atomic_set(&pernet->active_disable_times, 0); pernet->close_timeout =3D TCP_TIMEWAIT_LEN; pernet->checksum_enabled =3D 0; pernet->allow_join_initial_addr_port =3D 1; @@ -152,6 +157,20 @@ static int proc_available_schedulers(const struct ctl_= table *ctl, return ret; } =20 +static int proc_blackhole_detect_timeout(const struct ctl_table *table, + int write, void *buffer, size_t *lenp, + loff_t *ppos) +{ + struct mptcp_pernet *pernet =3D mptcp_get_pernet(current->nsproxy->net_ns= ); + int ret; + + ret =3D proc_dointvec_minmax(table, write, buffer, lenp, ppos); + if (write && ret =3D=3D 0) + atomic_set(&pernet->active_disable_times, 0); + + return ret; +} + static struct ctl_table mptcp_sysctl_table[] =3D { { .procname =3D "enabled", @@ -218,6 +237,13 @@ static struct ctl_table mptcp_sysctl_table[] =3D { .mode =3D 0644, .proc_handler =3D proc_dointvec_jiffies, }, + { + .procname =3D "blackhole_timeout", + .maxlen =3D sizeof(unsigned int), + .mode =3D 0644, + .proc_handler =3D proc_blackhole_detect_timeout, + .extra1 =3D SYSCTL_ZERO, + }, }; =20 static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pe= rnet) @@ -241,6 +267,7 @@ static int mptcp_pernet_new_table(struct net *net, stru= ct mptcp_pernet *pernet) table[6].data =3D &pernet->scheduler; /* table[7] is for available_schedulers which is read-only info */ table[8].data =3D &pernet->close_timeout; + table[9].data =3D &pernet->blackhole_timeout; =20 hdr =3D register_net_sysctl_sz(net, MPTCP_SYSCTL_PATH, table, ARRAY_SIZE(mptcp_sysctl_table)); @@ -278,6 +305,88 @@ static void mptcp_pernet_del_table(struct mptcp_pernet= *pernet) {} =20 #endif /* CONFIG_SYSCTL */ =20 +/* The following code block is to deal with middle box issues with MPTCP, + * similar to what is done with TFO. + * The proposed solution is to disable active MPTCP globally when SYN+MPC = are + * dropped, while SYN without MPC aren't. In this case, active side MPTCP = is + * disabled globally for 1hr at first. Then if it happens again, it is dis= abled + * for 2h, then 4h, 8h, ... + * The timeout is reset back to 1hr when a successful active MPTCP connect= ion is + * fully established. + */ + +/* Disable active MPTCP and record current jiffies and active_disable_time= s */ +void mptcp_active_disable(struct sock *sk) +{ + struct net *net =3D sock_net(sk); + struct mptcp_pernet *pernet; + + pernet =3D mptcp_get_pernet(net); + + if (!READ_ONCE(pernet->blackhole_timeout)) + return; + + /* Paired with READ_ONCE() in mptcp_active_should_disable() */ + WRITE_ONCE(pernet->active_disable_stamp, jiffies); + + /* Paired with smp_rmb() in mptcp_active_should_disable(). + * We want pernet->active_disable_stamp to be updated first. + */ + smp_mb__before_atomic(); + atomic_inc(&pernet->active_disable_times); + + MPTCP_INC_STATS(net, MPTCP_MIB_BLACKHOLE); +} + +/* Calculate timeout for MPTCP active disable + * Return true if we are still in the active MPTCP disable period + * Return false if timeout already expired and we should use active MPTCP + */ +bool mptcp_active_should_disable(struct sock *ssk) +{ + struct net *net =3D sock_net(ssk); + unsigned int blackhole_timeout; + struct mptcp_pernet *pernet; + unsigned long timeout; + int disable_times; + int multiplier; + + pernet =3D mptcp_get_pernet(net); + blackhole_timeout =3D READ_ONCE(pernet->blackhole_timeout); + + if (!blackhole_timeout) + return false; + + disable_times =3D atomic_read(&pernet->active_disable_times); + if (!disable_times) + return false; + + /* Paired with smp_mb__before_atomic() in mptcp_active_disable() */ + smp_rmb(); + + /* Limit timeout to max: 2^6 * initial timeout */ + multiplier =3D 1 << min(disable_times - 1, 6); + + /* Paired with the WRITE_ONCE() in mptcp_active_disable(). */ + timeout =3D READ_ONCE(pernet->active_disable_stamp) + + multiplier * blackhole_timeout * HZ; + + return time_before(jiffies, timeout); +} + +/* Enable active MPTCP and reset active_disable_times if needed */ +void mptcp_active_enable(struct sock *sk) +{ + struct mptcp_pernet *pernet =3D mptcp_get_pernet(sock_net(sk)); + + if (atomic_read(&pernet->active_disable_times)) { + struct dst_entry *dst =3D sk_dst_get(sk); + + if (dst && dst->dev && (dst->dev->flags & IFF_LOOPBACK)) + atomic_set(&pernet->active_disable_times, 0); + } +} + /* Check the number of retransmissions, and fallback to TCP if needed */ void mptcp_active_detect_blackhole(struct sock *ssk, bool expired) { @@ -290,10 +399,14 @@ void mptcp_active_detect_blackhole(struct sock *ssk, = bool expired) timeouts =3D inet_csk(ssk)->icsk_retransmits; subflow =3D mptcp_subflow_ctx(ssk); =20 - if (subflow->request_mptcp && ssk->sk_state =3D=3D TCP_SYN_SENT && - (timeouts =3D=3D 2 || (timeouts < 2 && expired))) { - MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_MPCAPABLEACTIVEDROP); - mptcp_subflow_early_fallback(mptcp_sk(subflow->conn), subflow); + if (subflow->request_mptcp && ssk->sk_state =3D=3D TCP_SYN_SENT) { + if (timeouts =3D=3D 2 || (timeouts < 2 && expired)) { + MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_MPCAPABLEACTIVEDROP); + subflow->mpc_drop =3D 1; + mptcp_subflow_early_fallback(mptcp_sk(subflow->conn), subflow); + } else { + subflow->mpc_drop =3D 0; + } } } =20 diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c index d70a3e2bfad6..38c2efc82b94 100644 --- a/net/mptcp/mib.c +++ b/net/mptcp/mib.c @@ -16,6 +16,7 @@ static const struct snmp_mib mptcp_snmp_list[] =3D { SNMP_MIB_ITEM("MPCapableFallbackACK", MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK), SNMP_MIB_ITEM("MPCapableFallbackSYNACK", MPTCP_MIB_MPCAPABLEACTIVEFALLBAC= K), SNMP_MIB_ITEM("MPCapableSYNTXDrop", MPTCP_MIB_MPCAPABLEACTIVEDROP), + SNMP_MIB_ITEM("MPCapableSYNTXDisabled", MPTCP_MIB_MPCAPABLEACTIVEDISABLED= ), SNMP_MIB_ITEM("MPFallbackTokenInit", MPTCP_MIB_TOKENFALLBACKINIT), SNMP_MIB_ITEM("MPTCPRetrans", MPTCP_MIB_RETRANSSEGS), SNMP_MIB_ITEM("MPJoinNoTokenFound", MPTCP_MIB_JOINNOTOKEN), @@ -74,6 +75,7 @@ static const struct snmp_mib mptcp_snmp_list[] =3D { SNMP_MIB_ITEM("RcvWndConflictUpdate", MPTCP_MIB_RCVWNDCONFLICTUPDATE), SNMP_MIB_ITEM("RcvWndConflict", MPTCP_MIB_RCVWNDCONFLICT), SNMP_MIB_ITEM("MPCurrEstab", MPTCP_MIB_CURRESTAB), + SNMP_MIB_ITEM("Blackhole", MPTCP_MIB_BLACKHOLE), SNMP_MIB_SENTINEL }; =20 diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h index 062775700b63..c8ffe18a8722 100644 --- a/net/mptcp/mib.h +++ b/net/mptcp/mib.h @@ -11,6 +11,7 @@ enum linux_mptcp_mib_field { MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK,/* Server-side fallback during 3-way h= andshake */ MPTCP_MIB_MPCAPABLEACTIVEFALLBACK, /* Client-side fallback during 3-way h= andshake */ MPTCP_MIB_MPCAPABLEACTIVEDROP, /* Client-side fallback due to a MPC drop = */ + MPTCP_MIB_MPCAPABLEACTIVEDISABLED, /* Client-side disabled due to past is= sues */ MPTCP_MIB_TOKENFALLBACKINIT, /* Could not init/allocate token */ MPTCP_MIB_RETRANSSEGS, /* Segments retransmitted at the MPTCP-level */ MPTCP_MIB_JOINNOTOKEN, /* Received MP_JOIN but the token was not found */ @@ -75,6 +76,7 @@ enum linux_mptcp_mib_field { */ MPTCP_MIB_RCVWNDCONFLICT, /* Conflict with while updating msk rcv wnd */ MPTCP_MIB_CURRESTAB, /* Current established MPTCP connections */ + MPTCP_MIB_BLACKHOLE, /* A blackhole has been detected */ __MPTCP_MIB_MAX }; =20 diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index a32f79db235a..d401cbe9412b 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3737,9 +3737,14 @@ static int mptcp_connect(struct sock *sk, struct soc= kaddr *uaddr, int addr_len) if (rcu_access_pointer(tcp_sk(ssk)->md5sig_info)) mptcp_subflow_early_fallback(msk, subflow); #endif - if (subflow->request_mptcp && mptcp_token_new_connect(ssk)) { - MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_TOKENFALLBACKINIT); - mptcp_subflow_early_fallback(msk, subflow); + if (subflow->request_mptcp) { + if (mptcp_active_should_disable(sk)) { + MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_MPCAPABLEACTIVEDISABLED); + mptcp_subflow_early_fallback(msk, subflow); + } else if (mptcp_token_new_connect(ssk) < 0) { + MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_TOKENFALLBACKINIT); + mptcp_subflow_early_fallback(msk, subflow); + } } =20 WRITE_ONCE(msk->write_seq, subflow->idsn); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 633a9bc7a0e7..02e51a469321 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -531,7 +531,8 @@ struct mptcp_subflow_context { valid_csum_seen : 1, /* at least one csum validated */ is_mptfo : 1, /* subflow is doing TFO */ close_event_done : 1, /* has done the post-closed part */ - __unused : 9; + mpc_drop : 1, /* the MPC option has been dropped in a rtx */ + __unused : 8; bool data_avail; bool scheduled; u32 remote_nonce; @@ -697,6 +698,11 @@ unsigned int mptcp_stale_loss_cnt(const struct net *ne= t); unsigned int mptcp_close_timeout(const struct sock *sk); int mptcp_get_pm_type(const struct net *net); const char *mptcp_get_scheduler(const struct net *net); + +void mptcp_active_disable(struct sock *sk); +bool mptcp_active_should_disable(struct sock *ssk); +void mptcp_active_enable(struct sock *sk); + void mptcp_get_available_schedulers(char *buf, size_t maxlen); void __mptcp_subflow_fully_established(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow, diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index b9b14e75e8c2..1040b3b9696b 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -546,6 +546,7 @@ static void subflow_finish_connect(struct sock *sk, con= st struct sk_buff *skb) subflow->mp_capable =3D 1; MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVEACK); mptcp_finish_connect(sk); + mptcp_active_enable(parent); mptcp_propagate_state(parent, sk, subflow, &mp_opt); } else if (subflow->request_join) { u8 hmac[SHA256_DIGEST_SIZE]; @@ -591,6 +592,9 @@ static void subflow_finish_connect(struct sock *sk, con= st struct sk_buff *skb) MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINPORTSYNACKRX); } } else if (mptcp_check_fallback(sk)) { + /* It looks like MPTCP is blocked, while TCP is not */ + if (subflow->mpc_drop) + mptcp_active_disable(parent); fallback: mptcp_propagate_state(parent, sk, subflow, NULL); } --=20 2.45.2