* [PATCH mptcp-next 0/3] mptcp: fallback to TCP after 3 MPC drop + cache
@ 2024-09-02 9:09 Matthieu Baerts (NGI0)
2024-09-02 9:09 ` [PATCH mptcp-next 1/3] mptcp: export mptcp_subflow_early_fallback() Matthieu Baerts (NGI0)
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Matthieu Baerts (NGI0) @ 2024-09-02 9:09 UTC (permalink / raw)
To: mptcp; +Cc: Matthieu Baerts (NGI0)
The SYN + MPTCP_CAPABLE packets could be explicitly dropped by firewall
somewhere in the network, e.g. with:
iptables -t filter -A FORWARD -p tcp --tcp-option 30 -j DROP
The idea of this series is to fallback to TCP after 3 SYN+MPC drop
(patch 2). If the connection succeeds after the fallback, it very likely
means a blackhole has been detected. In this case (patch 3), MPTCP can
be disabled for a certain period of time, 1h by default. If after this
period, MPTCP is still blocked, the period is doubled.
This should help applications which want to use MPTCP by default on the
client side if available.
This series has been validated by a new packetdrill test:
https://github.com/multipath-tcp/packetdrill/pull/156
Some questions:
- Should we let the user changes the number of retransmissions (2)
before falling back to TCP? For TFO, the data are never retransmitted
in a SYN. Maybe that's different here? A sysctl knob could always be
added later on.
- Should we globally disable all MPTCP connections if any retransmission
after the fallback is a success instead of only the first one? I guess
we reduce risks of accidents by only looking at the following
retransmission after the fallback.
- Is one hour a good time for the fallback?
For later:
- The restriction could be done per oif (sk_dst_get(ssk)->dev), but we
would need to store it somehow, or per MPTCP entrypoint. Or let the PM
calling mptcp_active_enable() when a new endpoint is added.
- Other cases could trigger mptcp_active_disable(): e.g. some fallbacks
or corruptions in the middle of the connections.
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
---
Matthieu Baerts (NGI0) (3):
mptcp: export mptcp_subflow_early_fallback()
mptcp: fallback to TCP after SYN+MPC drops
mptcp: disable active MPTCP in case of blackhole
Documentation/networking/mptcp-sysctl.rst | 11 +++
include/net/mptcp.h | 4 +
net/ipv4/tcp_timer.c | 1 +
net/mptcp/ctrl.c | 133 ++++++++++++++++++++++++++++++
net/mptcp/mib.c | 3 +
net/mptcp/mib.h | 3 +
net/mptcp/protocol.c | 18 ++--
net/mptcp/protocol.h | 16 +++-
net/mptcp/subflow.c | 4 +
9 files changed, 182 insertions(+), 11 deletions(-)
---
base-commit: 44106bc7908a7c9e461983032567a918e1d62b91
change-id: 20240822-mptcp-fallback-x-mpc-491bb35a8e66
Best regards,
--
Matthieu Baerts (NGI0) <matttbe@kernel.org>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH mptcp-next 1/3] mptcp: export mptcp_subflow_early_fallback()
2024-09-02 9:09 [PATCH mptcp-next 0/3] mptcp: fallback to TCP after 3 MPC drop + cache Matthieu Baerts (NGI0)
@ 2024-09-02 9:09 ` Matthieu Baerts (NGI0)
2024-09-02 9:09 ` [PATCH mptcp-next 2/3] mptcp: fallback to TCP after SYN+MPC drops Matthieu Baerts (NGI0)
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Matthieu Baerts (NGI0) @ 2024-09-02 9:09 UTC (permalink / raw)
To: mptcp; +Cc: Matthieu Baerts (NGI0)
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) <matttbe@kernel.org>
---
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;
}
-static void mptcp_subflow_early_fallback(struct mptcp_sock *msk,
- struct mptcp_subflow_context *subflow)
-{
- subflow->request_mptcp = 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 *ssk)
#define pr_fallback(a) pr_debug("%s:fallback to TCP (msk=%p)\n", __func__, a)
+static inline void mptcp_subflow_early_fallback(struct mptcp_sock *msk,
+ struct mptcp_subflow_context *subflow)
+{
+ pr_fallback(msk);
+ subflow->request_mptcp = 0;
+ __mptcp_do_fallback(msk);
+}
+
static inline bool mptcp_check_infinite_map(struct sk_buff *skb)
{
struct mptcp_ext *mpext;
--
2.45.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH mptcp-next 2/3] mptcp: fallback to TCP after SYN+MPC drops
2024-09-02 9:09 [PATCH mptcp-next 0/3] mptcp: fallback to TCP after 3 MPC drop + cache Matthieu Baerts (NGI0)
2024-09-02 9:09 ` [PATCH mptcp-next 1/3] mptcp: export mptcp_subflow_early_fallback() Matthieu Baerts (NGI0)
@ 2024-09-02 9:09 ` Matthieu Baerts (NGI0)
2024-09-02 9:09 ` [PATCH mptcp-next 3/3] mptcp: disable active MPTCP in case of blackhole Matthieu Baerts (NGI0)
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Matthieu Baerts (NGI0) @ 2024-09-02 9:09 UTC (permalink / raw)
To: mptcp; +Cc: Matthieu Baerts (NGI0)
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) <matttbe@kernel.org>
---
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)
return htonl(0u);
}
+
+void mptcp_active_detect_blackhole(struct sock *sk, bool expired);
#else
static inline void mptcp_init(void)
@@ -307,6 +309,8 @@ static inline struct request_sock *mptcp_subflow_reqsk_alloc(const struct reques
}
static inline __be32 mptcp_reset_option(const struct sk_buff *skb) { return htonl(0u); }
+
+static inline void mptcp_active_detect_blackhole(struct sock *sk, bool expired) { }
#endif /* CONFIG_MPTCP */
#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 = 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);
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 <net/netns/generic.h>
#include "protocol.h"
+#include "mib.h"
#define MPTCP_SYSCTL_PATH "net/mptcp"
@@ -277,6 +278,25 @@ static void mptcp_pernet_del_table(struct mptcp_pernet *pernet) {}
#endif /* CONFIG_SYSCTL */
+/* 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 = inet_csk(ssk)->icsk_retransmits;
+ subflow = mptcp_subflow_ctx(ssk);
+
+ if (subflow->request_mptcp && ssk->sk_state == TCP_SYN_SENT &&
+ (timeouts == 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 = 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[] = {
SNMP_MIB_ITEM("MPCapableACKRX", MPTCP_MIB_MPCAPABLEPASSIVEACK),
SNMP_MIB_ITEM("MPCapableFallbackACK", MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK),
SNMP_MIB_ITEM("MPCapableFallbackSYNACK", MPTCP_MIB_MPCAPABLEACTIVEFALLBACK),
+ 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 handshake */
MPTCP_MIB_MPCAPABLEACTIVEFALLBACK, /* Client-side fallback during 3-way handshake */
+ 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 */
--
2.45.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH mptcp-next 3/3] mptcp: disable active MPTCP in case of blackhole
2024-09-02 9:09 [PATCH mptcp-next 0/3] mptcp: fallback to TCP after 3 MPC drop + cache Matthieu Baerts (NGI0)
2024-09-02 9:09 ` [PATCH mptcp-next 1/3] mptcp: export mptcp_subflow_early_fallback() Matthieu Baerts (NGI0)
2024-09-02 9:09 ` [PATCH mptcp-next 2/3] mptcp: fallback to TCP after SYN+MPC drops Matthieu Baerts (NGI0)
@ 2024-09-02 9:09 ` Matthieu Baerts (NGI0)
2024-09-02 17:45 ` [PATCH mptcp-next 0/3] mptcp: fallback to TCP after 3 MPC drop + cache MPTCP CI
2024-09-09 16:49 ` Matthieu Baerts
4 siblings, 0 replies; 6+ messages in thread
From: Matthieu Baerts (NGI0) @ 2024-09-02 9:09 UTC (permalink / raw)
To: mptcp; +Cc: Matthieu Baerts (NGI0)
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) <matttbe@kernel.org>
---
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/networking/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.
+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.
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
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 = 1;
pernet->add_addr_timeout = TCP_RTO_MAX;
+ pernet->blackhole_timeout = 3600;
+ atomic_set(&pernet->active_disable_times, 0);
pernet->close_timeout = TCP_TIMEWAIT_LEN;
pernet->checksum_enabled = 0;
pernet->allow_join_initial_addr_port = 1;
@@ -152,6 +157,20 @@ static int proc_available_schedulers(const struct ctl_table *ctl,
return ret;
}
+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 = mptcp_get_pernet(current->nsproxy->net_ns);
+ int ret;
+
+ ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+ if (write && ret == 0)
+ atomic_set(&pernet->active_disable_times, 0);
+
+ return ret;
+}
+
static struct ctl_table mptcp_sysctl_table[] = {
{
.procname = "enabled",
@@ -218,6 +237,13 @@ static struct ctl_table mptcp_sysctl_table[] = {
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
},
+ {
+ .procname = "blackhole_timeout",
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = proc_blackhole_detect_timeout,
+ .extra1 = SYSCTL_ZERO,
+ },
};
static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet)
@@ -241,6 +267,7 @@ static int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet)
table[6].data = &pernet->scheduler;
/* table[7] is for available_schedulers which is read-only info */
table[8].data = &pernet->close_timeout;
+ table[9].data = &pernet->blackhole_timeout;
hdr = 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) {}
#endif /* CONFIG_SYSCTL */
+/* 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 disabled
+ * for 2h, then 4h, 8h, ...
+ * The timeout is reset back to 1hr when a successful active MPTCP connection is
+ * fully established.
+ */
+
+/* Disable active MPTCP and record current jiffies and active_disable_times */
+void mptcp_active_disable(struct sock *sk)
+{
+ struct net *net = sock_net(sk);
+ struct mptcp_pernet *pernet;
+
+ pernet = 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 = sock_net(ssk);
+ unsigned int blackhole_timeout;
+ struct mptcp_pernet *pernet;
+ unsigned long timeout;
+ int disable_times;
+ int multiplier;
+
+ pernet = mptcp_get_pernet(net);
+ blackhole_timeout = READ_ONCE(pernet->blackhole_timeout);
+
+ if (!blackhole_timeout)
+ return false;
+
+ disable_times = 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 = 1 << min(disable_times - 1, 6);
+
+ /* Paired with the WRITE_ONCE() in mptcp_active_disable(). */
+ timeout = 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 = mptcp_get_pernet(sock_net(sk));
+
+ if (atomic_read(&pernet->active_disable_times)) {
+ struct dst_entry *dst = 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 = inet_csk(ssk)->icsk_retransmits;
subflow = mptcp_subflow_ctx(ssk);
- if (subflow->request_mptcp && ssk->sk_state == TCP_SYN_SENT &&
- (timeouts == 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 == TCP_SYN_SENT) {
+ if (timeouts == 2 || (timeouts < 2 && expired)) {
+ MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_MPCAPABLEACTIVEDROP);
+ subflow->mpc_drop = 1;
+ mptcp_subflow_early_fallback(mptcp_sk(subflow->conn), subflow);
+ } else {
+ subflow->mpc_drop = 0;
+ }
}
}
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[] = {
SNMP_MIB_ITEM("MPCapableFallbackACK", MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK),
SNMP_MIB_ITEM("MPCapableFallbackSYNACK", MPTCP_MIB_MPCAPABLEACTIVEFALLBACK),
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[] = {
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
};
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 handshake */
MPTCP_MIB_MPCAPABLEACTIVEFALLBACK, /* Client-side fallback during 3-way handshake */
MPTCP_MIB_MPCAPABLEACTIVEDROP, /* Client-side fallback due to a MPC drop */
+ MPTCP_MIB_MPCAPABLEACTIVEDISABLED, /* Client-side disabled due to past issues */
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
};
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 sockaddr *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);
+ }
}
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 *net);
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, const struct sk_buff *skb)
subflow->mp_capable = 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, const 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);
}
--
2.45.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH mptcp-next 0/3] mptcp: fallback to TCP after 3 MPC drop + cache
2024-09-02 9:09 [PATCH mptcp-next 0/3] mptcp: fallback to TCP after 3 MPC drop + cache Matthieu Baerts (NGI0)
` (2 preceding siblings ...)
2024-09-02 9:09 ` [PATCH mptcp-next 3/3] mptcp: disable active MPTCP in case of blackhole Matthieu Baerts (NGI0)
@ 2024-09-02 17:45 ` MPTCP CI
2024-09-09 16:49 ` Matthieu Baerts
4 siblings, 0 replies; 6+ messages in thread
From: MPTCP CI @ 2024-09-02 17:45 UTC (permalink / raw)
To: Matthieu Baerts; +Cc: mptcp
Hi Matthieu,
Thank you for your modifications, that's great!
Our CI did some validations and here is its report:
- KVM Validation: normal: Success! ✅
- KVM Validation: debug: Success! ✅
- KVM Validation: btf (only bpftest_all): Success! ✅
- Task: https://github.com/multipath-tcp/mptcp_net-next/actions/runs/10670881116
Initiator: Patchew Applier
Commits: https://github.com/multipath-tcp/mptcp_net-next/commits/5f9d22a2f88b
Patchwork: https://patchwork.kernel.org/project/mptcp/list/?series=885758
If there are some issues, you can reproduce them using the same environment as
the one used by the CI thanks to a docker image, e.g.:
$ cd [kernel source code]
$ docker run -v "${PWD}:${PWD}:rw" -w "${PWD}" --privileged --rm -it \
--pull always mptcp/mptcp-upstream-virtme-docker:latest \
auto-normal
For more details:
https://github.com/multipath-tcp/mptcp-upstream-virtme-docker
Please note that despite all the efforts that have been already done to have a
stable tests suite when executed on a public CI like here, it is possible some
reported issues are not due to your modifications. Still, do not hesitate to
help us improve that ;-)
Cheers,
MPTCP GH Action bot
Bot operated by Matthieu Baerts (NGI0 Core)
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH mptcp-next 0/3] mptcp: fallback to TCP after 3 MPC drop + cache
2024-09-02 9:09 [PATCH mptcp-next 0/3] mptcp: fallback to TCP after 3 MPC drop + cache Matthieu Baerts (NGI0)
` (3 preceding siblings ...)
2024-09-02 17:45 ` [PATCH mptcp-next 0/3] mptcp: fallback to TCP after 3 MPC drop + cache MPTCP CI
@ 2024-09-09 16:49 ` Matthieu Baerts
4 siblings, 0 replies; 6+ messages in thread
From: Matthieu Baerts @ 2024-09-09 16:49 UTC (permalink / raw)
To: MPTCP Linux
Hello,
On 02/09/2024 11:09, Matthieu Baerts (NGI0) wrote:
> The SYN + MPTCP_CAPABLE packets could be explicitly dropped by firewall
> somewhere in the network, e.g. with:
>
> iptables -t filter -A FORWARD -p tcp --tcp-option 30 -j DROP
>
> The idea of this series is to fallback to TCP after 3 SYN+MPC drop
> (patch 2). If the connection succeeds after the fallback, it very likely
> means a blackhole has been detected. In this case (patch 3), MPTCP can
> be disabled for a certain period of time, 1h by default. If after this
> period, MPTCP is still blocked, the period is doubled.
>
> This should help applications which want to use MPTCP by default on the
> client side if available.
>
> This series has been validated by a new packetdrill test:
>
> https://github.com/multipath-tcp/packetdrill/pull/156
>
> Some questions:
>
> - Should we let the user changes the number of retransmissions (2)
> before falling back to TCP? For TFO, the data are never retransmitted
> in a SYN. Maybe that's different here? A sysctl knob could always be
> added later on.
> - Should we globally disable all MPTCP connections if any retransmission
> after the fallback is a success instead of only the first one? I guess
> we reduce risks of accidents by only looking at the following
> retransmission after the fallback.
> - Is one hour a good time for the fallback?
>
> For later:
>
> - The restriction could be done per oif (sk_dst_get(ssk)->dev), but we
> would need to store it somehow, or per MPTCP entrypoint. Or let the PM
> calling mptcp_active_enable() when a new endpoint is added.
> - Other cases could trigger mptcp_active_disable(): e.g. some fallbacks
> or corruptions in the middle of the connections.
I suggest addressing these questions later. Due to some external
circumstances, it is not possible to have more reviews for the moment. I
think there is no need to block that longer, fixes can always be
addressed later on.
New patches for t/upstream:
- a09026a9e8c4: mptcp: export mptcp_subflow_early_fallback()
- 4216aa51fb10: mptcp: fallback to TCP after SYN+MPC drops
- d0c7c7172eac: mptcp: disable active MPTCP in case of blackhole
- 0fd52c49c60b: conflict in
t/mptcp-annotate-data-races-around-subflow-fully_established
- Results: 29da3bae8ab9..fc8995744495 (export)
Tests are now in progress:
- export:
https://github.com/multipath-tcp/mptcp_net-next/commit/ca4d36d160ee56fa9bd50dc0006ad34d454d8f48/checks
Cheers,
Matt
--
Sponsored by the NGI0 Core fund.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2024-09-09 16:50 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-02 9:09 [PATCH mptcp-next 0/3] mptcp: fallback to TCP after 3 MPC drop + cache Matthieu Baerts (NGI0)
2024-09-02 9:09 ` [PATCH mptcp-next 1/3] mptcp: export mptcp_subflow_early_fallback() Matthieu Baerts (NGI0)
2024-09-02 9:09 ` [PATCH mptcp-next 2/3] mptcp: fallback to TCP after SYN+MPC drops Matthieu Baerts (NGI0)
2024-09-02 9:09 ` [PATCH mptcp-next 3/3] mptcp: disable active MPTCP in case of blackhole Matthieu Baerts (NGI0)
2024-09-02 17:45 ` [PATCH mptcp-next 0/3] mptcp: fallback to TCP after 3 MPC drop + cache MPTCP CI
2024-09-09 16:49 ` Matthieu Baerts
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox