TCP congestion control.
A TCP connection has no idea how fast the network can carry it. It guesses, ramps up, hits a loss, backs off, ramps up again. The shape of the resulting cwnd-over-time graph — a fast exponential climb, a linear walk, a sharp halving, repeat — is the signature of every internet transfer for the last 30 years.
Right after the TCP handshake, the sender has no idea what the network can handle. So it starts cautious: send 1 segment, wait for the ACK, then double the window. Round by round, cwnd grows exponentially. This is slow start despite the name — it ramps up FAST.
- cwnd · congestion window
- Bytes the sender is allowed to have in flight at once, based on its guess of what the network can absorb. Separate from the receive window (which is how much the receiver can buffer).
- RTT
- Round-trip time. cwnd doubles once per RTT in slow start, so 1 → 2 → 4 → 8 → 16 → 32... — log₂(BDP) RTTs to reach steady state.
Why TCP guesses instead of asking
The network doesn\'t tell senders how much capacity is available. Routers don\'t broadcast their queue depths. The only signal TCP gets is binary: did the packet make it (ACK arrives) or didn\'t (timeout or duplicate ACKs). From that signal, TCP infers congestion. The whole edifice of slow start, AIMD, and ssthresh is a clever inference protocol built from this single bit of feedback.
Reno · CUBIC · BBR · the variants
Reno is what we showed — the classic loss-based AIMD. CUBIC (default on Linux since 2006) replaces linear growth with a cubic function that ramps faster after a loss, especially on high-bandwidth long-RTT paths. BBR (Google, 2016) ignores loss almost entirely — instead it measures bottleneck bandwidth and RTT, then sends at exactly that rate. Often dramatically faster on lossy WiFi or noisy paths where Reno/CUBIC misinterpret single losses as congestion.
Where it shows up in production
BDP (bandwidth-delay product) is the magic number: bandwidth × RTT = bytes in flight needed to fill the pipe. 1 Gbit link with 50 ms RTT needs 6 MB in flight. Default Linux TCP buffers are usually big enough, but on the long fat networks (transatlantic, satellite), small buffers can cap throughput far below link speed. sysctl net.ipv4.tcp_rmem and tcp_wmem are the knobs. On the other side, fq_codel and CAKE qdiscs at routers fight bufferbloat, which is the opposite problem: too-big buffers hiding congestion signals from senders.
TCP, the long version →
Reno vs CUBIC vs BBR side by side, SACK and timestamps, pacing, ECN, the buffer-bloat saga, what changes on lossy wireless.
Open the Codex →