In-kernel QUIC (Linux)
A 15-patch series by Xin Long (posted July 2025) proposes a native QUIC implementation in the
Linux kernel under net/quic/. This is the work referenced in
LWN — In-kernel QUIC and tracked at
lxin/quic.
This is directly relevant to the large-transfer limitations of HTTP/3: moving QUIC into the kernel is the path to closing the gap with TCP offloads.
What kTLS is (and isn't)
Before diving into in-kernel QUIC, it helps to understand kTLS, which the benchmarks use as a reference:
Application
│
TLS ← kTLS moves crypto into the kernel
│
TCP
│
IP
kTLS is not a new transport protocol. It is an optimization that moves TLS record
encryption/decryption into the kernel after the handshake completes in user space. The negotiated
session keys are pushed down via setsockopt(SOL_TLS, ...), and from that point sendmsg() /
recvmsg() encrypt/decrypt transparently. This enables zero-copy via sendfile() because
the kernel can encrypt directly from the page cache.
kTLS = TLS crypto offloaded to kernel, still TCP underneath. In-kernel QUIC = entirely new transport (UDP-based), with TLS 1.3 baked in.
Architecture of net/quic
The design mirrors IPPROTO_MPTCP: a new socket protocol type IPPROTO_QUIC sitting over UDP
tunnels. ~9,000 lines across 34 new files.
Application (SMB, NFS, curl, httpd…)
│
IPPROTO_QUIC (net/quic/ — kernel)
│ ↑ TLS handshake offloaded to userspace via tlshd / GnuTLS
│ using the existing net/handshake netlink API
UDP
│
IP
Key design choices:
- TLS handshake stays in user space (via
tlshd/ GnuTLS); only the data path moves to the kernel. This avoids embedding a full TLS stack in the kernel. - Standard socket API:
socket/bind/listen/connect/accept/sendmsg/recvmsg/close, plus QUIC-specificsockoptsfor streams, connection migration, key updates, and ALPN routing. - RFC coverage: RFC 9000, 9001, 9002, 9221, 9287, 9368, 9369 — core QUIC, TLS-over-QUIC, loss detection/congestion, unreliable datagrams, version negotiation, and QUIC v2.
Performance (100G NIC, iperf)
| MTU | QUIC vs kTLS |
|---|---|
| 1500 | QUIC ~2–3× slower |
| 9000 (jumbo) | QUIC ~1.4× slower |
Known causes of the remaining gap:
- No GSO support yet (each packet is a separate syscall)
- Extra TX copy
- Header protection encryption overhead
These are the same structural issues described in the receiver-side overhead section of the HTTP/3 page — moving to the kernel is the fix, but the work is not complete.
Validation and status
- Interop: tested against all major QUIC stacks via QUIC Interop Runner.
- Fuzzing: Syzkaller running.
- Real-world:
curlHTTP/3 and anhttpd-portableHTTP/3 server already working against it. - Status: marked
EXPERIMENTAL. Parts 1–2 of a 5-part series (infrastructure + subcomponents); data processing, socket APIs, and docs come in follow-up patchsets. Not mainline yet.