From: Eva Kurchatova <eva.kurchatova@virtuozzo.com>
To: khorenko@virtuozzo.com
Cc: devel@openvz.org
Subject: [Devel] [PATCH hci-8.1 4/8] ms/mptcp: let the retrans scheduler do its job
Date: Fri, 6 Nov 2026 05:02:12 +0200 [thread overview]
Message-ID: <20261106030306.16014-5-eva.kurchatova@virtuozzo.com> (raw)
In-Reply-To: <20261106030306.16014-1-eva.kurchatova@virtuozzo.com>
From: Paolo Abeni <pabeni@redhat.com>
Currently the MPTCP core enforces that when MPTCP-level retrans timer
fires, at most a single dfrag is retransmitted. In some corner-cases, it
may be necessary to retransmit multiple dfrags, and the MPTCP socket
will need to wait multiple retrans timeout to accomplish that.
Remove the mentioned constraint, allowing to transmit multiple dfrags
per retrans period, as long as the scheduler keeps selecting subflows
for retransmissions and pending data is available in the rtx queue.
The default scheduler will transmit a dfrag per available subflow.
Tested-by: Gang Yan <yangang@kylinos.cn>
Tested-by: Geliang Tang <geliang@kernel.org>
Acked-by: Geliang Tang <geliang@kernel.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20260807-net-next-mptcp-oooq-pruning-v3-3-dbc1eb853cc3@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
(cherry picked from commit 96d846e3e2a7ea01ff8a584a0b5e2a42fa9ccc1e)
https://virtuozzo.atlassian.net/browse/VSTOR-153491
Feature: fix ms/net
Signed-off-by: Eva Kurchatova <eva.kurchatova@virtuozzo.com>
---
net/mptcp/protocol.c | 106 ++++++++++++++++++++++++++++++-------------
1 file changed, 75 insertions(+), 31 deletions(-)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 838b18bc19c9..2dcce47a1ef7 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -1000,13 +1000,6 @@ static void __mptcp_clean_una_wakeup(struct sock *sk)
mptcp_write_space(sk);
}
-static void mptcp_clean_una_wakeup(struct sock *sk)
-{
- mptcp_data_lock(sk);
- __mptcp_clean_una_wakeup(sk);
- mptcp_data_unlock(sk);
-}
-
static void mptcp_enter_memory_pressure(struct sock *sk)
{
struct mptcp_subflow_context *subflow;
@@ -2577,8 +2570,12 @@ static void mptcp_check_fastclose(struct mptcp_sock *msk)
sk_error_report(sk);
}
-/* Retransmit the specified data fragment on all the selected subflows. */
-static int __mptcp_push_retrans(struct sock *sk, struct mptcp_data_frag *dfrag)
+/*
+ * Retransmit the specified data fragment on all the selected subflows,
+ * starting from the specified sequence
+ */
+static int __mptcp_push_retrans(struct sock *sk, struct mptcp_data_frag *dfrag,
+ u64 sent_seq)
{
struct mptcp_sendmsg_info info = { .data_lock_held = true, };
struct mptcp_sock *msk = mptcp_sk(sk);
@@ -2588,6 +2585,7 @@ static int __mptcp_push_retrans(struct sock *sk, struct mptcp_data_frag *dfrag)
mptcp_for_each_subflow(msk, subflow) {
if (READ_ONCE(subflow->scheduled)) {
+ u16 offset = sent_seq - dfrag->data_seq;
u16 copied = 0;
mptcp_subflow_set_scheduled(subflow, false);
@@ -2597,7 +2595,7 @@ static int __mptcp_push_retrans(struct sock *sk, struct mptcp_data_frag *dfrag)
lock_sock(ssk);
/* limit retransmission to the bytes already sent on some subflows */
- info.sent = 0;
+ info.sent = offset;
info.limit = READ_ONCE(msk->csum_enabled) ? dfrag->data_len :
dfrag->already_sent;
@@ -2643,45 +2641,91 @@ static void __mptcp_retrans(struct sock *sk)
struct mptcp_sock *msk = mptcp_sk(sk);
struct mptcp_subflow_context *subflow;
struct mptcp_data_frag *dfrag;
+ u64 retrans_seq, sent_seq;
+ bool need_retrans;
int err, len;
mptcp_pm_chk_stale(msk);
- mptcp_clean_una_wakeup(sk);
-
- err = mptcp_sched_get_retrans(msk);
+ /* Get an updated and consistent rtx queue status. */
+ mptcp_data_lock(sk);
+ __mptcp_clean_una_wakeup(sk);
+ retrans_seq = msk->snd_una;
dfrag = mptcp_rtx_head(sk);
- if (!dfrag) {
+ need_retrans = !!dfrag;
+ mptcp_data_unlock(sk);
+
+ for (;;) {
+ bool already_acked;
+
+ err = mptcp_sched_get_retrans(msk);
+ if (err)
+ break;
+
+ /* `already_sent` can be 0 for `dfrag` belonging to the RTX
+ * queue due to __mptcp_retransmit_pending_data().
+ */
+ if (!dfrag || !dfrag->already_sent)
+ break;
+
+ /* Can fail only in case of fallback. */
+ len = __mptcp_push_retrans(sk, dfrag, retrans_seq);
+ if (len < 0)
+ goto clear_scheduled;
+
+ retrans_seq += len;
+ msk->bytes_retrans += len;
+ dfrag->already_sent = max_t(u16, dfrag->already_sent,
+ retrans_seq - dfrag->data_seq);
+
+ /* With csum enabled, retransmission can send new data. */
+ sent_seq = dfrag->already_sent + dfrag->data_seq;
+ if (after64(sent_seq, msk->snd_nxt))
+ WRITE_ONCE(msk->snd_nxt, sent_seq);
+
+ /* Attempt the next fragment only if the current one is
+ * completely retransmitted.
+ */
+ if (before64(retrans_seq, dfrag->data_seq + dfrag->data_len))
+ break;
+
+ dfrag = list_is_last(&dfrag->list, &msk->rtx_queue) ?
+ NULL : list_next_entry(dfrag, list);
+ if (!dfrag)
+ break;
+
+ /* Incoming acks can move snd_una after the current dfrag
+ * across loop iterations, if so start again from RTX head.
+ */
+ mptcp_data_lock(sk);
+ already_acked = !before64(msk->snd_una, dfrag->data_seq +
+ dfrag->already_sent);
+ if (already_acked) {
+ __mptcp_clean_una_wakeup(sk);
+ retrans_seq = msk->snd_una;
+ dfrag = mptcp_rtx_head(sk);
+ need_retrans = !!dfrag;
+ } else if (after64(msk->snd_una, retrans_seq)) {
+ retrans_seq = msk->snd_una;
+ }
+ mptcp_data_unlock(sk);
+ }
+
+ /* Attempt data-fin retransmission only when the RTX queue is empty. */
+ if (!need_retrans) {
if (mptcp_data_fin_enabled(msk)) {
struct inet_connection_sock *icsk = inet_csk(sk);
icsk->icsk_retransmits++;
mptcp_set_datafin_timeout(sk);
mptcp_send_ack(msk);
-
goto reset_timer;
}
if (!mptcp_send_head(sk))
goto clear_scheduled;
-
- goto reset_timer;
}
- if (err)
- goto reset_timer;
-
- len = __mptcp_push_retrans(sk, dfrag);
- if (len < 0)
- goto clear_scheduled;
-
- msk->bytes_retrans += len;
- dfrag->already_sent = max(dfrag->already_sent, len);
-
- /* With csum enabled retransmission can send new data. */
- if (after64(dfrag->already_sent + dfrag->data_seq, msk->snd_nxt))
- WRITE_ONCE(msk->snd_nxt, dfrag->already_sent + dfrag->data_seq);
-
reset_timer:
mptcp_check_and_set_pending(sk);
--
2.56.0
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel
next prev parent reply other threads:[~2026-11-06 3:04 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-06 3:02 [Devel] [PATCH hci-8.1 0/8] ms/mptcp: stability fixes Eva Kurchatova
2026-11-06 3:02 ` [Devel] [PATCH hci-8.1 1/8] ms/mptcp: fix retransmission loop when csum is enabled Eva Kurchatova
2026-11-06 3:07 ` no-reply
2026-11-06 3:02 ` [Devel] [PATCH hci-8.1 2/8] ms/mptcp: move the retrans loop to a separate helper Eva Kurchatova
2026-11-06 3:06 ` no-reply
2026-11-06 3:02 ` [Devel] [PATCH hci-8.1 3/8] ms/mptcp: move the stale logic out of retrans scheduler Eva Kurchatova
2026-11-06 3:07 ` no-reply
2026-11-06 3:02 ` Eva Kurchatova [this message]
2026-11-06 3:10 ` [Devel] [PATCH hci-8.1 4/8] ms/mptcp: let the retrans scheduler do its job no-reply
2026-11-06 3:02 ` [Devel] [PATCH hci-8.1 5/8] ms/mptcp: explicitly drop over memory limits Eva Kurchatova
2026-11-06 3:10 ` no-reply
2026-11-06 3:02 ` [Devel] [PATCH hci-8.1 6/8] ms/mptcp: implemented OoO queue pruning Eva Kurchatova
2026-11-06 3:11 ` no-reply
2026-11-06 3:02 ` [Devel] [PATCH hci-8.1 7/8] ms/mptcp: being below memory limit is a likely() condition Eva Kurchatova
2026-11-06 3:10 ` no-reply
2026-11-06 3:02 ` [Devel] [PATCH hci-8.1 8/8] ms/mptcp: avoid pruning for OoW data Eva Kurchatova
2026-11-06 3:11 ` no-reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261106030306.16014-5-eva.kurchatova@virtuozzo.com \
--to=eva.kurchatova@virtuozzo.com \
--cc=devel@openvz.org \
--cc=khorenko@virtuozzo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox