TCP congestion window simulator
TCP limits how much it sends with a congestion window that doubles in slow start, grows by one segment per round trip in congestion avoidance, and shrinks when packets are lost. Enter the threshold and the rounds where losses happen, and get the window round by round for Tahoe or Reno.
cwndssthreshslow start
Slow start in rounds 1 to 4; congestion avoidance in rounds 5 to 19; slow start in rounds 20 to 22; congestion avoidance in rounds 23 to 24.
| Round | cwnd | ssthresh | Phase | Segments |
|---|---|---|---|---|
| 1 | 1 | 16 | slow start | 1–1 |
| 2 | 2 | 16 | slow start | 2–3 |
| 3 | 4 | 16 | slow start | 4–7 |
| 4 | 8 | 16 | slow start | 8–15 |
| 5 | 16 | 16 | avoidance | 16–31 |
| 6 | 17 | 16 | avoidance | 32–48 |
| 7 | 18 | 16 | avoidance | 49–66 |
| 8 | 19 | 16 | avoidance | 67–85 |
| 9 | 20 | 16 | avoidance | 86–105 |
| 10 | 21 | 16 | avoidance | 106–126 |
| 11 | 22 | 16 | avoidance | 127–148 |
| 12 | 23 | 16 | avoidance, 3 dup ACKs | 149–171 |
| 13 | 11 | 11 | avoidance | 172–182 |
| 14 | 12 | 11 | avoidance | 183–194 |
| 15 | 13 | 11 | avoidance | 195–207 |
| 16 | 14 | 11 | avoidance | 208–221 |
| 17 | 15 | 11 | avoidance | 222–236 |
| 18 | 16 | 11 | avoidance | 237–252 |
| 19 | 17 | 11 | avoidance, timeout | 253–269 |
| 20 | 1 | 8 | slow start | 270–270 |
| 21 | 2 | 8 | slow start | 271–272 |
| 22 | 4 | 8 | slow start | 273–276 |
| 23 | 8 | 8 | avoidance | 277–284 |
| 24 | 9 | 8 | avoidance | 285–293 |
- 2Slow start: cwnd doubles, 1 × 2 = 2.
- 3Slow start: cwnd doubles, 2 × 2 = 4.
- 4Slow start: cwnd doubles, 4 × 2 = 8.
- 13Three duplicate ACKs in round 12: Reno halves, ssthresh = 11, cwnd = 11 = 11, and continues in congestion avoidance.
- 20A timeout in round 19: ssthresh = 17 / 2 = 8, cwnd = 1, slow start again.
How to use the simulator
Set the initial congestion window (usually 1 segment in exercises), the initial slow-start threshold, the number of rounds, and the rounds at whose end a loss is detected, for example "12 dup, 19 timeout". A round is one round trip, in which the sender transmits a full window. The chart shades slow start, the table lists cwnd, ssthresh and the segment numbers sent in every round, and you can ask which round sends a given segment.
- Switch between Tahoe and Reno to see the difference a triple duplicate ACK makes.
- Hover a row of the table for the reason the window changed.
- "Copy answer" gives the table and the phase intervals as text; "Copy link" saves the exercise.
What is congestion control?
A TCP sender may have at most the smaller of two windows unacknowledged: the receiver's advertised window, which protects the receiver, and the congestion window (cwnd), which protects the network. The sender has no direct signal of how much the path can carry, so it probes: it raises cwnd while data gets through and cuts it when a loss suggests a queue somewhere has overflowed.
The rule at the heart of it is additive increase, multiplicative decrease (AIMD): grow by a constant amount per round trip, halve on loss. Chiu and Jain showed in 1989 that this combination drives flows sharing a link towards a fair and efficient share.
Slow start and congestion avoidance
In slow start, cwnd increases by one segment for every segment acknowledged, so it doubles each round trip: 1, 2, 4, 8 and so on. Despite the name this is fast, exponential growth, and it ends when cwnd reaches the slow-start threshold (ssthresh). From there, congestion avoidance adds about one segment per round trip. The threshold remembers roughly where trouble started last time: it is set to half the window whenever a loss is detected.
Losses: Tahoe and Reno
A sender learns of a loss in two ways. A retransmission timeout means nothing has come back for a long time, a sign of heavy congestion. Three duplicate ACKs mean later segments are arriving while one is missing, so the network is still delivering.
- TCP Tahoe treats both the same: ssthresh = cwnd / 2, cwnd = 1, slow start again.
- TCP Reno does the same after a timeout. After three duplicate ACKs it retransmits at once (fast retransmit), sets ssthresh = cwnd / 2 and continues from there in congestion avoidance (fast recovery), instead of collapsing to one segment.
With a loss detected by duplicate ACKs every 10 rounds over 60 rounds, starting from ssthresh 32, Tahoe's window fell to 1 after each loss and it sent 659 segments; Reno's never fell below 9 and it sent 1,036.
Conventions that change the answer
Exercises model TCP round by round, and they simplify in different ways. Check which your course uses:
- Reaching ssthresh in slow start. If doubling would pass ssthresh, some solutions stop at ssthresh and others double past it before switching to linear growth.
- The window after three duplicate ACKs. RFC 5681's fast recovery sets cwnd to ssthresh + 3 segments while recovering and back to ssthresh afterwards; round-level exercises show either value.
- The floor on ssthresh. RFC 5681 sets ssthresh to at least two segments; small textbook examples often ignore it.
- Which round the loss is in. Here a loss "in round n" is detected at the end of round n, so round n + 1 already has the new window.
CUBIC and BBR
Reno grows by one segment per round trip, which is far too slow on fast, long paths: refilling a large window after a halving takes thousands of round trips. CUBIC, standardised in RFC 9438 and the default in Linux and Windows, grows the window as a cubic function of the time since the last loss, W(t) = C(t − K)³ + Wmax with C = 0.4, reducing it to 0.7 Wmax on a loss. It returns to the previous maximum after K = ∛(Wmax · 0.3 / 0.4) seconds, whatever the round trip:
| Window before the loss (segments) | CUBIC: K | Reno, 10 ms round trip | Reno, 100 ms round trip |
|---|---|---|---|
| 10 | 2.0 s | 0.1 s | 0.5 s |
| 100 | 4.2 s | 0.5 s | 5.0 s |
| 1,000 | 9.1 s | 5.0 s | 50.0 s |
| 10,000 | 19.6 s | 50.0 s | 500.0 s |
Google's BBR takes a different approach: rather than treating loss as the signal, it estimates the path's bottleneck bandwidth and minimum round-trip time and paces sending to match, which avoids filling buffers in the first place.
History
In October 1986 the early Internet suffered the first of a series of congestion collapses, during which, Van Jacobson reported, throughput between Lawrence Berkeley Laboratory and UC Berkeley fell from 32 kbit/s to 40 bit/s. Jacobson and Michael Karels's 1988 paper "Congestion Avoidance and Control" introduced slow start, congestion avoidance and better retransmit timers, shipped in 4.3BSD Tahoe; fast recovery followed in 4.3BSD Reno. The algorithms were standardised as RFC 2001 in 1997 and are now RFC 5681.
TCP congestion control questions and answers
How does TCP slow start work?
A new connection starts with a small congestion window (cwnd) and adds one segment for every segment acknowledged, so the window doubles every round trip. It keeps doubling until it reaches the slow-start threshold (ssthresh) or a loss happens, then switches to congestion avoidance.
What is the difference between TCP Tahoe and TCP Reno?
Both halve ssthresh on a loss. Tahoe also drops cwnd to one segment and slow-starts again, whatever the cause. Reno does that only after a timeout; on three duplicate ACKs it uses fast recovery, halving cwnd and continuing in congestion avoidance. With a loss every 10 rounds for 60 rounds, Reno sent 1,036 segments to Tahoe’s 659 in this page’s model.
What happens to cwnd and ssthresh after a timeout?
ssthresh is set to half the current window (RFC 5681 says half the data in flight, and at least two segments), cwnd goes back to one segment, and the sender slow-starts again. Because slow start ends at the new ssthresh, the window climbs quickly to half its old size and then grows by one segment per round trip.
Why does Reno add 3 to cwnd after three duplicate ACKs?
Each duplicate ACK means a segment has left the network, so during fast recovery Reno inflates the window by one segment per duplicate ACK, three for the three that triggered it, and deflates it to ssthresh when new data is acknowledged. Some textbooks show cwnd = ssthresh + 3 at that point, others show cwnd = ssthresh; this page lets you choose.
In which round is the nth segment sent?
Add up cwnd round by round from the first round: the round in which the running total reaches n is the one that sends segment n. The simulator does this for you: type the segment number under the table.
What congestion control do operating systems use today?
Not Reno. Linux and Windows default to CUBIC (RFC 9438), which grows the window as a cubic function of the time since the last loss, so recovery does not depend on the round-trip time. With 1,000 segments in flight before a loss, CUBIC returns to that window 9.1 s after the loss whatever the round trip; Reno, adding one segment per round trip, needs 50 s at a 100 ms round trip. Google’s BBR instead models the path’s bandwidth and round-trip time rather than reacting to loss.
Further reading
- Jacobson and Karels, SIGCOMM 1988Congestion Avoidance and ControlThe paper that introduced slow start and congestion avoidance.
- IETF, 2009RFC 5681: TCP Congestion ControlSlow start, congestion avoidance, fast retransmit and fast recovery as standardised.
- IETF, 2023RFC 9438: CUBIC for Fast and Long-Distance NetworksThe cubic window function and its constants.
- Chiu and Jain, 1989Analysis of the increase and decrease algorithms for congestion avoidance in computer networksWhy additive increase with multiplicative decrease converges to fairness.
- Cardwell et al., ACM Queue, 2016BBR: Congestion-Based Congestion ControlPacing to the measured bottleneck bandwidth and round-trip time.