§8.2
Chapter 08 · Handling High-Latency Networks and Long RTT Effects

§8.2Impact of Loss, Reordering, and ACK Delays on Recovery

RFC 9002

Learning objective. Understand why loss, reordering, and ACK delay hurt more on a long-RTT path: how the packet- and time-threshold rules interact with reordering, how reported ACK delay is removed from the RTT estimate, and why every PTO-driven retransmit costs a full, growing round trip.

The thing that changes on a long path: the cost of being wrong #

The loss-detection machinery of §3.2 is identical at any RTT. What changes on a long path is the cost of each recovery event: a retransmit that clears in 2 ms on a LAN costs 200 ms over satellite, and a mistaken retransmit wastes that same 200 ms plus congestion-window room. On long paths, recovery accuracy and timing dominate, so this section re-reads three mechanisms (thresholds, ACK delay, and the PTO) through the high-latency lens.

ReceiverSenderlong path — RTT 200 ms · everyretransmit costs a full RTTgot 10, 12, 13 — 11missingadjusted_rtt =latest_rtt −ack_delay, flooredat min_rtt11 is 3 behindlargest → packetthreshold →declared lostpacket 11 finallyarrives late (wasonly reordered, notlost)spurious retransmit — reorderingbeyond kPacketThreshold(3) /9·8×RTT looked like lossno ACK at all? PTO= srtt + 4·rttvar +max_ack_delay,doubling each timepacket 10packet 11 (reordered — takes theslow path)packet 12packet 13ACK largest=13 (ack_delay = 20ms)PTO probe (ack-eliciting) —recovery latency grows with RTT
Fig. 8.2-1Reordering and ACK delay on a long path. Packet 11 is only reordered, but it falls 3 behind the largest acknowledged, so the packet threshold declares it lost and the sender retransmits spuriously — costing a full RTT. Reported ack_delay is subtracted from the RTT sample (floored at min_rtt), and when nothing is acknowledged the PTO — smoothed_rtt + 4·rttvar + max_ack_delay, doubling each expiry — governs how long recovery takes.RFC 9002 §6.1.1, §5.3, §6.2.1

Reordering versus the loss thresholds #

QUIC declares a packet lost by one of two triggers ([RFC 9002 §6.1]): the packet threshold — a packet is lost once 3 later-numbered packets are acknowledged (kPacketThreshold = 3, [RFC 9002 §6.1.1]) — or the time threshold, once it is older than max(9/8 × max(smoothed_rtt, latest_rtt), kGranularity) (kTimeThreshold = 9/8, [RFC 9002 §6.1.2]). Both exist to tolerate reordering: a packet that arrives a little late, or a little out of order, is not immediately called lost.

The trouble is that neither threshold scales with the degree of reordering on a path. If a network can reorder a packet by more than 3 positions (common on multi-path or load-balanced long-haul links), the packet threshold fires while the packet is merely in transit, and the sender retransmits something that was never lost. That spurious retransmission costs a full RTT of useless data and needlessly cuts the congestion window. The time threshold's 9/8 factor is the reordering cushion in the time domain, and it does scale with RTT (via smoothed_rtt), which is why on high-reorder paths the time threshold is the gentler of the two. QUIC's design accepts a small spurious-retransmit rate as the price of fast recovery; on a long path that price is higher, which is the whole reason §8.3 and §8.4 work to avoid needing recovery at all.

ACK delay and the RTT estimate #

A receiver may hold an ACK briefly to batch it, and it reports how long it waited in the ACK frame's ACK Delay field ([RFC 9000 §19.3]). The sender must remove that reported delay before it pollutes the RTT estimate, because the delay is the receiver's processing choice, not the network's latency. The rule is precise ([RFC 9002 §5.3]):

adjusted_rtt = latest_rtt
if latest_rtt >= min_rtt + ack_delay:
    adjusted_rtt = latest_rtt - ack_delay
smoothed_rtt = 7/8 · smoothed_rtt + 1/8 · adjusted_rtt

