1use std::str::FromStr;
28use std::time::Duration;
29use std::time::Instant;
30
31use crate::frame;
32use crate::packet;
33use crate::ranges::RangeSet;
34pub(crate) use crate::recovery::bandwidth::Bandwidth;
35use crate::Config;
36use crate::Result;
37
38#[cfg(feature = "qlog")]
39use qlog::events::EventData;
40
41use smallvec::SmallVec;
42
43use self::congestion::recovery::LegacyRecovery;
44use self::gcongestion::GRecovery;
45pub use gcongestion::BbrBwLoReductionStrategy;
46pub use gcongestion::BbrParams;
47
48const INITIAL_PACKET_THRESHOLD: u64 = 3;
50
51const MAX_PACKET_THRESHOLD: u64 = 20;
52
53const INITIAL_TIME_THRESHOLD: f64 = 9.0 / 8.0;
57
58const PACKET_REORDER_TIME_THRESHOLD: f64 = 5.0 / 4.0;
70
71const INITIAL_TIME_THRESHOLD_OVERHEAD: f64 = 1.0 / 8.0;
78const TIME_THRESHOLD_OVERHEAD_MULTIPLIER: f64 = 2.0;
82
83const GRANULARITY: Duration = Duration::from_millis(1);
84
85const MAX_PTO_PROBES_COUNT: usize = 2;
86
87const MINIMUM_WINDOW_PACKETS: usize = 2;
88
89const LOSS_REDUCTION_FACTOR: f64 = 0.5;
90
91pub(super) const MAX_OUTSTANDING_NON_ACK_ELICITING: usize = 24;
94
95#[derive(Default)]
96struct LossDetectionTimer {
97 time: Option<Instant>,
98}
99
100impl LossDetectionTimer {
101 fn update(&mut self, timeout: Instant) {
102 self.time = Some(timeout);
103 }
104
105 fn clear(&mut self) {
106 self.time = None;
107 }
108}
109
110impl std::fmt::Debug for LossDetectionTimer {
111 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
112 match self.time {
113 Some(v) => {
114 let now = Instant::now();
115 if v > now {
116 let d = v.duration_since(now);
117 write!(f, "{d:?}")
118 } else {
119 write!(f, "exp")
120 }
121 },
122 None => write!(f, "none"),
123 }
124 }
125}
126
127#[derive(Clone, Copy, PartialEq)]
128pub struct RecoveryConfig {
129 pub initial_rtt: Duration,
130 pub max_send_udp_payload_size: usize,
131 pub max_ack_delay: Duration,
132 pub cc_algorithm: CongestionControlAlgorithm,
133 pub custom_bbr_params: Option<BbrParams>,
134 pub hystart: bool,
135 pub pacing: bool,
136 pub max_pacing_rate: Option<u64>,
137 pub initial_congestion_window_packets: usize,
138 pub enable_relaxed_loss_threshold: bool,
139}
140
141impl RecoveryConfig {
142 pub fn from_config(config: &Config) -> Self {
143 Self {
144 initial_rtt: config.initial_rtt,
145 max_send_udp_payload_size: config.max_send_udp_payload_size,
146 max_ack_delay: Duration::ZERO,
147 cc_algorithm: config.cc_algorithm,
148 custom_bbr_params: config.custom_bbr_params,
149 hystart: config.hystart,
150 pacing: config.pacing,
151 max_pacing_rate: config.max_pacing_rate,
152 initial_congestion_window_packets: config
153 .initial_congestion_window_packets,
154 enable_relaxed_loss_threshold: config.enable_relaxed_loss_threshold,
155 }
156 }
157}
158
159#[enum_dispatch::enum_dispatch(RecoveryOps)]
160#[allow(clippy::large_enum_variant)]
161#[derive(Debug)]
162pub(crate) enum Recovery {
163 Legacy(LegacyRecovery),
164 GCongestion(GRecovery),
165}
166
167#[derive(Debug, Default, PartialEq)]
168pub struct OnAckReceivedOutcome {
169 pub lost_packets: usize,
170 pub lost_bytes: usize,
171 pub acked_bytes: usize,
172 pub spurious_losses: usize,
173}
174
175#[derive(Debug, Default)]
176pub struct OnLossDetectionTimeoutOutcome {
177 pub lost_packets: usize,
178 pub lost_bytes: usize,
179}
180
181#[enum_dispatch::enum_dispatch]
182pub trait RecoveryOps {
184 fn lost_count(&self) -> usize;
185 fn bytes_lost(&self) -> u64;
186
187 fn should_elicit_ack(&self, epoch: packet::Epoch) -> bool;
190
191 fn next_acked_frame(&mut self, epoch: packet::Epoch) -> Option<frame::Frame>;
192
193 fn next_lost_frame(&mut self, epoch: packet::Epoch) -> Option<frame::Frame>;
194
195 fn get_largest_acked_on_epoch(&self, epoch: packet::Epoch) -> Option<u64>;
196 fn has_lost_frames(&self, epoch: packet::Epoch) -> bool;
197 fn loss_probes(&self, epoch: packet::Epoch) -> usize;
198 #[cfg(test)]
199 fn inc_loss_probes(&mut self, epoch: packet::Epoch);
200
201 fn ping_sent(&mut self, epoch: packet::Epoch);
202
203 fn on_packet_sent(
204 &mut self, pkt: Sent, epoch: packet::Epoch,
205 handshake_status: HandshakeStatus, now: Instant, trace_id: &str,
206 );
207 fn get_packet_send_time(&self, now: Instant) -> Instant;
208
209 #[allow(clippy::too_many_arguments)]
210 fn on_ack_received(
211 &mut self, ranges: &RangeSet, ack_delay: u64, epoch: packet::Epoch,
212 handshake_status: HandshakeStatus, now: Instant, skip_pn: Option<u64>,
213 trace_id: &str,
214 ) -> Result<OnAckReceivedOutcome>;
215
216 fn on_loss_detection_timeout(
217 &mut self, handshake_status: HandshakeStatus, now: Instant,
218 trace_id: &str,
219 ) -> OnLossDetectionTimeoutOutcome;
220 fn on_pkt_num_space_discarded(
221 &mut self, epoch: packet::Epoch, handshake_status: HandshakeStatus,
222 now: Instant,
223 );
224 fn on_path_change(
225 &mut self, epoch: packet::Epoch, now: Instant, _trace_id: &str,
226 ) -> (usize, usize);
227 fn loss_detection_timer(&self) -> Option<Instant>;
228 fn cwnd(&self) -> usize;
229 fn cwnd_available(&self) -> usize;
230 fn rtt(&self) -> Duration;
231
232 fn min_rtt(&self) -> Option<Duration>;
233
234 fn max_rtt(&self) -> Option<Duration>;
235
236 fn rttvar(&self) -> Duration;
237
238 fn pto(&self) -> Duration;
239
240 fn delivery_rate(&self) -> Bandwidth;
242
243 fn max_bandwidth(&self) -> Option<Bandwidth>;
245
246 fn startup_exit(&self) -> Option<StartupExit>;
248
249 fn max_datagram_size(&self) -> usize;
250
251 fn pmtud_update_max_datagram_size(&mut self, new_max_datagram_size: usize);
252
253 fn update_max_datagram_size(&mut self, new_max_datagram_size: usize);
254
255 fn on_app_limited(&mut self);
256
257 #[cfg(test)]
260 fn largest_sent_pkt_num_on_path(&self, epoch: packet::Epoch) -> Option<u64>;
261
262 #[cfg(test)]
263 fn app_limited(&self) -> bool;
264
265 #[cfg(test)]
266 fn sent_packets_len(&self, epoch: packet::Epoch) -> usize;
267
268 fn bytes_in_flight(&self) -> usize;
269
270 fn bytes_in_flight_duration(&self) -> Duration;
271
272 #[cfg(test)]
273 fn in_flight_count(&self, epoch: packet::Epoch) -> usize;
274
275 #[cfg(test)]
276 fn pacing_rate(&self) -> u64;
277
278 #[cfg(test)]
279 fn pto_count(&self) -> u32;
280
281 #[cfg(test)]
284 fn pkt_thresh(&self) -> Option<u64>;
285
286 #[cfg(test)]
287 fn time_thresh(&self) -> f64;
288
289 #[cfg(test)]
290 fn lost_spurious_count(&self) -> usize;
291
292 #[cfg(test)]
293 fn detect_lost_packets_for_test(
294 &mut self, epoch: packet::Epoch, now: Instant,
295 ) -> (usize, usize);
296
297 fn update_app_limited(&mut self, v: bool);
298
299 fn delivery_rate_update_app_limited(&mut self, v: bool);
300
301 fn update_max_ack_delay(&mut self, max_ack_delay: Duration);
302
303 #[cfg(feature = "qlog")]
304 fn state_str(&self, now: Instant) -> &'static str;
305
306 #[cfg(feature = "qlog")]
307 fn get_updated_qlog_event_data(&mut self) -> Option<EventData>;
308
309 #[cfg(feature = "qlog")]
310 fn get_updated_qlog_cc_state(&mut self, now: Instant)
311 -> Option<&'static str>;
312
313 fn send_quantum(&self) -> usize;
314
315 fn get_next_release_time(&self) -> ReleaseDecision;
316
317 fn gcongestion_enabled(&self) -> bool;
318}
319
320impl Recovery {
321 pub fn new_with_config(recovery_config: &RecoveryConfig) -> Self {
322 let grecovery = GRecovery::new(recovery_config);
323 if let Some(grecovery) = grecovery {
324 Recovery::from(grecovery)
325 } else {
326 Recovery::from(LegacyRecovery::new_with_config(recovery_config))
327 }
328 }
329
330 #[cfg(feature = "qlog")]
331 pub fn maybe_qlog(
332 &mut self, qlog: &mut qlog::streamer::QlogStreamer, now: Instant,
333 ) {
334 if let Some(ev_data) = self.get_updated_qlog_event_data() {
335 qlog.add_event_data_with_instant(ev_data, now).ok();
336 }
337
338 if let Some(cc_state) = self.get_updated_qlog_cc_state(now) {
339 let ev_data = EventData::CongestionStateUpdated(
340 qlog::events::quic::CongestionStateUpdated {
341 old: None,
342 new: cc_state.to_string(),
343 trigger: None,
344 },
345 );
346
347 qlog.add_event_data_with_instant(ev_data, now).ok();
348 }
349 }
350
351 #[cfg(test)]
352 pub fn new(config: &Config) -> Self {
353 Self::new_with_config(&RecoveryConfig::from_config(config))
354 }
355}
356
357#[derive(Debug, Copy, Clone, PartialEq, Eq)]
362#[repr(C)]
363pub enum CongestionControlAlgorithm {
364 Reno = 0,
366 CUBIC = 1,
368 Bbr2Gcongestion = 4,
371}
372
373impl FromStr for CongestionControlAlgorithm {
374 type Err = crate::Error;
375
376 fn from_str(name: &str) -> std::result::Result<Self, Self::Err> {
380 match name {
381 "reno" => Ok(CongestionControlAlgorithm::Reno),
382 "cubic" => Ok(CongestionControlAlgorithm::CUBIC),
383 "bbr" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
384 "bbr2" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
385 "bbr2_gcongestion" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
386 _ => Err(crate::Error::CongestionControl),
387 }
388 }
389}
390
391#[derive(Clone)]
392pub struct Sent {
393 pub pkt_num: u64,
394
395 pub frames: SmallVec<[frame::Frame; 1]>,
396
397 pub time_sent: Instant,
398
399 pub time_acked: Option<Instant>,
400
401 pub time_lost: Option<Instant>,
402
403 pub size: usize,
404
405 pub ack_eliciting: bool,
406
407 pub in_flight: bool,
408
409 pub delivered: usize,
410
411 pub delivered_time: Instant,
412
413 pub first_sent_time: Instant,
414
415 pub is_app_limited: bool,
416
417 pub tx_in_flight: usize,
418
419 pub lost: u64,
420
421 pub has_data: bool,
422
423 pub is_pmtud_probe: bool,
424}
425
426impl std::fmt::Debug for Sent {
427 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
428 write!(f, "pkt_num={:?} ", self.pkt_num)?;
429 write!(f, "pkt_sent_time={:?} ", self.time_sent)?;
430 write!(f, "pkt_size={:?} ", self.size)?;
431 write!(f, "delivered={:?} ", self.delivered)?;
432 write!(f, "delivered_time={:?} ", self.delivered_time)?;
433 write!(f, "first_sent_time={:?} ", self.first_sent_time)?;
434 write!(f, "is_app_limited={} ", self.is_app_limited)?;
435 write!(f, "tx_in_flight={} ", self.tx_in_flight)?;
436 write!(f, "lost={} ", self.lost)?;
437 write!(f, "has_data={} ", self.has_data)?;
438 write!(f, "is_pmtud_probe={}", self.is_pmtud_probe)?;
439
440 Ok(())
441 }
442}
443
444#[derive(Clone, Copy, Debug)]
445pub struct HandshakeStatus {
446 pub has_handshake_keys: bool,
447
448 pub peer_verified_address: bool,
449
450 pub completed: bool,
451}
452
453#[cfg(test)]
454impl Default for HandshakeStatus {
455 fn default() -> HandshakeStatus {
456 HandshakeStatus {
457 has_handshake_keys: true,
458
459 peer_verified_address: true,
460
461 completed: true,
462 }
463 }
464}
465
466#[derive(Default)]
471#[cfg(feature = "qlog")]
472struct QlogMetrics {
473 min_rtt: Duration,
474 smoothed_rtt: Duration,
475 latest_rtt: Duration,
476 rttvar: Duration,
477 cwnd: u64,
478 bytes_in_flight: u64,
479 ssthresh: Option<u64>,
480 pacing_rate: u64,
481}
482
483#[cfg(feature = "qlog")]
484impl QlogMetrics {
485 fn maybe_update(&mut self, latest: Self) -> Option<EventData> {
491 let mut emit_event = false;
492
493 let new_min_rtt = if self.min_rtt != latest.min_rtt {
494 self.min_rtt = latest.min_rtt;
495 emit_event = true;
496 Some(latest.min_rtt.as_secs_f32() * 1000.0)
497 } else {
498 None
499 };
500
501 let new_smoothed_rtt = if self.smoothed_rtt != latest.smoothed_rtt {
502 self.smoothed_rtt = latest.smoothed_rtt;
503 emit_event = true;
504 Some(latest.smoothed_rtt.as_secs_f32() * 1000.0)
505 } else {
506 None
507 };
508
509 let new_latest_rtt = if self.latest_rtt != latest.latest_rtt {
510 self.latest_rtt = latest.latest_rtt;
511 emit_event = true;
512 Some(latest.latest_rtt.as_secs_f32() * 1000.0)
513 } else {
514 None
515 };
516
517 let new_rttvar = if self.rttvar != latest.rttvar {
518 self.rttvar = latest.rttvar;
519 emit_event = true;
520 Some(latest.rttvar.as_secs_f32() * 1000.0)
521 } else {
522 None
523 };
524
525 let new_cwnd = if self.cwnd != latest.cwnd {
526 self.cwnd = latest.cwnd;
527 emit_event = true;
528 Some(latest.cwnd)
529 } else {
530 None
531 };
532
533 let new_bytes_in_flight =
534 if self.bytes_in_flight != latest.bytes_in_flight {
535 self.bytes_in_flight = latest.bytes_in_flight;
536 emit_event = true;
537 Some(latest.bytes_in_flight)
538 } else {
539 None
540 };
541
542 let new_ssthresh = if self.ssthresh != latest.ssthresh {
543 self.ssthresh = latest.ssthresh;
544 emit_event = true;
545 latest.ssthresh
546 } else {
547 None
548 };
549
550 let new_pacing_rate = if self.pacing_rate != latest.pacing_rate {
551 self.pacing_rate = latest.pacing_rate;
552 emit_event = true;
553 Some(latest.pacing_rate)
554 } else {
555 None
556 };
557
558 if emit_event {
559 return Some(EventData::MetricsUpdated(
561 qlog::events::quic::MetricsUpdated {
562 min_rtt: new_min_rtt,
563 smoothed_rtt: new_smoothed_rtt,
564 latest_rtt: new_latest_rtt,
565 rtt_variance: new_rttvar,
566 congestion_window: new_cwnd,
567 bytes_in_flight: new_bytes_in_flight,
568 ssthresh: new_ssthresh,
569 pacing_rate: new_pacing_rate,
570 ..Default::default()
571 },
572 ));
573 }
574
575 None
576 }
577}
578
579#[derive(Debug, Clone, Copy, PartialEq, Eq)]
581pub enum ReleaseTime {
582 Immediate,
583 At(Instant),
584}
585
586#[derive(Clone, Copy, Debug, PartialEq, Eq)]
588pub struct ReleaseDecision {
589 time: ReleaseTime,
590 allow_burst: bool,
591}
592
593impl ReleaseTime {
594 #[allow(dead_code)]
596 fn inc(&mut self, delay: Duration) {
597 match self {
598 ReleaseTime::Immediate => {},
599 ReleaseTime::At(time) => *time += delay,
600 }
601 }
602
603 #[allow(dead_code)]
605 fn set_max(&mut self, other: Instant) {
606 match self {
607 ReleaseTime::Immediate => *self = ReleaseTime::At(other),
608 ReleaseTime::At(time) => *self = ReleaseTime::At(other.max(*time)),
609 }
610 }
611}
612
613impl ReleaseDecision {
614 pub(crate) const EQUAL_THRESHOLD: Duration = Duration::from_micros(50);
615
616 #[allow(dead_code)]
619 #[inline]
620 pub fn time(&self, now: Instant) -> Option<Instant> {
621 match self.time {
622 ReleaseTime::Immediate => None,
623 ReleaseTime::At(other) => other.gt(&now).then_some(other),
624 }
625 }
626
627 #[allow(dead_code)]
629 #[inline]
630 pub fn can_burst(&self) -> bool {
631 self.allow_burst
632 }
633
634 #[allow(dead_code)]
636 #[inline]
637 pub fn time_eq(&self, other: &Self, now: Instant) -> bool {
638 let delta = match (self.time(now), other.time(now)) {
639 (None, None) => Duration::ZERO,
640 (Some(t), None) | (None, Some(t)) => t.duration_since(now),
641 (Some(t1), Some(t2)) if t1 < t2 => t2.duration_since(t1),
642 (Some(t1), Some(t2)) => t1.duration_since(t2),
643 };
644
645 delta <= Self::EQUAL_THRESHOLD
646 }
647}
648
649#[derive(Default, Debug)]
651pub struct RecoveryStats {
652 startup_exit: Option<StartupExit>,
653}
654
655impl RecoveryStats {
656 pub fn set_startup_exit(&mut self, startup_exit: StartupExit) {
658 if self.startup_exit.is_none() {
659 self.startup_exit = Some(startup_exit);
660 }
661 }
662}
663
664#[derive(Debug, Clone, Copy, PartialEq)]
666pub struct StartupExit {
667 pub cwnd: usize,
669
670 pub bandwidth: Option<u64>,
672
673 pub reason: StartupExitReason,
675}
676
677impl StartupExit {
678 fn new(
679 cwnd: usize, bandwidth: Option<Bandwidth>, reason: StartupExitReason,
680 ) -> Self {
681 let bandwidth = bandwidth.map(Bandwidth::to_bytes_per_second);
682 Self {
683 cwnd,
684 bandwidth,
685 reason,
686 }
687 }
688}
689
690#[derive(Debug, Clone, Copy, PartialEq)]
692pub enum StartupExitReason {
693 Loss,
695
696 BandwidthPlateau,
698
699 PersistentQueue,
701}
702
703#[cfg(test)]
704mod tests {
705 use super::*;
706 use crate::packet;
707 use crate::test_utils;
708 use crate::CongestionControlAlgorithm;
709 use crate::DEFAULT_INITIAL_RTT;
710 use rstest::rstest;
711 use smallvec::smallvec;
712 use std::str::FromStr;
713
714 fn recovery_for_alg(algo: CongestionControlAlgorithm) -> Recovery {
715 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
716 cfg.set_cc_algorithm(algo);
717 Recovery::new(&cfg)
718 }
719
720 #[test]
721 fn lookup_cc_algo_ok() {
722 let algo = CongestionControlAlgorithm::from_str("reno").unwrap();
723 assert_eq!(algo, CongestionControlAlgorithm::Reno);
724 assert!(!recovery_for_alg(algo).gcongestion_enabled());
725
726 let algo = CongestionControlAlgorithm::from_str("cubic").unwrap();
727 assert_eq!(algo, CongestionControlAlgorithm::CUBIC);
728 assert!(!recovery_for_alg(algo).gcongestion_enabled());
729
730 let algo = CongestionControlAlgorithm::from_str("bbr").unwrap();
731 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
732 assert!(recovery_for_alg(algo).gcongestion_enabled());
733
734 let algo = CongestionControlAlgorithm::from_str("bbr2").unwrap();
735 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
736 assert!(recovery_for_alg(algo).gcongestion_enabled());
737
738 let algo =
739 CongestionControlAlgorithm::from_str("bbr2_gcongestion").unwrap();
740 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
741 assert!(recovery_for_alg(algo).gcongestion_enabled());
742 }
743
744 #[test]
745 fn lookup_cc_algo_bad() {
746 assert_eq!(
747 CongestionControlAlgorithm::from_str("???"),
748 Err(crate::Error::CongestionControl)
749 );
750 }
751
752 #[rstest]
753 fn loss_on_pto(
754 #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
755 cc_algorithm_name: &str,
756 ) {
757 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
758 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
759
760 let mut r = Recovery::new(&cfg);
761
762 let mut now = Instant::now();
763
764 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
765
766 let p = Sent {
768 pkt_num: 0,
769 frames: smallvec![],
770 time_sent: now,
771 time_acked: None,
772 time_lost: None,
773 size: 1000,
774 ack_eliciting: true,
775 in_flight: true,
776 delivered: 0,
777 delivered_time: now,
778 first_sent_time: now,
779 is_app_limited: false,
780 tx_in_flight: 0,
781 lost: 0,
782 has_data: false,
783 is_pmtud_probe: false,
784 };
785
786 r.on_packet_sent(
787 p,
788 packet::Epoch::Application,
789 HandshakeStatus::default(),
790 now,
791 "",
792 );
793
794 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
795 assert_eq!(r.bytes_in_flight(), 1000);
796 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
797
798 let p = Sent {
799 pkt_num: 1,
800 frames: smallvec![],
801 time_sent: now,
802 time_acked: None,
803 time_lost: None,
804 size: 1000,
805 ack_eliciting: true,
806 in_flight: true,
807 delivered: 0,
808 delivered_time: now,
809 first_sent_time: now,
810 is_app_limited: false,
811 tx_in_flight: 0,
812 lost: 0,
813 has_data: false,
814 is_pmtud_probe: false,
815 };
816
817 r.on_packet_sent(
818 p,
819 packet::Epoch::Application,
820 HandshakeStatus::default(),
821 now,
822 "",
823 );
824
825 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
826 assert_eq!(r.bytes_in_flight(), 2000);
827 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
828
829 let p = Sent {
830 pkt_num: 2,
831 frames: smallvec![],
832 time_sent: now,
833 time_acked: None,
834 time_lost: None,
835 size: 1000,
836 ack_eliciting: true,
837 in_flight: true,
838 delivered: 0,
839 delivered_time: now,
840 first_sent_time: now,
841 is_app_limited: false,
842 tx_in_flight: 0,
843 lost: 0,
844 has_data: false,
845 is_pmtud_probe: false,
846 };
847
848 r.on_packet_sent(
849 p,
850 packet::Epoch::Application,
851 HandshakeStatus::default(),
852 now,
853 "",
854 );
855 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
856 assert_eq!(r.bytes_in_flight(), 3000);
857 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
858
859 let p = Sent {
860 pkt_num: 3,
861 frames: smallvec![],
862 time_sent: now,
863 time_acked: None,
864 time_lost: None,
865 size: 1000,
866 ack_eliciting: true,
867 in_flight: true,
868 delivered: 0,
869 delivered_time: now,
870 first_sent_time: now,
871 is_app_limited: false,
872 tx_in_flight: 0,
873 lost: 0,
874 has_data: false,
875 is_pmtud_probe: false,
876 };
877
878 r.on_packet_sent(
879 p,
880 packet::Epoch::Application,
881 HandshakeStatus::default(),
882 now,
883 "",
884 );
885 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
886 assert_eq!(r.bytes_in_flight(), 4000);
887 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
888
889 now += Duration::from_millis(10);
891
892 let mut acked = RangeSet::default();
894 acked.insert(0..2);
895
896 assert_eq!(
897 r.on_ack_received(
898 &acked,
899 25,
900 packet::Epoch::Application,
901 HandshakeStatus::default(),
902 now,
903 None,
904 "",
905 )
906 .unwrap(),
907 OnAckReceivedOutcome {
908 lost_packets: 0,
909 lost_bytes: 0,
910 acked_bytes: 2 * 1000,
911 spurious_losses: 0,
912 }
913 );
914
915 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
916 assert_eq!(r.bytes_in_flight(), 2000);
917 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
918 assert_eq!(r.lost_count(), 0);
919
920 now = r.loss_detection_timer().unwrap();
922
923 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
925 assert_eq!(r.loss_probes(packet::Epoch::Application), 1);
926 assert_eq!(r.lost_count(), 0);
927 assert_eq!(r.pto_count(), 1);
928
929 let p = Sent {
930 pkt_num: 4,
931 frames: smallvec![],
932 time_sent: now,
933 time_acked: None,
934 time_lost: None,
935 size: 1000,
936 ack_eliciting: true,
937 in_flight: true,
938 delivered: 0,
939 delivered_time: now,
940 first_sent_time: now,
941 is_app_limited: false,
942 tx_in_flight: 0,
943 lost: 0,
944 has_data: false,
945 is_pmtud_probe: false,
946 };
947
948 r.on_packet_sent(
949 p,
950 packet::Epoch::Application,
951 HandshakeStatus::default(),
952 now,
953 "",
954 );
955 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
956 assert_eq!(r.bytes_in_flight(), 3000);
957 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(30));
958
959 let p = Sent {
960 pkt_num: 5,
961 frames: smallvec![],
962 time_sent: now,
963 time_acked: None,
964 time_lost: None,
965 size: 1000,
966 ack_eliciting: true,
967 in_flight: true,
968 delivered: 0,
969 delivered_time: now,
970 first_sent_time: now,
971 is_app_limited: false,
972 tx_in_flight: 0,
973 lost: 0,
974 has_data: false,
975 is_pmtud_probe: false,
976 };
977
978 r.on_packet_sent(
979 p,
980 packet::Epoch::Application,
981 HandshakeStatus::default(),
982 now,
983 "",
984 );
985 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
986 assert_eq!(r.bytes_in_flight(), 4000);
987 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(30));
988 assert_eq!(r.lost_count(), 0);
989
990 now += Duration::from_millis(10);
992
993 let mut acked = RangeSet::default();
995 acked.insert(4..6);
996
997 assert_eq!(
998 r.on_ack_received(
999 &acked,
1000 25,
1001 packet::Epoch::Application,
1002 HandshakeStatus::default(),
1003 now,
1004 None,
1005 "",
1006 )
1007 .unwrap(),
1008 OnAckReceivedOutcome {
1009 lost_packets: 2,
1010 lost_bytes: 2000,
1011 acked_bytes: 2 * 1000,
1012 spurious_losses: 0,
1013 }
1014 );
1015
1016 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1017 assert_eq!(r.bytes_in_flight(), 0);
1018 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(40));
1019
1020 assert_eq!(r.lost_count(), 2);
1021
1022 now += r.rtt();
1024
1025 assert_eq!(
1026 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1027 (0, 0)
1028 );
1029
1030 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1031 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1032 assert!(r.startup_exit().is_some());
1033 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1034 } else {
1035 assert_eq!(r.startup_exit(), None);
1036 }
1037 }
1038
1039 #[rstest]
1040 fn loss_on_timer(
1041 #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
1042 cc_algorithm_name: &str,
1043 ) {
1044 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1045 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1046
1047 let mut r = Recovery::new(&cfg);
1048
1049 let mut now = Instant::now();
1050
1051 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1052
1053 let p = Sent {
1055 pkt_num: 0,
1056 frames: smallvec![],
1057 time_sent: now,
1058 time_acked: None,
1059 time_lost: None,
1060 size: 1000,
1061 ack_eliciting: true,
1062 in_flight: true,
1063 delivered: 0,
1064 delivered_time: now,
1065 first_sent_time: now,
1066 is_app_limited: false,
1067 tx_in_flight: 0,
1068 lost: 0,
1069 has_data: false,
1070 is_pmtud_probe: false,
1071 };
1072
1073 r.on_packet_sent(
1074 p,
1075 packet::Epoch::Application,
1076 HandshakeStatus::default(),
1077 now,
1078 "",
1079 );
1080 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1081 assert_eq!(r.bytes_in_flight(), 1000);
1082 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1083
1084 let p = Sent {
1085 pkt_num: 1,
1086 frames: smallvec![],
1087 time_sent: now,
1088 time_acked: None,
1089 time_lost: None,
1090 size: 1000,
1091 ack_eliciting: true,
1092 in_flight: true,
1093 delivered: 0,
1094 delivered_time: now,
1095 first_sent_time: now,
1096 is_app_limited: false,
1097 tx_in_flight: 0,
1098 lost: 0,
1099 has_data: false,
1100 is_pmtud_probe: false,
1101 };
1102
1103 r.on_packet_sent(
1104 p,
1105 packet::Epoch::Application,
1106 HandshakeStatus::default(),
1107 now,
1108 "",
1109 );
1110 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1111 assert_eq!(r.bytes_in_flight(), 2000);
1112 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1113
1114 let p = Sent {
1115 pkt_num: 2,
1116 frames: smallvec![],
1117 time_sent: now,
1118 time_acked: None,
1119 time_lost: None,
1120 size: 1000,
1121 ack_eliciting: true,
1122 in_flight: true,
1123 delivered: 0,
1124 delivered_time: now,
1125 first_sent_time: now,
1126 is_app_limited: false,
1127 tx_in_flight: 0,
1128 lost: 0,
1129 has_data: false,
1130 is_pmtud_probe: false,
1131 };
1132
1133 r.on_packet_sent(
1134 p,
1135 packet::Epoch::Application,
1136 HandshakeStatus::default(),
1137 now,
1138 "",
1139 );
1140 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1141 assert_eq!(r.bytes_in_flight(), 3000);
1142 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1143
1144 let p = Sent {
1145 pkt_num: 3,
1146 frames: smallvec![],
1147 time_sent: now,
1148 time_acked: None,
1149 time_lost: None,
1150 size: 1000,
1151 ack_eliciting: true,
1152 in_flight: true,
1153 delivered: 0,
1154 delivered_time: now,
1155 first_sent_time: now,
1156 is_app_limited: false,
1157 tx_in_flight: 0,
1158 lost: 0,
1159 has_data: false,
1160 is_pmtud_probe: false,
1161 };
1162
1163 r.on_packet_sent(
1164 p,
1165 packet::Epoch::Application,
1166 HandshakeStatus::default(),
1167 now,
1168 "",
1169 );
1170 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1171 assert_eq!(r.bytes_in_flight(), 4000);
1172 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1173
1174 now += Duration::from_millis(10);
1176
1177 let mut acked = RangeSet::default();
1179 acked.insert(0..2);
1180 acked.insert(3..4);
1181
1182 assert_eq!(
1183 r.on_ack_received(
1184 &acked,
1185 25,
1186 packet::Epoch::Application,
1187 HandshakeStatus::default(),
1188 now,
1189 None,
1190 "",
1191 )
1192 .unwrap(),
1193 OnAckReceivedOutcome {
1194 lost_packets: 0,
1195 lost_bytes: 0,
1196 acked_bytes: 3 * 1000,
1197 spurious_losses: 0,
1198 }
1199 );
1200
1201 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1202 assert_eq!(r.bytes_in_flight(), 1000);
1203 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
1204 assert_eq!(r.lost_count(), 0);
1205
1206 now = r.loss_detection_timer().unwrap();
1208
1209 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
1211 assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
1212
1213 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1214 assert_eq!(r.bytes_in_flight(), 0);
1215 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
1216
1217 assert_eq!(r.lost_count(), 1);
1218
1219 now += r.rtt();
1221
1222 assert_eq!(
1223 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1224 (0, 0)
1225 );
1226
1227 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1228 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1229 assert!(r.startup_exit().is_some());
1230 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1231 } else {
1232 assert_eq!(r.startup_exit(), None);
1233 }
1234 }
1235
1236 #[rstest]
1237 fn loss_on_reordering(
1238 #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
1239 cc_algorithm_name: &str,
1240 ) {
1241 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1242 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1243
1244 let mut r = Recovery::new(&cfg);
1245
1246 let mut now = Instant::now();
1247
1248 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1249
1250 for i in 0..4 {
1254 let p = test_utils::helper_packet_sent(i, now, 1000);
1255 r.on_packet_sent(
1256 p,
1257 packet::Epoch::Application,
1258 HandshakeStatus::default(),
1259 now,
1260 "",
1261 );
1262
1263 let pkt_count = (i + 1) as usize;
1264 assert_eq!(r.sent_packets_len(packet::Epoch::Application), pkt_count);
1265 assert_eq!(r.bytes_in_flight(), pkt_count * 1000);
1266 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1267 }
1268
1269 now += Duration::from_millis(10);
1271
1272 let mut acked = RangeSet::default();
1274 acked.insert(2..4);
1275 assert_eq!(
1276 r.on_ack_received(
1277 &acked,
1278 25,
1279 packet::Epoch::Application,
1280 HandshakeStatus::default(),
1281 now,
1282 None,
1283 "",
1284 )
1285 .unwrap(),
1286 OnAckReceivedOutcome {
1287 lost_packets: 1,
1288 lost_bytes: 1000,
1289 acked_bytes: 1000 * 2,
1290 spurious_losses: 0,
1291 }
1292 );
1293 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1296 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1297 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1298
1299 now += Duration::from_millis(10);
1301
1302 let mut acked = RangeSet::default();
1304 acked.insert(0..2);
1305 assert_eq!(
1306 r.on_ack_received(
1307 &acked,
1308 25,
1309 packet::Epoch::Application,
1310 HandshakeStatus::default(),
1311 now,
1312 None,
1313 "",
1314 )
1315 .unwrap(),
1316 OnAckReceivedOutcome {
1317 lost_packets: 0,
1318 lost_bytes: 0,
1319 acked_bytes: 1000,
1320 spurious_losses: 1,
1321 }
1322 );
1323 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1324 assert_eq!(r.bytes_in_flight(), 0);
1325 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(20));
1326
1327 assert_eq!(r.lost_count(), 1);
1329 assert_eq!(r.lost_spurious_count(), 1);
1330
1331 assert_eq!(r.pkt_thresh().unwrap(), 4);
1333 assert_eq!(r.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1334
1335 now += r.rtt();
1337
1338 assert_eq!(
1340 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1341 (0, 0)
1342 );
1343 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1344
1345 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1346 assert!(r.startup_exit().is_some());
1347 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1348 } else {
1349 assert_eq!(r.startup_exit(), None);
1350 }
1351 }
1352
1353 #[rstest]
1358 fn time_thresholds_on_reordering(
1359 #[values("bbr2_gcongestion")] cc_algorithm_name: &str,
1360 ) {
1361 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1362 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1363
1364 let mut now = Instant::now();
1365 let mut r = Recovery::new(&cfg);
1366 assert_eq!(r.rtt(), DEFAULT_INITIAL_RTT);
1367
1368 const THRESH_GAP: Duration = Duration::from_millis(30);
1382 let initial_thresh_ms =
1384 DEFAULT_INITIAL_RTT.mul_f64(INITIAL_TIME_THRESHOLD);
1385 let spurious_thresh_ms: Duration =
1387 DEFAULT_INITIAL_RTT.mul_f64(PACKET_REORDER_TIME_THRESHOLD);
1388 let between_thresh_ms = initial_thresh_ms + THRESH_GAP;
1390 assert!(between_thresh_ms > initial_thresh_ms);
1391 assert!(between_thresh_ms < spurious_thresh_ms);
1392 assert!(between_thresh_ms + THRESH_GAP > spurious_thresh_ms);
1393
1394 for i in 0..6 {
1395 let send_time = now + i * between_thresh_ms;
1396
1397 let p = test_utils::helper_packet_sent(i.into(), send_time, 1000);
1398 r.on_packet_sent(
1399 p,
1400 packet::Epoch::Application,
1401 HandshakeStatus::default(),
1402 send_time,
1403 "",
1404 );
1405 }
1406
1407 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 6);
1408 assert_eq!(r.bytes_in_flight(), 6 * 1000);
1409 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1410 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1411
1412 now += between_thresh_ms;
1415
1416 let mut acked = RangeSet::default();
1421 acked.insert(1..2);
1422 assert_eq!(
1423 r.on_ack_received(
1424 &acked,
1425 25,
1426 packet::Epoch::Application,
1427 HandshakeStatus::default(),
1428 now,
1429 None,
1430 "",
1431 )
1432 .unwrap(),
1433 OnAckReceivedOutcome {
1434 lost_packets: 1,
1435 lost_bytes: 1000,
1436 acked_bytes: 1000,
1437 spurious_losses: 0,
1438 }
1439 );
1440 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1441 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1442
1443 let mut acked = RangeSet::default();
1448 acked.insert(0..1);
1449 assert_eq!(
1450 r.on_ack_received(
1451 &acked,
1452 25,
1453 packet::Epoch::Application,
1454 HandshakeStatus::default(),
1455 now,
1456 None,
1457 "",
1458 )
1459 .unwrap(),
1460 OnAckReceivedOutcome {
1461 lost_packets: 0,
1462 lost_bytes: 0,
1463 acked_bytes: 0,
1464 spurious_losses: 1,
1465 }
1466 );
1467 assert_eq!(r.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1469
1470 now += between_thresh_ms;
1473
1474 let mut acked = RangeSet::default();
1479 acked.insert(3..4);
1480 assert_eq!(
1481 r.on_ack_received(
1482 &acked,
1483 25,
1484 packet::Epoch::Application,
1485 HandshakeStatus::default(),
1486 now,
1487 None,
1488 "",
1489 )
1490 .unwrap(),
1491 OnAckReceivedOutcome {
1492 lost_packets: 0,
1493 lost_bytes: 0,
1494 acked_bytes: 1000,
1495 spurious_losses: 0,
1496 }
1497 );
1498
1499 now += THRESH_GAP;
1502
1503 let mut acked = RangeSet::default();
1508 acked.insert(4..5);
1509 assert_eq!(
1510 r.on_ack_received(
1511 &acked,
1512 25,
1513 packet::Epoch::Application,
1514 HandshakeStatus::default(),
1515 now,
1516 None,
1517 "",
1518 )
1519 .unwrap(),
1520 OnAckReceivedOutcome {
1521 lost_packets: 1,
1522 lost_bytes: 1000,
1523 acked_bytes: 1000,
1524 spurious_losses: 0,
1525 }
1526 );
1527 }
1528
1529 #[rstest]
1532 fn relaxed_thresholds_on_reordering(
1533 #[values("bbr2_gcongestion")] cc_algorithm_name: &str,
1534 ) {
1535 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1536 cfg.enable_relaxed_loss_threshold = true;
1537 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1538
1539 let mut now = Instant::now();
1540 let mut r = Recovery::new(&cfg);
1541 assert_eq!(r.rtt(), DEFAULT_INITIAL_RTT);
1542
1543 const THRESH_GAP: Duration = Duration::from_millis(30);
1556 let initial_thresh_ms =
1558 DEFAULT_INITIAL_RTT.mul_f64(INITIAL_TIME_THRESHOLD);
1559 let spurious_thresh_ms: Duration =
1561 DEFAULT_INITIAL_RTT.mul_f64(PACKET_REORDER_TIME_THRESHOLD);
1562 let between_thresh_ms = initial_thresh_ms + THRESH_GAP;
1564 assert!(between_thresh_ms > initial_thresh_ms);
1565 assert!(between_thresh_ms < spurious_thresh_ms);
1566 assert!(between_thresh_ms + THRESH_GAP > spurious_thresh_ms);
1567
1568 for i in 0..6 {
1569 let send_time = now + i * between_thresh_ms;
1570
1571 let p = test_utils::helper_packet_sent(i.into(), send_time, 1000);
1572 r.on_packet_sent(
1573 p,
1574 packet::Epoch::Application,
1575 HandshakeStatus::default(),
1576 send_time,
1577 "",
1578 );
1579 }
1580
1581 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 6);
1582 assert_eq!(r.bytes_in_flight(), 6 * 1000);
1583 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1585 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1586
1587 now += between_thresh_ms;
1590
1591 let mut acked = RangeSet::default();
1596 acked.insert(1..2);
1597 assert_eq!(
1598 r.on_ack_received(
1599 &acked,
1600 25,
1601 packet::Epoch::Application,
1602 HandshakeStatus::default(),
1603 now,
1604 None,
1605 "",
1606 )
1607 .unwrap(),
1608 OnAckReceivedOutcome {
1609 lost_packets: 1,
1610 lost_bytes: 1000,
1611 acked_bytes: 1000,
1612 spurious_losses: 0,
1613 }
1614 );
1615 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1617 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1618
1619 let mut acked = RangeSet::default();
1624 acked.insert(0..1);
1625 assert_eq!(
1626 r.on_ack_received(
1627 &acked,
1628 25,
1629 packet::Epoch::Application,
1630 HandshakeStatus::default(),
1631 now,
1632 None,
1633 "",
1634 )
1635 .unwrap(),
1636 OnAckReceivedOutcome {
1637 lost_packets: 0,
1638 lost_bytes: 0,
1639 acked_bytes: 0,
1640 spurious_losses: 1,
1641 }
1642 );
1643 assert_eq!(r.pkt_thresh(), None);
1648 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1649
1650 now += between_thresh_ms;
1653 now += between_thresh_ms;
1657
1658 let mut acked = RangeSet::default();
1663 acked.insert(3..4);
1664 assert_eq!(
1665 r.on_ack_received(
1666 &acked,
1667 25,
1668 packet::Epoch::Application,
1669 HandshakeStatus::default(),
1670 now,
1671 None,
1672 "",
1673 )
1674 .unwrap(),
1675 OnAckReceivedOutcome {
1676 lost_packets: 1,
1677 lost_bytes: 1000,
1678 acked_bytes: 1000,
1679 spurious_losses: 0,
1680 }
1681 );
1682 assert_eq!(r.pkt_thresh(), None);
1684 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1685
1686 let mut acked = RangeSet::default();
1695 acked.insert(2..3);
1696 assert_eq!(
1697 r.on_ack_received(
1698 &acked,
1699 25,
1700 packet::Epoch::Application,
1701 HandshakeStatus::default(),
1702 now,
1703 None,
1704 "",
1705 )
1706 .unwrap(),
1707 OnAckReceivedOutcome {
1708 lost_packets: 0,
1709 lost_bytes: 0,
1710 acked_bytes: 0,
1711 spurious_losses: 1,
1712 }
1713 );
1714 assert_eq!(r.pkt_thresh(), None);
1718 let double_time_thresh_overhead =
1719 1.0 + 2.0 * INITIAL_TIME_THRESHOLD_OVERHEAD;
1720 assert_eq!(r.time_thresh(), double_time_thresh_overhead);
1721 }
1722
1723 #[rstest]
1724 fn pacing(
1725 #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
1726 cc_algorithm_name: &str,
1727 ) {
1728 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1729 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1730
1731 let mut r = Recovery::new(&cfg);
1732
1733 let mut now = Instant::now();
1734
1735 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1736
1737 for i in 0..10 {
1739 let p = Sent {
1740 pkt_num: i,
1741 frames: smallvec![],
1742 time_sent: now,
1743 time_acked: None,
1744 time_lost: None,
1745 size: 1200,
1746 ack_eliciting: true,
1747 in_flight: true,
1748 delivered: 0,
1749 delivered_time: now,
1750 first_sent_time: now,
1751 is_app_limited: false,
1752 tx_in_flight: 0,
1753 lost: 0,
1754 has_data: true,
1755 is_pmtud_probe: false,
1756 };
1757
1758 r.on_packet_sent(
1759 p,
1760 packet::Epoch::Application,
1761 HandshakeStatus::default(),
1762 now,
1763 "",
1764 );
1765 }
1766
1767 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 10);
1768 assert_eq!(r.bytes_in_flight(), 12000);
1769 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1770
1771 if cc_algorithm_name == "cubic" || cc_algorithm_name == "reno" {
1773 assert_eq!(r.pacing_rate(), 0);
1774 } else {
1775 assert_eq!(r.pacing_rate(), 103963);
1776 }
1777 assert_eq!(r.get_packet_send_time(now), now);
1778
1779 assert_eq!(r.cwnd(), 12000);
1780 assert_eq!(r.cwnd_available(), 0);
1781
1782 now += Duration::from_millis(50);
1784
1785 let mut acked = RangeSet::default();
1786 acked.insert(0..10);
1787
1788 assert_eq!(
1789 r.on_ack_received(
1790 &acked,
1791 10,
1792 packet::Epoch::Application,
1793 HandshakeStatus::default(),
1794 now,
1795 None,
1796 "",
1797 )
1798 .unwrap(),
1799 OnAckReceivedOutcome {
1800 lost_packets: 0,
1801 lost_bytes: 0,
1802 acked_bytes: 12000,
1803 spurious_losses: 0,
1804 }
1805 );
1806
1807 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1808 assert_eq!(r.bytes_in_flight(), 0);
1809 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(50));
1810 assert_eq!(r.rtt(), Duration::from_millis(50));
1811
1812 assert_eq!(r.cwnd(), 12000 + 1200 * 10);
1814
1815 let p = Sent {
1817 pkt_num: 10,
1818 frames: smallvec![],
1819 time_sent: now,
1820 time_acked: None,
1821 time_lost: None,
1822 size: 6000,
1823 ack_eliciting: true,
1824 in_flight: true,
1825 delivered: 0,
1826 delivered_time: now,
1827 first_sent_time: now,
1828 is_app_limited: false,
1829 tx_in_flight: 0,
1830 lost: 0,
1831 has_data: true,
1832 is_pmtud_probe: false,
1833 };
1834
1835 r.on_packet_sent(
1836 p,
1837 packet::Epoch::Application,
1838 HandshakeStatus::default(),
1839 now,
1840 "",
1841 );
1842
1843 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1844 assert_eq!(r.bytes_in_flight(), 6000);
1845 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(50));
1846
1847 if cc_algorithm_name == "cubic" || cc_algorithm_name == "reno" {
1848 assert_eq!(r.get_packet_send_time(now), now);
1850 } else {
1851 assert_ne!(r.get_packet_send_time(now), now);
1853 }
1854
1855 let p = Sent {
1857 pkt_num: 11,
1858 frames: smallvec![],
1859 time_sent: now,
1860 time_acked: None,
1861 time_lost: None,
1862 size: 6000,
1863 ack_eliciting: true,
1864 in_flight: true,
1865 delivered: 0,
1866 delivered_time: now,
1867 first_sent_time: now,
1868 is_app_limited: false,
1869 tx_in_flight: 0,
1870 lost: 0,
1871 has_data: true,
1872 is_pmtud_probe: false,
1873 };
1874
1875 r.on_packet_sent(
1876 p,
1877 packet::Epoch::Application,
1878 HandshakeStatus::default(),
1879 now,
1880 "",
1881 );
1882
1883 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1884 assert_eq!(r.bytes_in_flight(), 12000);
1885 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(50));
1886
1887 let p = Sent {
1889 pkt_num: 12,
1890 frames: smallvec![],
1891 time_sent: now,
1892 time_acked: None,
1893 time_lost: None,
1894 size: 1000,
1895 ack_eliciting: true,
1896 in_flight: true,
1897 delivered: 0,
1898 delivered_time: now,
1899 first_sent_time: now,
1900 is_app_limited: false,
1901 tx_in_flight: 0,
1902 lost: 0,
1903 has_data: true,
1904 is_pmtud_probe: false,
1905 };
1906
1907 r.on_packet_sent(
1908 p,
1909 packet::Epoch::Application,
1910 HandshakeStatus::default(),
1911 now,
1912 "",
1913 );
1914
1915 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1916 assert_eq!(r.bytes_in_flight(), 13000);
1917 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(50));
1918
1919 let pacing_rate = match cc_algorithm_name {
1922 "bbr2_gcongestion" | "bbr2" => {
1923 let cwnd_gain: f64 = 2.0;
1924 let bw = r.cwnd() as f64 /
1927 cwnd_gain /
1928 Duration::from_millis(50).as_secs_f64();
1929 bw as u64
1930 },
1931 _ => 0,
1932 };
1933 assert_eq!(r.pacing_rate(), pacing_rate);
1934
1935 let scale_factor = if cc_algorithm_name == "bbr2_gcongestion" ||
1936 cc_algorithm_name == "bbr2"
1937 {
1938 1.08333332
1941 } else {
1942 1.0
1943 };
1944 assert_eq!(
1945 r.get_packet_send_time(now) - now,
1946 if cc_algorithm_name == "bbr2_gcongestion" ||
1947 cc_algorithm_name == "bbr2"
1948 {
1949 Duration::from_secs_f64(
1950 scale_factor * 12000.0 / pacing_rate as f64,
1951 )
1952 } else {
1953 Duration::ZERO
1954 }
1955 );
1956 assert_eq!(r.startup_exit(), None);
1957 }
1958
1959 #[rstest]
1960 #[case::bw_estimate_equal_after_first_rtt(1.0, 1.0)]
1963 #[case::bw_estimate_decrease_after_first_rtt(2.0, 1.0)]
1966 #[case::bw_estimate_increase_after_first_rtt(0.5, 0.5)]
1972 #[cfg(feature = "internal")]
1973 fn initial_pacing_rate_override(
1974 #[case] initial_multipler: f64, #[case] expected_multiplier: f64,
1975 ) {
1976 let rtt = Duration::from_millis(50);
1977 let bw = Bandwidth::from_bytes_and_time_delta(12000, rtt);
1978 let initial_pacing_rate_hint = bw * initial_multipler;
1979 let expected_pacing_with_rtt_measurement = bw * expected_multiplier;
1980
1981 let cc_algorithm_name = "bbr2_gcongestion";
1982 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1983 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1984 cfg.set_custom_bbr_params(BbrParams {
1985 initial_pacing_rate_bytes_per_second: Some(
1986 initial_pacing_rate_hint.to_bytes_per_second(),
1987 ),
1988 ..Default::default()
1989 });
1990
1991 let mut r = Recovery::new(&cfg);
1992
1993 let mut now = Instant::now();
1994
1995 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1996
1997 for i in 0..2 {
1999 let p = test_utils::helper_packet_sent(i, now, 1200);
2000 r.on_packet_sent(
2001 p,
2002 packet::Epoch::Application,
2003 HandshakeStatus::default(),
2004 now,
2005 "",
2006 );
2007 }
2008
2009 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2010 assert_eq!(r.bytes_in_flight(), 2400);
2011 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2012
2013 assert_eq!(
2015 r.pacing_rate(),
2016 initial_pacing_rate_hint.to_bytes_per_second()
2017 );
2018 assert_eq!(r.get_packet_send_time(now), now);
2019
2020 assert_eq!(r.cwnd(), 12000);
2021 assert_eq!(r.cwnd_available(), 9600);
2022
2023 now += rtt;
2025
2026 let mut acked = RangeSet::default();
2027 acked.insert(0..2);
2028
2029 assert_eq!(
2030 r.on_ack_received(
2031 &acked,
2032 10,
2033 packet::Epoch::Application,
2034 HandshakeStatus::default(),
2035 now,
2036 None,
2037 "",
2038 )
2039 .unwrap(),
2040 OnAckReceivedOutcome {
2041 lost_packets: 0,
2042 lost_bytes: 0,
2043 acked_bytes: 2400,
2044 spurious_losses: 0,
2045 }
2046 );
2047
2048 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2049 assert_eq!(r.bytes_in_flight(), 0);
2050 assert_eq!(r.bytes_in_flight_duration(), rtt);
2051 assert_eq!(r.rtt(), rtt);
2052
2053 assert_eq!(
2056 r.pacing_rate(),
2057 expected_pacing_with_rtt_measurement.to_bytes_per_second()
2058 );
2059 }
2060
2061 #[rstest]
2062 fn validate_ack_range_on_ack_received(
2063 #[values("cubic", "bbr2", "bbr2_gcongestion")] cc_algorithm_name: &str,
2064 ) {
2065 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2066 cfg.set_cc_algorithm_name(cc_algorithm_name).unwrap();
2067
2068 let epoch = packet::Epoch::Application;
2069 let mut r = Recovery::new(&cfg);
2070 let mut now = Instant::now();
2071 assert_eq!(r.sent_packets_len(epoch), 0);
2072
2073 let pkt_size = 1000;
2075 let pkt_count = 4;
2076 for pkt_num in 0..pkt_count {
2077 let sent = test_utils::helper_packet_sent(pkt_num, now, pkt_size);
2078 r.on_packet_sent(sent, epoch, HandshakeStatus::default(), now, "");
2079 }
2080 assert_eq!(r.sent_packets_len(epoch), pkt_count as usize);
2081 assert_eq!(r.bytes_in_flight(), pkt_count as usize * pkt_size);
2082 assert!(r.get_largest_acked_on_epoch(epoch).is_none());
2083 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2084
2085 now += Duration::from_millis(10);
2087
2088 let mut acked = RangeSet::default();
2090 acked.insert(0..2);
2091
2092 assert_eq!(
2093 r.on_ack_received(
2094 &acked,
2095 25,
2096 epoch,
2097 HandshakeStatus::default(),
2098 now,
2099 None,
2100 "",
2101 )
2102 .unwrap(),
2103 OnAckReceivedOutcome {
2104 lost_packets: 0,
2105 lost_bytes: 0,
2106 acked_bytes: 2 * 1000,
2107 spurious_losses: 0,
2108 }
2109 );
2110
2111 assert_eq!(r.sent_packets_len(epoch), 2);
2112 assert_eq!(r.bytes_in_flight(), 2 * 1000);
2113
2114 assert_eq!(r.get_largest_acked_on_epoch(epoch).unwrap(), 1);
2115 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2116
2117 let mut acked = RangeSet::default();
2119 acked.insert(0..10);
2120 assert_eq!(
2121 r.on_ack_received(
2122 &acked,
2123 25,
2124 epoch,
2125 HandshakeStatus::default(),
2126 now,
2127 None,
2128 "",
2129 )
2130 .unwrap(),
2131 OnAckReceivedOutcome {
2132 lost_packets: 0,
2133 lost_bytes: 0,
2134 acked_bytes: 2 * 1000,
2135 spurious_losses: 0,
2136 }
2137 );
2138 assert_eq!(r.sent_packets_len(epoch), 0);
2139 assert_eq!(r.bytes_in_flight(), 0);
2140
2141 assert_eq!(r.get_largest_acked_on_epoch(epoch).unwrap(), 3);
2142 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2143 }
2144
2145 #[rstest]
2146 fn pmtud_loss_on_timer(
2147 #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
2148 cc_algorithm_name: &str,
2149 ) {
2150 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2151 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2152
2153 let mut r = Recovery::new(&cfg);
2154 assert_eq!(r.cwnd(), 12000);
2155
2156 let mut now = Instant::now();
2157
2158 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2159
2160 let p = Sent {
2162 pkt_num: 0,
2163 frames: smallvec![],
2164 time_sent: now,
2165 time_acked: None,
2166 time_lost: None,
2167 size: 1000,
2168 ack_eliciting: true,
2169 in_flight: true,
2170 delivered: 0,
2171 delivered_time: now,
2172 first_sent_time: now,
2173 is_app_limited: false,
2174 tx_in_flight: 0,
2175 lost: 0,
2176 has_data: false,
2177 is_pmtud_probe: false,
2178 };
2179
2180 r.on_packet_sent(
2181 p,
2182 packet::Epoch::Application,
2183 HandshakeStatus::default(),
2184 now,
2185 "",
2186 );
2187
2188 assert_eq!(r.in_flight_count(packet::Epoch::Application), 1);
2189 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
2190 assert_eq!(r.bytes_in_flight(), 1000);
2191 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2192
2193 let p = Sent {
2194 pkt_num: 1,
2195 frames: smallvec![],
2196 time_sent: now,
2197 time_acked: None,
2198 time_lost: None,
2199 size: 1000,
2200 ack_eliciting: true,
2201 in_flight: true,
2202 delivered: 0,
2203 delivered_time: now,
2204 first_sent_time: now,
2205 is_app_limited: false,
2206 tx_in_flight: 0,
2207 lost: 0,
2208 has_data: false,
2209 is_pmtud_probe: true,
2210 };
2211
2212 r.on_packet_sent(
2213 p,
2214 packet::Epoch::Application,
2215 HandshakeStatus::default(),
2216 now,
2217 "",
2218 );
2219
2220 assert_eq!(r.in_flight_count(packet::Epoch::Application), 2);
2221
2222 let p = Sent {
2223 pkt_num: 2,
2224 frames: smallvec![],
2225 time_sent: now,
2226 time_acked: None,
2227 time_lost: None,
2228 size: 1000,
2229 ack_eliciting: true,
2230 in_flight: true,
2231 delivered: 0,
2232 delivered_time: now,
2233 first_sent_time: now,
2234 is_app_limited: false,
2235 tx_in_flight: 0,
2236 lost: 0,
2237 has_data: false,
2238 is_pmtud_probe: false,
2239 };
2240
2241 r.on_packet_sent(
2242 p,
2243 packet::Epoch::Application,
2244 HandshakeStatus::default(),
2245 now,
2246 "",
2247 );
2248
2249 assert_eq!(r.in_flight_count(packet::Epoch::Application), 3);
2250
2251 now += Duration::from_millis(10);
2253
2254 let mut acked = RangeSet::default();
2256 acked.insert(0..1);
2257 acked.insert(2..3);
2258
2259 assert_eq!(
2260 r.on_ack_received(
2261 &acked,
2262 25,
2263 packet::Epoch::Application,
2264 HandshakeStatus::default(),
2265 now,
2266 None,
2267 "",
2268 )
2269 .unwrap(),
2270 OnAckReceivedOutcome {
2271 lost_packets: 0,
2272 lost_bytes: 0,
2273 acked_bytes: 2 * 1000,
2274 spurious_losses: 0,
2275 }
2276 );
2277
2278 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2279 assert_eq!(r.bytes_in_flight(), 1000);
2280 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
2281 assert_eq!(r.lost_count(), 0);
2282
2283 now = r.loss_detection_timer().unwrap();
2285
2286 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
2288 assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
2289
2290 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2291 assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
2292 assert_eq!(r.bytes_in_flight(), 0);
2293 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
2294 assert_eq!(r.cwnd(), 12000);
2295
2296 assert_eq!(r.lost_count(), 0);
2297
2298 now += r.rtt();
2300
2301 assert_eq!(
2302 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
2303 (0, 0)
2304 );
2305
2306 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2307 assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
2308 assert_eq!(r.bytes_in_flight(), 0);
2309 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
2310 assert_eq!(r.lost_count(), 0);
2311 assert_eq!(r.startup_exit(), None);
2312 }
2313
2314 #[rstest]
2317 fn congestion_delivery_rate(
2318 #[values("reno", "cubic", "bbr2")] cc_algorithm_name: &str,
2319 ) {
2320 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2321 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2322
2323 let mut r = Recovery::new(&cfg);
2324 assert_eq!(r.cwnd(), 12000);
2325
2326 let now = Instant::now();
2327
2328 let mut total_bytes_sent = 0;
2329 for pn in 0..10 {
2330 let bytes = 1000;
2332 let sent = test_utils::helper_packet_sent(pn, now, bytes);
2333 r.on_packet_sent(
2334 sent,
2335 packet::Epoch::Application,
2336 HandshakeStatus::default(),
2337 now,
2338 "",
2339 );
2340
2341 total_bytes_sent += bytes;
2342 }
2343
2344 let interval = Duration::from_secs(10);
2346 let mut acked = RangeSet::default();
2347 acked.insert(0..10);
2348 assert_eq!(
2349 r.on_ack_received(
2350 &acked,
2351 25,
2352 packet::Epoch::Application,
2353 HandshakeStatus::default(),
2354 now + interval,
2355 None,
2356 "",
2357 )
2358 .unwrap(),
2359 OnAckReceivedOutcome {
2360 lost_packets: 0,
2361 lost_bytes: 0,
2362 acked_bytes: total_bytes_sent,
2363 spurious_losses: 0,
2364 }
2365 );
2366 assert_eq!(r.delivery_rate().to_bytes_per_second(), 1000);
2367 assert_eq!(r.min_rtt().unwrap(), interval);
2368 assert_eq!(
2370 total_bytes_sent as u64 / interval.as_secs(),
2371 r.delivery_rate().to_bytes_per_second()
2372 );
2373 assert_eq!(r.startup_exit(), None);
2374 }
2375
2376 #[rstest]
2377 fn acks_with_no_retransmittable_data(
2378 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
2379 ) {
2380 let rtt = Duration::from_millis(100);
2381
2382 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2383 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2384
2385 let mut r = Recovery::new(&cfg);
2386
2387 let mut now = Instant::now();
2388
2389 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2390
2391 let mut next_packet = 0;
2392 for _ in 0..3 {
2394 let p = test_utils::helper_packet_sent(next_packet, now, 1200);
2395 next_packet += 1;
2396 r.on_packet_sent(
2397 p,
2398 packet::Epoch::Application,
2399 HandshakeStatus::default(),
2400 now,
2401 "",
2402 );
2403 }
2404
2405 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
2406 assert_eq!(r.bytes_in_flight(), 3600);
2407 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2408
2409 assert_eq!(
2410 r.pacing_rate(),
2411 if cc_algorithm_name == "bbr2_gcongestion" {
2412 103963
2413 } else {
2414 0
2415 },
2416 );
2417 assert_eq!(r.get_packet_send_time(now), now);
2418 assert_eq!(r.cwnd(), 12000);
2419 assert_eq!(r.cwnd_available(), 8400);
2420
2421 now += rtt;
2423
2424 let mut acked = RangeSet::default();
2425 acked.insert(0..3);
2426
2427 assert_eq!(
2428 r.on_ack_received(
2429 &acked,
2430 10,
2431 packet::Epoch::Application,
2432 HandshakeStatus::default(),
2433 now,
2434 None,
2435 "",
2436 )
2437 .unwrap(),
2438 OnAckReceivedOutcome {
2439 lost_packets: 0,
2440 lost_bytes: 0,
2441 acked_bytes: 3600,
2442 spurious_losses: 0,
2443 }
2444 );
2445
2446 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2447 assert_eq!(r.bytes_in_flight(), 0);
2448 assert_eq!(r.bytes_in_flight_duration(), rtt);
2449 assert_eq!(r.rtt(), rtt);
2450
2451 assert_eq!(
2454 r.pacing_rate(),
2455 if cc_algorithm_name == "bbr2_gcongestion" {
2456 120000
2457 } else {
2458 0
2459 },
2460 );
2461
2462 for iter in 3..1000 {
2464 let mut p = test_utils::helper_packet_sent(next_packet, now, 1200);
2465 p.in_flight = false;
2468 next_packet += 1;
2469 r.on_packet_sent(
2470 p,
2471 packet::Epoch::Application,
2472 HandshakeStatus::default(),
2473 now,
2474 "",
2475 );
2476
2477 now += rtt;
2478
2479 let mut acked = RangeSet::default();
2480 acked.insert(iter..(iter + 1));
2481
2482 assert_eq!(
2483 r.on_ack_received(
2484 &acked,
2485 10,
2486 packet::Epoch::Application,
2487 HandshakeStatus::default(),
2488 now,
2489 None,
2490 "",
2491 )
2492 .unwrap(),
2493 OnAckReceivedOutcome {
2494 lost_packets: 0,
2495 lost_bytes: 0,
2496 acked_bytes: 0,
2497 spurious_losses: 0,
2498 }
2499 );
2500
2501 assert_eq!(r.startup_exit(), None, "{iter}");
2503
2504 assert_eq!(
2506 r.sent_packets_len(packet::Epoch::Application),
2507 0,
2508 "{iter}"
2509 );
2510 assert_eq!(r.bytes_in_flight(), 0, "{iter}");
2511 assert_eq!(r.bytes_in_flight_duration(), rtt, "{iter}");
2512 assert_eq!(
2513 r.pacing_rate(),
2514 if cc_algorithm_name == "bbr2_gcongestion" ||
2515 cc_algorithm_name == "bbr2"
2516 {
2517 120000
2518 } else {
2519 0
2520 },
2521 "{iter}"
2522 );
2523 }
2524 }
2525}
2526
2527mod bandwidth;
2528mod bytes_in_flight;
2529mod congestion;
2530mod gcongestion;
2531mod rtt;