ant_quic/
congestion.rs

1// Copyright 2024 Saorsa Labs Ltd.
2//
3// This Saorsa Network Software is licensed under the General Public License (GPL), version 3.
4// Please see the file LICENSE-GPL, or visit <http://www.gnu.org/licenses/> for the full text.
5//
6// Full details available at https://saorsalabs.com/licenses
7
8//! Congestion Control Algorithms
9//!
10//! This module provides congestion control algorithms for QUIC connections.
11
12use crate::connection::RttEstimator;
13use std::any::Any;
14use std::time::Instant;
15
16// Re-export the congestion control implementations
17pub(crate) mod bbr;
18pub(crate) mod cubic;
19pub(crate) mod new_reno;
20
21// Re-export commonly used types
22// pub use self::bbr::{Bbr, BbrConfig};
23pub(crate) use self::cubic::CubicConfig;
24// pub use self::new_reno::{NewReno as NewRenoFull, NewRenoConfig};
25
26/// Metrics exported by congestion controllers
27#[derive(Debug, Default, Clone, Copy)]
28pub struct ControllerMetrics {
29    /// Current congestion window in bytes
30    pub congestion_window: u64,
31    /// Slow start threshold in bytes (optional)
32    pub ssthresh: Option<u64>,
33    /// Pacing rate in bytes per second (optional)
34    pub pacing_rate: Option<u64>,
35}
36
37/// Congestion controller interface
38pub trait Controller: Send + Sync {
39    /// Called when a packet is sent
40    fn on_sent(&mut self, now: Instant, bytes: u64, last_packet_number: u64) {
41        let _ = (now, bytes, last_packet_number);
42    }
43
44    /// Called when a packet is acknowledged
45    fn on_ack(
46        &mut self,
47        now: Instant,
48        sent: Instant,
49        bytes: u64,
50        app_limited: bool,
51        rtt: &RttEstimator,
52    );
53
54    /// Called when the known in-flight packet count has decreased (should be called exactly once per on_ack_received)
55    fn on_end_acks(
56        &mut self,
57        now: Instant,
58        in_flight: u64,
59        app_limited: bool,
60        largest_packet_num_acked: Option<u64>,
61    ) {
62        let _ = (now, in_flight, app_limited, largest_packet_num_acked);
63    }
64
65    /// Called when a congestion event occurs (packet loss)
66    fn on_congestion_event(
67        &mut self,
68        now: Instant,
69        sent: Instant,
70        is_persistent_congestion: bool,
71        lost_bytes: u64,
72    );
73
74    /// Called when the maximum transmission unit (MTU) changes
75    fn on_mtu_update(&mut self, new_mtu: u16);
76
77    /// Get the current congestion window size
78    fn window(&self) -> u64;
79
80    /// Get controller metrics
81    fn metrics(&self) -> ControllerMetrics {
82        ControllerMetrics {
83            congestion_window: self.window(),
84            ssthresh: None,
85            pacing_rate: None,
86        }
87    }
88
89    /// Clone this controller into a new boxed instance
90    fn clone_box(&self) -> Box<dyn Controller>;
91
92    /// Get the initial congestion window size
93    fn initial_window(&self) -> u64;
94
95    /// Convert this controller to Any for downcasting
96    fn into_any(self: Box<Self>) -> Box<dyn Any>;
97}
98
99/// Base datagram size constant
100pub(crate) const BASE_DATAGRAM_SIZE: u64 = 1200;
101
102/// Simplified NewReno congestion control algorithm
103///
104/// This is a minimal implementation that provides basic congestion control.
105#[derive(Clone)]
106#[allow(dead_code)]
107pub(crate) struct NewReno {
108    /// Current congestion window size
109    window: u64,
110
111    /// Slow start threshold
112    ssthresh: u64,
113
114    /// Minimum congestion window size
115    min_window: u64,
116
117    /// Maximum congestion window size
118    max_window: u64,
119
120    /// Initial window size
121    initial_window: u64,
122
123    /// Current MTU
124    current_mtu: u64,
125
126    /// Recovery start time
127    recovery_start_time: Instant,
128}
129
130impl NewReno {
131    /// Create a new NewReno controller
132    #[allow(dead_code)]
133    pub(crate) fn new(min_window: u64, max_window: u64, now: Instant) -> Self {
134        let initial_window = min_window.max(10 * BASE_DATAGRAM_SIZE);
135        Self {
136            window: initial_window,
137            ssthresh: max_window,
138            min_window,
139            max_window,
140            initial_window,
141            current_mtu: BASE_DATAGRAM_SIZE,
142            recovery_start_time: now,
143        }
144    }
145}
146
147impl Controller for NewReno {
148    fn on_ack(
149        &mut self,
150        _now: Instant,
151        sent: Instant,
152        bytes: u64,
153        app_limited: bool,
154        _rtt: &RttEstimator,
155    ) {
156        if app_limited || sent <= self.recovery_start_time {
157            return;
158        }
159
160        if self.window < self.ssthresh {
161            // Slow start
162            self.window = (self.window + bytes).min(self.max_window);
163        } else {
164            // Congestion avoidance - increase by MTU per RTT
165            let increase = (bytes * self.current_mtu) / self.window;
166            self.window = (self.window + increase).min(self.max_window);
167        }
168    }
169
170    fn on_congestion_event(
171        &mut self,
172        now: Instant,
173        sent: Instant,
174        is_persistent_congestion: bool,
175        _lost_bytes: u64,
176    ) {
177        if sent <= self.recovery_start_time {
178            return;
179        }
180
181        self.recovery_start_time = now;
182        self.window = (self.window / 2).max(self.min_window);
183        self.ssthresh = self.window;
184
185        if is_persistent_congestion {
186            self.window = self.min_window;
187        }
188    }
189
190    fn on_mtu_update(&mut self, new_mtu: u16) {
191        self.current_mtu = new_mtu as u64;
192        self.min_window = 2 * self.current_mtu;
193        self.window = self.window.max(self.min_window);
194    }
195
196    fn window(&self) -> u64 {
197        self.window
198    }
199
200    fn metrics(&self) -> ControllerMetrics {
201        ControllerMetrics {
202            congestion_window: self.window,
203            ssthresh: Some(self.ssthresh),
204            pacing_rate: None,
205        }
206    }
207
208    fn clone_box(&self) -> Box<dyn Controller> {
209        Box::new(self.clone())
210    }
211
212    fn initial_window(&self) -> u64 {
213        self.initial_window
214    }
215
216    fn into_any(self: Box<Self>) -> Box<dyn Any> {
217        self
218    }
219}
220
221/// Factory trait for creating congestion controllers
222pub trait ControllerFactory: Send + Sync {
223    /// Create a new controller instance
224    fn new_controller(
225        &self,
226        min_window: u64,
227        max_window: u64,
228        now: Instant,
229    ) -> Box<dyn Controller + Send + Sync>;
230}