Two safeguards matter on long paths. The subtraction only applies while the result stays at or above min_rtt, the sender's floor, computed from locally observed times and never adjusted for reported delay ([RFC 9002 §5.2]). So a peer that misreports a huge ack_delay cannot drive the estimate implausibly low. And after the handshake is confirmed, the sender caps the delay it will honour at the peer's advertised max_ack_delay (default 25 ms, [RFC 9000 §18.2]); the peer "promises to never intentionally delay acknowledgments... by more than the indicated value," and any excess "accrues to the RTT estimate" ([RFC 9000 §13.2.1]). Get this wrong and the smoothed RTT inflates, which (because it feeds the PTO) makes every subsequent recovery slower.

The PTO: recovery latency that grows with RTT #

When nothing is acknowledged (the tail of a flight is lost, or an ACK is lost), there is no threshold to fire, and recovery falls to the Probe Timeout ([RFC 9002 §6.2]):

PTO = smoothed_rtt + max(4 · rttvar, kGranularity) + max_ack_delay

The PTO is built from the RTT estimate, so it is already long on a long path. Worse, each time it expires without progress the backoff doubles it ([RFC 9002 §6.2.1]), so "connection recovery latency increases exponentially as packets continue to be dropped" ([RFC 9002 §6.2.4]). A PTO does not mark packets lost or collapse the congestion window ([RFC 9002 §6.2, §4.7]); it sends one or two ack-eliciting probe packets to elicit an ACK and get the connection moving again. On a 200 ms path a single lost tail packet already costs a ~450 ms PTO before the first probe. A second loss costs ~900 ms. This is why tail loss is disproportionately painful at high RTT, and why keeping the flight filled (so a loss is detected by threshold, not by timeout) is a latency strategy in itself.

Follow Figure 8.2-1 on a 200 ms path. The sender sends packets 10–13; the network delays 11 onto a slower route. The receiver acknowledges 10, 12, and 13, reporting a 20 ms ACK delay. On the sender, 11 is now 3 packets behind the largest acknowledged (13), so the packet threshold declares it lost and the sender retransmits, but 11 was only reordered and arrives moments later. The retransmit was spurious: 200 ms of bandwidth and a congestion-window cut, spent because the path reorders by more than 3. Meanwhile the 20 ms ack_delay is subtracted from the RTT sample (staying above min_rtt), keeping the estimate honest. Had the receiver simply gone silent instead, the sender would have waited a full PTO (smoothed_rtt + 4·rttvar + max_ack_delay, ~450 ms and doubling) before probing.

Note

min_rtt is the anchor that makes all of this robust. It is tracked from locally observed send/receive times only, never adjusted for the peer's reported ack_delay ([RFC 9002 §5.2]), so it is a trustworthy lower bound: the ACK-delay subtraction is floored at it, and loss-detection uses it to reject implausibly small samples. On a path whose true RTT later increases, though, min_rtt does not adapt upward on its own — it is reset on migration or after persistent congestion, so a stale min_rtt after a path change is a real diagnostic to watch for (§8.5).

In practice

editorial On a long or lossy path, watch two trace signals. First, the spurious-retransmission rate: if packets you retransmit are later acknowledged as originally sent, the path reorders beyond kPacketThreshold and you are paying full-RTT penalties for nothing. Some stacks expose a reordering-tolerance knob, but the honest fix is usually fewer, larger, better-paced flights. Second, the PTO count and backoff: repeated PTOs with doubling mean tail loss is dominating recovery; filling the congestion window so losses are detected by threshold instead of timeout is worth more here than any parameter tweak. Both are measured directly in §8.5.

Takeaways #

Loss, reordering, and ACK delay cost the same mechanism at any RTT but far more time on a long path. Reordering beyond kPacketThreshold (3) triggers spurious retransmits that waste a full RTT; reported ack_delay is subtracted from the RTT sample but floored at the locally observed min_rtt and capped at max_ack_delay; and tail loss falls to a PTO that is already long and doubles on each expiry. The response is to avoid needing recovery, through the latency-reduction strategies of §8.3 and the concurrency design of §8.4.