SEN2008 · Week 8 · Transport Layer Concepts (II): Congestion Control, Flow Control

Transport layer II: flow control, congestion control and RTT estimation

Flow control with rwnd, cwnd traces with slow start and AIMD (Tahoe and Reno), average TCP throughput, and timeout calculation with EWMA. The round-by-round cwnd table and a timeout question are certain to appear on the midterm.

flow controlreceive window (rwnd)congestion controlcongestion window (cwnd)slow startssthreshcongestion avoidanceAIMDfast retransmitfast recoveryTCP TahoeTCP Renoduplicate ACKSampleRTTEstimatedRTTDevRTTTimeoutIntervalEWMA

Last week we saw how TCP numbers segments. This week we talk about how fast it sends. There are two separate brakes: flow control so as not to overwhelm the receiver, and congestion control so as not to overwhelm the network. The exam almost always has a round-by-round cwnd table and a timeout calculation. Golden rules:

  1. Sender window = min(cwnd, rwnd). One comes from the receiver, one from the network.
  2. Slow start doubles, congestion avoidance adds 1. The switch point is ssthresh.
  3. On loss, ssthresh = cwnd / 2. In both versions, for both kinds of loss.
  4. On a timeout, cwnd = 1. Tahoe drops to 1 on a triple duplicate ACK too; Reno drops to ssthresh + 3.
  5. Timeout = EstimatedRTT + 4 · DevRTT.

Flow control

The receiver has a buffer (RcvBuffer). Bytes arriving from the network are written here, and the buffer empties as the application reads. If the application reads slowly, the buffer fills and new arrivals are lost. To prevent this, TCP sends the amount of free space, the receive window (rwnd) field, in the header of every segment:

rwnd=RcvBuffer−(LastByteRcvd−LastByteRead)\text{rwnd} = \text{RcvBuffer} - (\text{LastByteRcvd} - \text{LastByteRead})

The sender in turn keeps the data in flight below this value:

LastByteSent−LastByteAcked≤min⁡(cwnd,rwnd)\text{LastByteSent} - \text{LastByteAcked} \le \min(\text{cwnd}, \text{rwnd})

Worked example: RcvBuffer = 20000 bytes, LastByteRcvd = 15000, LastByteRead = 9000.

unread data in the buffer = 15000 − 9000 = 6000 bytes
rwnd = 20000 − 6000 = 14000 bytes

PITFALL · the rwnd = 0 deadlock. If the receiver said rwnd = 0 and has no data to send, it doesn’t announce the new rwnd. The sender could wait forever. That is why the sender sends 1-byte probe segments (zero window probes) while the window is zero.

The window is also a rate limit: at most one window’s worth of data is sent per RTT. Without window scaling, rwnd is at most 65535 bytes, and with RTT 50 ms the rate is at most 65535⋅8/0.05≈10.4965535 \cdot 8 / 0.05 \approx 10.49 Mbps.

Congestion control: cwnd and ssthresh

When the queues of the routers in the middle of the network fill up, packets are dropped. TCP gets no explicit signal from the network (classic TCP, the end-to-end approach). It treats loss as a sign of congestion and adjusts the congestion window (cwnd) on the sender side. The rate becomes roughly cwnd/RTT\text{cwnd} / RTT.

There are three phases:

PhaseRuleChange in one RTT
Slow startcwnd += 1 MSS per ACK×2
Congestion avoidancecwnd += MSS·(MSS/cwnd) per ACK+1 MSS
Fast recovery (Reno)After three duplicate ACKscwnd = ssthresh + 3, then linear

Reactions to loss:

EventssthreshTahoe cwndReno cwnd
3 duplicate ACKs (triple duplicate ACK)cwnd / 21 MSSssthresh + 3 MSS
Timeoutcwnd / 21 MSS1 MSS

When three duplicate ACKs arrive, the sender resends the missing segment immediately without waiting for the timeout. This is called fast retransmit. Why three? One or two duplicate ACKs can also come from mere reordering.

Worked example (fast retransmit): the sender sends segments 1 through 6, and segment 2 is lost. When segment 1 arrives, the receiver indicates that it wants segment 2. As segments 3, 4 and 5 arrive, the same ACK is repeated three times:

arriving seg   ACK (expected)   duplicate count at sender
1              2                -
3              2                1st duplicate
4              2                2nd duplicate
5              2                3rd duplicate → seg 2 is resent immediately

There is no need to wait for segment 6 to arrive or for the timer to expire. The loss is repaired in about one RTT.

AIMD (additive increase, multiplicative decrease): linear increase when there is no loss, halving on loss. Two AIMD connections sharing the same bottleneck approach an equal share over time. This is TCP’s fairness property.

