Loss-Based vs. Model-Based TCP Congestion Control
Loss-Based vs. Model-Based TCP Congestion Control
Every TCP connection has to answer the same question continuously: how fast can I send data before the network starts dropping packets? The algorithm that answers this question is the congestion control algorithm, and the choice of algorithm has measurable effects on throughput, latency, and behavior under packet loss.
For most of the internet’s modern history, the dominant algorithm has been CUBIC—the default in Linux and therefore used by the vast majority of servers. Google’s BBR (Bottleneck Bandwidth and Round-trip propagation time) takes a fundamentally different approach, and the philosophical gap between them explains a lot of network behavior that engineers often attribute to “the network being weird.”
The Loss-Based Approach
CUBIC and its predecessors (Reno, NewReno) are loss-based algorithms. The core idea: keep increasing the sending rate until you see packet loss, then cut back, then start climbing again. The resulting behavior is a sawtooth pattern—the connection perpetually overshoots, backs off, and recovers.
This works reasonably well when the bottleneck is a router with a small buffer and loss is a reliable signal that the queue is full. Modern networks break both assumptions. Large router buffers (the “bufferbloat” problem) mean packets queue up for hundreds of milliseconds before they’re dropped, inflating latency long before CUBIC detects any signal to back off. Wireless links introduce real packet loss that has nothing to do with congestion—a bad radio frame looks identical to a congested queue from CUBIC’s perspective. The algorithm backs off anyway, cutting throughput on a link that has plenty of capacity.
The Model-Based Approach
BBR doesn’t react to loss. Instead, it continuously estimates two physical properties of the network path:
- BtlBw: the bottleneck bandwidth—how fast the slowest link on the path can actually carry data
- RTprop: the minimum round-trip propagation delay—the latency of the path with no queuing added
From these two estimates, BBR calculates an optimal sending rate and an in-flight byte cap that keeps the pipe full without filling the buffer. It probes periodically to detect whether available bandwidth has increased, but its default operating point is deliberately below the queue-filling threshold.
The consequence is that BBR’s behavior is driven by what the network is, not by what it drops.
Where the Difference Shows Up in Practice
The gap is most visible in two scenarios.
On high-latency, high-bandwidth paths—trans-oceanic connections, satellite links—CUBIC’s sawtooth behavior keeps utilization chronically below the theoretical maximum. The bandwidth-delay product on a 100ms RTT, 1 Gbps link is enormous, and CUBIC’s additive-increase phase is too slow to fill it before the next loss event. BBR can saturate these links far more effectively because it probes bandwidth directly rather than discovering it by losing packets.
On lossy-but-uncongested links—cellular networks, Wi-Fi—CUBIC treats every dropped packet as a congestion signal and reduces its rate. BBR, because it infers congestion from shifts in its bandwidth and RTT model rather than from loss events, is substantially less sensitive to random packet loss. Sustained throughput on a 2% random-loss wireless link is dramatically different between the two algorithms.
The tradeoff is real, though. Early versions of BBR had documented fairness problems when sharing a bottleneck with CUBIC flows—BBR flows would claim a disproportionate share of capacity. BBR v2 addressed the most serious cases, but it illustrates the general principle: a congestion control algorithm that’s better in isolation isn’t automatically better in a mixed environment.
What This Means for Infrastructure Engineers
Linux defaults to CUBIC. Switching the kernel’s default congestion control algorithm to BBR is a single sysctl change, and it can meaningfully improve throughput for clients on high-latency or lossy paths—which describes most mobile and international traffic.
It also reframes how you think about performance anomalies. A file transfer running at a fraction of nominal link speed isn’t necessarily an application or bandwidth problem. The congestion control algorithm’s interaction with the specific network path is a real variable, and diagnosing it requires knowing which algorithm is in play and how it behaves under current path conditions.
Congestion control is one of the rare areas where a kernel-level algorithm choice translates directly into user-visible metrics: download speeds, video streaming buffer rates, interactive application latency. The underlying models are worth understanding.