[PATCH mptcp-next v2 0/8] mptcp: sched: reinjection and a send limit as scheduler actions

Matthieu Baerts (NGI0) posted 8 patches 4 days, 8 hours ago
Failed in applying to current master (apply log)
net/mptcp/bpf.c                                    |   6 +
net/mptcp/mib.c                                    |   2 +
net/mptcp/mib.h                                    |   2 +
net/mptcp/options.c                                |  12 +-
net/mptcp/protocol.c                               | 122 ++++++-
net/mptcp/protocol.h                               |  51 +++
net/mptcp/sched.c                                  | 384 ++++++++++++++++++++-
tools/testing/selftests/bpf/prog_tests/mptcp.c     | 130 +++++++
.../testing/selftests/bpf/progs/mptcp_bpf_limit.c  |  94 +++++
.../selftests/bpf/progs/mptcp_bpf_reinject.c       |  70 ++++
10 files changed, 868 insertions(+), 5 deletions(-)
[PATCH mptcp-next v2 0/8] mptcp: sched: reinjection and a send limit as scheduler actions
Posted by Matthieu Baerts (NGI0) 4 days, 8 hours ago
Note: this cover-letter has been written by Abdul. I only modified the
ChangeLog to add my recent modifications. (The results from the perf lab
were the ones from Abdul, before my modifications.)

This takes over Gregory's "update scheduler API" RFC [1], and redoes the
opportunistic reinjection RFC [2] as a scheduler action, as Matt asked.

Patch 1 is a fix: the send window could go past what the peer offered
after a retransmission, which reinjecting makes a lot more likely.

A scheduler can't do two things today:

- Send less than one dfrag per decision. msk->snd_burst is only checked
  once a whole dfrag is sent, and a dfrag can be 32 KB, so for example
  one MSS per subflow in turn is not possible. Patch 2 adds send_limit,
  a subflow field set in get_send, used for that decision only. This is
  the "limit" of [1], as a struct member checked at load time and not a
  second call with flags, as Mat suggested on [1]. Stopping inside a
  dfrag leaves it the send head, partly sent, as when a subflow runs out
  of space, so first_pending moves as before. Patch 6 lets BPF
  schedulers set it.

- Resend data that a slower subflow holds on an idle one. Patch 3 calls
  get_retrans for that too, so there is still one call per decision.
  msk->sched_retrans says why: the MPTCP RTO as before, or a subflow is
  idle while nothing new can be sent because the receive window is full,
  the send buffer is full, or the application has nothing more to write:
  patch 4 checks this on each DATA_ACK.
  The scheduler marks a subflow and sets reinject_limit there, and the
  core resends the DSN ranges the other subflows hold, which a BPF
  program can't walk. Patch 5 gives the default scheduler the policy of
  [2]: only when the copy arrives at least one RTT of the idle subflow
  sooner. Patch 6 lets BPF schedulers set reinject_limit too.

Shardul asked whether the application limited case should trigger it
[3]. I measured it: it is where most of the latency gain is, so it stays
and the reason is passed to the scheduler, which can ignore it.

Tests, on the current export with Shardul's v5:
- the two new BPF tests and the other mptcp BPF tests, on a debug kernel
  (KASAN, lockdep); the send limit test fails without patch 2 (32728
  bytes in one decision instead of at most 4096);
- mptcp_connect.sh (all modes), mptcp_join.sh, mptcp_sockopt.sh,
  pm_netlink.sh, simult_flows.sh, userspace_pm.sh, the kunit and
  packetdrill tests, on the same debug kernel;
- the perf lab [4], 5 runs of the base above as history, then the
  series (alpha 0.01). 106 tests unchanged, 28 improvements, 5 flagged.
  The largest changes, iperf3 received in Mbit/s:

    weak_secondary                                       20.6 -> 70.1
    bad_secondary                                        22.8 -> 70.5
    bad_secondary bbr                                    39.2 -> 68.0
    bloated_slow_secondary receiver_tcp_mem parallel=99  41.4 -> 92.4
    huge_lat_primary rmem=200                             8.1 -> 17.3

  Of the 5 flagged, 4 are only how the data is split between the paths,
  the total does not go down: huge_lat_primary, clientlim slow_secondary
  bw=5 and slow_primary bw=10 (their totals go up by 2-7%), and
  weak_secondary backup (about 12 bit/s on the backup path in both). The
  one cost is mem-pressure slow_primary both_tcp_mem parallel=10: iperf3
  received is 1-2% lower (51.2-51.7 vs 52.1, 4 runs), the receiver total
  is the same, so these are the copies. I reran the flagged suites to
  check, the results were the same.

[1] https://lore.kernel.org/mptcp/20240527-sched_per_packet-v1-0-09a41d405f7c@gmail.com/
[2] https://lore.kernel.org/mptcp/20261025134643.1537069-1-w453y.me@gmail.com/
[3] https://lore.kernel.org/mptcp/6ac6cd6f5c7d67c598ae34bbf3bcf6a0edd0e983.camel@mpiricsoftware.com/
[4] https://github.com/multipath-tcp/mptcp-upstream-virtme-docker/blob/latest/PERF.md#tracking-regressions-locally

Based-on: <20261028-mptcp_penalise_send_v2-v5-0-32fb379ce117@mpiricsoftware.com>
Signed-off-by: Abdul Wasey <w453y.me@gmail.com>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
---
Changes in v2 (of [2]):
- a scheduler action through get_retrans, not in the core for every
  scheduler;
- rebased on Shardul's "penalise a slow subflow" v5;
- the reason is passed to the scheduler (Shardul);
- the subflow list is only walked while no process owns the msk, the
  ranges are merged, and the budget is exact (sashiko-bot);
- a scheduler that doesn't implement get_retrans never wakes the worker
  (MPTCP CI, BPF first test);
- fix the send window after a retransmission, new patch 1;
- check for an idle subflow with all schedulers, deferred if msk owned;
- a refusal is only final for a snd_una with an idle subflow;
- joining and closed subflows are no longer seen as gone;
- only copy what slow or gone subflows hold, lowest DSN first;
- clear left-over send_limit and scheduled flags.

---
Abdul Wasey (6):
      mptcp: sched: let get_retrans reinject on an idle subflow
      mptcp: sched: look for an idle subflow on each DATA_ACK
      mptcp: sched: reinject on an idle subflow with the default scheduler
      mptcp: sched: let a BPF scheduler set the send and reinject limits
      selftests: bpf: mptcp: test the send limit of a scheduler
      selftests: bpf: mptcp: test a scheduler reinjecting on an idle subflow

Gregory Detal (1):
      mptcp: sched: let get_send limit what one decision sends

Matthieu Baerts (NGI0) (1):
      mptcp: do not use a raised snd_wnd for the send window

 net/mptcp/bpf.c                                    |   6 +
 net/mptcp/mib.c                                    |   2 +
 net/mptcp/mib.h                                    |   2 +
 net/mptcp/options.c                                |  12 +-
 net/mptcp/protocol.c                               | 122 ++++++-
 net/mptcp/protocol.h                               |  51 +++
 net/mptcp/sched.c                                  | 384 ++++++++++++++++++++-
 tools/testing/selftests/bpf/prog_tests/mptcp.c     | 130 +++++++
 .../testing/selftests/bpf/progs/mptcp_bpf_limit.c  |  94 +++++
 .../selftests/bpf/progs/mptcp_bpf_reinject.c       |  70 ++++
 10 files changed, 868 insertions(+), 5 deletions(-)
---
base-commit: df540f052ed58044886a6f6f98cc98c25172764f
change-id: 20261031-mptcp-sched-opp-retrans-6d9a1dd6cb8f

Best regards,
--  
Matthieu Baerts (NGI0) <matttbe@kernel.org>
Re: [PATCH mptcp-next v2 0/8] mptcp: sched: reinjection and a send limit as scheduler actions
Posted by MPTCP CI 3 days, 17 hours ago
Hi Abdul,

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): Unstable: 3 failed test(s): bpftest_test_progs-cpuv4_mptcp bpftest_test_progs-no_alu32_mptcp bpftest_test_progs_mptcp ⚠️ 
- KVM Validation: btf-debug (only bpftest_all): Unstable: 3 failed test(s): bpftest_test_progs-cpuv4_mptcp bpftest_test_progs-no_alu32_mptcp bpftest_test_progs_mptcp ⚠️ 
- Perf: Success! ✅
- Task: https://github.com/multipath-tcp/mptcp_net-next/actions/runs/41303657351

Initiator: Matthieu Baerts (NGI0)
Commits: https://github.com/multipath-tcp/mptcp_net-next/commits/43988ca731f2
Patchwork: https://patchwork.kernel.org/project/mptcp/list/?series=1197916


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)