Skip to content

colibri 0.11.0: BBRv3, PEM files and DNSSEC checks

Choose a tag to compare

@c4milo c4milo released this 01 Nov 14:13
· 110 commits to main since this release

colibri 0.11.0 runs BBRv3 on each QUIC connection by default, and CUBIC stays a choice. It reads the PEM files an operator holds, checks DNSSEC signatures in a new dnssec module, and sends more request content from the program's memory with no copy. It pins chapulin f59c7e3f and stdx 5fd03aa.

Breaking changes

  • Each module's constants are grouped by who sets them (decision 137): protocol for what the RFCs fix, limits for the bounds colibri chose, policy for the other values colibri chose, and one file for each algorithm. quic.constants.frame_ack becomes quic.constants.protocol.frame_ack, and the same holds for every module.
  • A QUIC connection runs BBRv3 (draft-ietf-ccwg-bbr-06) by default, where 0.10.0 ran CUBIC (decision 143). server.Config, client.Config and quic.Connection's options take .congestion_controller = .cubic to keep CUBIC. Under BBRv3 a connection draws its probe waits from the source init takes (decision 136).
  • A program with its own tls_provider.Provider must fill Negotiated.group (decision 140) and give writable_len and encrypt_parts (decision 139).
  • A response whose Content-Length is larger than its body ends too_large at its head (decision 124 as amended). h11 closes the connection, and h2 and h3 reset the stream. Before, colibri read and dropped the whole content.
  • Each session and connection is larger: tls.record.Client grows from 40,968 to 49,800 bytes, quic.Connection from 176,888 to 208,304 bytes, and server.Endpoint at its default capacity from 51,310,368 to 52,422,080 bytes. tls.constants.limits.anchors_max is 256. docs/performance.md lists each size.

What's new

  • quic.CongestionController selects BBRv3 or CUBIC. BBRv3 keeps its model of the path from delivery rate samples, moves through Startup, Drain, ProbeBW and ProbeRTT, and undoes a spurious loss episode. spec/lean proves its arithmetic, and spec/tla/bbr checks its states.
  • tls.pem reads a certificate chain, a P-256 key and a CA bundle from PEM (RFC 7468, decision 141). tls.P256Key holds the key.
  • The new dnssec module checks DNSSEC signatures and DS digests through chapulin: dnssec.verify, dnssec.Hash, dnssec.Algorithm and dnssec.DigestType (decision 142).
  • tls_provider.Negotiated.group and tls.quic.Client.negotiated() report the key-exchange group beside the cipher suite (decision 140).
  • quic.PeerAddress.scope_id carries an IPv6 address's interface, so a pool dials a link-local address (RFC 9000 §9).
  • h2.Connection.write_data_header writes a DATA frame's header for data the caller writes after it (decision 138).

Fixes

  • A cancel during a handshake that then failed left the pool's attempt open, so the next request ended refused with no connection opened (#100).

Speed

The judge's bulk run downloads a file of 2 MiB over h3 through a bottleneck of 20 Mbit/s and 25 ms (design §8 steps 13k and 29c.2):

  • At 1% loss from one connection, BBRv3 gives 14.5 to 14.8 Mbit/s, and CUBIC 1.7. From four connections, BBRv3 gives 17.1 Mbit/s, and CUBIC 8.1.
  • With no loss and four connections, a small GET's p99 beside the download is 186 ms under BBRv3, and 509 to 718 ms under CUBIC.
  • When the two share the bottleneck with no loss, CUBIC takes about 0.82 of it. #123 tracks CUBIC's goodput at 1% loss.
  • The h11 client sends request content from the program's memory, and the h2 client seals each DATA frame from two slices over TLS and writes its data after the header in cleartext (decision 139).

Checked

GitHub's main workflow passed on 83c922b1 (run 41306132768), and tools/ci.sh passed all 38 sections on it.