Re: [PATCH mptcp-next 1/3] mptcp: sched: penalise a slow subflow by halving its cwnd

Shardul Bankar <[email protected]>
Newsgroups dev.linux.lists.mptcp
Message-ID <087874be7587606209365cb9e9791a9f0e11b934.camel@mpiricsoftware.com>
Hi Matt,

On Wed, 2026-07-29 at 13:49 +0200, Matthieu Baerts wrote:
> Hi Shardul,
> 
> On 26/07/2026 07:55, Shardul Bankar wrote:
> > 
> 
> Could you reduce the size of the comments, please? I understood that
> LLM
> tends to leave long comments, but too long is not always good:
> explanations can go in the commit message, or be understood by
> reading
> the conditions (or that's a sign the code should be improved).
> Ideally,
> comments should not be needed when reading the code, or limited to
> one,
> with some exceptions for complex cases.
> 
> Here for example, I think you could limit the comment to one line:
> 
> /* Penalise subflows with pacing rate < this fraction of the fastest
> path */
> 

Yes, shortened them to one line each and moved the rationale into the
commit messages.

> > +
> > +/* Halve the congestion window (and ssthresh, if cwnd is past it)
> > of a subflow
> > + * the scheduler flagged. Runs in the push path under the subflow
> > socket lock,
> > + * which protects snd_cwnd. The congestion control grows the
> > window back,
> > + * ACK-clocked, and that regrowth is the built-in probe, so no
> > explicit probing
> > + * is needed.
> > + */
> 
> Same here: I think what is important to mention is that it is under
> subflow socket lock, and you can move the comment about the CC
> growing
> the window back below: no explicit probing required then.
> 

Ack'ed.

> > +static void mptcp_penalise_cwnd(struct sock *ssk)
> > +{
> > +       struct mptcp_subflow_context *subflow =
> > mptcp_subflow_ctx(ssk);
> > +       struct tcp_sock *tp = tcp_sk(ssk);
> > +       u32 cwnd = tcp_snd_cwnd(tp);
> > +
> > +       subflow->penalise = false;
> 
> You probably need to check inet_csk(ssk)->icsk_ca_state ==
> TCP_CA_Open
> again here, under the subflow socket lock, just in case it has been
> modified in between.

Added: mptcp_penalise_cwnd() now re-reads it under the subflow lock and
bails if it is no longer Open.

> > +       subflow->last_penalise = tcp_jiffies32;
> > +       tcp_snd_cwnd_set(tp, max_t(u32, cwnd >> 1, 2));
> > +       if (cwnd >= tp->snd_ssthresh)
> > +               tp->snd_ssthresh = max_t(u32, tp->snd_ssthresh >>
> > 1, 2);
> > +}
> > +
> >  /* implement the mptcp packet scheduler;
> >   * returns the subflow that will transmit the next DSS
> >   * additionally updates the rtx timeout
> > @@ -1565,9 +1603,9 @@ struct sock *mptcp_subflow_get_send(struct
> > mptcp_sock *msk)
> >         struct subflow_send_info send_info[SSK_MODE_MAX];
> >         struct mptcp_subflow_context *subflow;
> >         struct sock *sk = (struct sock *)msk;
> > -       u32 pace, burst, wmem;
> > +       u32 pace, burst, wmem, max_pace = 0;
> 
> Sashiko is (rightly I think) mentioning that the size of these
> variables
> are wrong. I guess a separate fix is needed to change "pace" to
> "unsigned long" is required. "max_pace" will get this type too then.
> 

I am splitting that into its own patch (1/4, Fixes: 3ce0852c86b9).

> >  
> > +       /* Flag the chosen subflow for cwnd halving (applied in the
> > push path)
> > +        * when its delivery rate is a small fraction of the
> > fastest path's and
> > +        * that fast path is saturated (cwnd-limited), so moving
> > load off the
> > +        * slow path is worthwhile. Only penalise a path in
> > TCP_CA_Open, one
> > +        * whose cwnd is not already being shrunk by loss recovery,
> > and at most
> > +        * once per RTT.
> > +        */
> 
> Same here. Maybe a comment is not needed, or limited?
> 

Ack'ed.

> > +       subflow = mptcp_subflow_ctx(ssk);
> > +       subflow->penalise = fastest && ssk != fastest &&
> > +                           (u64)subflow->avg_pacing_rate *
> > MPTCP_PENALISE_RATE_RATIO < max_pace &&
> 
> (or divide max_pace once before?)
> 

Changed to avg_pacing_rate < max_pace / MPTCP_PENALISE_RATE_RATIO.

> > +                           inet_csk(ssk)->icsk_ca_state ==
> > TCP_CA_Open &&
> > +                           tcp_is_cwnd_limited(fastest) &&
> > +                           mptcp_penalise_throttle_ok(subflow);
> > +
> >         burst = min(MPTCP_SEND_BURST_SIZE, mptcp_wnd_end(msk) -
> > msk->snd_nxt);
> >         wmem = READ_ONCE(ssk->sk_wmem_queued);
> >         if (!burst)
> >                 return ssk;
> >  
> > -       subflow = mptcp_subflow_ctx(ssk);
> >         subflow->avg_pacing_rate = div_u64((u64)subflow-
> > >avg_pacing_rate * wmem +
> >                                            READ_ONCE(ssk-
> > >sk_pacing_rate) * burst,
> 
> (here as well, it looks like there is an existing bug, and a cast to
> u64
> is probably needed for 32-bit system, as pointed by Sashiko)
> 

Added in the same fix as the issue reported above.

> >                                            burst + wmem);
> > @@ -1685,6 +1744,9 @@ static int __subflow_push_pending(struct sock
> > *sk, struct sock *ssk,
> >         struct mptcp_data_frag *dfrag;
> >         int len, copied = 0, err = 0;
> >  
> > +       if (mptcp_subflow_ctx(ssk)->penalise)
> > +               mptcp_penalise_cwnd(ssk);
> > +
> >         while ((dfrag = mptcp_send_head(sk))) {
> >                 info->sent = dfrag->already_sent;
> >                 info->limit = dfrag->data_len;
> > diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
> > index da40c6f3705f..2bf801292563 100644
> > --- a/net/mptcp/protocol.h
> > +++ b/net/mptcp/protocol.h
> > @@ -587,6 +587,7 @@ struct mptcp_subflow_context {
> >                 __unused : 8;
> >         bool    data_avail;
> >         bool    scheduled;
> > +       bool    penalise;           /* scheduler flagged this
> > subflow for cwnd halving */
> 
> (If you don't need to read this locklessly, then you can probably use
> one unused bit.)
> 

It is written under two locks (set in the scheduler under the msk lock,
cleared in the push path under the subflow lock), so a shared bitfield
word would race on the read-modify-write, and I kept it a bool for that
reason. If you see a single-lock way to do it, I am glad to move it to
a bit.

Thanks,
Shardul
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.