net_sched: sch_fq: fix pacing delay underflow with pacing offload

When pacing offload is enabled (q->offload_horizon > 0),
FQ can dequeue packets early (now < f->time_next_packet).

In this case, the drift calculation (now - f->time_next_packet)
underflows to a large unsigned value.

min(len/2, now - f->time_next_packet) then evaluates to len/2,
incorrectly halving the pacing delay for the next packet.

Fix this by only applying drift compensation if now > f->time_next_packet.

This bug was triggered when flow_max_rate was set on the qdisc
or for non EDT packets (packets with a zero skb->tstamp).

Fixes: f26080d470 ("net_sched: sch_fq: add the ability to offload pacing")
Reported-by: Willem de Bruijn <willemb@google.com>
Closes: https://lore.kernel.org/netdev/CANn89iK6O7ujR9zCJzd04MNLQoDi3mA+HWsR-hgQWYzLS3gZfw@mail.gmail.com/
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Willem de Bruijn <willemb@google.com>
Link: https://patch.msgid.link/20260820120706.1995449-1-willemdebruijn.kernel@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Eric Dumazet 2026-08-20 08:06:25 -04:00 committed by Jakub Kicinski
parent 039f248a6c
commit 137b8ae233

View File

@ -828,8 +828,12 @@ static struct sk_buff *fq_dequeue(struct Qdisc *sch)
* f->time_next_packet was set when prior packet was sent,
* and current time (@now) can be too late by tens of us.
*/
if (f->time_next_packet)
len -= min(len/2, now - f->time_next_packet);
if (f->time_next_packet) {
s64 drift = now - f->time_next_packet;
if (drift > 0)
len -= min_t(u64, len / 2, drift);
}
f->time_next_packet = now + len;
}
out: