quiche/recovery/gcongestion/
mod.rs

1// Copyright (C) 2024, Cloudflare, Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright notice,
9//       this list of conditions and the following disclaimer.
10//
11//     * Redistributions in binary form must reproduce the above copyright
12//       notice, this list of conditions and the following disclaimer in the
13//       documentation and/or other materials provided with the distribution.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27mod bbr;
28mod bbr2;
29pub mod pacer;
30mod recovery;
31
32use std::fmt::Debug;
33use std::str::FromStr;
34use std::time::Instant;
35
36pub use self::recovery::GRecovery;
37use crate::recovery::bandwidth::Bandwidth;
38
39use crate::recovery::rtt::RttStats;
40use crate::recovery::RecoveryConfig;
41use crate::recovery::RecoveryStats;
42
43#[derive(Debug)]
44pub struct Lost {
45    pub(super) packet_number: u64,
46    pub(super) bytes_lost: usize,
47}
48
49#[derive(Debug)]
50pub struct Acked {
51    pub(super) pkt_num: u64,
52    pub(super) time_sent: Instant,
53}
54
55#[enum_dispatch::enum_dispatch(CongestionControl)]
56#[allow(clippy::large_enum_variant)]
57#[derive(Debug)]
58pub(crate) enum Congestion {
59    BBRv2(bbr2::BBRv2),
60}
61
62impl Congestion {
63    pub(super) fn bbrv2(
64        initial_tcp_congestion_window: usize, max_congestion_window: usize,
65        recovery_config: &RecoveryConfig,
66    ) -> Self {
67        Congestion::BBRv2(bbr2::BBRv2::new(
68            initial_tcp_congestion_window,
69            max_congestion_window,
70            recovery_config.max_send_udp_payload_size,
71            recovery_config.initial_rtt,
72            recovery_config.custom_bbr_params.as_ref(),
73        ))
74    }
75}
76
77#[enum_dispatch::enum_dispatch]
78pub(super) trait CongestionControl: Debug {
79    /// Returns the name of the current state of the congestion control state
80    /// machine. Used to annotate qlogs after state transitions.
81    #[cfg(feature = "qlog")]
82    fn state_str(&self) -> &'static str;
83
84    /// Returns the size of the current congestion window in bytes. Note, this
85    /// is not the *available* window. Some send algorithms may not use a
86    /// congestion window and will return 0.
87    fn get_congestion_window(&self) -> usize;
88
89    /// Returns the size of the current congestion window in packets. Note, this
90    /// is not the *available* window. Some send algorithms may not use a
91    /// congestion window and will return 0.
92    fn get_congestion_window_in_packets(&self) -> usize;
93
94    /// Make decision on whether the sender can send right now.  Note that even
95    /// when this method returns true, the sending can be delayed due to pacing.
96    fn can_send(&self, bytes_in_flight: usize) -> bool;
97
98    /// Inform that we sent `bytes` to the wire, and if the packet is
99    /// retransmittable. `bytes_in_flight` is the number of bytes in flight
100    /// before the packet was sent. Note: this function must be called for
101    /// every packet sent to the wire.
102    fn on_packet_sent(
103        &mut self, sent_time: Instant, bytes_in_flight: usize,
104        packet_number: u64, bytes: usize, is_retransmissible: bool,
105        rtt_stats: &RttStats,
106    );
107
108    /// Inform that `packet_number` has been neutered.
109    fn on_packet_neutered(&mut self, _packet_number: u64) {}
110
111    /// Indicates an update to the congestion state, caused either by an
112    /// incoming ack or loss event timeout. `rtt_updated` indicates whether a
113    /// new `latest_rtt` sample has been taken, `prior_in_flight` the bytes in
114    /// flight prior to the congestion event. `acked_packets` and `lost_packets`
115    /// are any packets considered acked or lost as a result of the
116    /// congestion event.
117    #[allow(clippy::too_many_arguments)]
118    fn on_congestion_event(
119        &mut self, rtt_updated: bool, prior_in_flight: usize,
120        bytes_in_flight: usize, event_time: Instant, acked_packets: &[Acked],
121        lost_packets: &[Lost], least_unacked: u64, rtt_stats: &RttStats,
122        recovery_stats: &mut RecoveryStats,
123    );
124
125    /// Called when an RTO fires.  Resets the retransmission alarm if there are
126    /// remaining unacked packets.
127    fn on_retransmission_timeout(&mut self, packets_retransmitted: bool);
128
129    /// Called when connection migrates and cwnd needs to be reset.
130    #[allow(dead_code)]
131    fn on_connection_migration(&mut self);
132
133    /// Adjust the current cwnd to a new maximal size
134    fn limit_cwnd(&mut self, _max_cwnd: usize) {}
135
136    fn is_in_recovery(&self) -> bool;
137
138    #[allow(dead_code)]
139    fn is_cwnd_limited(&self, bytes_in_flight: usize) -> bool;
140
141    #[cfg(test)]
142    fn is_app_limited(&self, bytes_in_flight: usize) -> bool {
143        !self.is_cwnd_limited(bytes_in_flight)
144    }
145
146    fn pacing_rate(
147        &self, bytes_in_flight: usize, rtt_stats: &RttStats,
148    ) -> Bandwidth;
149
150    fn bandwidth_estimate(&self, rtt_stats: &RttStats) -> Bandwidth;
151
152    fn update_mss(&mut self, new_mss: usize);
153
154    fn on_app_limited(&mut self, _bytes_in_flight: usize) {}
155
156    #[cfg(feature = "qlog")]
157    fn ssthresh(&self) -> Option<u64> {
158        None
159    }
160}
161
162/// BBR settings used to customize the algorithm's behavior.
163///
164/// This functionality is experimental and will be removed in the future.
165///
166/// A congestion control algorithm has dual-responsibility of effective network
167/// utilization and avoiding congestion. Custom values should be choosen
168/// carefully since incorrect values can lead to network degradation for all
169/// connections on the shared network.
170#[derive(Debug, Default, Copy, Clone, PartialEq)]
171#[repr(C)]
172#[doc(hidden)]
173pub struct BbrParams {
174    /// Controls the BBR startup gain.
175    pub startup_cwnd_gain: Option<f32>,
176
177    /// Controls the BBR startup pacing gain.
178    pub startup_pacing_gain: Option<f32>,
179
180    /// Controls the BBR full bandwidth threshold.
181    pub full_bw_threshold: Option<f32>,
182
183    /// Controls the BBR startup loss count necessary to exit startup.
184    pub startup_full_loss_count: Option<usize>,
185
186    /// Controls the BBR drain cwnd gain.
187    pub drain_cwnd_gain: Option<f32>,
188
189    /// Controls the BBR drain pacing gain.
190    pub drain_pacing_gain: Option<f32>,
191
192    /// Controls if BBR should respect Reno coexistence.
193    pub enable_reno_coexistence: Option<bool>,
194
195    /// Controls if BBR should enable code in Bandwidth Sampler that
196    /// attempts to avoid overestimating bandwidth on ack compression.
197    pub enable_overestimate_avoidance: Option<bool>,
198
199    /// Controls if BBR should enable a possible fix in Bandwidth
200    /// Sampler that attempts to bandwidth over estimation avoidance.
201    pub choose_a0_point_fix: Option<bool>,
202
203    /// Controls the BBR bandwidth probe up pacing gain.
204    pub probe_bw_probe_up_pacing_gain: Option<f32>,
205
206    /// Controls the BBR bandwidth probe down pacing gain.
207    pub probe_bw_probe_down_pacing_gain: Option<f32>,
208
209    /// Controls the BBR probe bandwidth cwnd gain.
210    pub probe_bw_cwnd_gain: Option<f32>,
211
212    /// Controls the number of rounds BBR should stay in probe up if
213    /// bytes_in_flight doesn't drop below target.
214    pub max_probe_up_queue_rounds: Option<usize>,
215
216    /// Controls the BBR loss threshold.
217    pub loss_threshold: Option<f32>,
218
219    /// Controls if BBR should use bytes delievered as an estimate for
220    /// inflight_hi.
221    pub use_bytes_delivered_for_inflight_hi: Option<bool>,
222
223    /// Controls if BBR should adjust startup pacing at round end.
224    pub decrease_startup_pacing_at_end_of_round: Option<bool>,
225
226    /// Controls the BBR bandwidth lo reduction strategy.
227    pub bw_lo_reduction_strategy: Option<BbrBwLoReductionStrategy>,
228
229    /// Determines whether app limited rounds with no bandwidth growth count
230    /// towards the rounds threshold to exit startup.
231    pub ignore_app_limited_for_no_bandwidth_growth: Option<bool>,
232}
233
234/// Controls BBR's bandwidth reduction strategy on congestion event.
235///
236/// This functionality is experimental and will be removed in the future.
237#[derive(Debug, Copy, Clone, PartialEq, Eq)]
238#[repr(C)]
239#[doc(hidden)]
240pub enum BbrBwLoReductionStrategy {
241    /// Uses the default strategy based on `BBRBeta`.
242    Default           = 0,
243
244    /// Considers min-rtt to estimate bandwidth reduction.
245    MinRttReduction   = 1,
246
247    /// Considers inflight data to estimate bandwidth reduction.
248    InflightReduction = 2,
249
250    /// Considers cwnd to estimate bandwidth reduction.
251    CwndReduction     = 3,
252}
253
254#[doc(hidden)]
255impl FromStr for BbrBwLoReductionStrategy {
256    type Err = crate::Error;
257
258    /// Converts a string to `BbrBwLoReductionStrategy`.
259    ///
260    /// If `name` is not valid, `Error::CongestionControl` is returned.
261    fn from_str(name: &str) -> Result<Self, Self::Err> {
262        match name {
263            "default" => Ok(BbrBwLoReductionStrategy::Default),
264            "minrtt" => Ok(BbrBwLoReductionStrategy::MinRttReduction),
265            "inflight" => Ok(BbrBwLoReductionStrategy::InflightReduction),
266            "cwnd" => Ok(BbrBwLoReductionStrategy::CwndReduction),
267
268            _ => Err(crate::Error::CongestionControl),
269        }
270    }
271}