TIP · the table rule. On this page, traces are written per round (RTT). When doubling cwnd in slow start, if you would exceed ssthresh, we stop at ssthresh: cwnd = min(2·cwnd, ssthresh). Some instructors skip the +3 in Reno and write cwnd = ssthresh. On the exam, read the question’s rule.

Worked example: a Tahoe and Reno trace

Start: cwnd = 1 MSS, ssthresh = 8 MSS. At the end of round 12, three duplicate ACKs are seen.

round :   1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
Tahoe :   1  2  4  8  9 10 11 12 13 14 15 16  1  2  4  8  9 10 11 12
Reno  :   1  2  4  8  9 10 11 12 13 14 15 16 11 12 13 14 15 16 17 18
ssth  :   8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8

Step by step:

  • Rounds 1-4: slow start, 1 → 8. In round 4, cwnd = ssthresh = 8, and we are now in congestion avoidance.
  • Rounds 5-12: +1 per round, 9 → 16.
  • Three duplicate ACKs at the end of round 12: ssthresh = 16 / 2 = 8 (it stays the same).
  • Tahoe: cwnd = 1, slow start again: 1, 2, 4, 8 (rounds 13-16), then 9, 10, 11, 12.
  • Reno: cwnd = 8 + 3 = 11 (round 13), then linear: 12, 13, … 18.

Eight rounds later Reno is at 18 and Tahoe at 12. That is the gain of fast recovery.

Typical things the questions ask: “In which rounds is it slow start?” (the rounds where cwnd < ssthresh), “Is the loss detection a triple duplicate ACK or a timeout?” (if cwnd drops to 1 and it is Reno, it is a timeout; if it is halved, it is a triple duplicate ACK), “What is ssthresh in round n?” (half of the cwnd at the last loss).

Average TCP throughput

In congestion avoidance the window rises to the value W at the moment of loss, halves, and rises again. The average of the sawtooth is 34W\frac{3}{4}W:

average rate≈0.75⋅WRTT\text{average rate} \approx \frac{0.75 \cdot W}{RTT}

Worked example: W = 40 segments, MSS = 1500 bytes, RTT = 100 ms.

W = 40 × 1500 × 8 = 480000 bit
0.75 × 480000 / 0.1 s = 3600000 bit/s = 3.6 Mbps

RTT estimation and timeout

If the timeout is too short, there are unnecessary retransmissions; if it is too long, the reaction to loss is late. TCP smooths the measured round-trip times (SampleRTT) with an exponentially weighted moving average (EWMA):

EstimatedRTT=(1−α) EstimatedRTT+α SampleRTT,α=0.125\text{EstimatedRTT} = (1-\alpha)\,\text{EstimatedRTT} + \alpha\,\text{SampleRTT}, \quad \alpha = 0.125

DevRTT=(1−β) DevRTT+β ∣SampleRTT−EstimatedRTT∣,β=0.25\text{DevRTT} = (1-\beta)\,\text{DevRTT} + \beta\,\lvert \text{SampleRTT} - \text{EstimatedRTT} \rvert, \quad \beta = 0.25

TimeoutInterval=EstimatedRTT+4⋅DevRTT\text{TimeoutInterval} = \text{EstimatedRTT} + 4\cdot\text{DevRTT}

Worked example: EstimatedRTT = 100 ms, DevRTT = 10 ms, new SampleRTT = 140 ms.

Est     = 0.875 × 100 + 0.125 × 140 = 87.5 + 17.5 = 105 ms
Dev     = 0.75 × 10 + 0.25 × |140 − 105| = 7.5 + 8.75 = 16.25 ms
Timeout = 105 + 4 × 16.25 = 170 ms

PITFALL · the update order. The order in the textbook: first EstimatedRTT, then DevRTT with the new Est. RFC 6298, on the other hand, updates DevRTT first with the old Est: Dev = 0.75·10 + 0.25·|140 − 100| = 17.5, Timeout = 175 ms. If the question doesn’t specify the order, use the textbook order and state the order you used.

If several samples arrive, chain the same step. Starting with Est = 80, Dev = 8 and samples 120, 60, 96 ms:

sample  EstimatedRTT   DevRTT       Timeout
120     85             14.75        144
60      81.875         16.53125     148
96      83.640625      15.48828125  145.59375

A single large sample (120) moves Est by only 5 ms but increases Dev immediately. What really protects the timeout is the Dev term.

Two additional rules:

  • Karn’s algorithm: no SampleRTT is taken from the ACK of a retransmitted segment, because it is unclear which copy the ACK belongs to.
  • Exponential backoff: on a timeout, the next timeout doubles (1.25 s → 2.5 s → 5 s). When a new ACK arrives, return to the formula.

Common mistakes

