How the Sender Decides How Fast to Go
TCP does not simply blast data at full speed and hope for the best. It uses a congestion control algorithm to probe the network's capacity, back off when congestion is detected, and recover. The algorithm runs entirely on the sender side and determines how quickly the congestion window (cwnd) — the sender's self-imposed limit on in-flight data — grows and shrinks.
The classic algorithm (Reno/Cubic) works in phases:
- Slow Start: cwnd begins at ~10 segments (~14 KB). It doubles every RTT until a loss event occurs or a threshold is reached. Despite the name, this is the fastest growth phase.
- Congestion Avoidance: After the threshold, cwnd grows by one segment per RTT (linear growth). The sender is probing carefully.
- Loss Detection: A dropped packet (timeout or three duplicate ACKs) signals congestion. cwnd is cut in half (Reno) or reduced by a factor (Cubic). The cycle repeats.
The problem with loss-based algorithms on modern networks:
Loss-based algorithms like Reno and Cubic treat packet loss as the only signal of congestion. On a high-speed link, by the time loss occurs, the network is already severely congested. They also cannot distinguish between congestion loss and random loss (common on wireless links) — a random drop causes an unnecessary cwnd reduction.
BBR (Bottleneck Bandwidth and Round-trip propagation time):
Developed by Google and available in Linux since kernel 4.9, BBR takes a fundamentally different approach. Instead of reacting to loss, it continuously measures two things:
- BtlBw: The bottleneck bandwidth (maximum delivery rate observed).
- RTprop: The minimum RTT observed (a proxy for the propagation delay with no queuing).
BBR then sets cwnd to keep the pipe full at BtlBw without building up queue (which would inflate RTT). It periodically probes for more bandwidth by briefly increasing the send rate.
Switching to BBR is a runtime kernel parameter change on any kernel since 4.9, with one prerequisite: BBR requires the fq (fair queuing) packet scheduler on the network interface to work correctly, so both settings need to be in place together.
When to use which algorithm:
| Algorithm | Best For | Avoid When |
|---|---|---|
| Cubic | Datacenter, low-loss wired links | High random loss (wireless) |
| BBR | WAN, high-RTT, mixed loss environments | Shared links where fairness with Cubic flows matters |
| Reno | Legacy compatibility | Any modern high-speed link |
BBR is not universally superior. In environments where BBR flows share a bottleneck with Cubic flows, BBR can be unfairly aggressive, capturing a disproportionate share of bandwidth. This is an active area of research (BBRv2 and BBRv3 address some of these fairness issues).
Key Point: Loss-based algorithms (Cubic) react to congestion after it has already occurred. BBR proactively models the network's capacity and avoids building queues, making it significantly more effective on high-RTT and lossy links.