All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH export v3 0/4] mptcp: fix TCP fallback on single-subflow MP_FAIL
@ 2026-08-12  5:46 Chenguang Zhao
  2026-08-12  5:46 ` [PATCH export v3 1/4] mptcp: add MPFailFallback MIB Chenguang Zhao
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Chenguang Zhao @ 2026-08-12  5:46 UTC (permalink / raw)
  To: mptcp; +Cc: chenguang.zhao, Chenguang Zhao

From: Chenguang Zhao <zhaochenguang@kylinos.cn>

When a valid MP_FAIL is received and infinite fallback is still allowed
(single contiguous subflow), RFC8684 section 3.7 requires leaving MPTCP
mode. Today the stack only clears allow_subflows and defers the real
fallback to the later infinite-map transmit path. If no data is sent in
between, the peer can still complete the 4th ACK as MPTCP and keep using
MPTCP options.

This series adds a dedicated MPFailFallback MIB, rejects joins after
fallback via mptcp_is_fully_established(), resets when the OoO queue
blocks infinite mapping, and falls back immediately after the MP_FAIL
response through mptcp_try_fallback().

Patch 1 adds the MPFailFallback MIB.
Patch 2 rejects joins once fallback has completed.
Patch 3 resets on MP_FAIL when the OoO queue is non-empty.
Patch 4 falls back to TCP after sending the MP_FAIL response.

v3:
- Address Matthieu Baerts' review

- Introduce the MIB first (Fixes: c65c2e3bae69) and reuse
  mptcp_try_fallback() in the functional fix

- Split mptcp_is_fully_established() and OoO handling into dedicated
  commits for easier backport

- Check FALLBACK_DONE via test_bit()

- Drop allow_subflows from mptcp_is_fully_established() (and the
  READ/WRITE_ONCE follow-up)

- On OoO failure, reset without sending MP_FAIL

- This patch series is based on the export branch, The git repository
  is: git://git.kernel.org/pub/scm/linux/kernel/git/mptcp/linux.git

Chenguang Zhao (4):
  mptcp: add MPFailFallback MIB
  mptcp: reject joins after fallback in mptcp_is_fully_established
  mptcp: reset subflow on MP_FAIL when OoO queue is non-empty
  mptcp: fallback to TCP on MP_FAIL with a single subflow

 net/mptcp/mib.c      |  1 +
 net/mptcp/mib.h      |  1 +
 net/mptcp/pm.c       | 17 +++++++++++++++--
 net/mptcp/protocol.c |  4 +++-
 net/mptcp/protocol.h |  5 ++++-
 5 files changed, 24 insertions(+), 4 deletions(-)

---
v2:
 https://lore.kernel.org/all/20260715061830.1057851-1-chenguang.zhao@linux.dev/

v1:
 https://lore.kernel.org/all/20260713064134.914507-1-chenguang.zhao@linux.dev/
-- 
2.25.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH export v3 1/4] mptcp: add MPFailFallback MIB
  2026-08-12  5:46 [PATCH export v3 0/4] mptcp: fix TCP fallback on single-subflow MP_FAIL Chenguang Zhao
@ 2026-08-12  5:46 ` Chenguang Zhao
  2026-08-12  5:46 ` [PATCH export v3 2/4] mptcp: reject joins after fallback in mptcp_is_fully_established Chenguang Zhao
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Chenguang Zhao @ 2026-08-12  5:46 UTC (permalink / raw)
  To: mptcp; +Cc: chenguang.zhao, Chenguang Zhao

From: Chenguang Zhao <zhaochenguang@kylinos.cn>

Add a dedicated MIB to track TCP fallbacks triggered by receiving
MP_FAIL. A follow-up change will use it from
mptcp_pm_mp_fail_received() via mptcp_try_fallback().

Fixes: c65c2e3bae69 ("mptcp: track fallbacks accurately via mibs")
Signed-off-by: Chenguang Zhao <zhaochenguang@kylinos.cn>
---
 net/mptcp/mib.c | 1 +
 net/mptcp/mib.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c
index 608cb568897c..3e1bb4ff07b7 100644
--- a/net/mptcp/mib.c
+++ b/net/mptcp/mib.c
@@ -90,6 +90,7 @@ static const struct snmp_mib mptcp_snmp_list[] = {
 	SNMP_MIB_ITEM("DssFallback", MPTCP_MIB_DSSFALLBACK),
 	SNMP_MIB_ITEM("DssReset", MPTCP_MIB_DSSRESET),
 	SNMP_MIB_ITEM("SimultConnectFallback", MPTCP_MIB_SIMULTCONNFALLBACK),
+	SNMP_MIB_ITEM("MPFailFallback", MPTCP_MIB_MPFAILFALLBACK),
 	SNMP_MIB_ITEM("FallbackFailed", MPTCP_MIB_FALLBACKFAILED),
 	SNMP_MIB_ITEM("WinProbe", MPTCP_MIB_WINPROBE),
 	SNMP_MIB_ITEM("BacklogDrop", MPTCP_MIB_BACKLOGDROP),
diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h
index 1ebdb55e9534..89ebf7086cc6 100644
--- a/net/mptcp/mib.h
+++ b/net/mptcp/mib.h
@@ -93,6 +93,7 @@ enum linux_mptcp_mib_field {
 	MPTCP_MIB_DSSFALLBACK,		/* Bad or missing DSS */
 	MPTCP_MIB_DSSRESET,		/* MP_RST: bad data mapping */
 	MPTCP_MIB_SIMULTCONNFALLBACK,	/* Simultaneous connect */
+	MPTCP_MIB_MPFAILFALLBACK,	/* Received MP_FAIL, fallback to TCP */
 	MPTCP_MIB_FALLBACKFAILED,	/* Can't fallback due to msk status */
 	MPTCP_MIB_WINPROBE,		/* MPTCP-level zero window probe */
 	MPTCP_MIB_BACKLOGDROP,		/* Backlog over memory limit */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH export v3 2/4] mptcp: reject joins after fallback in mptcp_is_fully_established
  2026-08-12  5:46 [PATCH export v3 0/4] mptcp: fix TCP fallback on single-subflow MP_FAIL Chenguang Zhao
  2026-08-12  5:46 ` [PATCH export v3 1/4] mptcp: add MPFailFallback MIB Chenguang Zhao
