TCP Congestion Control
TCP congestion control manages network traffic by adjusting data transmission rates in response to perceived congestion. Without it, senders would flood the network with more data than it can handle, leading to widespread packet loss and degraded performance for everyone. This section covers the core mechanisms: slow start, congestion avoidance, and fast retransmit/fast recovery, along with the key variables that drive them.
Concept of Network Congestion
Network congestion occurs when the demand for network resources exceeds available capacity. Think of multiple users on the same link all streaming video or transferring large files at the same time. Routers and links between them become bottlenecks.
Congestion produces three main symptoms:
- Packet loss: Routers have finite buffer space. When buffers fill up, incoming packets are simply dropped. The sender must then retransmit, which adds even more traffic to an already overloaded network.
- Increased latency: Even before buffers overflow, packets sit in longer and longer queues at congested routers. This drives up round-trip times (RTT), sometimes dramatically (a phenomenon called bufferbloat).
- Reduced throughput: TCP senders interpret loss and delay as congestion signals and slow down. The result is lower effective data transfer speeds for all flows sharing the congested path.
Purpose of TCP Congestion Control
TCP congestion control exists to prevent and react to congestion, ensuring fair and efficient use of shared network resources.
- Prevents congestion collapse. In the 1980s, the early ARPANET experienced congestion collapse: senders kept retransmitting lost packets, which only made congestion worse, until the network carried almost no useful data. TCP congestion control was introduced specifically to stop this positive feedback loop.
- Achieves fairness. When multiple TCP flows share a bottleneck link, congestion control drives them toward an equal share of the available bandwidth over time. No single flow should starve the others.
Three core mechanisms make this work:
- Slow start gradually ramps up the sending rate at the beginning of a connection or after a timeout (exponential growth phase).
- Congestion avoidance probes for additional bandwidth more cautiously once the connection is running (linear growth phase, using additive increase/multiplicative decrease).
- Fast retransmit and fast recovery detect and recover from isolated packet losses quickly, without waiting for a full timeout.

Slow Start and Congestion Avoidance
Slow Start
Slow start controls how a new connection (or one recovering from a timeout) ramps up its sending rate.
- The sender initializes the congestion window () to a small value, typically 1 MSS (Maximum Segment Size).
- For each ACK received, increases by 1 MSS. Because one ACK arrives per segment sent, this effectively doubles every round-trip time. The growth is exponential despite the name "slow start."
- This exponential growth continues until one of two things happens:
- reaches the slow start threshold (), at which point the sender transitions to congestion avoidance.
- A packet loss is detected, signaling congestion.
Congestion Avoidance
Once , the sender switches from exponential to linear growth:
- Additive increase: grows by 1 MSS per RTT (not per ACK). This cautiously probes for spare bandwidth without overwhelming the network.
- Multiplicative decrease: When a loss event is detected, is set to half of the current , and is reduced. This 50% cut is aggressive enough to relieve congestion quickly.
The combination of additive increase and multiplicative decrease (AIMD) is what gives TCP's congestion window its characteristic "sawtooth" pattern over time: gradual linear climbs followed by sharp drops on loss.
Role of cwnd and ssthresh
These two variables are the core state that drives all congestion control decisions.
Congestion window ():
- Represents the maximum amount of unacknowledged data the sender can have in flight at any moment (measured in bytes or segments).
- Directly controls the sending rate. A larger means more data in the pipeline and higher throughput.
- The effective window the sender actually uses is , where is the receiver's advertised window. This means flow control and congestion control work together: the sender respects whichever limit is smaller.
Slow start threshold ():
- Acts as the boundary between slow start (exponential growth) and congestion avoidance (linear growth).
- Initially set to a large value, often equal to the receiver's advertised window, so the first slow start phase can run freely.
- On a loss event, is updated to . This captures the sender's best estimate of the network's safe capacity and ensures the next slow start phase transitions to linear growth earlier.

Fast Retransmit and Fast Recovery
Waiting for a timeout to detect a lost packet is expensive: the sender sits idle, and resets to 1 MSS. Fast retransmit and fast recovery avoid this.
- Fast retransmit: When the sender receives 3 duplicate ACKs for the same sequence number, it infers that a specific segment was lost (rather than just reordered). It retransmits that segment immediately, without waiting for the retransmission timeout (RTO) to expire.
- Fast recovery: After the fast retransmit, the sender sets and sets MSS (accounting for the 3 duplicate ACKs that triggered it). The sender then stays in congestion avoidance rather than dropping back to slow start.
The distinction matters: a timeout indicates severe congestion ( resets to 1 MSS, slow start restarts), while 3 duplicate ACKs suggest a single lost packet in an otherwise flowing connection ( is only halved).
Advantages vs. Limitations of Congestion Control
Advantages:
- Self-regulating: Each sender independently adapts its rate to available capacity, with no central coordinator required.
- Fair sharing: AIMD mathematically converges toward equal bandwidth allocation among competing TCP flows on the same bottleneck.
- Prevents congestion collapse: By backing off when loss occurs, TCP keeps the network in a usable state even under heavy load.
Limitations:
- Reactive, not proactive: TCP detects congestion only after packets have been lost or delayed. By that point, router buffers have already overflowed.
- Struggles with high bandwidth-delay product networks: On "long fat networks" (high bandwidth, high latency), the linear increase phase of AIMD takes a very long time to fill the pipe after a loss event. This leaves significant bandwidth unused.
- Misinterprets wireless losses: Standard TCP assumes all packet loss is caused by congestion. In wireless networks, packets can be lost due to signal interference or handoffs. TCP reacts by cutting its window, which is the wrong response for non-congestion losses.
- Loss-based signaling is inherently late: Relying on packet loss as the primary congestion signal means TCP always pushes the network to the point of buffer overflow before backing off. Newer approaches like TCP BBR instead use RTT measurements to detect congestion before loss occurs.