flare_mlake · API · quic

flare.quic.cc

QUIC congestion control (RFC 9002 section 7): Reno + CUBIC (HyStart++).

Sans-I/O, sans-clock controllers: the caller feeds byte counts and the monotonic millisecond clock; the controller answers "may I send another bytes right now?" via :meth:can_send and grows / shrinks the congestion window on ACK / loss. No socket, no timer -- the :mod:flare.quic._loss_recovery bookkeeping and the client / server send paths own those and consult a controller through the :trait:CongestionController contract.

Two algorithms ship:

  • :struct:RenoController -- the RFC 9002 section 7.3 NewReno reference (slow start + AIMD congestion avoidance). Simple, robust, the safe default.
  • :struct:CubicController -- RFC 9438 CUBIC with the RFC 9406 HyStart++ slow-start exit. Better throughput on high bandwidth-delay-product paths (the case HTTP/3 over WAN hits).

:struct:CcChoice selects between them. Both share the RFC 9002 constants below and the in-recovery guard (one window reduction per round-trip, keyed on the lost packet's send time).

These controllers model the window only -- they do not pace egress (no inter-packet send timer). The QUIC send path uses the window as a gate (burst up to cwnd - bytes_in_flight); add a pacer (RFC 9002 section 7.7) only if a profile shows bursty loss. The upgrade path is a next_send_time accessor here plus a timer in the reactor.

Structs

CcChoice

struct CcChoice

Which congestion controller a connection uses.

CcChoice.reno() / CcChoice.cubic() are the two values; the QUIC send path reads :attr:kind to pick the controller. Kept a tiny tagged value (not a Mojo enum) so it round-trips through config structs and comparisons cheaply.

Implements Copyable, Movable

Fields
kind: Int
comptime RENO = Int(0)
comptime CUBIC = Int(1)

__eq__

def __eq__(self, other: Self) -> Bool

__ne__

def __ne__(self, other: Self) -> Bool

reno

def reno() -> Self

cubic

def cubic() -> Self

RenoController

struct RenoController

RFC 9002 section 7.3 NewReno: slow start until cwnd reaches ssthresh, then additive-increase / multiplicative-decrease.

Implements CongestionController, Copyable, Movable

Fields
cwnd: UInt64
ssthresh: UInt64
recovery_start_ms: UInt64

__init__

def __init__(out self)

window

def window(self) -> UInt64

can_send

def can_send(self, bytes_in_flight: UInt64, bytes: UInt64) -> Bool

on_packet_acked

def on_packet_acked(mut self, bytes: UInt64, rtt_ms: UInt64, now_ms: UInt64)

on_congestion_event

def on_congestion_event(mut self, sent_time_ms: UInt64, now_ms: UInt64)

CubicController

struct CubicController

RFC 9438 CUBIC with the RFC 9406 HyStart++ slow-start exit.

In slow start the window grows exponentially (like Reno) but HyStart++ watches per-round minimum RTT: a sustained delay rise means the path queue is filling, so it exits slow start before a loss (setting ssthresh = cwnd). In congestion avoidance the window follows the CUBIC cubic curve around w_max (the window at the last loss), with a Reno-friendly floor so it never underperforms Reno on short-RTT paths.

Implements CongestionController, Copyable, Movable

Fields
cwnd: UInt64
ssthresh: UInt64
recovery_start_ms: UInt64
w_max: Float64
epoch_start_ms: UInt64
k: Float64

__init__

def __init__(out self)

window

def window(self) -> UInt64

can_send

def can_send(self, bytes_in_flight: UInt64, bytes: UInt64) -> Bool

on_packet_acked

def on_packet_acked(mut self, bytes: UInt64, rtt_ms: UInt64, now_ms: UInt64)

on_congestion_event

def on_congestion_event(mut self, sent_time_ms: UInt64, now_ms: UInt64)

Traits

CongestionController

The window-management contract the QUIC send path consults.

A controller owns the congestion window (in bytes) and updates it on ACK / loss. It never touches a socket or a clock; the caller passes byte counts, RTT samples (ms), and the monotonic clock (ms).

Implements Copyable, Movable

window

def window(self) -> UInt64

Current congestion window in bytes.

can_send

def can_send(self, bytes_in_flight: UInt64, bytes: UInt64) -> Bool

True if sending bytes more keeps in-flight <= window.

on_packet_acked

def on_packet_acked(mut self, bytes: UInt64, rtt_ms: UInt64, now_ms: UInt64)

Grow the window for bytes newly acknowledged.

on_congestion_event

def on_congestion_event(mut self, sent_time_ms: UInt64, now_ms: UInt64)

React to loss of a packet sent at sent_time_ms (one window reduction per round-trip).

Aliases

comptime MAX_DATAGRAM_SIZE = UInt64(1200)

Assumed max UDP payload (RFC 9002 kMaxDatagramSize); the window is an integer multiple of this in spirit, tracked in bytes.

comptime INITIAL_WINDOW = UInt64(12000)

RFC 9002 section 7.2 recommended initial window: min(10*MDS, max(2*MDS, 14720)) == 10*1200 == 12000 here.

comptime MINIMUM_WINDOW = UInt64(2400)

Floor the window never drops below (RFC 9002 kMinimumWindow).