nquic_cc_newreno (nquic v1.0.0)
View SourceNewReno congestion control per RFC 9002 Section 7.3.
Implements slow start, congestion avoidance, and loss recovery with a
loss reduction factor of 0.5. Initial window follows RFC 9002 Section 7.2:
min(10 * MSS, max(14720, 2 * MSS)).
Summary
Functions
Get the current congestion window size in bytes.
Get the current maximum datagram size in bytes.
Get the current slow start threshold.
Initialize NewReno state with default 1200-byte MSS and computed initial window.
Halve the congestion window on a loss event, entering a new recovery period.
Reset the congestion window to initial_window(MSS) after an idle
period (RFC 9002 Section 7.8). Recovery period and the spurious-loss
snapshot are also cleared since neither survives a fresh start.
Increase the congestion window on packet acknowledgement (slow start or congestion avoidance).
Handle a sent packet (no-op for NewReno).
Collapse the congestion window to the minimum (2 * max_datagram_size)
on persistent congestion (RFC 9002 Section 7.6.2).
The recovery period is also reset so that subsequent ACKs for newly sent
packets can grow the window again. Any pending spurious-loss snapshot is
discarded; by definition the loss was real.
Roll back the most recent congestion-event reduction (RFC 9002 Appendix A.10) when a packet that was previously declared lost is later acknowledged. No-op when no rollback snapshot is available (e.g. the window has already grown past the saved value or the snapshot was consumed).
Set the maximum datagram size, recalculating cwnd if still at the initial window.
Functions
-spec get_cwnd(#state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}) -> non_neg_integer().
Get the current congestion window size in bytes.
-spec get_max_datagram_size(#state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}) -> pos_integer().
Get the current maximum datagram size in bytes.
-spec get_ssthresh(#state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}) -> non_neg_integer().
Get the current slow start threshold.
-spec init() -> #state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}.
Initialize NewReno state with default 1200-byte MSS and computed initial window.
-spec initial_window(pos_integer()) -> non_neg_integer().
-spec on_congestion_event(#state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}, non_neg_integer(), non_neg_integer(), non_neg_integer()) -> #state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}.
Halve the congestion window on a loss event, entering a new recovery period.
-spec on_idle_reset(#state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}) -> #state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}.
Reset the congestion window to initial_window(MSS) after an idle
period (RFC 9002 Section 7.8). Recovery period and the spurious-loss
snapshot are also cleared since neither survives a fresh start.
-spec on_packet_acked(#state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}, #sent_packet{packet_number :: nquic_packet_number:t(), time_sent :: non_neg_integer(), size :: non_neg_integer(), ack_eliciting :: boolean(), in_flight :: boolean(), frames :: [nquic_frame:t()]}, non_neg_integer(), map()) -> #state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}.
Increase the congestion window on packet acknowledgement (slow start or congestion avoidance).
-spec on_packet_sent(#state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}, non_neg_integer(), non_neg_integer()) -> #state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}.
Handle a sent packet (no-op for NewReno).
-spec on_persistent_congestion(#state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}) -> #state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}.
Collapse the congestion window to the minimum (2 * max_datagram_size)
on persistent congestion (RFC 9002 Section 7.6.2).
The recovery period is also reset so that subsequent ACKs for newly sent
packets can grow the window again. Any pending spurious-loss snapshot is
discarded; by definition the loss was real.
-spec on_spurious_congestion(#state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}) -> #state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}.
Roll back the most recent congestion-event reduction (RFC 9002 Appendix A.10) when a packet that was previously declared lost is later acknowledged. No-op when no rollback snapshot is available (e.g. the window has already grown past the saved value or the snapshot was consumed).
-spec set_max_datagram_size(#state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}, pos_integer()) -> #state{cwnd :: non_neg_integer(), ssthresh :: non_neg_integer(), recovery_start_time :: integer(), max_datagram_size :: pos_integer(), congestion_occurred :: boolean(), prev_state :: undefined | {non_neg_integer(), non_neg_integer(), integer(), boolean()}}.
Set the maximum datagram size, recalculating cwnd if still at the initial window.