Wrong ideaCorrect
Slow start grows slowly (linearly)It is exponential, ×2 every RTT
Flow control = congestion controlFlow: the receiver (rwnd). Congestion: the network (cwnd)
Window = cwndWindow = min(cwnd, rwnd)
On loss ssthresh is half the old ssthreshHalf of the cwnd at the moment of loss
Reno halves on a timeout tooOn a timeout Reno also goes to cwnd = 1
Tahoe halves on three duplicate ACKsTahoe goes to cwnd = 1 on every loss
Average rate = W / RTT≈ 0.75 · W / RTT (sawtooth)
Timeout = EstimatedRTTA safety margin of 4·DevRTT is added
RTT is also measured from a retransmitted segmentKarn: it is not measured

Test yourself

Exam-style questions. Solve them on paper first, then reveal the answer.

Question 1easy

A TCP receiver has RcvBuffer = 16384 bytes, LastByteRcvd = 31000 and LastByteRead = 22000. What rwnd does it advertise?

Show answer
7384 bytes

Data waiting in the buffer that the application has not yet read: 31000 − 22000 = 9000 bytes.
rwnd = RcvBuffer − (LastByteRcvd − LastByteRead) = 16384 − 9000 = 7384 bytes.

Question 2medium

A sender has LastByteSent = 50000 and LastByteAcked = 42000. Its cwnd is 12000 bytes and the last advertised rwnd is 10000 bytes. How many more bytes may it send right now?

Show answer
2000 bytes

Data in flight (unacknowledged): 50000 − 42000 = 8000 bytes.
Effective window = min(cwnd, rwnd) = min(12000, 10000) = 10000 bytes.
Additional bytes that can be sent: 10000 − 8000 = 2000 bytes.

Question 3medium

With no window scaling, rwnd is at most 65535 bytes. What is the maximum TCP throughput on a path with RTT = 50 ms?

Show answer
≈ 10.49 Mbps

At most one window is sent per RTT: throughput ≤rwndRTT\le \dfrac{\text{rwnd}}{RTT}.65535×8 bit0.05 s=10 485 600\dfrac{65535 \times 8\ \text{bit}}{0.05\ \text{s}} = 10\,485\,600 bit/s ≈ 10.49 Mbps. Whatever the capacity of the line, you can't exceed this limit.

Question 4easy

During slow start (no losses), how does cwnd change?

  1. It increases by 1 MSS per RTT
  2. It doubles every RTT (increases by 1 MSS per ACK)
  3. It halves every RTT
  4. It stays constant until a timeout
Show answer
B) It doubles every RTT (increases by 1 MSS per ACK)

In slow start each arriving ACK increases cwnd by 1 MSS. Since cwnd ACKs arrive in one RTT, the window doubles every RTT: 1, 2, 4, 8... The name says "slow" but the growth is exponential.

Question 5medium

A connection starts with cwnd = 1 MSS and ssthresh = 64 MSS. With no losses, after how many RTTs does cwnd first reach 32 MSS?

Show answer
5 RTTs

Round 1: 1, round 2: 2, round 3: 4, round 4: 8, round 5: 16, round 6: 32.
From round 1 to round 6, 5 RTTs pass. In general 2k2^k MSS is reached in kk RTTs: 25=322^5 = 32.

Question 6hard

TCP Reno starts with cwnd = 1 MSS, ssthresh = 16 MSS. A timeout occurs at the end of round 9, and a triple duplicate ACK at the end of round 16. Using cwnd = min(2·cwnd, ssthresh) in slow start and cwnd = ssthresh + 3 after a triple duplicate ACK, give cwnd in rounds 10, 14 and 17, and ssthresh in round 17.

Show answer
Round 10: 1, round 14: 10, round 17: 9; ssthresh = 6

Rounds 1-5 slow start: 1, 2, 4, 8, 16. Rounds 6-9 congestion avoidance: 17, 18, 19, 20.
Timeout at the end of round 9: ssthresh = 20/2 = 10, cwnd = 1. Round 10: 1.
Rounds 11-14: 2, 4, 8, then min(16, 10) = 10. Round 15: 11, round 16: 12.
Triple duplicate ACK at the end of round 16: ssthresh = 12/2 = 6, Reno cwnd = 6 + 3 = 9 (round 17), then it grows linearly.

Question 7hard

Same scenario as before but with TCP Tahoe. What is cwnd in round 20?

Show answer
6

Up to round 16 it is the same as Reno (on a timeout both behave the same): cwnd = 12 in round 16.
Tahoe drops cwnd to 1 on a triple duplicate ACK too, and ssthresh = 6.
Round 17: 1, round 18: 2, round 19: 4, round 20: min(8, 6) = 6.

Question 8medium

