quic_cc behaviour (quic v3.0.0)
View SourceQUIC congestion control behavior and facade.
This module defines the behavior for pluggable congestion control algorithms and provides a facade that delegates to the selected implementation.
Available Algorithms
- newreno (default): RFC 9002 NewReno implementation - bbr: BBRv3, draft-ietf-ccwg-bbr-07
Usage
%% Create with default algorithm (NewReno)
State = quic_cc:new(),
State = quic_cc:new(#{initial_window => 65536}),
%% Create with explicit algorithm
State = quic_cc:new(newreno, #{}),
State = quic_cc:new(bbr, #{}).
Summary
Functions
The ACK frequency to ask of the peer, given the smoothed RTT in microseconds, or none to leave its ACK behaviour as it is. Only BBR asks (draft-ietf-ccwg-bbr-07 Section 4.1.3.3).
Get the algorithm name for this CC state.
Get the available congestion window.
Get bytes currently in flight.
Check if we can send more bytes.
Get the current congestion window.
Get pacing tokens for sending.
Whether the last packet of a flight should carry IMMEDIATE_ACK.
Check if in recovery phase.
Check if in slow start phase.
The congestion window this controller was configured with. cwnd evolves away from it, so a reset needs it to restore the configured value rather than a hardcoded default.
Get the current max datagram size.
Get minimum recovery duration setting.
Create a new congestion control state with default algorithm (NewReno).
Create a new congestion control state with options. Uses the algorithm specified in options, or NewReno by default.
Create a new congestion control state with explicit algorithm.
The peer was asked for this ACK frequency.
The sender has nothing queued to send. BBR marks its delivery rate samples application-limited (draft-ietf-ccwg-bbr-07 Section 4.1.2.4); the other algorithms do not use it.
Handle a congestion event (packet loss detected). A window cut at once lets the next packet out regardless of the new window (RFC 9002 Section 7.3.2).
Record that a packet was sent.
Process acknowledged packets.
Process acknowledged packets with largest acked sent time.
Remove bytes for packets whose packet number space was discarded. Not a congestion event: the packets were neither acknowledged nor lost, they simply stopped existing, so the window and recovery state are untouched (RFC 9002 Section 6.4).
Process lost packets.
Batched on_packet_sent for a run: one update for newreno, a fold for other algorithms.
Handle persistent congestion.
Undo the last window reduction: every packet it was for turned out to be delivered, only late.
Check if pacing allows sending.
Calculate pacing delay.
Start the window over after a Retry (RFC 9002 Section 6.3), keeping the algorithm, MTU and configured windows. Rebuilding the controller instead would silently drop those.
Fused send check (cwnd + pacing) for the hot send path. See the behavior callback for the return shape.
Batched send_check: approve up to MaxK packets of Size in one pass. Native for newreno; other algorithms fold send_check/2 with identical results.
Get the slow start threshold.
Update congestion control state when MTU changes.
Update pacing rate based on smoothed RTT.
Types
-type ack_frequency() :: {non_neg_integer(), pos_integer(), non_neg_integer()}.
-type cc_algorithm() :: newreno | bbr | cubic.
-type cc_opts() :: #{initial_window => pos_integer(), minimum_window => pos_integer(), min_recovery_duration => non_neg_integer(), max_datagram_size => pos_integer(), algorithm => cc_algorithm()}.
-opaque cc_state()
Callbacks
-callback available_cwnd(State :: term()) -> non_neg_integer().
-callback bytes_in_flight(State :: term()) -> non_neg_integer().
-callback can_send(State :: term(), Size :: non_neg_integer()) -> boolean().
-callback cwnd(State :: term()) -> non_neg_integer().
-callback get_pacing_tokens(State :: term(), Size :: non_neg_integer()) -> {non_neg_integer(), State :: term()}.
-callback initial_window(State :: term()) -> non_neg_integer().
-callback max_datagram_size(State :: term()) -> pos_integer().
-callback min_recovery_duration(State :: term()) -> non_neg_integer().
-callback on_congestion_event(State :: term(), SentTime :: non_neg_integer()) -> State :: term().
-callback on_packet_sent(State :: term(), Size :: non_neg_integer()) -> State :: term().
-callback on_packets_acked(State :: term(), AckedBytes :: non_neg_integer()) -> State :: term().
-callback on_packets_acked(State :: term(), AckedBytes :: non_neg_integer(), LargestAckedSentTime :: non_neg_integer()) -> State :: term().
-callback on_packets_discarded(State :: term(), Bytes :: non_neg_integer()) -> State :: term().
-callback on_packets_lost(State :: term(), LostBytes :: non_neg_integer()) -> State :: term().
-callback pacing_allows(State :: term(), Size :: non_neg_integer()) -> boolean().
-callback pacing_delay(State :: term(), Size :: non_neg_integer()) -> non_neg_integer().
-callback send_check(State :: term(), Size :: non_neg_integer()) -> {ok, State :: term()} | {blocked_cwnd, non_neg_integer()} | {blocked_pacing, non_neg_integer()}.
-callback ssthresh(State :: term()) -> non_neg_integer() | infinity.
-callback update_mtu(State :: term(), NewMTU :: pos_integer()) -> State :: term().
-callback update_pacing_rate(State :: term(), SmoothedRTT :: non_neg_integer()) -> State :: term().
Functions
-spec ack_frequency(cc_state(), non_neg_integer()) -> ack_frequency() | none.
The ACK frequency to ask of the peer, given the smoothed RTT in microseconds, or none to leave its ACK behaviour as it is. Only BBR asks (draft-ietf-ccwg-bbr-07 Section 4.1.3.3).
-spec algorithm(cc_state()) -> cc_algorithm().
Get the algorithm name for this CC state.
-spec available_cwnd(cc_state()) -> non_neg_integer().
Get the available congestion window.
-spec bytes_in_flight(cc_state()) -> non_neg_integer().
Get bytes currently in flight.
-spec can_send(cc_state(), non_neg_integer()) -> boolean().
Check if we can send more bytes.
-spec cwnd(cc_state()) -> non_neg_integer().
Get the current congestion window.
-spec get_pacing_tokens(cc_state(), non_neg_integer()) -> {non_neg_integer(), cc_state()}.
Get pacing tokens for sending.
Whether the last packet of a flight should carry IMMEDIATE_ACK.
Check if in recovery phase.
Check if in slow start phase.
-spec initial_window(cc_state()) -> non_neg_integer().
The congestion window this controller was configured with. cwnd evolves away from it, so a reset needs it to restore the configured value rather than a hardcoded default.
-spec max_datagram_size(cc_state()) -> pos_integer().
Get the current max datagram size.
-spec min_recovery_duration(cc_state()) -> non_neg_integer().
Get minimum recovery duration setting.
-spec new() -> cc_state().
Create a new congestion control state with default algorithm (NewReno).
Create a new congestion control state with options. Uses the algorithm specified in options, or NewReno by default.
Options: - algorithm: CC algorithm (newreno | bbr), default: newreno - max_datagram_size: Maximum datagram size (default: 1200) - initial_window: Override initial congestion window - minimum_window: Lower bound for cwnd after congestion events - min_recovery_duration: Minimum time in recovery before exit (ms)
-spec new(cc_algorithm(), cc_opts()) -> cc_state().
Create a new congestion control state with explicit algorithm.
Algorithm: newreno | bbr Options: Same as new/1 (algorithm option is ignored)
-spec on_ack_frequency(cc_state(), ack_frequency()) -> cc_state().
The peer was asked for this ACK frequency.
The sender has nothing queued to send. BBR marks its delivery rate samples application-limited (draft-ietf-ccwg-bbr-07 Section 4.1.2.4); the other algorithms do not use it.
-spec on_congestion_event(cc_state(), non_neg_integer()) -> cc_state().
Handle a congestion event (packet loss detected). A window cut at once lets the next packet out regardless of the new window (RFC 9002 Section 7.3.2).
-spec on_packet_sent(cc_state(), non_neg_integer()) -> cc_state().
Record that a packet was sent.
-spec on_packets_acked(cc_state(), non_neg_integer()) -> cc_state().
Process acknowledged packets.
-spec on_packets_acked(cc_state(), non_neg_integer(), non_neg_integer()) -> cc_state().
Process acknowledged packets with largest acked sent time.
-spec on_packets_discarded(cc_state(), non_neg_integer()) -> cc_state().
Remove bytes for packets whose packet number space was discarded. Not a congestion event: the packets were neither acknowledged nor lost, they simply stopped existing, so the window and recovery state are untouched (RFC 9002 Section 6.4).
-spec on_packets_lost(cc_state(), non_neg_integer()) -> cc_state().
Process lost packets.
-spec on_packets_sent(cc_state(), [non_neg_integer()]) -> cc_state().
Batched on_packet_sent for a run: one update for newreno, a fold for other algorithms.
Handle persistent congestion.
Undo the last window reduction: every packet it was for turned out to be delivered, only late.
-spec pacing_allows(cc_state(), non_neg_integer()) -> boolean().
Check if pacing allows sending.
-spec pacing_delay(cc_state(), non_neg_integer()) -> non_neg_integer().
Calculate pacing delay.
Start the window over after a Retry (RFC 9002 Section 6.3), keeping the algorithm, MTU and configured windows. Rebuilding the controller instead would silently drop those.
-spec send_check(cc_state(), non_neg_integer()) -> {ok, cc_state()} | {blocked_cwnd, non_neg_integer()} | {blocked_pacing, non_neg_integer()}.
Fused send check (cwnd + pacing) for the hot send path. See the behavior callback for the return shape.
-spec send_check_run(cc_state(), non_neg_integer(), non_neg_integer()) -> {non_neg_integer(), cc_state()}.
Batched send_check: approve up to MaxK packets of Size in one pass. Native for newreno; other algorithms fold send_check/2 with identical results.
-spec ssthresh(cc_state()) -> non_neg_integer() | infinity.
Get the slow start threshold.
-spec update_mtu(cc_state(), pos_integer()) -> cc_state().
Update congestion control state when MTU changes.
-spec update_pacing_rate(cc_state(), non_neg_integer()) -> cc_state().
Update pacing rate based on smoothed RTT.