include/trace/events/mptcp.h | 33 ++++++++++++++++ net/mptcp/mib.c | 2 + net/mptcp/mib.h | 2 + net/mptcp/protocol.c | 89 ++++++++++++++++++++++++++++++++++++++++---- net/mptcp/protocol.h | 2 + 5 files changed, 121 insertions(+), 7 deletions(-)
A subflow that is slow relative to the others can soak up connection
resources and cause head-of-line blocking of the aggregate stream. This
series lets the packet scheduler send less than such a subflow's
congestion window by halving it, and leaves the congestion control to
raise it again. It implements issue #345 [1]. This is a deliberately
simple first form.
- Patch 1: a prerequisite fix. The scheduler truncates the pacing rate to a
u32, which skews subflow selection on fast paths (Fixes).
- Patch 2: penalise a slow subflow by halving its cwnd, triggered on its
pacing rate and gated on the fast path being cwnd-limited.
- Patch 3: skip the penalty when the transfer is receive-window-limited,
where it would otherwise slow the transfer.
- Patch 4: MPTcpExt counters and a dedicated mptcp_subflow_penalise
tracepoint for observability.
Validation, baseline versus this series (test helper, its run_matrix.sh
base-vs-patch driver, and run steps are in [2]):
- No regression in the mptcp selftests.
- No regression versus baseline across the buffer-limited transfers
(send-buffer, receive-window, both, sndbuf>rcvbuf): the two-path completion
time with the penalty enabled matches the unpatched kernel. Where the
slow subflow is beneficial (send-buffer-limited), the two-path transfer
stays faster than the fast path alone.
- Patch 3's gate keeps the penalty from firing when receive-window-limited,
where halving cwnd would slow the transfer.
- With a bufferbloated slow path, the penalty roughly halves the slow path's
queueing latency (subflow srtt), with the transfer time unchanged. It does
not reduce the aggregate out-of-order volume or move data off the slow
path; that is the role of issue #332 [3], and the two are complementary.
- The conditions above do not catch one case: with the buffers left to
autotuning and a subflow that is slow because of latency rather than limited
bandwidth, penalising it costs throughput, and the cost grows as the added
delay grows.
[1] https://github.com/multipath-tcp/mptcp_net-next/issues/345
[2] https://github.com/shardulsdk-mpiric/linux/blob/e0f78406d921/tools/testing/selftests/net/mptcp/mptcp_sched_penalise.sh
(run_matrix.sh + runs.conf are alongside it in the same directory)
[3] https://github.com/multipath-tcp/mptcp_net-next/issues/332
Changes in v4:
- Patch 1: compute the pacing-rate average with 128-bit intermediates
(mul_u64_u64_div_u64); a single 64-bit numerator overflows at a high
pacing rate with a large send queue. Dividing before multiplying loses
too much precision on slow paths, details in the commit message.
- Patch 1: add a second Fixes tag. The u32 truncation predates the
averaging formula; it dates to d5f49190def6.
- Patch 2: evaluate the conditions on the subflow itself where the penalty is
applied, under that subflow's socket lock; the scheduler only marks a
candidate. Annotate the cross-subflow tcp_is_cwnd_limited() read with
data_race().
- Patch 2: exclude backup subflows from the fastest-path comparison. A
backup carries no data while an active subflow exists, so its rate and
cwnd-limited state go stale, and using one as the reference penalised
the subflow that was actually sending.
- Patch 3: drop a throughput figure taken from an early debug-kernel run;
the mechanism argument stands without it.
- Patch 4: add the send burst to mptcp_subflow_penalise, and emit the
verdict once the burst is known.
- Longer explanations moved from code comments into the commit messages.
- Retested base versus this series on one kernel configuration, congestion
control pinned to reno, three runs of the full matrix on each side. No
behavioural difference against v3.
- Link to v3: https://patch.msgid.link/20260817-mptcp_penalise_send_v2-v3-0-e6a2ad2f1b82@mpiricsoftware.com
Changes in v3:
- Dropped the RFC tag (Matthieu Baerts (NGI0)). No changes to the patches themselves.
- Rebased on current export.
- Link to v2: https://patch.msgid.link/20260815-mptcp_penalise_send_v2-v2-0-3e5049a73681@mpiricsoftware.com
Changes in v2
- Patch 1 (new, not in v1): fix the scheduler's pre-existing u32 pacing-rate
truncation (Fixes: 3ce0852c86b9).
- Patch 2 (v1's 1/3): also skip a subflow already at the cwnd floor
(MPTCP_PENALISE_MIN_CWND); clear the flag when returning without send-window
room; re-check TCP_CA_Open in the apply path; express the rate trigger as a
division (avg_pacing_rate < max_pace / ratio, using the widened pace from
patch 1) instead of a u64-cast multiply.
- Patch 3 (v1's 2/3): make the receive-window test wrap-safe
(after64, like tcp_snd_wnd_test()); same condition otherwise.
- Patch 4 (v1's 3/3): real MPTcpExt counters (dropped DO-NOT-MERGE) plus
a dedicated mptcp_subflow_penalise tracepoint (not a field on
mptcp_subflow_get_send).
- Rebased on current export.
- Link to v1:
https://lore.kernel.org/mptcp/20260726-mptcp_penalise_send-v1-0-84485e0e995b@mpiricsoftware.com
Signed-off-by: Shardul Bankar <shardul.b@mpiricsoftware.com>
---
Shardul Bankar (4):
mptcp: sched: avoid truncating the pacing rate in the scheduler
mptcp: sched: penalise a slow subflow by halving its cwnd
mptcp: sched: do not penalise when receive-window-limited
mptcp: sched: add penalise counters and tracepoint
include/trace/events/mptcp.h | 33 ++++++++++++++++
net/mptcp/mib.c | 2 +
net/mptcp/mib.h | 2 +
net/mptcp/protocol.c | 89 ++++++++++++++++++++++++++++++++++++++++----
net/mptcp/protocol.h | 2 +
5 files changed, 121 insertions(+), 7 deletions(-)
---
base-commit: b49aa4201a14e200297db9adcde3495e5a778517
change-id: 20260815-mptcp_penalise_send_v2-ed6206f70a84
Best regards,
--
Shardul Bankar <shardul.b@mpiricsoftware.com>
Hi Shardul,
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/34588145416
Initiator: Patchew Applier
Commits: https://github.com/multipath-tcp/mptcp_net-next/commits/b027657feb6a
Patchwork: https://patchwork.kernel.org/project/mptcp/list/?series=1162787
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)
© 2016 - 2026 Red Hat, Inc.