Escape from the Kernel – QUIC, HTTP/3 and the End of TCP Ossification
🎧 Listen to this article
Cloud Computing · 2026-10-27
Fully AI-generated article (no prior review).
The Hook
Between September 2010 and April 2011, a group of researchers from Tokyo, Bucharest and London shipped an odd measurement tool to volunteers around the world. The program opened TCP connections to a server and stuffed the packets with things that did not belong there: unknown TCP options, deliberate gaps in the sequence number space, inconsistent retransmissions. The question was not whether the Internet would carry these packets. The question was whether it would carry them unmodified.
The answer was sobering. On port 80, an unknown TCP option in the SYN packet failed to reach the receiver on 14 % of the measured paths — someone along the way had removed it. 18 % of the paths on port 80 rewrote the sequence numbers in at least one direction. And when the researchers tested whether you may leave a gap in the sequence space open — a technique that any extension transmitting data out of order would need — it failed in roughly a quarter of cases even on a completely unremarkable, unregistered port.
That paper is called "Is it Still Possible to Extend TCP?" (Honda et al., ACM IMC 2011). Its finding became the founding myth of a new transport protocol — and it is almost always misquoted. The authors do not conclude that TCP can no longer be extended. Their abstract says, in so many words: we can still extend TCP, but the design of such extensions is very constrained, because it has to take prevalent middlebox behaviour into account.
Six years later, 21 Google engineers framed the same problem economically rather than technically. Their 2017 SIGCOMM paper contains the sentence that set the direction for the following decade: deploying changes to TCP has reached a point of diminishing returns, where simple protocol changes are now expected to take upwards of a decade to see significant deployment. Not for want of ideas. But because TCP sits inside the operating system kernel — and because between sender and receiver there are devices that believe they understand TCP.
The consequence was radical: build the transport anew, in user space, on top of UDP, and encrypt it so thoroughly that nobody along the path can see enough to interfere. The result is called QUIC, has been an IETF Standards Track document since May 2021, and is today supported by over 40 % of all websites according to a commercial survey.
And then comes the twist that makes this article worth writing: on a gigabit link, QUIC in the Chrome browser was up to 45.2 % slower than the old TCP combination in a 2024 measurement — lightweight command-line clients lost only 7–16 % (cURL) or 8–12 % (quic_client) in the same setup. Not because the design was wrong, but because the escape from the kernel carries a price that the kernel had previously been paying.
Part 1: The Problem – Why Protocols Ossify
Two Layers of Concrete
TCP's ossification has two independent causes, and it is worth separating them, because QUIC attacks each one differently.
First layer: the implementation layer. TCP is commonly implemented in the operating system kernel. The Google paper describes the consequence plainly: pushing changes to TCP stacks typically requires OS upgrades, and even server upgrades you control yourself can take many months. For clients — millions of mobile phones, televisions, embedded devices — months turn into a decade, or never.
Second layer: the path layer. Along the way sit firewalls, NATs, load balancers, transparent proxies, traffic shapers. The Google paper puts it this way: middleboxes have accidentally become key control points in the Internet's architecture. These devices parse TCP headers. What they do not recognise they treat conservatively: they strip it, rewrite it, or drop the packet.
What Honda et al. Actually Measured
The measurement covered 142 access networks in 24 countries (home connections, hotspots, cellular, universities, enterprises, hosting) and three ports: 80, 443, and the unassigned port 34343 as a control group.
| Test | Port 34343 | Port 80 | Port 443 |
|---|---|---|---|
| Unknown option in SYN passes through | 96 % | 86 % | 94 % |
| Unknown option in SYN removed | 4 % | 14 % | 6 % |
| Sequence numbers unchanged | 93 % | 82 % | 90 % |
| Sequence gap by data segment permitted | 97 % | 85 % | 95 % |
| Sequence gap by ACK segment permitted | 76 % | 67 % | 74 % |
Three things stand out.
First: the port matters. Port 80 is the most hostile, because HTTP-specific middleboxes and proxies are particularly common there. Same protocol, same packets, different port — different result. (A note on source fidelity: in the running text of Section 4.1 the authors state that "only 80 % of paths" passed options on port 80, while their Table 3 reports 86 % there. The table values are the ones above; the discrepancy is an inconsistency in the paper, not in this article.)
Second: the ACK row is the real catastrophe. Only three quarters of the paths permitted a sequence gap opened by an ACK segment. The authors themselves call this result a surprise: even on port 34343, middleboxes interfered with end-to-end behaviour 24 % of the time. Any extension that deliberately transmits data out of order — and that is exactly what you need in order to avoid head-of-line blocking — runs into a wall here.
Third: the averages are not the problem, the minority is. If an extension works on 86 % of paths, you cannot simply switch it on — you need a fallback path to regular TCP behaviour, and that fallback has to remain available forever. This is precisely why Honda et al. arrive at "extensible, but severely constrained" rather than "not extensible": extensions have to be negotiated in the SYN exchange, and falling back to regular TCP has to be acceptable.
The Way Out That Was Not a Way Out
You cannot fix middleboxes. There is no authority that updates them. So two strategies remain: you go around them, or you make yourself unreadable to them. QUIC does both.
Part 2: The Design – What QUIC Actually Is
RFC 9000, "QUIC: A UDP-Based Multiplexed and Secure Transport", edited by Jana Iyengar (Fastly) and Martin Thomson (Mozilla), was published in May 2021 as a Standards Track document. Its abstract is remarkably terse: the document defines the core of the QUIC transport protocol; QUIC provides applications with flow-controlled streams for structured communication, low-latency connection establishment, and network path migration, together with security measures for confidentiality, integrity and availability. Everything else — TLS integration, loss detection, an exemplary congestion control algorithm — is delegated to accompanying documents.
UDP Is a Means, Not an End
QUIC does not run on UDP because UDP is good. RFC 9000 justifies the choice explicitly in Section 1: QUIC packets are carried in UDP datagrams to better facilitate deployment in existing systems and networks. UDP is the lorry that fits through the existing gates. Everything that makes a transport protocol — connection state, streams, flow control, loss detection, congestion control — QUIC builds anew on top of it.
That QUIC is consequently typically implemented in user space is, incidentally, not a topic for the standard: the abstract and Section 1 of RFC 9000 say nothing about it. The user-space character is a property of the prevalent implementations — prominently named as a design motive in the 2017 Google paper — not a stipulation of the protocol. That sounds like a quibble, but it becomes the decisive point in Part 7.
Streams: Independence, Precisely Worded
The popular narrative goes: "QUIC eliminates head-of-line blocking." This is the point at which a fact-checker has to become careful. In the abstract, Section 1 and Section 2 of RFC 9000, the term "head-of-line blocking" does not appear at all — in this family of documents it shows up in RFC 9114, specifically in Section 4.2.1, where it concerns compression rather than transport. What the document does say is more precise and weaker:
Streams can be created by either endpoint, can concurrently send data interleaved with other streams, and can be cancelled. And then the key sentence from Section 2: QUIC provides no means of ensuring ordering between bytes on different streams.
That is a statement about ordering guarantees, not directly about blocking. But it is the foundation from which freedom from blocking follows: if there is no ordering between streams, a receiver can deliver stream B while a gap still yawns in stream A. Within a stream, by contrast, order remains binding — Section 4.3 records that packet loss can cause gaps in the receive buffer, preventing the application from consuming data. Head-of-line blocking therefore does not disappear; it is demoted from the connection level to the stream level.
This distinction is not hair-splitting. It explains why HTTP/3 needed a new header compression scheme (Part 5), and why a single large download structurally gains little from QUIC.
Flow Control on Two Levels
RFC 9000 Section 4.1 describes a limit-based flow control scheme with two levels:
- Stream level – prevents a single stream from consuming the entire receive buffer for a connection. Credit is granted via
MAX_STREAM_DATA, blocking is signalled viaSTREAM_DATA_BLOCKED. - Connection level – limits the total across all streams. Credit via
MAX_DATA, signal viaDATA_BLOCKED.
Senders must not exceed either limit. In addition, the number of concurrently open streams is bounded (MAX_STREAMS, STREAMS_BLOCKED; Section 4.6, "Controlling Concurrency"). Anyone who has built a backpressure mechanism in a distributed system will recognise a cleanly two-tier credit scheme here — and the insight that a single global window does not suffice once multiplexing enters the picture.
Connection IDs and Migration – with One Hard Limitation
TCP identifies a connection by the four-tuple of IP addresses and ports. If the address changes — Wi-Fi to cellular, NAT rebinding — the connection is dead. QUIC decouples identity from address: connections are not strictly bound to a single network path, and connection IDs allow a connection to be transferred to a new path. A connection therefore survives changes in network topology or address mappings, such as might be caused by NAT rebinding.
And now the sentence that nearly every summary omits — RFC 9000, Section 1, verbatim: only clients are able to migrate in this version of QUIC. Server migration is not provided for in QUIC version 1. A server with no mechanism for continuing connections across an address change should, per Section 5.2.3, even actively signal that it does not support migration (transport parameter disable_active_migration).
The flip side is in the document too: zero-length connection IDs are permitted, but with a shared IP/port combination they will cause failures in the presence of peer connection migration, NAT rebinding and client port reuse (Section 5.1). And Section 5.1.2 records as given behaviour that endpoints — as discussed in Section 9.5 — limit the use of a connection ID to packets sent from a single local address to a single destination address. Otherwise the connection ID itself becomes a linkability marker across network changes.
What QUIC Deliberately Does Not Do
A standard becomes good by naming its limits. RFC 9000 does so explicitly in several places:
- No prioritisation. Section 2.3: QUIC does not provide a mechanism for exchanging prioritization information. Priority comes from the application.
- No API. Sections 2.4 and 5.3: this document does not define an API for QUIC. Every library invents its own — anyone who has moved from quiche to msquic to quic-go has felt that.
- Version negotiation only half specified. Section 6 is titled "Version Negotiation" and defines version negotiation packets and their handling (6.1, 6.2); what remains open is the how. Section 6.2: how to perform version negotiation is left as future work. For a protocol whose reason for existing is de-ossification, that is a remarkable gap — see Part 8.
- No replay protection for 0-RTT. Section 5 records that 0-RTT provides no protection against replay attacks, and refers to RFC 9001.
Part 3: Encryption as Armour, Not as an Add-On
Here lies the real architectural trick. With TLS over TCP, the encryption is a tenant in somebody else's house: TLS records sit inside the TCP byte stream, while the TCP header itself stays in the clear and is therefore readable — and modifiable — by any middlebox.
QUIC inverts that. RFC 9001, "Using TLS to Secure QUIC" (Martin Thomson, Mozilla; Sean Turner, sn3rd; May 2021), describes in Section 3 that instead of carrying TLS records over QUIC as with TCP, TLS handshake and alert messages are carried directly over the QUIC transport — and that QUIC takes over the responsibilities of the TLS record layer. Section 4.1.3 puts it even more briefly: TLS record protection is not used by QUIC. Handshake data travels in CRYPTO frames (Section 4).
The consequences are concrete:
- TLS 1.3 is mandatory. Section 4.2: clients must not offer TLS versions older than 1.3, and an endpoint must terminate the connection if a version of TLS older than 1.3 is negotiated. A newer version is permitted provided it supports the TLS 1.3 features that QUIC uses.
- No ChangeCipherSpec, no TLS KeyUpdate. Section 2.1: neither of these messages is used by QUIC. QUIC has its own key update mechanism (Section 6).
- Header protection. Parts of the QUIC header — the packet number among them — are protected with a separately derived key. For a middlebox, not even the packet number is visible any more. But exactly what has to stay visible does stay visible: RFC 8999 ("Version-Independent Properties of QUIC", Martin Thomson, May 2021) fixes the properties that remain stable across QUIC versions — the header form bit, the version field in long-header packets, and the connection IDs. The same document notes in Section 7 that the QUIC version number does not appear in all QUIC packets, which means that reliably extracting information from a flow based on version-specific traits requires middleboxes to retain state for every connection ID they see. The attack surface for classifiers therefore shrinks drastically; it does not vanish.
This is de-ossification by cryptography: what stops middleboxes from interpreting QUIC semantics is not prohibition but unreadability.
The Price: 0-RTT and Replay
Connection establishment fuses cryptographic and transport parameter negotiation. RFC 9000, Section 1: the QUIC handshake combines negotiation of cryptographic and transport parameters; QUIC integrates the TLS handshake, although using a customized framing for protecting packets. The handshake is structured to permit the exchange of application data as soon as possible — including an option for clients to send data immediately (0-RTT), which requires some form of prior communication or configuration to enable.
And then the warning an architect ought to have tattooed somewhere. RFC 9001, Section 2.1, in substance: in a 0-RTT handshake the client uses information it has previously learned about the server to send application data immediately. This application data can be replayed by an attacker — 0-RTT is therefore not suitable for carrying instructions that might initiate any action that could cause unwanted effects if replayed.
In practice: an idempotent GET may go in 0-RTT. A POST /payments may not. Anyone who enables 0-RTT globally because it sounds so temptingly like "faster" in the configuration file is building a replay vulnerability into the payment path.
Part 4: Loss Detection Without Ambiguity
RFC 9002, "QUIC Loss Detection and Congestion Control" (Jana Iyengar, Fastly; Ian Swett, Google; May 2021), has the tersest abstract of the series: this document describes loss detection and congestion control mechanisms for QUIC. Section 4 places it in context: readers familiar with TCP's loss detection and congestion control will find algorithms here that parallel well-known TCP ones — however, protocol differences between QUIC and TCP contribute to algorithmic differences.
Four of those differences deserve to be named individually, because they show where a redesign removes complexity:
1. Monotonically increasing packet numbers. Section 3: packet numbers never repeat within a packet number space for the lifetime of a connection, and are sent in monotonically increasing order within a space, preventing ambiguity. The same section draws the consequence: this design obviates the need for disambiguating between transmissions and retransmissions, and eliminates significant complexity from QUIC's interpretation of TCP loss detection mechanisms. In TCP, the sequence number identifies data; an ACK does not say which transmission of that data arrived. RFC 9002 names this problem in Section 4.2 as the "retransmission ambiguity" problem. I am of the opinion that a considerable part of TCP's historically accumulated complexity traces back to exactly this ambiguity — the sources checked here do not enumerate the individual TCP mechanisms involved. QUIC separates transmission order from delivery order (Section 4.2) — and saves two decades of repair work in the process.
2. Separate packet number spaces. Section 4.1: QUIC uses separate packet number spaces for each encryption level, except that 0-RTT and all generations of 1-RTT keys use the same packet number space.
3. Explicit correction for delayed acknowledgments. Section 4.6: QUIC endpoints measure the delay incurred between when a packet is received and when the corresponding acknowledgment is sent, allowing a peer to maintain a more accurate RTT estimate. In TCP, a delayed acknowledgment is indistinguishable from network latency as far as the sender is concerned; QUIC turns it into a reported field.
4. No reneging. Section 4.4: QUIC does not allow a packet acknowledgment to be reneged, greatly simplifying implementations on both sides and reducing memory pressure on the sender.
On congestion control, the document is explicitly restrained. Section 7 specifies a sender-side congestion controller similar to TCP NewReno. The signals QUIC provides for congestion control are generic and designed to support different sender-side algorithms; a sender can unilaterally choose a different algorithm to use, such as CUBIC. The only mandate is that a sender using a different controller must conform to the congestion control guidelines of RFC 8085. NewReno is therefore the reference, not the requirement — and in practice the large deployments have long been speaking CUBIC or BBR.
Part 5: HTTP/3 – When the Application Has to Follow the Transport
RFC 9114, "HTTP/3", edited by Mike Bishop (Akamai) in June 2022, is the document in which it becomes apparent that a new transport is not free: the application layer has to follow suit.
The abstract describes the approach openly: the QUIC transport protocol has several features that are desirable in a transport for HTTP — stream multiplexing, per-stream flow control, and low-latency connection establishment; the document describes a mapping of HTTP semantics over QUIC, identifies HTTP/2 features that are subsumed by QUIC, and describes how HTTP/2 extensions can be ported to HTTP/3.
One Stream per Request-Response Pair
Section 2 says it verbatim: each request-response pair consumes a single QUIC stream. Section 4.1 is more precise: a request is sent on a request stream — a client-initiated bidirectional QUIC stream — and a client must send only a single request on a given stream. The client then closes its sending side; the server closes its own after the final response.
That makes the mapping as simple as it never was in HTTP/2: a request is a stream, not a stream identifier inside a shared TCP byte stream. If a packet is lost, the gap at first affects only that one request — with one exception, treated in the next subsection.
HPACK Had to Die
And here the sentence from Part 2 strikes back. Section 2 of RFC 9114, in substance: because HPACK relies on in-order transmission of compressed field sections — a guarantee that QUIC does not provide — HTTP/3 replaces HPACK with QPACK. QPACK uses separate unidirectional streams to modify and track field table state, while encoded field sections refer to the state of the table without modifying it.
This is an instructive pattern for anyone designing protocols or distributed caches: HPACK was a stateful, incremental compressor whose correctness depended on ordering. That is exactly the assumption QUIC removed. The price was a new format — and QPACK has to manage the trade-off explicitly: RFC 9114 describes it in Section 4.2.1 as a variation of HPACK that gives an encoder some control over how much head-of-line blocking can be caused by compression. So you do not get freedom from blocking for free; you get a dial.
And here is the exception to "one packet loss, one affected request": that the QPACK table state travels over separate unidirectional streams is stated in Section 2. That loss on that stream holds up other requests is not stated explicitly by RFC 9114 — it follows from Section 4.2.1, where compression itself is named as a possible source of head-of-line blocking; the mechanics are described in RFC 9204 (QPACK). I am of the opinion that the decoupling is therefore good, but not complete.
Further stipulations: QUIC version 1 uses TLS version 1.3 or greater as its handshake protocol (Section 3.2), the ALPN token is h3 (Section 3.1), and HTTP/3 relies on QUIC to provide confidentiality and integrity protection of data (Section 1.2). Server push still exists and is managed through the PUSH_PROMISE, MAX_PUSH_ID and CANCEL_PUSH frames; RFC 9114 describes it as a trade-off of network usage against a potential latency gain.
Part 6: What the 2017 Measurement Said – and What It Already Qualified Back Then
The Google paper "The QUIC Transport Protocol: Design and Internet-Scale Deployment" (21 authors, all Google, SIGCOMM '17, Los Angeles, 21–25 August 2017) is the largest published field measurement of QUIC. But one qualification has to come first, one the paper makes itself: it describes pre-IETF QUIC — Google's own variant, not RFC 9000. Details, the authors say, are expected to change during IETF standardisation. Any transfer of these numbers to today's HTTP/3 is therefore an extrapolation, not a measurement.
The core figures from the introduction, verbatim-sourced:
| Metric | Desktop | Mobile |
|---|---|---|
| Reduction in latency of Google Search responses (mean) | 8.0 % | 3.6 % |
| Reduction in rebuffer rate of YouTube playbacks (mean) | 18.0 % | 15.3 % |
Here "desktop" means Chrome on desktop platforms and "mobile" means apps on Android devices — so the mobile figures reflect both the network environment and a different implementation.
Further sourced values:
- 0-RTT: QUIC's handshake latency is largely insensitive to RTT because 0-RTT handshakes carry a fixed (namely zero) latency cost — and these constituted about 88 % of all QUIC handshakes (Section 6.2). Broken down: ~88 % of desktop connections for Search, 68 % for the mobile Search app, an average of 85 % for desktop video, but only 65 % in the YouTube app.
- Deployment in 2017: QUIC at that time accounted for over 30 % of Google's total egress traffic in bytes, and consequently an estimated 7 % of global Internet traffic. The jump from 15 % to over 30 % coincided with the YouTube app moving to QUIC in September 2016, which doubled QUIC's share of Google's egress traffic.
- Reachability: QUIC is successfully used for 95.3 % of video clients attempting to use it; 4.4 % of clients are unable to use QUIC (QUIC or UDP blocked, or path MTU too small); the remaining 0.3 % are in networks that seem to rate limit QUIC and/or UDP traffic (measurement from November 2016).
- CPU cost: when Google began measuring the cost of serving YouTube traffic over QUIC, QUIC's server CPU utilisation was about 3.5 times higher than TLS/TCP (Section 6.7). After optimisations, the CPU cost of serving web traffic over QUIC came down to approximately twice that of TLS/TCP.
On that last point the attribution of cause is decisive, because it is often got wrong. Section 6.7 names three major sources of QUIC's CPU cost: cryptography, sending and receiving of UDP packets, and maintaining internal QUIC state. And the paper explicitly concedes that the implementation was initially written with a focus on rapid feature development and ease of debugging, not CPU efficiency. That the transport runs in user space is not named by the authors as a cause; kernel bypass appears in their text only as a possible future lever. I am of the opinion that the move out of the kernel is part of this price — but that is my reading, not the paper's finding.
The Limitation That Was Already There in 2017
Section 6.8 of the paper is headed "Performance Limitations", and it states verbatim: the use of QUIC on networks with plentiful bandwidth, low delay and low loss rate shows little gain and occasionally negative performance impact. More pointedly: when used over a very high-bandwidth (over 100 Mbps) and/or very low RTT connection (a few milliseconds), QUIC may perform worse than TCP. As a conjecture, the authors name client CPU limits and/or client-side scheduler inefficiencies in the OS or application.
This paragraph is worth reading twice. The people who built and deployed QUIC named the weakness in 2017 — including the correct conjecture about its cause. Seven years later, somebody measured it.
Part 7: The Counter-Finding – "QUIC is not Quick Enough over Fast Internet"
In 2024, the ACM Web Conference (WWW '24, Singapore, 13–17 May 2024) saw a paper whose title questions ten years of marketing: "QUIC is not Quick Enough over Fast Internet", by Xumiao Zhang, Shuowei Jin, Yi He, Z. Morley Mao (University of Michigan), Ahmad Hassan and Feng Qian (University of Southern California), and Zhi-Li Zhang (University of Minnesota).
The central measured finding per the abstract: a data rate reduction of up to 45.2 % for UDP+QUIC+HTTP/3 compared with the TCP+TLS+HTTP/2 counterpart — and the observation that the performance gap between QUIC and HTTP/2 grows as the underlying bandwidth increases.
The structure of the measurement matters more than the headline number:
| Client / tool | Finding |
|---|---|
| cURL (1 Gbps Ethernet) | QUIC throughput 7–16 % lower |
quic_client (1 Gbps Ethernet) |
8–12 % lower |
| Chrome | falls behind once bandwidth exceeds ~500 Mbps; average QUIC throughput "can barely hit 478 Mbps"; at 1 Gbps, 45.2 % slower than HTTP/2 |
| Video streaming (dash.js, 4K) | bitrate reduction up to 9.8 % (Ethernet and 5G); on 4G "not that significant" |
| Page load time (Alexa top 100, local mirror) | 3.0 % longer on average, over 50 % and up to 74.9 % in the tail |
Below roughly 600 Mbps the authors find comparable performance for cURL and quic_client; Chrome already falls behind above roughly 500 Mbps. (A note on source fidelity, analogous to the one about Honda et al.: this assignment appears in Section 3.2, in Section 3.3 — there explicitly compared against the "600 Mbps bottleneck point identified in the lightweight client tests" — and in the introduction. The summarising sentence in Section 4.1 swaps the two values. The inconsistency is in the paper, not in this article.) In other words: the finding is not a rejection of QUIC but a bandwidth threshold. Anyone working at 100 Mbps over a link with 40 ms RTT is not affected by this paper.
The Cause: the Receiver, Not the Network
The authors identify the cause as high receiver-side processing overhead, in particular excessive data packets and QUIC's user-space ACKs. They break this into two layers:
- Kernel side: none of the QUIC implementations they examine uses UDP generic receive offload (GRO). This produces more
netif_receive_skbcalls than TCP and hence more CPU load per byte. TCP benefits here from GRO/LRO, a mechanism that merges many small packets into large ones before protocol processing. - User-space side: additional overhead from excess packets, the user-space nature of QUIC's ACKs, and the lack of certain optimisations such as delayed ACK.
For calibration: a faster client processor (Core i7-10700 at 4.80 GHz) reached 530 Mbps — this narrowed the gap only marginally. The bottleneck is therefore not simply "CPU too slow" but the path every packet takes through the receiver.
What This Paper Explicitly Does Not Claim
Discipline is required here, because this paper has become a favourite citation for "QUIC is bad":
- It speaks of comparable performance at low bandwidth ("QUIC and HTTP/2 exhibit similar performance when the network bandwidth is relatively low") — a statement about similarity, not an acquittal from any degradation. The roughly 600 Mbps threshold for the lightweight clients is stated in Section 3.2, not in the same sentence.
- It does not examine all implementations; server-side it ran OpenLiteSpeed v1.7.15 (on LSQUIC) and nginx-quic, client-side Chrome v102, Firefox v105, Edge v106 and Opera v93, with profiling mainly on Chromium v102. quic-go, picoquic and MsQuic are not tested.
- It does not unambiguously classify the cause as a design flaw. Missing UDP GRO and user-space ACKs are implementation and operating-system properties; at the same time the authors point to "unique challenges" arising from QUIC's design in handling data reception.
- The mitigations it names come with caveats: UDP GRO faces challenges, GSO pacing was only tested in data centre networks, parallel downloads may incur fairness issues.
I am of the opinion that the correct reading of this paper is the following: it is not a finding about QUIC as a protocol, but about the current maturity of receiver paths. Holding on to exactly that difference is the difference between a well-founded technology decision and a second-hand quotation.
Part 8: The Paradox of De-Ossification
Now the arc can be closed, and it ends in a contradiction one has to live with.
What was gained: QUIC has drastically reduced the attack surface of the path layer — it has not defeated it. Because almost everything is encrypted and authenticated, including the packet number via header protection, there is considerably less left for middleboxes to latch onto. The invariants from RFC 8999 do remain visible, however, and plain blocking or rate limiting of UDP still works: in Google's measurement, 4.4 % of video clients could not use QUIC and 0.3 % were rate limited.
What was paid: CPU. Google measured an initial 3.5-fold, and after optimisation still roughly double, server CPU load compared with TLS/TCP — the paper names cryptography, UDP packet processing and state maintenance as the causes, not the relocation as such. Zhang et al. measure the mirror image at the receiver, where the kernel and NIC optimisations grown over decades for TCP — GRO, offloads, delayed ACK — did not yet apply equivalently to UDP/QUIC at the time of measurement (Chromium v102, LSQUIC). That this cost item depends more on offloads and implementation than on the layer is an active research topic: the publication list of the Chair of Network Architectures and Services at TU Munich lists, for NOMS 2026, a contribution by Johannes Späth, Stefan Lachnit, Marcel Kempf, Kilian Holzinger, Georg Carle and Johannes Zirngibl titled "Kernel Bypass Surgery: A Viable Procedure for Maximizing QUIC Bandwidth?" — the question is thus documented; I have not checked its results in this run.
What is open: whether QUIC itself stays immune to ossification is not proven, merely intended. RFC 9000 Section 6.2 explicitly records that how to perform version negotiation is left as future work. And the Google paper tells a story in Section 7.5 that should be read as a warning: a change to a single bit in the flags in October 2016 caused packets to disappear behind one firewall vendor's classifier. One bit. Encryption protects only what is actually encrypted — anything that has to stay in the clear can become a point of calcification.
The general lesson, and this is my reading rather than that of any of the papers: de-ossification is not a state you reach but an ongoing price you pay. You pay it in CPU cycles, in implementation diversity without a common API (RFC 9000, Sections 2.4 and 5.3), and in the need to keep moving parts actively moving.
Part 9: Where We Stand in 2026
Standardisation is complete: RFC 9000 (transport), RFC 9001 (TLS), RFC 9002 (loss detection and congestion control) since May 2021, RFC 9114 (HTTP/3) since June 2022.
On deployment there is no peer-reviewed source that would be current for 2026. The commercial survey by W3Techs reports for October 2026 that HTTP/3 is used by 41.1 % of all websites (accessed 27 October 2026). That figure should be read with care: W3Techs is a commercial market research survey with its own sampling logic, not a scientific measurement study, and "used by a website" is not the same as "carries traffic share X".
What can be said responsibly: QUIC has gone from a Google experiment to a standardised, broadly implemented transport whose advantages materialise where handshake round trips and loss dominate — and whose disadvantages show up where the receiver path is the bottleneck.
The Central Takeaway
1. Head-of-line blocking does not disappear, it is demoted. RFC 9000 promises no freedom from blocking; in Section 2 it merely records that there is no ordering guarantee between streams. Within a stream, loss still blocks. Consequence for design: a single large download gains structurally little — the handshake gain remains, the multiplexing gain does not, because there are no independent streams there between which an ordering could be dropped. I am of the opinion that the gain can grow with the number of independent resources — none of the sources checked here establishes that; and RFC 9114 names header compression itself, in Section 4.2.1, as a possible source of head-of-line blocking. So the decoupling does not reach into the application layer.
2. The documented gains are in handshake round trips and loss robustness, not in throughput. Google's measurement — taken on pre-IETF QUIC and therefore only extrapolatable to today's HTTP/3 — shows a mean 8.0 % (desktop) and 3.6 % (mobile) reduction in Search latency and 18.0 % and 15.3 % less rebuffering, driven above all by the fact that about 88 % of handshakes were 0-RTT. On a fast, loss-free link little of that remains — both papers say so, Google in 2017 for anything above 100 Mbps and Zhang et al. in 2024 measurably above roughly 500 Mbps in the browser (Chrome) and roughly 600 Mbps for lightweight clients.
3. Practical next step: enable HTTP/3 where path conditions are poor, and measure where it hurts. For an application with mobile users, high RTT or loss, HTTP/3 is the obvious choice — and in addition to HTTP/2, not instead of it, because in Google's November 2016 measurement 4.4 % of video clients could not use Google's QUIC variant at all; no comparably solid current figure for HTTP/3 is available, which is why HTTP/2 should remain as a fallback path. And do not measure the mean: Zhang et al. find 3.0 % longer page load times on average, and up to 74.9 % in the tail.
4. Treat 0-RTT as a security decision, not a performance switch. RFC 9001 Section 2.1 is unambiguous: 0-RTT data can be replayed by an attacker. Idempotent requests yes, state-changing requests no.
5. Factor in the CPU price — but as an implementation-dependent quantity, not a constant of nature. Google's 2017 figure (after optimisation, roughly double the server CPU load compared with TLS/TCP) comes from a stack that by its own account was not initially written for CPU efficiency. It works as an indication of the order of magnitude, not as a price tag for the architectural pattern.
The Reflection Question
QUIC defeated ossification by making itself unreadable. That also means: network operators, corporate firewalls and school filters see less than they used to, and in-network diagnosis becomes harder — for exactly the same reason that manipulation becomes harder.
Where do you draw the line in your own architecture between evolvability through unreadability and operability through visibility? And for which component of your system have you so far not made that decision, but inherited it?
Fact Check
This article was subjected to a structured check in two rounds after drafting: first the complete draft, then all modified passages once more. 154 checkable claims were extracted from the draft (88 hard facts, 16 quotations, 24 source attributions, 26 synthesis claims) and checked against the primary sources. 123 claims remained confirmed unchanged, 31 were corrected — of those, 3 as false, 24 as worded too strongly, and 4 as not verifiable.
The three most important corrections:
- Wrong attribution of cause for the CPU cost. The draft attributed QUIC's higher server CPU load to the relocation into user space. Instead, the Google paper names cryptography, UDP packet processing and state maintenance in Section 6.7, and concedes that the implementation was not initially written for CPU efficiency. The interpretation is now marked as the author's own view.
- False statement about unreadability. The draft claimed that after header protection there are "practically no stable fields" for a classifier to latch onto. RFC 8999 explicitly fixes the header form bit, the version field and the connection IDs as stable across versions — and the article itself demonstrated two sections later that a classifier can depend on them.
- Swapped and over-generalised measurement values. The 45.2 % from the 2024 paper applies to Chrome at 1 Gbps, not to QUIC in general; lightweight clients lost only 7–16 % in the same setup. In addition, the bandwidth thresholds had been swapped (roughly 500 Mbps for Chrome, roughly 600 Mbps for the command-line clients).
The second round found six further points, including one misquotation: RFC 9000 Section 5.1.2 phrases the restriction of a connection ID to one address pair as given behaviour, not as "necessary", as the corrected draft had claimed.
Four points remained unverifiable: resolution of the DOIs via dl.acm.org (returns 4xx); the results of the NOMS 2026 contribution on kernel bypass (only title, authors and venue are documented); whether the term "head-of-line blocking" occurs in RFC 9000 beyond Section 8.2 (the retrievable full text breaks off there — up to that point it does not occur); and, for the same reason, whether RFC 9000 Section 9.5 words the connection ID restriction as "necessary".
Automated AI check against primary sources; no human expert review.
Cross-References in the Vault
- The Long Tail of Latency: Tail Latency and Why Averages Lie in the Cloud – the methodological basis for point 3 of the takeaway: Zhang et al. find 3.0 % on average and 74.9 % in the tail. That gap is precisely the subject there.
- The Programmable Kernel: eBPF and the Sandbox at the Heart of the Operating System – the counter-movement: QUIC leaves the kernel, eBPF brings programmability into the kernel. Two answers to the same question.
- The Key That Dies After Every Message: The Signal Protocol, the Double Ratchet, and the Art of End-to-End Encryption – key rotation and forward secrecy; QUIC has its own key update mechanism instead of TLS KeyUpdate.
- The End of the Password: Passkeys, WebAuthn and the Anatomy of Phishing-Resistant Sign-In – a second case in which a standard has to guard explicitly against replay.
- Harvest Now, Decrypt Later: Post-Quantum Cryptography and the Race Against the Quantum Computer – the next migration, which has to pass through exactly this TLS 1.3 handshake.
- Betting on a Stranger's Code: Firecracker microVMs and the End of the Container-versus-VM Dilemma – the same trade: isolation and mobility against efficiency per cycle.
Sources and Further Reading
- J. Iyengar, M. Thomson (Eds.), "QUIC: A UDP-Based Multiplexed and Secure Transport", RFC 9000, IETF, May 2021 (Standards Track). https://www.rfc-editor.org/rfc/rfc9000.html – core specification: streams, flow control, connection IDs, migration (clients only), explicit non-goals (no prioritisation, no API, version negotiation left open).
- M. Thomson, S. Turner (Eds.), "Using TLS to Secure QUIC", RFC 9001, IETF, May 2021. https://www.rfc-editor.org/rfc/rfc9001.html – TLS 1.3 mandatory, CRYPTO frames instead of TLS records, header protection, the replay warning for 0-RTT.
- J. Iyengar, I. Swett (Eds.), "QUIC Loss Detection and Congestion Control", RFC 9002, IETF, May 2021. https://www.rfc-editor.org/rfc/rfc9002.html – monotonically increasing packet numbers, separate packet number spaces, no reneging, NewReno as the reference.
- M. Bishop (Ed.), "HTTP/3", RFC 9114, IETF, June 2022. https://www.rfc-editor.org/rfc/rfc9114.html – one stream per request-response pair, QPACK instead of HPACK, ALPN token
h3. - A. Langley et al. (21 authors), "The QUIC Transport Protocol: Design and Internet-Scale Deployment", SIGCOMM '17, Los Angeles, August 2017. https://doi.org/10.1145/3098822.3098842 – the large field measurement (pre-IETF QUIC): 8.0 %/3.6 % Search latency, 18.0 %/15.3 % rebuffering, 88 % 0-RTT, CPU 3.5× → ~2×, and its own limitation in Section 6.8.
- M. Honda, Y. Nishida, C. Raiciu, A. Greenhalgh, M. Handley, H. Tokuda, "Is it Still Possible to Extend TCP?", ACM IMC '11, Berlin, November 2011. Full text checked via https://www.cl.cam.ac.uk/teaching/2021/CompNet/files/honda2011still.pdf – 142 access networks in 24 countries; the measurement on which the ossification argument rests – with the often overlooked conclusion "extensible, but severely constrained".
- X. Zhang, S. Jin, Y. He, A. Hassan, Z. M. Mao, F. Qian, Z.-L. Zhang, "QUIC is not Quick Enough over Fast Internet", WWW '24, Singapore, May 2024. https://doi.org/10.1145/3589334.3645323 (preprint: https://arxiv.org/abs/2310.09423) – up to 45.2 % data rate reduction above the bandwidth threshold; cause on the receiver side.
- W3Techs, "Usage Statistics of HTTP/3 for Websites", October 2026. https://w3techs.com/technologies/details/ce-http3 – 41.1 % of all websites (accessed 27 October 2026). Commercial survey, not peer-reviewed.
- M. Thomson, "Version-Independent Properties of QUIC", RFC 8999, IETF, May 2021. https://www.rfc-editor.org/rfc/rfc8999.html – the properties that remain stable across QUIC versions and therefore observable by the network: header form bit, version field (long header only), connection IDs.
- Chair of Network Architectures and Services, TU Munich, publication list. https://net.cit.tum.de/publications/ – documents title, authors and venue of "Kernel Bypass Surgery: A Viable Procedure for Maximizing QUIC Bandwidth?" (NOMS 2026). The contribution's results were not checked in this run.