open atlas
↑ Back to track
Networking & Protocols NET · 10 · 05

Loss detection and congestion control

QUIC uses monotonically increasing packet numbers and pluggable congestion control — NewReno, CUBIC, BBR — eliminating Karn''''s algorithm ambiguity and enabling per-application CC upgrades.

NET Middle ◷ 12 min
Level
FoundationsJuniorMiddleSenior

TCP retransmits a dropped packet with the same sequence number. The ACK that comes back is ambiguous — did the server acknowledge the original send or the retransmit? QUIC gives every packet a unique number, and this single change makes loss detection unambiguous and congestion control pluggable.

Monotonic packet numbers

QUIC packet numbers are strictly increasing integers — a lost packet gets a new packet number on retransmit. Unlike TCP where retransmitted packets carry the same sequence number (creating ambiguity about which send the ACK acknowledges — Karn’s algorithm workaround), QUIC never reuses a packet number.

ACK ranges: QUIC ACK frames list ranges of acknowledged packet numbers:

ack_ranges: [1000..1005, 1008..1010]

Gap at 1006 and 1007 means those packets are not yet received. This is equivalent to TCP SACK but native to the protocol.

Loss declaration happens when:

  1. A later packet is acknowledged and a reorder window has expired (typically 1.5× max RTT after the out-of-order packet was sent).
  2. Or the PTO (Probe Timeout) fires — analogous to TCP’s RTO but computed per packet-number space.

The monotonic model is simpler than TCP’s but requires retransmitted frames to be re-serialized with new packet numbers — a minor CPU cost.

Packet number model: TCP vs QUIC
TCP (ambiguous)
Send seq=100 → LOST
Retransmit seq=100 → ACK 101
ACK: original or retransmit?
→ Karn’s algorithm required
QUIC (unambiguous)
Send pkt#100 → LOST
Retransmit as pkt#101 → ACK 101
ACK#101 = retransmit confirmed
→ No ambiguity, no workaround

Pluggable congestion control

Because QUIC lives in user space, congestion control is pluggable. RFC 9002 specifies NewReno as the baseline. Major implementations ship:

  • NewReno — slow start, additive increase, halve cwnd on loss.
  • CUBIC (quiche from Cloudflare, Linux kernel standard) — aggressive probing after loss with a cubic function.
  • BBR (Google, YouTube, Cloudflare edges) — model bottleneck bandwidth and minimum RTT; ignore random loss.
  • HyStart++ — exit slow start early by detecting queueing, used with CUBIC.

Applications can select the algorithm at connection open. A single QUIC library can support multiple algorithms. This agility is impossible with kernel TCP where changing congestion control requires recompiling or sysctl changes across millions of servers. Together these four algorithms cover the full deployment spectrum — NewReno for safe defaults, CUBIC for aggressive LAN probing, BBR for high-throughput WAN; without pluggable CC, QUIC would be locked to the same algorithm for a decade the way kernel TCP has been.

The trade-off: Flexibility makes benchmarking hard — comparing two QUIC stacks with different CC algorithms is not a fair comparison of QUIC itself.

Quiz

Why does QUIC avoid Karn's algorithm, and what design choice makes this possible?

Quiz

Why is pluggable congestion control in QUIC significant compared to kernel TCP?

Which RFC?

Which RFC defines QUIC's loss detection algorithm and congestion control baseline?

Why this works

Why not just use TCP’s congestion control in QUIC? TCP’s congestion control is implemented in the kernel’s socket layer, where it has direct access to packet timestamps, kernel buffers, and NIC offload. Reimplementing it in user space (as QUIC does) costs CPU — each packet must be processed by user code without hardware assistance. The benefit: user space can iterate faster, can access application-level metadata (e.g., video stream priority) to make smarter CC decisions, and can be updated with the application without touching the OS.

QUIC congestion control algorithms
RFC 9002 baseline
NewReno (slow start + AIMD)
Cloudflare quiche default
CUBIC (aggressive probing)
Google YouTube / GCP
BBR (bandwidth-RTT model)
User-space CC update cycle
weekly (vs monthly+ for kernel TCP)
Per-connection CC selection
at connection open
Recall before you leave
  1. 01
    What is Karn's algorithm and why does QUIC not need it?
  2. 02
    How does QUIC's ACK range mechanism work, and what TCP feature does it resemble?
  3. 03
    What is PTO in QUIC and how does it differ from TCP's RTO?
Recap

TCP’s sequence number reuse on retransmit creates Karn’s algorithm ambiguity — you cannot measure RTT from a retransmitted ACK. QUIC eliminates this by assigning every send a new, strictly increasing packet number. ACK frames carry ranges so gaps in acknowledged numbers reveal lost packets exactly, equivalent to TCP SACK but always active. Loss is declared via a reorder window or PTO (computed per packet-number space). Because QUIC runs in user space, congestion control is pluggable: RFC 9002 specifies NewReno as the baseline, but CUBIC and BBR ship in major libraries and can be selected per-connection. Applications on CDN edges can update their CC algorithm weekly without touching the kernel. Now when you read a QUIC implementation’s configuration and see a cc_algorithm = bbr option, you will know what made that possible — user-space placement meaning the protocol can swap the entire loss model with a config flag, no kernel patch required.

Practice

Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.

recallapplystretch0 of 5 done
Connected lessons
appears again in165

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.