1use super::{
8 params::VegasParams, rtt::RoundtripTimeEstimator, CongestionControlAlgorithm,
9 CongestionSignals, CongestionWindow, State,
10};
11use crate::Result;
12
13use tor_error::{error_report, internal};
14
15#[derive(Clone, Debug, Default)]
19pub(crate) struct BdpEstimator {
20 bdp: u32,
22}
23
24impl BdpEstimator {
25 fn get(&self) -> u32 {
27 self.bdp
28 }
29
30 fn update(
35 &mut self,
36 cwnd: &CongestionWindow,
37 rtt: &RoundtripTimeEstimator,
38 signals: &CongestionSignals,
39 ) {
40 if rtt.clock_stalled() {
42 self.bdp = if signals.channel_blocked {
43 cwnd.get()
46 .saturating_sub(signals.channel_outbound_size)
47 .max(cwnd.min())
48 } else {
49 cwnd.get()
50 };
51 } else {
52 self.bdp = cwnd
58 .get()
59 .saturating_mul(rtt.min_rtt_usec())
60 .saturating_div(rtt.ewma_rtt_usec());
61 }
62 }
63}
64
65#[derive(Clone, Debug)]
75pub(crate) struct Vegas {
76 params: VegasParams,
78 bdp: BdpEstimator,
81 cwnd: CongestionWindow,
84 num_cell_until_sendme: u32,
86 num_sendme_until_cwnd_update: u32,
89 num_sendme_per_cwnd: u32,
92 num_inflight: u32,
95 is_blocked_on_chan: bool,
99}
100
101impl Vegas {
102 pub(crate) fn new(params: &VegasParams, state: &State, cwnd: CongestionWindow) -> Self {
104 Self {
105 params: params.clone(),
106 bdp: BdpEstimator::default(),
107 num_cell_until_sendme: cwnd.sendme_inc(),
108 num_inflight: 0,
109 num_sendme_per_cwnd: 0,
110 num_sendme_until_cwnd_update: cwnd.update_rate(state),
111 cwnd,
112 is_blocked_on_chan: false,
113 }
114 }
115}
116
117impl CongestionControlAlgorithm for Vegas {
118 fn uses_stream_sendme(&self) -> bool {
119 false
121 }
122 fn is_next_cell_sendme(&self) -> bool {
123 self.num_inflight % self.cwnd.sendme_inc() == 0
126 }
127
128 fn can_send(&self) -> bool {
129 self.num_inflight < self.cwnd.get()
130 }
131
132 fn cwnd(&self) -> Option<&CongestionWindow> {
133 Some(&self.cwnd)
134 }
135
136 fn sendme_received(
147 &mut self,
148 state: &mut State,
149 rtt: &mut RoundtripTimeEstimator,
150 signals: CongestionSignals,
151 ) -> Result<()> {
152 self.num_sendme_until_cwnd_update = self.num_sendme_until_cwnd_update.saturating_sub(1);
154 self.num_sendme_per_cwnd = self.num_sendme_per_cwnd.saturating_sub(1);
156
157 self.bdp.update(&self.cwnd, rtt, &signals);
164
165 if rtt.is_ready() {
168 if signals.channel_blocked {
169 if !self.is_blocked_on_chan {
172 self.num_sendme_until_cwnd_update = 0;
173 }
174 } else {
175 if self.is_blocked_on_chan {
178 self.num_sendme_until_cwnd_update = 0;
179 }
180 }
181 }
182 self.is_blocked_on_chan = signals.channel_blocked;
183
184 if !rtt.is_ready() && !self.is_blocked_on_chan {
186 debug_assert!(self.num_inflight >= self.cwnd.sendme_inc());
190 self.num_inflight = self.num_inflight.saturating_sub(self.cwnd.sendme_inc());
191 return Ok(());
192 }
193
194 let queue_use = self.cwnd.get().saturating_sub(self.bdp.get());
197
198 self.cwnd.eval_fullness(
200 self.num_inflight,
201 self.params.cwnd_full_gap(),
202 self.params.cwnd_full_min_pct().as_percent(),
203 );
204
205 if state.in_slow_start() {
207 if queue_use < self.params.cell_in_queue_params().gamma() && !self.is_blocked_on_chan {
208 if self.cwnd.is_full() {
210 let inc = self
212 .cwnd
213 .rfc3742_ss_inc(self.params.cell_in_queue_params().ss_cwnd_cap());
214
215 if (inc * self.cwnd.sendme_per_cwnd())
218 <= (self.cwnd.increment() * self.cwnd.increment_rate())
219 {
220 *state = State::Steady;
221 }
222 }
223 } else {
224 self.cwnd
226 .set(self.bdp.get() + self.params.cell_in_queue_params().gamma());
227 *state = State::Steady;
229 }
230
231 if self.cwnd.get() >= self.params.ss_cwnd_max() {
233 self.cwnd.set(self.params.ss_cwnd_max());
234 *state = State::Steady;
235 }
236 } else if self.num_sendme_until_cwnd_update == 0 {
237 if queue_use > self.params.cell_in_queue_params().delta() {
239 self.cwnd.set(
241 self.bdp.get() + self.params.cell_in_queue_params().delta()
242 - self.cwnd.increment(),
243 );
244 } else if queue_use > self.params.cell_in_queue_params().beta()
245 || self.is_blocked_on_chan
246 {
247 self.cwnd.dec();
249 } else if self.cwnd.is_full() && queue_use < self.params.cell_in_queue_params().alpha()
250 {
251 self.cwnd.inc();
253 }
254 }
255
256 if self.num_sendme_until_cwnd_update == 0 {
258 self.num_sendme_until_cwnd_update = self.cwnd.update_rate(state);
259 }
260 if self.num_sendme_per_cwnd == 0 {
261 self.num_sendme_per_cwnd = self.cwnd.sendme_per_cwnd();
262 }
263
264 if self.params.cwnd_full_per_cwnd() != 0 {
266 if self.num_sendme_per_cwnd == self.cwnd.sendme_per_cwnd() {
267 self.cwnd.reset_full();
268 }
269 } else if self.num_sendme_until_cwnd_update == self.cwnd.update_rate(state) {
270 self.cwnd.reset_full();
271 }
272
273 self.num_inflight = self.num_inflight.saturating_sub(self.cwnd.sendme_inc());
275 Ok(())
276 }
277
278 fn sendme_sent(&mut self) -> Result<()> {
279 self.num_cell_until_sendme = self.cwnd.sendme_inc();
281 Ok(())
282 }
283
284 fn data_received(&mut self) -> Result<bool> {
285 if self.num_cell_until_sendme == 0 {
286 error_report!(internal!("Congestion control unexptected data cell"), "");
290 return Ok(false);
291 }
292
293 self.num_cell_until_sendme = self.num_cell_until_sendme.saturating_sub(1);
295
296 Ok(self.num_cell_until_sendme == 0)
299 }
300
301 fn data_sent(&mut self) -> Result<()> {
302 self.num_inflight = self.num_inflight.saturating_add(1);
304 Ok(())
305 }
306
307 #[cfg(feature = "conflux")]
308 fn inflight(&self) -> Option<u32> {
309 Some(self.num_inflight)
310 }
311
312 #[cfg(test)]
313 fn send_window(&self) -> u32 {
314 self.cwnd.get()
315 }
316}
317
318#[cfg(test)]
319#[allow(clippy::print_stderr)]
320pub(crate) mod test {
321 #![allow(clippy::bool_assert_comparison)]
323 #![allow(clippy::clone_on_copy)]
324 #![allow(clippy::dbg_macro)]
325 #![allow(clippy::mixed_attributes_style)]
326 #![allow(clippy::print_stderr)]
327 #![allow(clippy::print_stdout)]
328 #![allow(clippy::single_char_pattern)]
329 #![allow(clippy::unwrap_used)]
330 #![allow(clippy::unchecked_duration_subtraction)]
331 #![allow(clippy::useless_vec)]
332 #![allow(clippy::needless_pass_by_value)]
333 use std::{
336 collections::VecDeque,
337 time::{Duration, Instant},
338 };
339 use tor_units::Percentage;
340
341 use super::*;
342 use crate::congestion::{
343 params::VegasParamsBuilder,
344 test_utils::{new_cwnd, new_rtt_estimator},
345 };
346
347 impl Vegas {
348 pub(crate) fn set_inflight(&mut self, v: u32) {
350 self.num_inflight = v;
351 }
352 fn is_blocked_on_chan(&self) -> bool {
354 self.is_blocked_on_chan
355 }
356 fn set_is_blocked_on_chan(&mut self, v: bool) {
358 self.is_blocked_on_chan = v;
359 }
360 }
361
362 #[derive(Debug)]
365 struct TestVectorParams {
366 sent_usec_in: u64,
368 got_sendme_usec_in: u64,
369 or_conn_blocked_in: bool,
370 inflight_in: u32,
371 ewma_rtt_usec_out: u32,
373 min_rtt_usec_out: u32,
374 cwnd_out: u32,
375 in_slow_start_out: bool,
376 cwnd_full_out: bool,
377 blocked_chan_out: bool,
378 }
379
380 impl From<[u32; 10]> for TestVectorParams {
381 fn from(arr: [u32; 10]) -> Self {
382 Self {
383 sent_usec_in: u64::from(arr[0]),
384 got_sendme_usec_in: u64::from(arr[1]),
385 or_conn_blocked_in: arr[2] == 1,
386 inflight_in: arr[3],
387 ewma_rtt_usec_out: arr[4],
388 min_rtt_usec_out: arr[5],
389 cwnd_out: arr[6],
390 in_slow_start_out: arr[7] == 1,
391 cwnd_full_out: arr[8] == 1,
392 blocked_chan_out: arr[9] == 1,
393 }
394 }
395 }
396
397 struct VegasTest {
398 params: VecDeque<TestVectorParams>,
399 rtt: RoundtripTimeEstimator,
400 state: State,
401 vegas: Vegas,
402 }
403
404 impl VegasTest {
405 fn new(vec: Vec<[u32; 10]>) -> Self {
406 let mut params = VecDeque::new();
407 for values in vec {
408 params.push_back(values.into());
409 }
410 let state = State::default();
411 Self {
412 params,
413 rtt: new_rtt_estimator(),
414 vegas: Vegas::new(&build_vegas_params(), &state, new_cwnd()),
415 state,
416 }
417 }
418
419 fn run_once(&mut self, p: &TestVectorParams) {
420 eprintln!("Testing vector: {:?}", p);
421 self.vegas.set_inflight(p.inflight_in);
423 self.vegas.set_is_blocked_on_chan(p.or_conn_blocked_in);
424
425 let now = Instant::now();
426 self.rtt
427 .expect_sendme(now + Duration::from_micros(p.sent_usec_in));
428 let ret = self.rtt.update(
429 now + Duration::from_micros(p.got_sendme_usec_in),
430 &self.state,
431 self.vegas.cwnd().expect("No CWND"),
432 );
433 assert!(ret.is_ok());
434
435 let signals = CongestionSignals::new(p.or_conn_blocked_in, 0);
436 let ret = self
437 .vegas
438 .sendme_received(&mut self.state, &mut self.rtt, signals);
439 assert!(ret.is_ok());
440
441 assert_eq!(self.rtt.ewma_rtt_usec(), p.ewma_rtt_usec_out);
442 assert_eq!(self.rtt.min_rtt_usec(), p.min_rtt_usec_out);
443 assert_eq!(self.vegas.cwnd().expect("No CWND").get(), p.cwnd_out);
444 assert_eq!(
445 self.vegas.cwnd().expect("No CWND").is_full(),
446 p.cwnd_full_out
447 );
448 assert_eq!(self.state.in_slow_start(), p.in_slow_start_out);
449 assert_eq!(self.vegas.is_blocked_on_chan(), p.blocked_chan_out);
450 }
451
452 fn run(&mut self) {
453 while let Some(param) = self.params.pop_front() {
454 self.run_once(¶m);
455 }
456 }
457 }
458
459 pub(crate) fn build_vegas_params() -> VegasParams {
460 const OUTBUF_CELLS: u32 = 62;
461 VegasParamsBuilder::default()
462 .cell_in_queue_params(
463 (
464 3 * OUTBUF_CELLS, 4 * OUTBUF_CELLS, 5 * OUTBUF_CELLS, 3 * OUTBUF_CELLS, 600, )
470 .into(),
471 )
472 .ss_cwnd_max(5_000)
473 .cwnd_full_gap(4)
474 .cwnd_full_min_pct(Percentage::new(25))
475 .cwnd_full_per_cwnd(1)
476 .build()
477 .expect("Unable to build Vegas parameters")
478 }
479
480 #[test]
481 fn test_vectors() {
482 let vec1 = vec![
483 [100000, 200000, 0, 124, 100000, 100000, 155, 1, 0, 0],
484 [200000, 300000, 0, 155, 100000, 100000, 186, 1, 1, 0],
485 [350000, 500000, 0, 186, 133333, 100000, 217, 1, 1, 0],
486 [500000, 550000, 0, 217, 77777, 77777, 248, 1, 1, 0],
487 [600000, 700000, 0, 248, 92592, 77777, 279, 1, 1, 0],
488 [700000, 750000, 0, 279, 64197, 64197, 310, 1, 0, 0], [750000, 875000, 0, 310, 104732, 64197, 341, 1, 1, 0],
490 [875000, 900000, 0, 341, 51577, 51577, 372, 1, 1, 0],
491 [900000, 950000, 0, 279, 50525, 50525, 403, 1, 1, 0],
492 [950000, 1000000, 0, 279, 50175, 50175, 434, 1, 1, 0],
493 [1000000, 1050000, 0, 279, 50058, 50058, 465, 1, 1, 0],
494 [1050000, 1100000, 0, 279, 50019, 50019, 496, 1, 1, 0],
495 [1100000, 1150000, 0, 279, 50006, 50006, 527, 1, 1, 0],
496 [1150000, 1200000, 0, 279, 50002, 50002, 558, 1, 1, 0],
497 [1200000, 1250000, 0, 550, 50000, 50000, 589, 1, 1, 0],
498 [1250000, 1300000, 0, 550, 50000, 50000, 620, 1, 0, 0], [1300000, 1350000, 0, 550, 50000, 50000, 635, 1, 1, 0],
500 [1350000, 1400000, 0, 550, 50000, 50000, 650, 1, 1, 0],
501 [1400000, 1450000, 0, 150, 50000, 50000, 650, 1, 0, 0], [1450000, 1500000, 0, 150, 50000, 50000, 650, 1, 0, 0], [1500000, 1550000, 0, 550, 50000, 50000, 664, 1, 1, 0], [1500000, 1600000, 0, 550, 83333, 50000, 584, 0, 1, 0], [1600000, 1650000, 0, 550, 61111, 50000, 585, 0, 1, 0], [1650000, 1700000, 0, 550, 53703, 50000, 586, 0, 1, 0],
507 [1700000, 1750000, 0, 100, 51234, 50000, 586, 0, 0, 0], [1750000, 1900000, 0, 100, 117078, 50000, 559, 0, 0, 0], [1900000, 2000000, 0, 100, 105692, 50000, 558, 0, 0, 0], [2000000, 2075000, 0, 500, 85230, 50000, 558, 0, 1, 0], [2075000, 2125000, 1, 500, 61743, 50000, 557, 0, 1, 1], [2125000, 2150000, 0, 500, 37247, 37247, 558, 0, 1, 0], [2150000, 2350000, 0, 500, 145749, 37247, 451, 0, 1, 0], ];
515 VegasTest::new(vec1).run();
516
517 let vec2 = vec![
518 [100000, 200000, 0, 124, 100000, 100000, 155, 1, 0, 0],
519 [200000, 300000, 0, 155, 100000, 100000, 186, 1, 1, 0],
520 [350000, 500000, 0, 186, 133333, 100000, 217, 1, 1, 0],
521 [500000, 550000, 1, 217, 77777, 77777, 403, 0, 1, 1], [600000, 700000, 0, 248, 92592, 77777, 404, 0, 1, 0], [700000, 750000, 1, 404, 64197, 64197, 403, 0, 0, 1], [750000, 875000, 0, 403, 104732, 64197, 404, 0, 1, 0],
525 ];
526 VegasTest::new(vec2).run();
527
528 let vec3 = vec![
529 [18258527, 19002938, 0, 83, 744411, 744411, 155, 1, 0, 0],
530 [18258580, 19254257, 0, 52, 911921, 744411, 186, 1, 1, 0],
531 [20003224, 20645298, 0, 164, 732023, 732023, 217, 1, 1, 0],
532 [20003367, 21021444, 0, 133, 922725, 732023, 248, 1, 1, 0],
533 [20003845, 21265508, 0, 102, 1148683, 732023, 279, 1, 1, 0],
534 [20003975, 21429157, 0, 71, 1333015, 732023, 310, 1, 0, 0],
535 [20004309, 21707677, 0, 40, 1579917, 732023, 310, 1, 0, 0],
536 ];
537 VegasTest::new(vec3).run();
538
539 let vec4 = vec![
540 [358297091, 358854163, 0, 83, 557072, 557072, 155, 1, 0, 0],
541 [358297649, 359123845, 0, 52, 736488, 557072, 186, 1, 1, 0],
542 [359492879, 359995330, 0, 186, 580463, 557072, 217, 1, 1, 0],
543 [359493043, 360489243, 0, 217, 857621, 557072, 248, 1, 1, 0],
544 [359493232, 360489673, 0, 248, 950167, 557072, 279, 1, 1, 0],
545 [359493795, 360489971, 0, 279, 980839, 557072, 310, 1, 0, 0],
546 [359493918, 360490248, 0, 310, 991166, 557072, 341, 1, 1, 0],
547 [359494029, 360716465, 0, 341, 1145346, 557072, 372, 1, 1, 0],
548 [359996888, 360948867, 0, 372, 1016434, 557072, 403, 1, 1, 0],
549 [359996979, 360949330, 0, 403, 973712, 557072, 434, 1, 1, 0],
550 [360489528, 361113615, 0, 434, 740628, 557072, 465, 1, 1, 0],
551 [360489656, 361281604, 0, 465, 774841, 557072, 496, 1, 1, 0],
552 [360489837, 361500461, 0, 496, 932029, 557072, 482, 0, 1, 0],
553 [360489963, 361500631, 0, 482, 984455, 557072, 482, 0, 1, 0],
554 [360490117, 361842481, 0, 482, 1229727, 557072, 481, 0, 1, 0],
555 ];
556 VegasTest::new(vec4).run();
557 }
558}