@ 2026-08-12  5:46 ` Chenguang Zhao
  2026-08-12  5:46 ` [PATCH export v3 3/4] mptcp: reset subflow on MP_FAIL when OoO queue is non-empty Chenguang Zhao
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Chenguang Zhao @ 2026-08-12  5:46 UTC (permalink / raw)
  To: mptcp; +Cc: chenguang.zhao, Chenguang Zhao

From: Chenguang Zhao <zhaochenguang@kylinos.cn>

After fallback, treat the connection as not fully established so later
MP_JOIN attempts are rejected.

Signed-off-by: Chenguang Zhao <zhaochenguang@kylinos.cn>
---
 net/mptcp/protocol.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index 7e168e450fb0..bf2483a7ed92 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -957,8 +957,11 @@ static inline void mptcp_start_tout_timer(struct sock *sk)
 
 static inline bool mptcp_is_fully_established(struct sock *sk)
 {
+	struct mptcp_sock *msk = mptcp_sk(sk);
+
 	return inet_sk_state_load(sk) == TCP_ESTABLISHED &&
-	       READ_ONCE(mptcp_sk(sk)->fully_established);
+	       READ_ONCE(msk->fully_established) &&
+	       !test_bit(MPTCP_FALLBACK_DONE, &msk->flags);
 }
 
 static inline u64 mptcp_stamp(void)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH export v3 3/4] mptcp: reset subflow on MP_FAIL when OoO queue is non-empty
  2026-08-12  5:46 [PATCH export v3 0/4] mptcp: fix TCP fallback on single-subflow MP_FAIL Chenguang Zhao
  2026-08-12  5:46 ` [PATCH export v3 1/4] mptcp: add MPFailFallback MIB Chenguang Zhao
  2026-08-12  5:46 ` [PATCH export v3 2/4] mptcp: reject joins after fallback in mptcp_is_fully_established Chenguang Zhao
@ 2026-08-12  5:46 ` Chenguang Zhao
  2026-08-12  6:07   ` sashiko-bot
  2026-08-12  5:46 ` [PATCH export v3 4/4] mptcp: fallback to TCP on MP_FAIL with a single subflow Chenguang Zhao
  2026-08-12  6:57 ` [PATCH export v3 0/4] mptcp: fix TCP fallback on single-subflow MP_FAIL MPTCP CI
  4 siblings, 1 reply; 7+ messages in thread
From: Chenguang Zhao @ 2026-08-12  5:46 UTC (permalink / raw)
  To: mptcp; +Cc: chenguang.zhao, Chenguang Zhao

From: Chenguang Zhao <zhaochenguang@kylinos.cn>

Infinite mapping needs contiguous data. If the MPTCP OoO queue is not
empty, reset the subflow instead of falling back.

Signed-off-by: Chenguang Zhao <zhaochenguang@kylinos.cn>
---
 net/mptcp/pm.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index ba7c6f80a183..8c263084db7b 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -882,6 +882,16 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq)
 		spin_unlock_bh(&msk->fallback_lock);
 		return;
 	}
