Skip to content

mptcp: add regression test for stale ADD_ADDR on id 0 removal (issue #620) - #201

Merged
matttbe merged 1 commit into
multipath-tcp:mptcp-net-nextfrom
k-jani-git:fix/620-id0-stale-anno
Aug 7, 2026
Merged

mptcp: add regression test for stale ADD_ADDR on id 0 removal (issue #620)#201
matttbe merged 1 commit into
multipath-tcp:mptcp-net-nextfrom
k-jani-git:fix/620-id0-stale-anno

Conversation

@k-jani-git

Copy link
Copy Markdown

Regression test for the kernel fix at:
https://lore.kernel.org/mptcp/ (v5 patch 1)

Issue: multipath-tcp/mptcp_net-next#620

The id 0 endpoint removal path used to skip cancelling a pending
ADD_ADDR announcement, leaving the anno_list entry alive. A subsequent
PM reselection would re-announce that address and trip WARN_ON_ONCE()
in mptcp_pm_announced_alloc().

The test establishes an MPC connection with a second MP_JOIN subflow,
signals the MPC address as id 0 (creating a pending anno_list entry),
withholds the echo, then deletes and re-adds id 0. It probes with a
data segment and expects a plain DSS ACK back with no ADD_ADDR
piggybacked. On an unfixed kernel a spurious ADD_ADDR(id=0) appears
on that ACK and the test fails.

Co-developed-by: Tao Cui cuitao@kylinos.cn
Signed-off-by: Kalpan Jani kalpan.jani@mpiricsoftware.com

@matttbe matttbe left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the new test! Here is a first global comment

Comment thread gtests/net/mptcp/regressions/id0_stale_anno.pkt Outdated
Comment thread gtests/net/mptcp/regressions/id0_stale_anno.pkt Outdated
@k-jani-git
k-jani-git force-pushed the fix/620-id0-stale-anno branch from 007821e to 7150307 Compare July 8, 2026 05:58
@k-jani-git

Copy link
Copy Markdown
Author

Hi Matt,

Thanks for the review.

Fixed in the latest push:

  • Reformatted to long single lines per .pkt style
  • Removed TCP timestamps from all packet lines
  • Changed tolerance_usecs to 100000 to match other regression tests;
    the +0~+0.5 window on the ADD_ADDR line handles the async PM timing
    independently

Cheers,
Kalpan


--tolerance_usecs=100000
`../common/defaults.sh`
`sysctl -wq net.mptcp.add_addr_timeout=1`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mmh, how did you test this?

parse error at '`sysctl -wq net.mptcp.add_addr_timeout=1`': syntax error

after having fixed that, I get an error at line 35:

semantic error: TCP options are not padded correctly to ensure TCP header is a multiple of 4 bytes: 2 excess bytes

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmmh, I continued debugging this, and it really looks like this .pkt was generated by AI... It looks correct, but full of errors. Plus untested.

I just sent what I modified so far, but I didn't finish, and late for other meetings. I hope this is just a one off...

@matttbe
matttbe force-pushed the fix/620-id0-stale-anno branch from 7150307 to 492bf80 Compare July 8, 2026 16:59
@k-jani-git

Copy link
Copy Markdown
Author

Hi @matttbe

I apologize — the test was not validated locally before submission.
That was my mistake and I should not have submitted untested code.

I do have a working tested reproducer from an earlier version: a
selftest that reliably triggers the WARN on unpatched kernels and
passes cleanly on the patched one. Would it be acceptable to close
this PR and resubmit once I have a properly tested version — either
the selftest ported into mptcp_join.sh or a corrected packetdrill
test validated through the docker CI first?

Sorry for the wasted time.

@matttbe matttbe left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@k-jani-git : with what happened here, I do think it is best if you fix this packetdrill test.

Comment thread gtests/net/mptcp/pm/kernel_id0_stale_anno.pkt Outdated
+0.0 `ip mptcp endpoint delete id 0 $OPT_LOCAL_IP`

// ---- Signal saddr0 as id 0; kernel sends ADD_ADDR(id=0); echo withheld ----
+0.0 `ip mptcp endpoint add $OPT_LOCAL_IP signal`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here, better add a small delay like .5 sec


// ---- Re-add id 0 to force PM reselection ----
+0.0 `ip mptcp endpoint add $OPT_LOCAL_IP signal`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here, we should see the ADD_ADDR, the echo can be injected.

// 3. Signal saddr0 as id 0: kernel sends ADD_ADDR(id=0); echo withheld
// 4. Delete id 0: fixed kernel cancels anno entry; unfixed leaves it stale
// 5. Re-add id 0: fixed kernel finds no stale entry; unfixed hits WARN
// 6. Inject data, expect plain DSS ACK (no ADD_ADDR piggybacked)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the sequence can be removed: no longer correct, and it was redundant with the comments below

@matttbe

matttbe commented Jul 28, 2026

Copy link
Copy Markdown
Member

@k-jani-git : did you manage to have a working reproducer with packetdrill? Note that the current implementation has some limitations, it is possible that it is not possible to reproduce the bug with the current version, and that's fine, but in this case, it would be good to know the limitations. Knowing them, I can also help to find workarounds (if possible).

@k-jani-git

Copy link
Copy Markdown
Author

Hi @matttbe Not yet, I haven't been able to get back to this. I'll send an update once I have something tested.

Thanks for the offer — once I've had a proper look I'll come back with the specific point where packetdrill blocks it, so you can see whether there's a workaround. Happy to take any input you have at that stage.

@matttbe

matttbe commented Jul 29, 2026

Copy link
Copy Markdown
Member

@k-jani-git thank you for your reply. No problem, we can hold this and the attached kernel patch a bit longer.

@k-jani-git
k-jani-git force-pushed the fix/620-id0-stale-anno branch 2 times, most recently from f4e8f77 to b59c4d4 Compare August 7, 2026 07:06
@k-jani-git

Copy link
Copy Markdown
Author

Hi @matttbe

Pushed a rewritten test. This time I validated it in the virtme-docker
environment against both an unpatched and a patched kernel before pushing.

On export/20260622T173908, without the fix:

FAIL [/opt/packetdrill/gtests/net/mptcp/pm/kernel_id0_stale_anno.pkt (ipv4)]
stderr:
BUG: add_addr_signaled not decremented after delete id 0
kernel_id0_stale_anno.pkt:51: error executing `ss -inmHM | grep -q ...` command: non-zero status 1
Ran 3 tests: 0 passing, 3 failing, 0 timed out

With the "mptcp: pm: drop pending ADD_ADDR when removing id 0 endpoint" patch
applied:

OK [/opt/packetdrill/gtests/net/mptcp/pm/kernel_id0_stale_anno.pkt (ipv4)]
OK [/opt/packetdrill/gtests/net/mptcp/pm/kernel_id0_stale_anno.pkt (ipv4-mapped-v6)]
OK [/opt/packetdrill/gtests/net/mptcp/pm/kernel_id0_stale_anno.pkt (ipv6)]
Ran 3 tests: 3 passing, 0 failing, 0 timed out

While getting there I also confirmed the WARNING itself is reachable from this
sequence: adding a second 'signal' endpoint after the removal raises
endp_signal_max to 2, the PM re-enters the announce branch, and it hits
WARN_ON_ONCE() in mptcp_pm_announced_alloc() with the same call chain as the
syzbot report (mptcp_pm_nl_add_addr_doit ->
mptcp_pm_create_subflow_or_signal_addr). I left that step out of the final
test: packetdrill does not fail on a kernel WARNING, so the counter check is
what actually discriminates.

Your explanation about the endpoint linked to the initial subflow is what
unblocked this. The test adds the 'signal' endpoint after the connection is
established instead of deleting and re-adding it: mptcp_mpc_endpoint_setup()
has already run at that point, so the bit is never cleared and the address is
announced with ID 0. Same end state as the delete/re-add sequence, but it does
not generate an RM_ADDR, which matters because of point 1 below. Happy to
switch to the delete/re-add form if you prefer it.

Three limitations I hit, since you asked about them:

  1. remove_address cannot be asserted in a .pkt today. same_mptcp_opt() in
    run_packet.c loops opt_a->length bytes starting at
    data.remove_addr.address_id instead of looping over the number of IDs. For a
    single-ID RM_ADDR that reads 3 bytes past the option in both buffers, so the
    comparison fails even when the two packets print identically. I can send a
    separate PR for this if you would like.

  2. "ip mptcp endpoint delete id 0 " does not remove the pernet endpoint,
    so a subsequent "endpoint add" of the same address returns -EEXIST. That is
    why the announce is set up by adding the endpoint late rather than by
    delete/re-add. (iproute2 also rejects an address argument together with a
    non-zero id, so the delete has to be done by id alone.)

  3. After "delete id 0" no second ADD_ADDR is emitted even on a fixed kernel, so
    I could not use the reselection as the assertion. The check is on the path
    manager counter via ss(8) instead of on a packet. The ADD_ADDR(id=0) that
    precedes it is still asserted at packet level. If you would rather this live
    in mptcp_join.sh as a chk_mptcp_info check, say so and I will move it.

Sorry again for the earlier untested submission, and thanks for the time you
spent fixing it up.

Regression test for issue #620:
multipath-tcp/mptcp_net-next#620

Removing the endpoint linked to the initial subflow with "delete id 0"
used to skip cancelling a pending ADD_ADDR announcement: the anno_list
entry was left alive and add_addr_signaled was not decremented. A later
PM reselection would then re-announce that address and trip
WARN_ON_ONCE() in mptcp_pm_announced_alloc().

The test establishes an MPC connection and lets the kernel create a
second subflow from a 'subflow' endpoint. The 'signal' endpoint is then
added after the connection is established: mptcp_mpc_endpoint_setup()
has already run without clearing its bit, so the address is announced
with ID 0. The echo is withheld, the endpoint is removed with
"delete id 0", and the PM counter is checked via ss(8): add_addr_signal
must be back to 0.

On an unfixed kernel the counter stays at 1 and the test fails.

Note that the reselection itself is not asserted: after "delete id 0" no
second ADD_ADDR is emitted even on a fixed kernel, so the check is on the
path manager counter rather than on a packet.

Suggested-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Signed-off-by: Kalpan Jani <kalpan.jani@mpiricsoftware.com>
[ Disable TCP TS, fix alignment, expect RM_ADDR, remove sleep ]
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
@matttbe
matttbe force-pushed the fix/620-id0-stale-anno branch from b59c4d4 to 4bbbd09 Compare August 7, 2026 10:04
@matttbe
matttbe merged commit 5c83655 into multipath-tcp:mptcp-net-next Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants