Decision records

ADR-0030: Kernel TLS for HTTPS/1.1 file bodies (opt-in)

  • Status: Accepted (2026-10-06), opt-in
  • Extends ADR-0027 (sendfile) to TLS connections.

Context

Most traffic is HTTPS. ADR-0027 sends large files with sendfile(2) only on plain TCP: with rustls the data has to pass through user space to be encrypted. Linux kernel TLS (tls module, 4.13+) can encrypt in the kernel, so sendfile/writev on the socket carry plaintext and the kernel produces TLS records.

Decision

  • server.ktls: true (default false; needs modprobe tls). At start scalwsd probes which cipher suites the kernel accepts (ktls::CompatibleCiphers; the probe briefly listens on an ephemeral port on all interfaces). If none, it logs a warning and serves TLS as before.
  • The rustls handshake runs as usual over ktls::CorkStream, which lets the stream be drained exactly at a record boundary. When the client negotiated http/1.1 and a kernel-supported suite, the session keys are handed to the kernel (config_ktls_server; rustls enable_secret_extraction). HTTP/2 connections and other suites stay on rustls.
  • KtlsStream reads (it handles TLS control messages); writes bypass it to the SendfileIo underneath, vectored, so hyper keeps queueing body buffers and the placeholder protocol of ADR-0027 works unchanged (KtlsStream alone does not support vectored writes, which would make hyper copy — and thus zero — placeholders). Shutdown goes through KtlsStream (close_notify).
  • A failure while switching to kTLS closes that connection (the TLS stream is consumed by the switch); the start-up probe makes this rare.

Consequences

  • Encryption cost moves into the kernel and is accounted to the process as system time.
  • TLS 1.3 key updates are handled by the kernel only on recent kernels; ktls refuses them otherwise, which ends the connection (clients reconnect).