+
+	/* RFC8684 §3.7: Infinite mapping requires contiguous data */
+	if (!subflow->fail_tout &&
+	    !RB_EMPTY_ROOT(&msk->out_of_order_queue)) {
+		spin_unlock_bh(&msk->fallback_lock);
+		MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FALLBACKFAILED);
+		mptcp_subflow_reset(sk);
+		return;
+	}
+
 	msk->allow_subflows = false;
 	spin_unlock_bh(&msk->fallback_lock);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH export v3 4/4] mptcp: fallback to TCP on MP_FAIL with a single subflow
  2026-08-12  5:46 [PATCH export v3 0/4] mptcp: fix TCP fallback on single-subflow MP_FAIL Chenguang Zhao
                   ` (2 preceding siblings ...)
  2026-08-12  5:46 ` [PATCH export v3 3/4] mptcp: reset subflow on MP_FAIL when OoO queue is non-empty Chenguang Zhao
@ 2026-08-12  5:46 ` Chenguang Zhao
  2026-08-12  6:57 ` [PATCH export v3 0/4] mptcp: fix TCP fallback on single-subflow MP_FAIL MPTCP CI
  4 siblings, 0 replies; 7+ messages in thread
From: Chenguang Zhao @ 2026-08-12  5:46 UTC (permalink / raw)
  To: mptcp; +Cc: chenguang.zhao, Chenguang Zhao

From: Chenguang Zhao <zhaochenguang@kylinos.cn>

Fall back immediately via mptcp_try_fallback() after accepting MP_FAIL
on a single contiguous subflow, as required by RFC8684 §3.7.

Fixes: 1e39e5a32ad7 ("mptcp: infinite mapping sending")
Signed-off-by: Chenguang Zhao <zhaochenguang@kylinos.cn>
---
 net/mptcp/pm.c       | 9 ++++++---
 net/mptcp/protocol.c | 4 +++-
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index 8c263084db7b..cb85caf1df43 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -876,7 +876,6 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq)
 
 	pr_debug("fail_seq=%llu\n", fail_seq);
 
-	/* After accepting the fail, we can't create any other subflows */
 	spin_lock_bh(&msk->fallback_lock);
 	if (!msk->allow_infinite_fallback) {
 		spin_unlock_bh(&msk->fallback_lock);
@@ -891,8 +890,6 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq)
 		mptcp_subflow_reset(sk);
 		return;
 	}
-
-	msk->allow_subflows = false;
 	spin_unlock_bh(&msk->fallback_lock);
 
 	if (!subflow->fail_tout) {
@@ -901,6 +898,12 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq)
 		subflow->send_mp_fail = 1;
 		subflow->send_infinite_map = 1;
 		tcp_send_ack(sk);
+
+		/* RFC8684 §3.7: fallback with a single subflow */
+		if (!mptcp_try_fallback(sk, MPTCP_MIB_MPFAILFALLBACK)) {
+			MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FALLBACKFAILED);
+			mptcp_subflow_reset(sk);
+		}
 	} else {
 		pr_debug("MP_FAIL response received\n");
 		WRITE_ONCE(subflow->fail_tout, 0);
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index f879b1061f2d..519e8d9c3164 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -1418,7 +1418,9 @@ static void mptcp_update_infinite_map(struct mptcp_sock *msk,
 	mpext->infinite_map = 1;
 	mpext->data_len = 0;
 
-	if (!mptcp_try_fallback(ssk, MPTCP_MIB_INFINITEMAPTX)) {
+	if (__mptcp_check_fallback(msk)) {
+		MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_INFINITEMAPTX);
+	} else if (!mptcp_try_fallback(ssk, MPTCP_MIB_INFINITEMAPTX)) {
 		MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_FALLBACKFAILED);
 		mptcp_subflow_reset(ssk);
 		return;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH export v3 3/4] mptcp: reset subflow on MP_FAIL when OoO queue is non-empty
  2026-08-12  5:46 ` [PATCH export v3 3/4] mptcp: reset subflow on MP_FAIL when OoO queue is non-empty Chenguang Zhao
@ 2026-08-12  6:07   ` sashiko-bot
  0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-08-12  6:07 UTC (permalink / raw)
  To: Chenguang Zhao; +Cc: mptcp

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] TOCTOU race due to lockless access of `msk->out_of_order_queue`.
--

--- Patch [3]: [PATCH export v3 3/4] mptcp: reset subflow on MP_FAIL when OoO queue is non-empty ---
commit fe6cef2f543d25c806aed2ee11c8a4d7a936c259
Author: Chenguang Zhao <zhaochenguang@kylinos.cn>