Why does TCP Reno react more mildly to a triple duplicate ACK than to a timeout?

  1. Duplicate ACKs mean the receiver's buffer is full
  2. Duplicate ACKs show later segments are still getting through, so congestion is mild; a timeout suggests heavier congestion
  3. A timeout only happens with UDP
  4. Duplicate ACKs are ignored by Reno
Show answer
B) Duplicate ACKs show later segments are still getting through, so congestion is mild; a timeout suggests heavier congestion

The arrival of duplicate ACKs shows that segments after the lost one reached the receiver: the network is still carrying traffic. So Reno halves the window (fast recovery) and continues. At a timeout no ACK has arrived at all, the situation is considered worse, and cwnd drops to 1 MSS.

Question 9medium

Using the approximation average throughput = 0.75 · W / RTT, find the average throughput for W = 20 segments, MSS = 1460 bytes, RTT = 80 ms.

Show answer
≈ 2.19 Mbps

W in bytes: 20 × 1460 = 29200 bytes = 233600 bits.0.75×2336000.08=2 190 0000.75 \times \dfrac{233600}{0.08} = 2\,190\,000 bit/s ≈ 2.19 Mbps.
Where 0.75 comes from: under AIMD the window traces a sawtooth between W/2 and W, with average 3W/4.

Question 10medium

EstimatedRTT = 200 ms and DevRTT = 20 ms. A new SampleRTT of 160 ms arrives. With α = 0.125 and β = 0.25, updating EstimatedRTT first and then DevRTT with the new EstimatedRTT, find the new TimeoutInterval.

Show answer
290 ms

EstimatedRTT = 0.875 × 200 + 0.125 × 160 = 175 + 20 = 195 ms.
DevRTT = 0.75 × 20 + 0.25 × |160 − 195| = 15 + 8.75 = 23.75 ms.
TimeoutInterval = 195 + 4 × 23.75 = 195 + 95 = 290 ms.

Question 11hard

EstimatedRTT = 80 ms, DevRTT = 8 ms. Two samples arrive in order: 120 ms then 60 ms. Using α = 0.125, β = 0.25 (EstimatedRTT updated first), give EstimatedRTT, DevRTT and TimeoutInterval after both samples.

Show answer
EstimatedRTT = 81.875 ms, DevRTT ≈ 16.53 ms, Timeout = 148 ms

Sample 1 (120): Est = 0.875·80 + 0.125·120 = 70 + 15 = 85. Dev = 0.75·8 + 0.25·|120 − 85| = 6 + 8.75 = 14.75. (Timeout 85 + 59 = 144.)
Sample 2 (60): Est = 0.875·85 + 0.125·60 = 74.375 + 7.5 = 81.875. Dev = 0.75·14.75 + 0.25·|60 − 81.875| = 11.0625 + 5.46875 = 16.53125.
Timeout = 81.875 + 4·16.53125 = 81.875 + 66.125 = 148 ms.

Question 12medium

A TCP sender's TimeoutInterval is 1.25 s. The same segment times out twice in a row. What is the timeout value used for the next retransmission?

Show answer
5 s

After every timeout TCP doubles the interval (exponential backoff) and does not recompute it from the EWMA: 1.25 → 2.5 (after the 1st timeout) → 5 s (after the 2nd timeout). When a new ACK arrives, the value is again computed from the EWMA formula.

Verification: rwnd and sendable-byte calculations, round-by-round cwnd/ssthresh traces (a simulator written for Tahoe and Reno, using the rule cwnd = min(2·cwnd, ssthresh) in slow start), 0.75·W/RTT throughputs and EWMA/DevRTT/Timeout values were computed with node (verify/SEN2008/08.mjs).

Review card

rwnd = RcvBuffer − (LastByteRcvd − LastByteRead) Data in flight = LastByteSent − LastByteAcked ≤ min(cwnd, rwnd) Rate ≤ window / RTT 65535 B / 50 ms ≈ 10.49 Mbps Slow start: cwnd 1 MSS, +1 per ACK → ×2 per RTT, up to ssthresh Congestion avoidance: +1 MSS per RTT (linear, additive increase) 3 duplicate ACKs: fast retransmit. ssthresh = cwnd/2 Tahoe: cwnd = 1, slow start Reno: cwnd = ssthresh + 3, then linear Timeout (both): ssthresh = cwnd/2, cwnd = 1, slow start Average rate ≈ 0.75 · W / RTT (AIMD sawtooth, between W/2 and W) EstRTT = 0.875·EstRTT + 0.125·Sample DevRTT = 0.75·DevRTT + 0.25·|Sample − EstRTT| Timeout = EstRTT + 4·DevRTT on timeout the interval ×2 Karn: don't take SampleRTT from a retransmitted segment