TCP Congestion Control: CUBIC vs BBR Explained
TCP congestion control is the sender-side process that adapts a connection’s transmission rate to the network path. It matters when a website loads slowly, a backup fails to fill a fast link, or a shared network experiences queues and packet loss. CUBIC and BBR are two widely used approaches, but neither is a universal speed switch: their results depend on the path, operating system, competing traffic, and workload.
What Is TCP Congestion Control?
TCP delivers an ordered byte stream, but it cannot send unlimited data at once. A sender tracks bytes in flight with a congestion window, or cwnd. The receiver also advertises a receive window, rwnd, to protect its own buffers. The sender is constrained by the smaller of the two, so a large receive window does not override a network congestion limit.
The congestion-control algorithm adjusts cwnd and, in paced implementations, the timing of packets. It estimates how much traffic the path can carry without persistently overloading a bottleneck. TCP’s core specification defines the transport behavior; individual congestion-control algorithms decide how a sender probes for capacity and reacts to congestion signals.
RFC 9438 specifies CUBIC for TCP. Linux exposes the configured congestion-control algorithm through networking sysctls, including net.ipv4.tcp_congestion_control and the available-algorithm list. The Linux IP sysctl documentation describes those controls. Google’s BBR project and documentation explain BBR as a model-based alternative that estimates bottleneck bandwidth and round-trip time.
Why Does Congestion Control Exist?
If many senders transmit faster than a shared link can forward packets, the bottleneck queue grows. Queuing adds delay; when buffers fill, packets are dropped. Lost packets require recovery and can make a connection appear slower even when the physical link has unused capacity at other times.
Congestion control is distinct from flow control. Flow control protects the receiver from more data than it can buffer. Congestion control protects the path from excessive offered load. It is also different from quality-of-service scheduling: a router’s scheduler can prioritize or shape traffic, while each TCP sender still needs to adjust its own transmission in response to the path.
This is why a high-bandwidth, long-distance transfer is a useful test case. The bandwidth-delay product estimates the amount of data that must be in flight to fill the path. A sender that probes too cautiously may leave capacity unused; one that builds queues can raise latency for itself and other users. Latency and bandwidth are separate performance constraints, and TCP congestion control influences how effectively a connection uses a path with a large bandwidth-delay product.
How CUBIC and BBR Work
CUBIC is a window-based, loss-responsive algorithm. After a congestion event, it records the congestion window at that point and grows the window according to a cubic function of elapsed time. Growth is faster when the current window is well below the previous operating point and more gradual near it, allowing CUBIC to probe for additional capacity without remaining in a simple linear-growth pattern. On a loss signal, it reduces its window and begins probing again.
This time-based shape is intended to make recovery and growth more practical on fast, long-distance paths than older TCP behavior. The CUBIC RFC also describes its relationship to Reno-friendly behavior. That does not mean it is perfectly fair against every other algorithm, queue discipline, or traffic pattern; fairness is an observed property of a particular mix of flows, not a guarantee implied by the name.
BBR stands for Bottleneck Bandwidth and Round-trip propagation time. Instead of treating packet loss as its primary estimate of congestion, BBR builds a model from delivery-rate samples and the minimum observed round-trip time. The delivery rate estimates bottleneck bandwidth (BtlBw); the minimum round-trip time approximates propagation delay without persistent queueing (RTprop).
BBR uses those estimates to pace packets and target an amount of data in flight sufficient to use the estimated path capacity. Its probing phases test whether bandwidth has changed and periodically seek a less-queued RTT sample. Loss still matters to TCP reliability and to the algorithm’s implementation, but BBR is designed not to wait for loss before learning that a link can carry more data. The exact behavior differs between BBR versions and kernel implementations, so measurements should name the implementation being tested.
| Feature | CUBIC | BBR |
|---|---|---|
| Main model | Congestion-window growth shaped by time since a congestion event | Estimates bottleneck bandwidth and propagation RTT |
| Primary capacity probe | Grows cwnd and observes congestion signals |
Paces traffic and samples delivery rate |
| Reaction to congestion | Reduces the window after loss or an ECN congestion signal | Adjusts its model and pacing; loss is not its sole capacity signal |
| Long, high-bandwidth paths | Designed to grow efficiently on high-speed, long-distance paths | Can use bandwidth-delay product estimates to target high utilization |
| Queue behavior | Can build queues while probing, depending on the path and competing flows | Tries to model delivery and RTT, but may still create queues while probing |
| Fairness | RFC defines Reno-friendly behavior, not universal fairness | Depends on BBR version, RTTs, bottleneck, and competing algorithms |
| Operational support | Commonly available in Linux and other TCP stacks | Availability and defaults depend on kernel and platform |
The table describes design intent, not a benchmark result. A path with random wireless loss, a congested uplink, a fast data-center fabric, and a rate-limited VPN can produce very different comparisons.
Key Concepts That Affect Results
Congestion signals are not identical to congestion itself
Packet loss is visible and important, but it can also result from a radio link or a faulty device rather than an overloaded bottleneck. Explicit Congestion Notification (ECN), where supported and configured along the path, lets a router signal congestion without dropping the marked packet. Algorithms may respond differently to loss and ECN, and middleboxes can affect whether ECN works end to end.
A flow’s path and its competitors matter
The same server can see different RTTs, bottlenecks, and packet loss for different clients. On a shared link, several CUBIC flows may behave differently from a mixture of CUBIC and BBR. Flow count and RTT also influence how bandwidth is divided. A single-stream throughput figure cannot establish that an algorithm is fair or that it improves the experience for every user.
The sender chooses the algorithm
TCP congestion control is generally selected at the sending endpoint for outgoing traffic. Changing a Linux host’s default does not change the algorithm used by a remote peer, and it may not override applications that explicitly select a per-socket algorithm. For a bidirectional workload, each direction has its own sender and potentially its own algorithm.
Where CUBIC and BBR Are Used
CUBIC is a common choice for general-purpose Linux TCP workloads and is also implemented in other operating systems. It can be a reasonable baseline when a system has mixed traffic, established operational practices, and no measured evidence that another algorithm solves a real problem.
BBR is worth evaluating where throughput on high-bandwidth, high-RTT paths is important, or where loss is not a reliable indicator of a bottleneck. Operators may test it for replication, storage transfers, content delivery, or data movement between regions. Such use does not make BBR automatically preferable: a test must include the network’s real bottleneck, concurrent flows, and latency-sensitive users.
The choice also belongs to the deployment boundary. A server administrator may control its kernel and TCP defaults, while a cloud service, mobile device, client application, or managed appliance may not expose that setting. If the issue is a full queue, bad Wi-Fi, an undersized receive window, application serialization, or a traffic shaper, switching algorithms may simply move the symptom.
Test CUBIC and BBR on Linux
First inspect the running kernel’s available algorithms and current default:
sysctl net.ipv4.tcp_available_congestion_control
sysctl net.ipv4.tcp_congestion_control
The available list depends on kernel configuration and loaded modules. If bbr is not listed, do not assume that writing the setting will install or enable it; use a kernel that provides it or consult the distribution’s documentation. On a test host where BBR is available, change the default temporarily:
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr
sysctl net.ipv4.tcp_congestion_control
This changes the default used for new TCP connections in that environment; it does not retroactively change every active connection. The setting is not persistent across reboot. Restore the previous algorithm (for example, if CUBIC is available) after the test:
sudo sysctl -w net.ipv4.tcp_congestion_control=cubic
Run tests between two hosts on a path you control. With iperf3 running in server mode on the receiver, measure a single stream and then a parallel-flow case from the sender:
iperf3 -c 192.0.2.10 -t 60 -P 1
iperf3 -c 192.0.2.10 -t 60 -P 4
iperf3 -c 192.0.2.10 -t 60 -P 1 --reverse
Replace the documentation-only address with the receiver’s reachable address. Repeat each test under comparable conditions with each algorithm. --reverse changes which endpoint sends the bulk data, so its congestion-control setting is the one that matters for that direction.
Record throughput, RTT under load, retransmissions, CPU use, and the effects on concurrent applications. Keep the test duration and endpoint workload stable, and compare repeated runs rather than selecting the best result from each set. Avoid testing on a public service or a network you do not administer. Linux queue disciplines, traffic shaping, offloads, and application behavior can all change the outcome; keep those factors consistent before attributing a difference to CUBIC or BBR.
Do not make a global production change based on one iperf3 result. A persistent sysctl setting affects more than one benchmark connection and can change how a host shares a constrained uplink. Change one variable at a time, document how to roll it back, and monitor the production workload that motivated the experiment.
Common Misconceptions
“BBR is always faster than CUBIC”
No algorithm wins on every path. BBR can be beneficial when its bandwidth and RTT model fits the workload, while CUBIC may perform well on the same network or interact differently with its competing flows. Test the actual bottleneck and application, not just a nearby speed test.
“BBR prevents packet loss and queueing”
BBR is not a lossless transport or a substitute for queue management. Packets can still be lost, and probing or competing traffic can still create queues. Congestion control influences the sender’s behavior; it cannot repair a broken link or guarantee low latency at an overloaded router.
“Changing the algorithm fixes any slow TCP connection”
Slow application processing, packet filtering, poor wireless coverage, insufficient receive buffers, retransmission, or a distant endpoint may be the real cause. Diagnose the path and workload before tuning. TCP’s role relative to UDP and HTTP explains where congestion control fits in the larger protocol stack.
Related Articles
- TCP, UDP, and HTTP explained separates transport protocols from application protocols.
- Latency vs. bandwidth explains round-trip delay, throughput, and bandwidth-delay product.
- Linux kernel performance tuning covers kernel settings and the risks of changing them.
- Linux network troubleshooting provides tools for diagnosing connectivity and packet flow.
Changelog
- Initial publication.
Last updated: 10 October.

