[PATCH mptcp-next] mptcp: force a push after arming infinite map on MP_FAIL

Kalpan Jani posted 1 patch 4 days, 3 hours ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/multipath-tcp/mptcp_net-next tags/patchew/20260922071245.1997430-1-kalpan.jani@mpiricsoftware.com
net/mptcp/pm.c | 5 +++++
1 file changed, 5 insertions(+)
[PATCH mptcp-next] mptcp: force a push after arming infinite map on MP_FAIL
Posted by Kalpan Jani 4 days, 3 hours ago
When MP_FAIL is received, the subflow sets send_infinite_map and
sends a bare ACK, but the infinite-map DSS mapping itself is only
emitted the next time mptcp_sendmsg_frag() runs with new data. If
the subflow has nothing new to send at that point, the flag stays
armed indefinitely and the connection stalls until unrelated data
arrives or the transfer times out.

Force a push right after arming the flag, the same way the
__mptcp_check_fallback() branch in mptcp_incoming_options() already
does.

Locally, this removes the "Infinite map" / "MP_FAIL MP_RST"
mptcp_join.sh flakiness seen at ~3-5% before this change, with no
failures observed across several hundred local runs, including under
a debug config (lockdep, spinlock/atomic-sleep debugging). Not yet
tested under concurrent system load, which the original report also
points to as a factor.

Reported-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/491
Fixes: a3038fe5d060 ("mptcp: add MP_FAIL response support")
Signed-off-by: Kalpan Jani <kalpan.jani@mpiricsoftware.com>
---
 net/mptcp/pm.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index ba7c6f80a183..b65cbcfdb3e5 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -891,6 +891,11 @@ 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);
+
+		mptcp_data_lock(subflow->conn);
+		if (sk_stream_memory_free(sk))
+			__mptcp_check_push(subflow->conn, sk);
+		mptcp_data_unlock(subflow->conn);
 	} else {
 		pr_debug("MP_FAIL response received\n");
 		WRITE_ONCE(subflow->fail_tout, 0);
-- 
2.43.0
Re: [PATCH mptcp-next] mptcp: force a push after arming infinite map on MP_FAIL
Posted by Kalpan Jani 1 day ago
Thanks for the review. I looked into this further and wanted to share
where I landed, including two dead ends, rather than go quiet while
I kept poking at it.

The gap is real: mptcp_established_options_dss() copies the mpext
already attached to a given skb rather than checking
send_infinite_map fresh per-transmission. So once all data is sent
and only pending ACK (mptcp_send_head(sk) == NULL), there's no way
for the infinite map to reach the wire -- a plain TCP-level
retransmit of an already-queued skb just resends its original,
frozen mapping. The only way out is a genuinely new mapping via
mptcp_sendmsg_frag(), which requires either new data (not present in
this scenario) or MPTCP's own retrans path -- which
__mptcp_push_retrans() unconditionally blocks via
!msk->allow_subflows, set just before send_infinite_map is armed in
mptcp_pm_mp_fail_received().

First attempt: relaxed that gate to let retransmission through when
send_infinite_map is pending on the subflow, and explicitly triggered
it via mptcp_schedule_work()/MPTCP_RETRANSMIT. This deadlocks:
__mptcp_push_retrans() holds fallback_lock across its whole retry
loop, and mptcp_sendmsg_frag() -> mptcp_update_infinite_map() ->
__mptcp_try_fallback() tries to re-acquire that same lock. Reproduced
as a soft lockup escalating to a kernel panic under CI.

Second attempt: threaded a fallback_lock_held flag through
__mptcp_try_fallback(), mptcp_try_fallback(),
mptcp_update_infinite_map(), and mptcp_sendmsg_info, so the nested
fallback check could skip re-acquiring the lock when the caller
(__mptcp_push_retrans()) already holds it. This avoids the deadlock
-- confirmed clean across repeated runs of a shrunk-file repro (data
fully drained before the corrupting packet lands) with correct
MPTcpExtInfiniteMapRx/Tx and MPTcpExtMPTCPRetrans counters every
time, no lockdep/RCU/softlockup issues.

But re-running the original, unshrunk "Infinite map" test (128 KB)
against this version consistently reproduces a data mismatch between
what the client sends and what the server receives -- 5/5 runs, vs.
zero occurrences across several hundred runs of the same test against
the unmodified retrans path. So relaxing the gate this way, even with
the lock ordering fixed, appears to let retransmission interleave
with the infinite-map transition in a way that corrupts data --
likely because the sequence/checksum semantics genuinely change once
mpext->infinite_map is set (data_len becomes 0, checksum no longer
validated per RFC 8684), and the existing dfrag/already_sent
bookkeeping doesn't account for that transition happening mid-loop.

I don't have a safe fix for the unacked-data case at this point.
Both attempts I tried address the locking/triggering problem but not
the underlying data-integrity question of what retransmission is
allowed to do once a subflow is mid-transition into infinite mapping.
Would appreciate direction on whether that's the right area to keep
digging, or whether there's a different intended approach for
flushing the infinite map when no new data is available.
Re: [PATCH mptcp-next] mptcp: force a push after arming infinite map on MP_FAIL
Posted by MPTCP CI 4 days, 2 hours ago
Hi Kalpan,

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! ✅
- Perf: Success! ✅
- Task: https://github.com/multipath-tcp/mptcp_net-next/actions/runs/35700537880

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


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)