SYSTEM Cited by 1 source
CUBIC congestion control¶
CUBIC is a loss-based congestion control algorithm (CCA) standardised in RFC 9438. It is the default congestion controller in the Linux TCP stack and the default CCA shipped by quiche, Cloudflare's open-source QUIC / HTTP/3 library — which together govern how most TCP and QUIC connections on the public Internet probe for bandwidth, back off after loss, and recover afterward (Source: sources/2026-05-12-cloudflare-when-idle-isnt-idle-how-a-linux-kernel-optimization-became-a-quic-bug).
Algorithmic core¶
CUBIC is the loss-based CCA family member that uses a cubic growth curve instead of Reno's linear AIMD. Like every loss-based CCA, it operates on two premises:
- No loss → increase sending rate. Probe for more bandwidth.
- Loss → back off. Assume the network is saturated, shrink
the congestion window (
cwnd).
Where CUBIC differs from Reno:
cwndgrows along the cubic functionW_cubic(delta_t) = C·(delta_t − K)^3 + W_maxwheredelta_t = now − epoch_start(see concepts/cubic-epoch),W_maxis thecwndat the last loss event, andKis a parameter.- Fast ramp-up far from
W_max, gentler near it. This gives CUBIC better throughput on high-BDP paths than Reno. - Binary increase around
W_max: probing past the last-known- safe window is careful, then accelerates once it looks safe.
The epoch — a load-bearing state variable¶
The epoch (epoch_start) is the reference timestamp CUBIC
anchors its growth curve to. It is reset whenever CUBIC restarts
the growth function — most notably after a loss event reduces
cwnd. Between resets, delta_t = now − epoch_start grows
monotonically with wall-clock time.
The canonical CUBIC bug-class, documented by both the 2017 Linux
kernel fix and the 2026-05-12 quiche fix: if epoch_start is
not advanced during application-idle periods, delta_t grows
while no data is being sent; the next packet sent after idleness
reads delta_t as huge, computes a massive bic_target, and
CUBIC tries to inflate cwnd to an unreasonable value. See
concepts/cubic-epoch for the full state-variable semantics.
The 2017 Linux "CUBIC after idle" fix¶
Jana Iyengar's initial fix was to reset epoch_start when the
application resumes sending — but Neal Cardwell pointed out this
would ask CUBIC to restart the growth curve from cwnd's current
value, behaving as if a loss just happened. The accepted fix
(Eric Dumazet / Yuchung Cheng / Neal Cardwell, commit
30927520dbae):
shift epoch_start forward by the idle duration rather than
resetting it — preserving the cubic growth curve's shape, just
sliding it in time.
~1 week later a follow-up commit
(c2e7204d180f)
titled "tcp_cubic: do not set epoch_start in the future"
fixed a bug in the fix — noting that "tracking idle time in
bictcp_cwnd_event() is imprecise, as epoch_start is normally
set at ACK processing time, not at send time".
The 2020 quiche port — and the 2026 fix¶
In 2020, Cloudflare ported the 2017 fix into quiche's
on_packet_sent() using bytes_in_flight == 0 as the idle
predicate and now - last_sent_time as the idle delta — but did
not port the 1-week-later follow-up. At minimum cwnd
(two packets), bytes_in_flight drops to zero on every ACK
cycle, and last_sent_time is the start of the previous RTT, so
the "idle" delta is ~RTT (not ~0), and the recovery boundary is
advanced into the future — triggering the
CUBIC minimum-cwnd death
spiral.
Cloudflare's 2026-05-12 fix (three lines of logic) adds a
last_ack_time state variable and uses
max(last_ack_time, last_sent_time) as the idle-delta anchor,
correctly distinguishing transient congestion-limited
bytes_in_flight == 0 dips from genuine application idleness.
See patterns/measure-idle-from-last-ack-not-last-send.
Seen in¶
- sources/2026-05-12-cloudflare-when-idle-isnt-idle-how-a-linux-kernel-optimization-became-a-quic-bug
— canonical wiki instance. The minimum-cwnd death spiral is
CUBIC-specific (verified by a Reno control experiment that
passed 100%); the bug's trigger is the 2017 idle-period
adjustment's misbehaviour when
bytes_in_flight == 0reflects congestion-limiting rather than application-idleness. - concepts/congestion-window — CUBIC is named here alongside
Reno and BBR as a canonical loss-based CCA whose
cwnd-growth curve is cubic and whose failure modes include bufferbloat and minimum-cwnd recovery regressions.
Related¶
- concepts/cubic-epoch — the reference-timestamp state variable the entire CUBIC growth function is parameterised on.
- concepts/congestion-window — the universal CCA-output variable CUBIC computes.
- concepts/bytes-in-flight — the input signal the 2017 idle-period adjustment consults.
- concepts/minimum-cwnd-death-spiral — the failure shape specific to the userspace port of the idle-period adjustment.
- systems/quiche — CUBIC's canonical userspace embedder.
- systems/tcp-reno — sibling loss-based CCA; structurally simpler (no epoch state), and the control experiment that localised the 2026-05-12 bug to CUBIC.
- systems/bbrv3 — the model-based alternative Cloudflare is increasingly deploying.
- companies/cloudflare