§ 12. TCP Loss-Based Congestion Control
Tahoe, Reno, NewReno, BIC, CUBIC, HTCP, and the cwnd mechanics behind the classic TCP sawtooth.
1. Overview
Loss-based congestion control treats packet loss as the primary signal that the network queue overflowed. The sender gates transmission with cwnd, still respecting receiver flow control through rwnd, and lets ACKs clock new data into the path.
2. § 12.1 — Congestion Control Framework
The core invariant is bytes_in_flight <= min(cwnd, rwnd). Slow start doubles cwnd each RTT until it reaches ssthresh; congestion avoidance then adds roughly one MSS per RTT.
AIMD is the stable loss-based pattern: additive increase probes for a little more bandwidth, and multiplicative decrease backs off sharply after loss. Three duplicate ACKs are a mild loss signal; an RTO is severe and restarts from a tiny window.
| Variable | Meaning | Interview trap |
|---|---|---|
cwnd | Sender-side congestion window, measured in bytes or MSS units. | It is not advertised on the wire. |
rwnd | Receiver advertised window, driven by socket receive buffer space. | It is flow control, not congestion control. |
ssthresh | Boundary between exponential slow start and linear avoidance. | Loss usually sets it to about half the flight/window. |
Minimal C Demo — CC Phases Animator
3. § 12.2–12.3 — Tahoe, Reno, and NewReno
Tahoe is conservative: any loss sets ssthresh = cwnd / 2 and resets cwnd to one MSS. Reno keeps the ACK clock alive after three duplicate ACKs by entering fast recovery instead of dropping all the way back to slow start.
NewReno fixes Reno's multiple-loss weakness with a recovery marker. Partial ACKs retransmit the next missing segment but do not exit recovery until the whole pre-loss window is acknowledged.
- Tahoe introduced slow start, congestion avoidance, and fast retransmit in early BSD TCP.
- Reno treats dupACK loss and timeout loss differently; timeout still resets to one MSS.
- Classic Reno performs poorly when several packets in the same flight are lost because recovery advances one loss per RTT.
Minimal C Demo — Reno Fast Recovery
4. § 12.4 — BIC and CUBIC
BIC searched between the last known safe window and the failed window. CUBIC keeps that high-BDP intent but replaces the binary search shape with a smooth time-based cubic function, W(t) = C(t - K)^3 + Wmax.
K is the time needed to return to the old Wmax after a reduction. Growth is fast just after loss, careful near the old limit, and aggressive again after the connection proves the path may support more.
- CUBIC's beta is about 0.7, so it cuts less deeply than Reno's half-window decrease.
- Because growth is driven by wall-clock time, CUBIC is less RTT-biased than Reno on mixed-RTT paths.
- HyStart exits slow start early when ACK-train spacing or RTT growth suggests the queue is filling before a hard loss.
Minimal C Demo — CUBIC Interactive Curve
5. § 12.5 — HTCP
HTCP, Hamilton TCP, is another high-speed TCP variant. It increases more aggressively when a flow has gone a long time without congestion and can scale its behavior for high-BDP paths, but it never became as dominant in Linux deployments as CUBIC.
Minimal C Demo — HTCP Growth Intuition
6. Kernel Source Pointers
net/ipv4/tcp_cong.c: congestion-control registration and default helpers.net/ipv4/tcp_input.c: ACK processing, fast retransmit, and recovery entry points.net/ipv4/tcp_cubic.c: CUBIC, HyStart, and Reno-friendly fallback logic.include/net/tcp.h: congestion-control operations and TCP control block fields.net/ipv4/tcp_timer.c: RTO handling and timeout-driven cwnd reset paths.
7. Interview Prep
| Question | Concise answer |
|---|---|
| What is the Tahoe vs Reno difference on 3 dupACKs? | Tahoe resets cwnd to one MSS; Reno halves, inflates during fast recovery, then deflates to ssthresh. |
| Why does an RTO hurt more than dupACK loss? | RTO means the ACK clock stopped, so TCP assumes severe congestion and restarts slow start. |
| What does CUBIC's K represent? | The time offset where the cubic curve reaches the previous maximum window, Wmax. |
| Why is CUBIC more RTT-independent than Reno? | Its main growth function is based on elapsed time since loss, not one additive step per RTT. |
| Why does HyStart exist? | It exits slow start before loss when delay or ACK spacing suggests queues are forming. |