mptcp: reset subflow on MP_FAIL when OoO queue is non-empty

This commit updates the handling of an MP_FAIL response to reset the subflow
instead of falling back when the out-of-order queue is not empty. This is done
to ensure the contiguous data requirements for infinite mapping are met.

> diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
> index ba7c6f80a183c..8c263084db7be 100644
> --- a/net/mptcp/pm.c
> +++ b/net/mptcp/pm.c
> @@ -882,6 +882,16 @@ void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq)
>  		spin_unlock_bh(&msk->fallback_lock);
>  		return;
>  	}
> +
> +	/* RFC8684 §3.7: Infinite mapping requires contiguous data */
> +	if (!subflow->fail_tout &&
> +	    !RB_EMPTY_ROOT(&msk->out_of_order_queue)) {

[Severity: High]
Can this lockless check of the out-of-order queue lead to a race condition?

Looking at mptcp_pm_mp_fail_received(), the out_of_order_queue is checked
for emptiness while only holding msk->fallback_lock, without the required
mptcp_data_lock.

If another active subflow concurrently receives out-of-order data, acquires
the msk data lock, and inserts data into the queue, this check might
incorrectly conclude the queue is empty.

If the queue is populated right after this lockless check but before
mptcp_try_fallback() is called, could this cause an infinite map TCP ACK to
be incorrectly transmitted before the fallback is ultimately aborted? 

Furthermore, if the queue is populated immediately after fallback occurs,
could this stranded MPTCP out-of-order data be improperly appended to the
plain TCP receive queue as the stream advances, resulting in data duplication
and stream corruption?

> +		spin_unlock_bh(&msk->fallback_lock);
> +		MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_FALLBACKFAILED);
> +		mptcp_subflow_reset(sk);
> +		return;
> +	}
> +
>  	msk->allow_subflows = false;
>  	spin_unlock_bh(&msk->fallback_lock);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260812054653.43799-1-chenguang.zhao@linux.dev?part=3

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH export v3 0/4] mptcp: fix TCP fallback on single-subflow MP_FAIL
  2026-08-12  5:46 [PATCH export v3 0/4] mptcp: fix TCP fallback on single-subflow MP_FAIL Chenguang Zhao
                   ` (3 preceding siblings ...)
  2026-08-12  5:46 ` [PATCH export v3 4/4] mptcp: fallback to TCP on MP_FAIL with a single subflow Chenguang Zhao
@ 2026-08-12  6:57 ` MPTCP CI
  4 siblings, 0 replies; 7+ messages in thread
From: MPTCP CI @ 2026-08-12  6:57 UTC (permalink / raw)
  To: Chenguang Zhao; +Cc: mptcp

Hi Chenguang,

Thank you for your modifications, that's great!

Our CI did some validations and here is its report:

- KVM Validation: normal (except selftest_mptcp_join): Success! ✅
- KVM Validation: normal (only selftest_mptcp_join): Success! ✅
- KVM Validation: debug (except selftest_mptcp_join): Success! ✅
- KVM Validation: debug (only selftest_mptcp_join): Success! ✅
- KVM Validation: btf-normal (only bpftest_all): Success! ✅
- KVM Validation: btf-debug (only bpftest_all): Success! ✅
- Task: https://github.com/multipath-tcp/mptcp_net-next/actions/runs/31568808826

Initiator: Patchew Applier
Commits: https://github.com/multipath-tcp/mptcp_net-next/commits/185641831778
Patchwork: https://patchwork.kernel.org/project/mptcp/list/?series=1144463


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] 7+ messages in thread

end of thread, other threads:[~2026-08-12  6:57 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-12  5:46 [PATCH export v3 0/4] mptcp: fix TCP fallback on single-subflow MP_FAIL Chenguang Zhao
2026-08-12  5:46 ` [PATCH export v3 1/4] mptcp: add MPFailFallback MIB Chenguang Zhao
2026-08-12  5:46 ` [PATCH export v3 2/4] mptcp: reject joins after fallback in mptcp_is_fully_established Chenguang Zhao
2026-08-12  5:46 ` [PATCH export v3 3/4] mptcp: reset subflow on MP_FAIL when OoO queue is non-empty Chenguang Zhao
2026-08-12  6:07   ` sashiko-bot
2026-08-12  5:46 ` [PATCH export v3 4/4] mptcp: fallback to TCP on MP_FAIL with a single subflow Chenguang Zhao
2026-08-12  6:57 ` [PATCH export v3 0/4] mptcp: fix TCP fallback on single-subflow MP_FAIL MPTCP CI

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.