[PATCH mptcp-net v2] mptcp: disconnect: reset first subflow's local_id

Matthieu Baerts (NGI0) posted 1 patch 6 hours ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/multipath-tcp/mptcp_net-next tags/patchew/20261015-mptcp-first-disco-id-reset-v2-1-49b71541b059@kernel.org
net/mptcp/protocol.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
[PATCH mptcp-net v2] mptcp: disconnect: reset first subflow's local_id
Posted by Matthieu Baerts (NGI0) 6 hours ago
The first subflow can get disconnected for various reasons and
mptcp_subflow_ctx_reset() will reset most fields and set local_id to -1.
That's fine until the subflow is reused after a reconnect.

As mentioned by Clashiko [1]: on the retry, local_id is -1, so the
connect goes through:

  tcp_connect()
    subflow_rebuild_header()
      subflow_chk_local_id()
        mptcp_pm_get_local_id()

mptcp_pm_get_local_id() returns 0 only when the msk local address
matches the subflow's address. The addresses can change, but even if
they don't, for an unbound msk, the address is therefore still zero at
this point. (Note: in MPTCP disconnect selftests, the address is the
same, and mptcp_pm_get_local_id() will return 0.)

At this stage, the kernel PM might then give the MPC subflow a non-zero
ID, either from a matching endpoint or by adding an "implicit" endpoint.
The RFC 8684 says that the first subflow always has the ID 0, and the
PMs rely on that for special cases. So it is important to reset it to 0
when msk->first exists (which might not be the case in case of
connect(AF_UNSPEC) for an unconnected socket...).

While at it, fix the comment above: msk->subflow has been removed for a
long time: first is used instead.

Note that we need to keep it to -1 in mptcp_subflow_ctx_reset() to avoid
a double closures in mptcp_close_ssk().

This issue was found by code analysis, and confirmed by looking at the
ID after a reconnection.

Fixes: a7cfe7766370 ("mptcp: fix data races on local_id")
Link: https://lore.kernel.org/179198834484.434549.4616694240552704738@kernel.org
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
---
Changes in v2:
- check msk->first is not NULL + fix comment
- Link to v1: https://patch.msgid.link/20261015-mptcp-first-disco-id-reset-v1-1-6ae41e8f02c6@kernel.org
---
 net/mptcp/protocol.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 60cbd91be632..a165e6683e6b 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -3649,11 +3649,13 @@ static int mptcp_disconnect(struct sock *sk, int flags)
 
 	mptcp_pm_connection_closed(msk);
 
-	/* msk->subflow is still intact, the following will not free the first
+	/* msk->first is still intact, the following will not free the first
 	 * subflow
 	 */
 	mptcp_do_fastclose(sk);
 	mptcp_destroy_common(msk);
+	if (msk->first)
+		WRITE_ONCE(mptcp_subflow_ctx(msk->first)->local_id, 0);
 
 	/* The first subflow is already in TCP_CLOSE status, the following
 	 * can't overlap with a fallback anymore

---
base-commit: 6a6728a8e881c12c984d104403ecaa0523d3b7e8
change-id: 20261015-mptcp-first-disco-id-reset-a0866d67d9a6

Best regards,
--  
Matthieu Baerts (NGI0) <matttbe@kernel.org>
Re: [PATCH mptcp-net v2] mptcp: disconnect: reset first subflow's local_id
Posted by MPTCP CI 5 hours ago
Hi Matthieu,

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/38770828855

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


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)
Re: [PATCH mptcp-net v2] mptcp: disconnect: reset first subflow's local_id
Posted by Matthieu Baerts 6 hours ago
On 15/10/2026 18:14, Matthieu Baerts (NGI0) wrote:
> The first subflow can get disconnected for various reasons and
> mptcp_subflow_ctx_reset() will reset most fields and set local_id to -1.
> That's fine until the subflow is reused after a reconnect.
> 
> As mentioned by Clashiko [1]: on the retry, local_id is -1, so the
> connect goes through:
> 
>   tcp_connect()
>     subflow_rebuild_header()
>       subflow_chk_local_id()
>         mptcp_pm_get_local_id()
> 
> mptcp_pm_get_local_id() returns 0 only when the msk local address
> matches the subflow's address. The addresses can change, but even if
> they don't, for an unbound msk, the address is therefore still zero at
> this point. (Note: in MPTCP disconnect selftests, the address is the
> same, and mptcp_pm_get_local_id() will return 0.)
> 
> At this stage, the kernel PM might then give the MPC subflow a non-zero
> ID, either from a matching endpoint or by adding an "implicit" endpoint.
> The RFC 8684 says that the first subflow always has the ID 0, and the
> PMs rely on that for special cases. So it is important to reset it to 0
> when msk->first exists (which might not be the case in case of
> connect(AF_UNSPEC) for an unconnected socket...).

Here is the test for that:

https://github.com/multipath-tcp/packetdrill/pull/210

Cheers,
Matt
-- 
Sponsored by the NGI0 Core fund.