quiche/recovery/congestion/
prr.rs1use std::cmp;
34
35#[derive(Default, Debug)]
36pub struct PRR {
37 prr_delivered: usize,
39
40 recoverfs: usize,
42
43 prr_out: usize,
45
46 pub snd_cnt: usize,
48}
49
50impl PRR {
51 pub fn on_packet_sent(&mut self, sent_bytes: usize) {
52 self.prr_out += sent_bytes;
53
54 self.snd_cnt = self.snd_cnt.saturating_sub(sent_bytes);
55 }
56
57 pub fn congestion_event(&mut self, bytes_in_flight: usize) {
58 self.prr_delivered = 0;
59
60 self.recoverfs = bytes_in_flight;
61
62 self.prr_out = 0;
63
64 self.snd_cnt = 0;
65 }
66
67 pub fn on_packet_acked(
68 &mut self, delivered_data: usize, pipe: usize, ssthresh: usize,
69 max_datagram_size: usize,
70 ) {
71 self.prr_delivered += delivered_data;
72
73 self.snd_cnt = if pipe > ssthresh {
74 if self.recoverfs > 0 {
76 (self.prr_delivered * ssthresh)
77 .div_ceil(self.recoverfs)
78 .saturating_sub(self.prr_out)
79 } else {
80 0
81 }
82 } else {
83 let limit = cmp::max(
85 self.prr_delivered.saturating_sub(self.prr_out),
86 delivered_data,
87 ) + max_datagram_size;
88
89 cmp::min(ssthresh - pipe, limit)
91 };
92
93 self.snd_cnt = cmp::max(self.snd_cnt, 0);
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn congestion_event() {
104 let mut prr = PRR::default();
105 let bytes_in_flight = 1000;
106
107 prr.congestion_event(bytes_in_flight);
108
109 assert_eq!(prr.recoverfs, bytes_in_flight);
110 assert_eq!(prr.snd_cnt, 0);
111 }
112
113 #[test]
114 fn on_packet_sent() {
115 let mut prr = PRR::default();
116 let bytes_in_flight = 1000;
117 let bytes_sent = 500;
118
119 prr.congestion_event(bytes_in_flight);
120
121 prr.on_packet_sent(bytes_sent);
122
123 assert_eq!(prr.prr_out, bytes_sent);
124 assert_eq!(prr.snd_cnt, 0);
125 }
126
127 #[test]
128 fn on_packet_acked_prr() {
129 let mut prr = PRR::default();
130 let max_datagram_size = 1000;
131 let bytes_in_flight = max_datagram_size * 10;
132 let ssthresh = bytes_in_flight / 2;
133 let acked = 1000;
134
135 prr.congestion_event(bytes_in_flight);
136
137 let pipe = bytes_in_flight;
139
140 prr.on_packet_acked(acked, pipe, ssthresh, max_datagram_size);
141
142 assert_eq!(prr.snd_cnt, 500);
143
144 let snd_cnt = prr.snd_cnt;
145
146 prr.on_packet_sent(snd_cnt);
148
149 prr.on_packet_acked(acked, pipe, ssthresh, max_datagram_size);
150
151 assert_eq!(prr.snd_cnt, 500);
152 }
153
154 #[test]
155 fn on_packet_acked_prr_overflow() {
156 let mut prr = PRR::default();
157 let max_datagram_size = 1000;
158 let bytes_in_flight = max_datagram_size * 10;
159 let ssthresh = bytes_in_flight / 2;
160 let acked = 1000;
161
162 prr.congestion_event(bytes_in_flight);
163
164 prr.on_packet_sent(max_datagram_size);
165
166 let pipe = bytes_in_flight + max_datagram_size;
168
169 prr.on_packet_acked(acked, pipe, ssthresh, max_datagram_size);
170
171 assert_eq!(prr.snd_cnt, 0);
172 }
173
174 #[test]
175 fn on_packet_acked_prr_zero_in_flight() {
176 let mut prr = PRR::default();
177 let max_datagram_size = 1000;
178 let bytes_in_flight = 0;
179 let ssthresh = 3000;
180 let acked = 1000;
181
182 prr.congestion_event(bytes_in_flight);
183
184 let pipe = ssthresh + 1000;
186
187 prr.on_packet_acked(acked, pipe, ssthresh, max_datagram_size);
188
189 assert_eq!(prr.snd_cnt, 0);
190 }
191
192 #[test]
193 fn on_packet_acked_prr_ssrb() {
194 let mut prr = PRR::default();
195 let max_datagram_size = 1000;
196 let bytes_in_flight = max_datagram_size * 10;
197 let ssthresh = bytes_in_flight / 2;
198 let acked = 1000;
199
200 prr.congestion_event(bytes_in_flight);
201
202 let pipe = max_datagram_size;
204
205 prr.on_packet_acked(acked, pipe, ssthresh, max_datagram_size);
206
207 assert_eq!(prr.snd_cnt, 2000);
208
209 let snd_cnt = prr.snd_cnt;
210
211 prr.on_packet_sent(snd_cnt);
213
214 prr.on_packet_acked(acked, pipe, ssthresh, max_datagram_size);
215
216 assert_eq!(prr.snd_cnt, 2000);
217 }
218
219 #[test]
220 fn on_packet_acked_prr_ssrb_overflow() {
221 let mut prr = PRR::default();
222 let max_datagram_size = 1000;
223 let bytes_in_flight = max_datagram_size * 10;
224 let ssthresh = bytes_in_flight / 2;
225 let acked = 500;
226
227 prr.congestion_event(bytes_in_flight);
228
229 let pipe = max_datagram_size;
231
232 prr.on_packet_sent(max_datagram_size);
233
234 prr.on_packet_acked(acked, pipe, ssthresh, max_datagram_size);
235
236 assert_eq!(prr.snd_cnt, 1500);
237 }
238}