noq_proto/congestion/
new_reno.rs1use std::any::Any;
2use std::sync::Arc;
3
4use super::{BASE_DATAGRAM_SIZE, Controller, ControllerFactory};
5use crate::Instant;
6use crate::connection::RttEstimator;
7
8#[derive(Debug, Clone)]
10pub struct NewReno {
11 config: Arc<NewRenoConfig>,
12 current_mtu: u64,
13 window: u64,
15 ssthresh: u64,
18 recovery_start_time: Instant,
21 bytes_acked: u64,
23}
24
25impl NewReno {
26 pub fn new(config: Arc<NewRenoConfig>, now: Instant, current_mtu: u16) -> Self {
28 Self {
29 window: config.initial_window,
30 ssthresh: u64::MAX,
31 recovery_start_time: now,
32 current_mtu: current_mtu as u64,
33 config,
34 bytes_acked: 0,
35 }
36 }
37
38 fn minimum_window(&self) -> u64 {
39 2 * self.current_mtu
40 }
41}
42
43impl Controller for NewReno {
44 fn on_ack(
45 &mut self,
46 _now: Instant,
47 sent: Instant,
48 bytes: u64,
49 _pn: u64,
50 app_limited: bool,
51 _rtt: &RttEstimator,
52 ) {
53 if app_limited || sent <= self.recovery_start_time {
54 return;
55 }
56
57 if self.window < self.ssthresh {
58 self.window += bytes;
60
61 if self.window >= self.ssthresh {
62 self.bytes_acked = self.window - self.ssthresh;
69 }
70 } else {
71 self.bytes_acked += bytes;
78
79 if self.bytes_acked >= self.window {
80 self.bytes_acked -= self.window;
81 self.window += self.current_mtu;
82 }
83 }
84 }
85
86 fn on_congestion_event(
87 &mut self,
88 now: Instant,
89 sent: Instant,
90 is_persistent_congestion: bool,
91 _is_ecn: bool,
92 _lost_bytes: u64,
93 _largest_lost_pn: u64,
94 ) {
95 if sent <= self.recovery_start_time {
96 return;
97 }
98
99 self.recovery_start_time = now;
100 self.window = (self.window as f32 * self.config.loss_reduction_factor) as u64;
101 self.window = self.window.max(self.minimum_window());
102 self.ssthresh = self.window;
103
104 if is_persistent_congestion {
105 self.window = self.minimum_window();
106 }
107 }
108
109 fn on_mtu_update(&mut self, new_mtu: u16) {
110 self.current_mtu = new_mtu as u64;
111 self.window = self.window.max(self.minimum_window());
112 }
113
114 fn window(&self) -> u64 {
115 self.window
116 }
117
118 fn metrics(&self) -> super::ControllerMetrics {
119 super::ControllerMetrics {
120 congestion_window: self.window(),
121 ssthresh: Some(self.ssthresh),
122 pacing_rate: None,
123 send_quantum: None,
124 }
125 }
126
127 fn clone_box(&self) -> Box<dyn Controller> {
128 Box::new(self.clone())
129 }
130
131 fn initial_window(&self) -> u64 {
132 self.config.initial_window
133 }
134
135 fn into_any(self: Box<Self>) -> Box<dyn Any> {
136 self
137 }
138}
139
140#[derive(Debug, Clone)]
142pub struct NewRenoConfig {
143 initial_window: u64,
144 loss_reduction_factor: f32,
145}
146
147impl NewRenoConfig {
148 pub fn initial_window(&mut self, value: u64) -> &mut Self {
152 self.initial_window = value;
153 self
154 }
155
156 pub fn loss_reduction_factor(&mut self, value: f32) -> &mut Self {
158 self.loss_reduction_factor = value;
159 self
160 }
161}
162
163impl Default for NewRenoConfig {
164 fn default() -> Self {
165 Self {
166 initial_window: 14720.clamp(2 * BASE_DATAGRAM_SIZE, 10 * BASE_DATAGRAM_SIZE),
167 loss_reduction_factor: 0.5,
168 }
169 }
170}
171
172impl ControllerFactory for NewRenoConfig {
173 fn build(self: Arc<Self>, now: Instant, current_mtu: u16) -> Box<dyn Controller> {
174 Box::new(NewReno::new(self, now, current_mtu))
175 }
176}