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 fn inc(&mut self, delay: Duration) {
596 match self {
597 ReleaseTime::Immediate => {},
598 ReleaseTime::At(time) => *time += delay,
599 }
600 }
601
602 fn set_max(&mut self, other: Instant) {
604 match self {
605 ReleaseTime::Immediate => *self = ReleaseTime::At(other),
606 ReleaseTime::At(time) => *self = ReleaseTime::At(other.max(*time)),
607 }
608 }
609}
610
611impl ReleaseDecision {
612 pub(crate) const EQUAL_THRESHOLD: Duration = Duration::from_micros(50);
613
614 #[inline]
617 pub fn time(&self, now: Instant) -> Option<Instant> {
618 match self.time {
619 ReleaseTime::Immediate => None,
620 ReleaseTime::At(other) => other.gt(&now).then_some(other),
621 }
622 }
623
624 #[inline]
626 pub fn can_burst(&self) -> bool {
627 self.allow_burst
628 }
629
630 #[inline]
632 pub fn time_eq(&self, other: &Self, now: Instant) -> bool {
633 let delta = match (self.time(now), other.time(now)) {
634 (None, None) => Duration::ZERO,
635 (Some(t), None) | (None, Some(t)) => t.duration_since(now),
636 (Some(t1), Some(t2)) if t1 < t2 => t2.duration_since(t1),
637 (Some(t1), Some(t2)) => t1.duration_since(t2),
638 };
639
640 delta <= Self::EQUAL_THRESHOLD
641 }
642}
643
644#[derive(Default, Debug)]
646pub struct RecoveryStats {
647 startup_exit: Option<StartupExit>,
648}
649
650impl RecoveryStats {
651 pub fn set_startup_exit(&mut self, startup_exit: StartupExit) {
653 if self.startup_exit.is_none() {
654 self.startup_exit = Some(startup_exit);
655 }
656 }
657}
658
659#[derive(Debug, Clone, Copy, PartialEq)]
661pub struct StartupExit {
662 pub cwnd: usize,
664
665 pub bandwidth: Option<u64>,
667
668 pub reason: StartupExitReason,
670}
671
672impl StartupExit {
673 fn new(
674 cwnd: usize, bandwidth: Option<Bandwidth>, reason: StartupExitReason,
675 ) -> Self {
676 let bandwidth = bandwidth.map(Bandwidth::to_bytes_per_second);
677 Self {
678 cwnd,
679 bandwidth,
680 reason,
681 }
682 }
683}
684
685#[derive(Debug, Clone, Copy, PartialEq)]
687pub enum StartupExitReason {
688 Loss,
690
691 BandwidthPlateau,
693
694 PersistentQueue,
696}
697
698#[cfg(test)]
699mod tests {
700 use super::*;
701 use crate::packet;
702 use crate::test_utils;
703 use crate::CongestionControlAlgorithm;
704 use crate::DEFAULT_INITIAL_RTT;
705 use rstest::rstest;
706 use smallvec::smallvec;
707 use std::str::FromStr;
708
709 fn recovery_for_alg(algo: CongestionControlAlgorithm) -> Recovery {
710 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
711 cfg.set_cc_algorithm(algo);
712 Recovery::new(&cfg)
713 }
714
715 #[test]
716 fn lookup_cc_algo_ok() {
717 let algo = CongestionControlAlgorithm::from_str("reno").unwrap();
718 assert_eq!(algo, CongestionControlAlgorithm::Reno);
719 assert!(!recovery_for_alg(algo).gcongestion_enabled());
720
721 let algo = CongestionControlAlgorithm::from_str("cubic").unwrap();
722 assert_eq!(algo, CongestionControlAlgorithm::CUBIC);
723 assert!(!recovery_for_alg(algo).gcongestion_enabled());
724
725 let algo = CongestionControlAlgorithm::from_str("bbr").unwrap();
726 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
727 assert!(recovery_for_alg(algo).gcongestion_enabled());
728
729 let algo = CongestionControlAlgorithm::from_str("bbr2").unwrap();
730 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
731 assert!(recovery_for_alg(algo).gcongestion_enabled());
732
733 let algo =
734 CongestionControlAlgorithm::from_str("bbr2_gcongestion").unwrap();
735 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
736 assert!(recovery_for_alg(algo).gcongestion_enabled());
737 }
738
739 #[test]
740 fn lookup_cc_algo_bad() {
741 assert_eq!(
742 CongestionControlAlgorithm::from_str("???"),
743 Err(crate::Error::CongestionControl)
744 );
745 }
746
747 #[rstest]
748 fn loss_on_pto(
749 #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
750 cc_algorithm_name: &str,
751 ) {
752 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
753 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
754
755 let mut r = Recovery::new(&cfg);
756
757 let mut now = Instant::now();
758
759 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
760
761 let p = Sent {
763 pkt_num: 0,
764 frames: smallvec![],
765 time_sent: now,
766 time_acked: None,
767 time_lost: None,
768 size: 1000,
769 ack_eliciting: true,
770 in_flight: true,
771 delivered: 0,
772 delivered_time: now,
773 first_sent_time: now,
774 is_app_limited: false,
775 tx_in_flight: 0,
776 lost: 0,
777 has_data: false,
778 is_pmtud_probe: false,
779 };
780
781 r.on_packet_sent(
782 p,
783 packet::Epoch::Application,
784 HandshakeStatus::default(),
785 now,
786 "",
787 );
788
789 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
790 assert_eq!(r.bytes_in_flight(), 1000);
791 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
792
793 let p = Sent {
794 pkt_num: 1,
795 frames: smallvec![],
796 time_sent: now,
797 time_acked: None,
798 time_lost: None,
799 size: 1000,
800 ack_eliciting: true,
801 in_flight: true,
802 delivered: 0,
803 delivered_time: now,
804 first_sent_time: now,
805 is_app_limited: false,
806 tx_in_flight: 0,
807 lost: 0,
808 has_data: false,
809 is_pmtud_probe: false,
810 };
811
812 r.on_packet_sent(
813 p,
814 packet::Epoch::Application,
815 HandshakeStatus::default(),
816 now,
817 "",
818 );
819
820 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
821 assert_eq!(r.bytes_in_flight(), 2000);
822 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
823
824 let p = Sent {
825 pkt_num: 2,
826 frames: smallvec![],
827 time_sent: now,
828 time_acked: None,
829 time_lost: None,
830 size: 1000,
831 ack_eliciting: true,
832 in_flight: true,
833 delivered: 0,
834 delivered_time: now,
835 first_sent_time: now,
836 is_app_limited: false,
837 tx_in_flight: 0,
838 lost: 0,
839 has_data: false,
840 is_pmtud_probe: false,
841 };
842
843 r.on_packet_sent(
844 p,
845 packet::Epoch::Application,
846 HandshakeStatus::default(),
847 now,
848 "",
849 );
850 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
851 assert_eq!(r.bytes_in_flight(), 3000);
852 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
853
854 let p = Sent {
855 pkt_num: 3,
856 frames: smallvec![],
857 time_sent: now,
858 time_acked: None,
859 time_lost: None,
860 size: 1000,
861 ack_eliciting: true,
862 in_flight: true,
863 delivered: 0,
864 delivered_time: now,
865 first_sent_time: now,
866 is_app_limited: false,
867 tx_in_flight: 0,
868 lost: 0,
869 has_data: false,
870 is_pmtud_probe: false,
871 };
872
873 r.on_packet_sent(
874 p,
875 packet::Epoch::Application,
876 HandshakeStatus::default(),
877 now,
878 "",
879 );
880 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
881 assert_eq!(r.bytes_in_flight(), 4000);
882 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
883
884 now += Duration::from_millis(10);
886
887 let mut acked = RangeSet::default();
889 acked.insert(0..2);
890
891 assert_eq!(
892 r.on_ack_received(
893 &acked,
894 25,
895 packet::Epoch::Application,
896 HandshakeStatus::default(),
897 now,
898 None,
899 "",
900 )
901 .unwrap(),
902 OnAckReceivedOutcome {
903 lost_packets: 0,
904 lost_bytes: 0,
905 acked_bytes: 2 * 1000,
906 spurious_losses: 0,
907 }
908 );
909
910 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
911 assert_eq!(r.bytes_in_flight(), 2000);
912 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
913 assert_eq!(r.lost_count(), 0);
914
915 now = r.loss_detection_timer().unwrap();
917
918 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
920 assert_eq!(r.loss_probes(packet::Epoch::Application), 1);
921 assert_eq!(r.lost_count(), 0);
922 assert_eq!(r.pto_count(), 1);
923
924 let p = Sent {
925 pkt_num: 4,
926 frames: smallvec![],
927 time_sent: now,
928 time_acked: None,
929 time_lost: None,
930 size: 1000,
931 ack_eliciting: true,
932 in_flight: true,
933 delivered: 0,
934 delivered_time: now,
935 first_sent_time: now,
936 is_app_limited: false,
937 tx_in_flight: 0,
938 lost: 0,
939 has_data: false,
940 is_pmtud_probe: false,
941 };
942
943 r.on_packet_sent(
944 p,
945 packet::Epoch::Application,
946 HandshakeStatus::default(),
947 now,
948 "",
949 );
950 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
951 assert_eq!(r.bytes_in_flight(), 3000);
952 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(30));
953
954 let p = Sent {
955 pkt_num: 5,
956 frames: smallvec![],
957 time_sent: now,
958 time_acked: None,
959 time_lost: None,
960 size: 1000,
961 ack_eliciting: true,
962 in_flight: true,
963 delivered: 0,
964 delivered_time: now,
965 first_sent_time: now,
966 is_app_limited: false,
967 tx_in_flight: 0,
968 lost: 0,
969 has_data: false,
970 is_pmtud_probe: false,
971 };
972
973 r.on_packet_sent(
974 p,
975 packet::Epoch::Application,
976 HandshakeStatus::default(),
977 now,
978 "",
979 );
980 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
981 assert_eq!(r.bytes_in_flight(), 4000);
982 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(30));
983 assert_eq!(r.lost_count(), 0);
984
985 now += Duration::from_millis(10);
987
988 let mut acked = RangeSet::default();
990 acked.insert(4..6);
991
992 assert_eq!(
993 r.on_ack_received(
994 &acked,
995 25,
996 packet::Epoch::Application,
997 HandshakeStatus::default(),
998 now,
999 None,
1000 "",
1001 )
1002 .unwrap(),
1003 OnAckReceivedOutcome {
1004 lost_packets: 2,
1005 lost_bytes: 2000,
1006 acked_bytes: 2 * 1000,
1007 spurious_losses: 0,
1008 }
1009 );
1010
1011 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1012 assert_eq!(r.bytes_in_flight(), 0);
1013 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(40));
1014
1015 assert_eq!(r.lost_count(), 2);
1016
1017 now += r.rtt();
1019
1020 assert_eq!(
1021 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1022 (0, 0)
1023 );
1024
1025 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1026 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1027 assert!(r.startup_exit().is_some());
1028 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1029 } else {
1030 assert_eq!(r.startup_exit(), None);
1031 }
1032 }
1033
1034 #[rstest]
1035 fn loss_on_timer(
1036 #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
1037 cc_algorithm_name: &str,
1038 ) {
1039 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1040 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1041
1042 let mut r = Recovery::new(&cfg);
1043
1044 let mut now = Instant::now();
1045
1046 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1047
1048 let p = Sent {
1050 pkt_num: 0,
1051 frames: smallvec![],
1052 time_sent: now,
1053 time_acked: None,
1054 time_lost: None,
1055 size: 1000,
1056 ack_eliciting: true,
1057 in_flight: true,
1058 delivered: 0,
1059 delivered_time: now,
1060 first_sent_time: now,
1061 is_app_limited: false,
1062 tx_in_flight: 0,
1063 lost: 0,
1064 has_data: false,
1065 is_pmtud_probe: false,
1066 };
1067
1068 r.on_packet_sent(
1069 p,
1070 packet::Epoch::Application,
1071 HandshakeStatus::default(),
1072 now,
1073 "",
1074 );
1075 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1076 assert_eq!(r.bytes_in_flight(), 1000);
1077 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1078
1079 let p = Sent {
1080 pkt_num: 1,
1081 frames: smallvec![],
1082 time_sent: now,
1083 time_acked: None,
1084 time_lost: None,
1085 size: 1000,
1086 ack_eliciting: true,
1087 in_flight: true,
1088 delivered: 0,
1089 delivered_time: now,
1090 first_sent_time: now,
1091 is_app_limited: false,
1092 tx_in_flight: 0,
1093 lost: 0,
1094 has_data: false,
1095 is_pmtud_probe: false,
1096 };
1097
1098 r.on_packet_sent(
1099 p,
1100 packet::Epoch::Application,
1101 HandshakeStatus::default(),
1102 now,
1103 "",
1104 );
1105 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1106 assert_eq!(r.bytes_in_flight(), 2000);
1107 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1108
1109 let p = Sent {
1110 pkt_num: 2,
1111 frames: smallvec![],
1112 time_sent: now,
1113 time_acked: None,
1114 time_lost: None,
1115 size: 1000,
1116 ack_eliciting: true,
1117 in_flight: true,
1118 delivered: 0,
1119 delivered_time: now,
1120 first_sent_time: now,
1121 is_app_limited: false,
1122 tx_in_flight: 0,
1123 lost: 0,
1124 has_data: false,
1125 is_pmtud_probe: false,
1126 };
1127
1128 r.on_packet_sent(
1129 p,
1130 packet::Epoch::Application,
1131 HandshakeStatus::default(),
1132 now,
1133 "",
1134 );
1135 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1136 assert_eq!(r.bytes_in_flight(), 3000);
1137 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1138
1139 let p = Sent {
1140 pkt_num: 3,
1141 frames: smallvec![],
1142 time_sent: now,
1143 time_acked: None,
1144 time_lost: None,
1145 size: 1000,
1146 ack_eliciting: true,
1147 in_flight: true,
1148 delivered: 0,
1149 delivered_time: now,
1150 first_sent_time: now,
1151 is_app_limited: false,
1152 tx_in_flight: 0,
1153 lost: 0,
1154 has_data: false,
1155 is_pmtud_probe: false,
1156 };
1157
1158 r.on_packet_sent(
1159 p,
1160 packet::Epoch::Application,
1161 HandshakeStatus::default(),
1162 now,
1163 "",
1164 );
1165 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1166 assert_eq!(r.bytes_in_flight(), 4000);
1167 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1168
1169 now += Duration::from_millis(10);
1171
1172 let mut acked = RangeSet::default();
1174 acked.insert(0..2);
1175 acked.insert(3..4);
1176
1177 assert_eq!(
1178 r.on_ack_received(
1179 &acked,
1180 25,
1181 packet::Epoch::Application,
1182 HandshakeStatus::default(),
1183 now,
1184 None,
1185 "",
1186 )
1187 .unwrap(),
1188 OnAckReceivedOutcome {
1189 lost_packets: 0,
1190 lost_bytes: 0,
1191 acked_bytes: 3 * 1000,
1192 spurious_losses: 0,
1193 }
1194 );
1195
1196 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1197 assert_eq!(r.bytes_in_flight(), 1000);
1198 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
1199 assert_eq!(r.lost_count(), 0);
1200
1201 now = r.loss_detection_timer().unwrap();
1203
1204 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
1206 assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
1207
1208 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1209 assert_eq!(r.bytes_in_flight(), 0);
1210 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
1211
1212 assert_eq!(r.lost_count(), 1);
1213
1214 now += r.rtt();
1216
1217 assert_eq!(
1218 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1219 (0, 0)
1220 );
1221
1222 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1223 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1224 assert!(r.startup_exit().is_some());
1225 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1226 } else {
1227 assert_eq!(r.startup_exit(), None);
1228 }
1229 }
1230
1231 #[rstest]
1232 fn loss_on_reordering(
1233 #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
1234 cc_algorithm_name: &str,
1235 ) {
1236 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1237 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1238
1239 let mut r = Recovery::new(&cfg);
1240
1241 let mut now = Instant::now();
1242
1243 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1244
1245 for i in 0..4 {
1249 let p = test_utils::helper_packet_sent(i, now, 1000);
1250 r.on_packet_sent(
1251 p,
1252 packet::Epoch::Application,
1253 HandshakeStatus::default(),
1254 now,
1255 "",
1256 );
1257
1258 let pkt_count = (i + 1) as usize;
1259 assert_eq!(r.sent_packets_len(packet::Epoch::Application), pkt_count);
1260 assert_eq!(r.bytes_in_flight(), pkt_count * 1000);
1261 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1262 }
1263
1264 now += Duration::from_millis(10);
1266
1267 let mut acked = RangeSet::default();
1269 acked.insert(2..4);
1270 assert_eq!(
1271 r.on_ack_received(
1272 &acked,
1273 25,
1274 packet::Epoch::Application,
1275 HandshakeStatus::default(),
1276 now,
1277 None,
1278 "",
1279 )
1280 .unwrap(),
1281 OnAckReceivedOutcome {
1282 lost_packets: 1,
1283 lost_bytes: 1000,
1284 acked_bytes: 1000 * 2,
1285 spurious_losses: 0,
1286 }
1287 );
1288 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1291 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1292 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1293
1294 now += Duration::from_millis(10);
1296
1297 let mut acked = RangeSet::default();
1299 acked.insert(0..2);
1300 assert_eq!(
1301 r.on_ack_received(
1302 &acked,
1303 25,
1304 packet::Epoch::Application,
1305 HandshakeStatus::default(),
1306 now,
1307 None,
1308 "",
1309 )
1310 .unwrap(),
1311 OnAckReceivedOutcome {
1312 lost_packets: 0,
1313 lost_bytes: 0,
1314 acked_bytes: 1000,
1315 spurious_losses: 1,
1316 }
1317 );
1318 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1319 assert_eq!(r.bytes_in_flight(), 0);
1320 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(20));
1321
1322 assert_eq!(r.lost_count(), 1);
1324 assert_eq!(r.lost_spurious_count(), 1);
1325
1326 assert_eq!(r.pkt_thresh().unwrap(), 4);
1328 assert_eq!(r.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1329
1330 now += r.rtt();
1332
1333 assert_eq!(
1335 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1336 (0, 0)
1337 );
1338 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1339
1340 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1341 assert!(r.startup_exit().is_some());
1342 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1343 } else {
1344 assert_eq!(r.startup_exit(), None);
1345 }
1346 }
1347
1348 #[rstest]
1353 fn time_thresholds_on_reordering(
1354 #[values("bbr2_gcongestion")] cc_algorithm_name: &str,
1355 ) {
1356 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1357 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1358
1359 let mut now = Instant::now();
1360 let mut r = Recovery::new(&cfg);
1361 assert_eq!(r.rtt(), DEFAULT_INITIAL_RTT);
1362
1363 const THRESH_GAP: Duration = Duration::from_millis(30);
1377 let initial_thresh_ms =
1379 DEFAULT_INITIAL_RTT.mul_f64(INITIAL_TIME_THRESHOLD);
1380 let spurious_thresh_ms: Duration =
1382 DEFAULT_INITIAL_RTT.mul_f64(PACKET_REORDER_TIME_THRESHOLD);
1383 let between_thresh_ms = initial_thresh_ms + THRESH_GAP;
1385 assert!(between_thresh_ms > initial_thresh_ms);
1386 assert!(between_thresh_ms < spurious_thresh_ms);
1387 assert!(between_thresh_ms + THRESH_GAP > spurious_thresh_ms);
1388
1389 for i in 0..6 {
1390 let send_time = now + i * between_thresh_ms;
1391
1392 let p = test_utils::helper_packet_sent(i.into(), send_time, 1000);
1393 r.on_packet_sent(
1394 p,
1395 packet::Epoch::Application,
1396 HandshakeStatus::default(),
1397 send_time,
1398 "",
1399 );
1400 }
1401
1402 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 6);
1403 assert_eq!(r.bytes_in_flight(), 6 * 1000);
1404 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1405 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1406
1407 now += between_thresh_ms;
1410
1411 let mut acked = RangeSet::default();
1416 acked.insert(1..2);
1417 assert_eq!(
1418 r.on_ack_received(
1419 &acked,
1420 25,
1421 packet::Epoch::Application,
1422 HandshakeStatus::default(),
1423 now,
1424 None,
1425 "",
1426 )
1427 .unwrap(),
1428 OnAckReceivedOutcome {
1429 lost_packets: 1,
1430 lost_bytes: 1000,
1431 acked_bytes: 1000,
1432 spurious_losses: 0,
1433 }
1434 );
1435 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1436 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1437
1438 let mut acked = RangeSet::default();
1443 acked.insert(0..1);
1444 assert_eq!(
1445 r.on_ack_received(
1446 &acked,
1447 25,
1448 packet::Epoch::Application,
1449 HandshakeStatus::default(),
1450 now,
1451 None,
1452 "",
1453 )
1454 .unwrap(),
1455 OnAckReceivedOutcome {
1456 lost_packets: 0,
1457 lost_bytes: 0,
1458 acked_bytes: 0,
1459 spurious_losses: 1,
1460 }
1461 );
1462 assert_eq!(r.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1464
1465 now += between_thresh_ms;
1468
1469 let mut acked = RangeSet::default();
1474 acked.insert(3..4);
1475 assert_eq!(
1476 r.on_ack_received(
1477 &acked,
1478 25,
1479 packet::Epoch::Application,
1480 HandshakeStatus::default(),
1481 now,
1482 None,
1483 "",
1484 )
1485 .unwrap(),
1486 OnAckReceivedOutcome {
1487 lost_packets: 0,
1488 lost_bytes: 0,
1489 acked_bytes: 1000,
1490 spurious_losses: 0,
1491 }
1492 );
1493
1494 now += THRESH_GAP;
1497
1498 let mut acked = RangeSet::default();
1503 acked.insert(4..5);
1504 assert_eq!(
1505 r.on_ack_received(
1506 &acked,
1507 25,
1508 packet::Epoch::Application,
1509 HandshakeStatus::default(),
1510 now,
1511 None,
1512 "",
1513 )
1514 .unwrap(),
1515 OnAckReceivedOutcome {
1516 lost_packets: 1,
1517 lost_bytes: 1000,
1518 acked_bytes: 1000,
1519 spurious_losses: 0,
1520 }
1521 );
1522 }
1523
1524 #[rstest]
1527 fn relaxed_thresholds_on_reordering(
1528 #[values("bbr2_gcongestion")] cc_algorithm_name: &str,
1529 ) {
1530 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1531 cfg.enable_relaxed_loss_threshold = true;
1532 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1533
1534 let mut now = Instant::now();
1535 let mut r = Recovery::new(&cfg);
1536 assert_eq!(r.rtt(), DEFAULT_INITIAL_RTT);
1537
1538 const THRESH_GAP: Duration = Duration::from_millis(30);
1551 let initial_thresh_ms =
1553 DEFAULT_INITIAL_RTT.mul_f64(INITIAL_TIME_THRESHOLD);
1554 let spurious_thresh_ms: Duration =
1556 DEFAULT_INITIAL_RTT.mul_f64(PACKET_REORDER_TIME_THRESHOLD);
1557 let between_thresh_ms = initial_thresh_ms + THRESH_GAP;
1559 assert!(between_thresh_ms > initial_thresh_ms);
1560 assert!(between_thresh_ms < spurious_thresh_ms);
1561 assert!(between_thresh_ms + THRESH_GAP > spurious_thresh_ms);
1562
1563 for i in 0..6 {
1564 let send_time = now + i * between_thresh_ms;
1565
1566 let p = test_utils::helper_packet_sent(i.into(), send_time, 1000);
1567 r.on_packet_sent(
1568 p,
1569 packet::Epoch::Application,
1570 HandshakeStatus::default(),
1571 send_time,
1572 "",
1573 );
1574 }
1575
1576 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 6);
1577 assert_eq!(r.bytes_in_flight(), 6 * 1000);
1578 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1580 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1581
1582 now += between_thresh_ms;
1585
1586 let mut acked = RangeSet::default();
1591 acked.insert(1..2);
1592 assert_eq!(
1593 r.on_ack_received(
1594 &acked,
1595 25,
1596 packet::Epoch::Application,
1597 HandshakeStatus::default(),
1598 now,
1599 None,
1600 "",
1601 )
1602 .unwrap(),
1603 OnAckReceivedOutcome {
1604 lost_packets: 1,
1605 lost_bytes: 1000,
1606 acked_bytes: 1000,
1607 spurious_losses: 0,
1608 }
1609 );
1610 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1612 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1613
1614 let mut acked = RangeSet::default();
1619 acked.insert(0..1);
1620 assert_eq!(
1621 r.on_ack_received(
1622 &acked,
1623 25,
1624 packet::Epoch::Application,
1625 HandshakeStatus::default(),
1626 now,
1627 None,
1628 "",
1629 )
1630 .unwrap(),
1631 OnAckReceivedOutcome {
1632 lost_packets: 0,
1633 lost_bytes: 0,
1634 acked_bytes: 0,
1635 spurious_losses: 1,
1636 }
1637 );
1638 assert_eq!(r.pkt_thresh(), None);
1643 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1644
1645 now += between_thresh_ms;
1648 now += between_thresh_ms;
1652
1653 let mut acked = RangeSet::default();
1658 acked.insert(3..4);
1659 assert_eq!(
1660 r.on_ack_received(
1661 &acked,
1662 25,
1663 packet::Epoch::Application,
1664 HandshakeStatus::default(),
1665 now,
1666 None,
1667 "",
1668 )
1669 .unwrap(),
1670 OnAckReceivedOutcome {
1671 lost_packets: 1,
1672 lost_bytes: 1000,
1673 acked_bytes: 1000,
1674 spurious_losses: 0,
1675 }
1676 );
1677 assert_eq!(r.pkt_thresh(), None);
1679 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1680
1681 let mut acked = RangeSet::default();
1690 acked.insert(2..3);
1691 assert_eq!(
1692 r.on_ack_received(
1693 &acked,
1694 25,
1695 packet::Epoch::Application,
1696 HandshakeStatus::default(),
1697 now,
1698 None,
1699 "",
1700 )
1701 .unwrap(),
1702 OnAckReceivedOutcome {
1703 lost_packets: 0,
1704 lost_bytes: 0,
1705 acked_bytes: 0,
1706 spurious_losses: 1,
1707 }
1708 );
1709 assert_eq!(r.pkt_thresh(), None);
1713 let double_time_thresh_overhead =
1714 1.0 + 2.0 * INITIAL_TIME_THRESHOLD_OVERHEAD;
1715 assert_eq!(r.time_thresh(), double_time_thresh_overhead);
1716 }
1717
1718 #[rstest]
1719 fn pacing(
1720 #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
1721 cc_algorithm_name: &str,
1722 #[values(false, true)] time_sent_set_to_now: bool,
1723 ) {
1724 let pacing_enabled = cc_algorithm_name == "bbr2" ||
1725 cc_algorithm_name == "bbr2_gcongestion";
1726
1727 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1728 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1729
1730 #[cfg(feature = "internal")]
1731 cfg.set_custom_bbr_params(BbrParams {
1732 time_sent_set_to_now: Some(time_sent_set_to_now),
1733 ..Default::default()
1734 });
1735
1736 let mut r = Recovery::new(&cfg);
1737
1738 let mut now = Instant::now();
1739
1740 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1741
1742 for i in 0..10 {
1744 let p = Sent {
1745 pkt_num: i,
1746 frames: smallvec![],
1747 time_sent: now,
1748 time_acked: None,
1749 time_lost: None,
1750 size: 1200,
1751 ack_eliciting: true,
1752 in_flight: true,
1753 delivered: 0,
1754 delivered_time: now,
1755 first_sent_time: now,
1756 is_app_limited: false,
1757 tx_in_flight: 0,
1758 lost: 0,
1759 has_data: true,
1760 is_pmtud_probe: false,
1761 };
1762
1763 r.on_packet_sent(
1764 p,
1765 packet::Epoch::Application,
1766 HandshakeStatus::default(),
1767 now,
1768 "",
1769 );
1770 }
1771
1772 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 10);
1773 assert_eq!(r.bytes_in_flight(), 12000);
1774 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1775
1776 if !pacing_enabled {
1777 assert_eq!(r.pacing_rate(), 0);
1778 } else {
1779 assert_eq!(r.pacing_rate(), 103963);
1780 }
1781 assert_eq!(r.get_packet_send_time(now), now);
1782
1783 assert_eq!(r.cwnd(), 12000);
1784 assert_eq!(r.cwnd_available(), 0);
1785
1786 let initial_rtt = Duration::from_millis(50);
1788 now += initial_rtt;
1789
1790 let mut acked = RangeSet::default();
1791 acked.insert(0..10);
1792
1793 assert_eq!(
1794 r.on_ack_received(
1795 &acked,
1796 10,
1797 packet::Epoch::Application,
1798 HandshakeStatus::default(),
1799 now,
1800 None,
1801 "",
1802 )
1803 .unwrap(),
1804 OnAckReceivedOutcome {
1805 lost_packets: 0,
1806 lost_bytes: 0,
1807 acked_bytes: 12000,
1808 spurious_losses: 0,
1809 }
1810 );
1811
1812 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1813 assert_eq!(r.bytes_in_flight(), 0);
1814 assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
1815 assert_eq!(r.min_rtt(), Some(initial_rtt));
1816 assert_eq!(r.rtt(), initial_rtt);
1817
1818 assert_eq!(r.cwnd(), 12000 + 1200 * 10);
1820
1821 let p = Sent {
1823 pkt_num: 10,
1824 frames: smallvec![],
1825 time_sent: now,
1826 time_acked: None,
1827 time_lost: None,
1828 size: 6000,
1829 ack_eliciting: true,
1830 in_flight: true,
1831 delivered: 0,
1832 delivered_time: now,
1833 first_sent_time: now,
1834 is_app_limited: false,
1835 tx_in_flight: 0,
1836 lost: 0,
1837 has_data: true,
1838 is_pmtud_probe: false,
1839 };
1840
1841 r.on_packet_sent(
1842 p,
1843 packet::Epoch::Application,
1844 HandshakeStatus::default(),
1845 now,
1846 "",
1847 );
1848
1849 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1850 assert_eq!(r.bytes_in_flight(), 6000);
1851 assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
1852
1853 if !pacing_enabled {
1854 assert_eq!(r.get_packet_send_time(now), now);
1856 } else {
1857 assert_ne!(r.get_packet_send_time(now), now);
1859 }
1860
1861 let p = Sent {
1863 pkt_num: 11,
1864 frames: smallvec![],
1865 time_sent: now,
1866 time_acked: None,
1867 time_lost: None,
1868 size: 6000,
1869 ack_eliciting: true,
1870 in_flight: true,
1871 delivered: 0,
1872 delivered_time: now,
1873 first_sent_time: now,
1874 is_app_limited: false,
1875 tx_in_flight: 0,
1876 lost: 0,
1877 has_data: true,
1878 is_pmtud_probe: false,
1879 };
1880
1881 r.on_packet_sent(
1882 p,
1883 packet::Epoch::Application,
1884 HandshakeStatus::default(),
1885 now,
1886 "",
1887 );
1888
1889 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1890 assert_eq!(r.bytes_in_flight(), 12000);
1891 assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
1892
1893 let p = Sent {
1895 pkt_num: 12,
1896 frames: smallvec![],
1897 time_sent: now,
1898 time_acked: None,
1899 time_lost: None,
1900 size: 1000,
1901 ack_eliciting: true,
1902 in_flight: true,
1903 delivered: 0,
1904 delivered_time: now,
1905 first_sent_time: now,
1906 is_app_limited: false,
1907 tx_in_flight: 0,
1908 lost: 0,
1909 has_data: true,
1910 is_pmtud_probe: false,
1911 };
1912
1913 r.on_packet_sent(
1914 p,
1915 packet::Epoch::Application,
1916 HandshakeStatus::default(),
1917 now,
1918 "",
1919 );
1920
1921 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1922 assert_eq!(r.bytes_in_flight(), 13000);
1923 assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
1924
1925 let pacing_rate = if pacing_enabled {
1928 let cwnd_gain: f64 = 2.0;
1929 let bw = r.cwnd() as f64 / cwnd_gain / initial_rtt.as_secs_f64();
1932 bw as u64
1933 } else {
1934 0
1935 };
1936 assert_eq!(r.pacing_rate(), pacing_rate);
1937
1938 let scale_factor = if pacing_enabled {
1939 1.08333332
1942 } else {
1943 1.0
1944 };
1945 assert_eq!(
1946 r.get_packet_send_time(now) - now,
1947 if pacing_enabled {
1948 Duration::from_secs_f64(
1949 scale_factor * 12000.0 / pacing_rate as f64,
1950 )
1951 } else {
1952 Duration::ZERO
1953 }
1954 );
1955 assert_eq!(r.startup_exit(), None);
1956
1957 let reduced_rtt = Duration::from_millis(40);
1958 now += reduced_rtt;
1959
1960 let mut acked = RangeSet::default();
1961 acked.insert(10..11);
1962
1963 assert_eq!(
1964 r.on_ack_received(
1965 &acked,
1966 0,
1967 packet::Epoch::Application,
1968 HandshakeStatus::default(),
1969 now,
1970 None,
1971 "",
1972 )
1973 .unwrap(),
1974 OnAckReceivedOutcome {
1975 lost_packets: 0,
1976 lost_bytes: 0,
1977 acked_bytes: 6000,
1978 spurious_losses: 0,
1979 }
1980 );
1981
1982 let expected_srtt = (7 * initial_rtt + reduced_rtt) / 8;
1983 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1984 assert_eq!(r.bytes_in_flight(), 7000);
1985 assert_eq!(r.bytes_in_flight_duration(), initial_rtt + reduced_rtt);
1986 assert_eq!(r.min_rtt(), Some(reduced_rtt));
1987 assert_eq!(r.rtt(), expected_srtt);
1988
1989 let mut acked = RangeSet::default();
1990 acked.insert(11..12);
1991
1992 assert_eq!(
1993 r.on_ack_received(
1994 &acked,
1995 0,
1996 packet::Epoch::Application,
1997 HandshakeStatus::default(),
1998 now,
1999 None,
2000 "",
2001 )
2002 .unwrap(),
2003 OnAckReceivedOutcome {
2004 lost_packets: 0,
2005 lost_bytes: 0,
2006 acked_bytes: 6000,
2007 spurious_losses: 0,
2008 }
2009 );
2010
2011 let expected_min_rtt = if pacing_enabled &&
2015 !time_sent_set_to_now &&
2016 cfg!(feature = "internal")
2017 {
2018 reduced_rtt - Duration::from_millis(25)
2019 } else {
2020 reduced_rtt
2021 };
2022
2023 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
2024 assert_eq!(r.bytes_in_flight(), 1000);
2025 assert_eq!(r.bytes_in_flight_duration(), initial_rtt + reduced_rtt);
2026 assert_eq!(r.min_rtt(), Some(expected_min_rtt));
2027
2028 let expected_srtt = (7 * expected_srtt + expected_min_rtt) / 8;
2029 assert_eq!(r.rtt(), expected_srtt);
2030
2031 let mut acked = RangeSet::default();
2032 acked.insert(12..13);
2033
2034 assert_eq!(
2035 r.on_ack_received(
2036 &acked,
2037 0,
2038 packet::Epoch::Application,
2039 HandshakeStatus::default(),
2040 now,
2041 None,
2042 "",
2043 )
2044 .unwrap(),
2045 OnAckReceivedOutcome {
2046 lost_packets: 0,
2047 lost_bytes: 0,
2048 acked_bytes: 1000,
2049 spurious_losses: 0,
2050 }
2051 );
2052
2053 let expected_min_rtt = if pacing_enabled &&
2056 !time_sent_set_to_now &&
2057 cfg!(feature = "internal")
2058 {
2059 Duration::from_millis(0)
2060 } else {
2061 reduced_rtt
2062 };
2063 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2064 assert_eq!(r.bytes_in_flight(), 0);
2065 assert_eq!(r.bytes_in_flight_duration(), initial_rtt + reduced_rtt);
2066 assert_eq!(r.min_rtt(), Some(expected_min_rtt));
2067
2068 let expected_srtt = (7 * expected_srtt + expected_min_rtt) / 8;
2069 assert_eq!(r.rtt(), expected_srtt);
2070 }
2071
2072 #[rstest]
2073 #[case::bw_estimate_equal_after_first_rtt(1.0, 1.0)]
2076 #[case::bw_estimate_decrease_after_first_rtt(2.0, 1.0)]
2079 #[case::bw_estimate_increase_after_first_rtt(0.5, 0.5)]
2085 #[cfg(feature = "internal")]
2086 fn initial_pacing_rate_override(
2087 #[case] initial_multipler: f64, #[case] expected_multiplier: f64,
2088 ) {
2089 let rtt = Duration::from_millis(50);
2090 let bw = Bandwidth::from_bytes_and_time_delta(12000, rtt);
2091 let initial_pacing_rate_hint = bw * initial_multipler;
2092 let expected_pacing_with_rtt_measurement = bw * expected_multiplier;
2093
2094 let cc_algorithm_name = "bbr2_gcongestion";
2095 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2096 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2097 cfg.set_custom_bbr_params(BbrParams {
2098 initial_pacing_rate_bytes_per_second: Some(
2099 initial_pacing_rate_hint.to_bytes_per_second(),
2100 ),
2101 ..Default::default()
2102 });
2103
2104 let mut r = Recovery::new(&cfg);
2105
2106 let mut now = Instant::now();
2107
2108 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2109
2110 for i in 0..2 {
2112 let p = test_utils::helper_packet_sent(i, now, 1200);
2113 r.on_packet_sent(
2114 p,
2115 packet::Epoch::Application,
2116 HandshakeStatus::default(),
2117 now,
2118 "",
2119 );
2120 }
2121
2122 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2123 assert_eq!(r.bytes_in_flight(), 2400);
2124 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2125
2126 assert_eq!(
2128 r.pacing_rate(),
2129 initial_pacing_rate_hint.to_bytes_per_second()
2130 );
2131 assert_eq!(r.get_packet_send_time(now), now);
2132
2133 assert_eq!(r.cwnd(), 12000);
2134 assert_eq!(r.cwnd_available(), 9600);
2135
2136 now += rtt;
2138
2139 let mut acked = RangeSet::default();
2140 acked.insert(0..2);
2141
2142 assert_eq!(
2143 r.on_ack_received(
2144 &acked,
2145 10,
2146 packet::Epoch::Application,
2147 HandshakeStatus::default(),
2148 now,
2149 None,
2150 "",
2151 )
2152 .unwrap(),
2153 OnAckReceivedOutcome {
2154 lost_packets: 0,
2155 lost_bytes: 0,
2156 acked_bytes: 2400,
2157 spurious_losses: 0,
2158 }
2159 );
2160
2161 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2162 assert_eq!(r.bytes_in_flight(), 0);
2163 assert_eq!(r.bytes_in_flight_duration(), rtt);
2164 assert_eq!(r.rtt(), rtt);
2165
2166 assert_eq!(
2169 r.pacing_rate(),
2170 expected_pacing_with_rtt_measurement.to_bytes_per_second()
2171 );
2172 }
2173
2174 #[rstest]
2175 fn validate_ack_range_on_ack_received(
2176 #[values("cubic", "bbr2", "bbr2_gcongestion")] cc_algorithm_name: &str,
2177 ) {
2178 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2179 cfg.set_cc_algorithm_name(cc_algorithm_name).unwrap();
2180
2181 let epoch = packet::Epoch::Application;
2182 let mut r = Recovery::new(&cfg);
2183 let mut now = Instant::now();
2184 assert_eq!(r.sent_packets_len(epoch), 0);
2185
2186 let pkt_size = 1000;
2188 let pkt_count = 4;
2189 for pkt_num in 0..pkt_count {
2190 let sent = test_utils::helper_packet_sent(pkt_num, now, pkt_size);
2191 r.on_packet_sent(sent, epoch, HandshakeStatus::default(), now, "");
2192 }
2193 assert_eq!(r.sent_packets_len(epoch), pkt_count as usize);
2194 assert_eq!(r.bytes_in_flight(), pkt_count as usize * pkt_size);
2195 assert!(r.get_largest_acked_on_epoch(epoch).is_none());
2196 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2197
2198 now += Duration::from_millis(10);
2200
2201 let mut acked = RangeSet::default();
2203 acked.insert(0..2);
2204
2205 assert_eq!(
2206 r.on_ack_received(
2207 &acked,
2208 25,
2209 epoch,
2210 HandshakeStatus::default(),
2211 now,
2212 None,
2213 "",
2214 )
2215 .unwrap(),
2216 OnAckReceivedOutcome {
2217 lost_packets: 0,
2218 lost_bytes: 0,
2219 acked_bytes: 2 * 1000,
2220 spurious_losses: 0,
2221 }
2222 );
2223
2224 assert_eq!(r.sent_packets_len(epoch), 2);
2225 assert_eq!(r.bytes_in_flight(), 2 * 1000);
2226
2227 assert_eq!(r.get_largest_acked_on_epoch(epoch).unwrap(), 1);
2228 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2229
2230 let mut acked = RangeSet::default();
2232 acked.insert(0..10);
2233 assert_eq!(
2234 r.on_ack_received(
2235 &acked,
2236 25,
2237 epoch,
2238 HandshakeStatus::default(),
2239 now,
2240 None,
2241 "",
2242 )
2243 .unwrap(),
2244 OnAckReceivedOutcome {
2245 lost_packets: 0,
2246 lost_bytes: 0,
2247 acked_bytes: 2 * 1000,
2248 spurious_losses: 0,
2249 }
2250 );
2251 assert_eq!(r.sent_packets_len(epoch), 0);
2252 assert_eq!(r.bytes_in_flight(), 0);
2253
2254 assert_eq!(r.get_largest_acked_on_epoch(epoch).unwrap(), 3);
2255 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2256 }
2257
2258 #[rstest]
2259 fn pmtud_loss_on_timer(
2260 #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
2261 cc_algorithm_name: &str,
2262 ) {
2263 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2264 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2265
2266 let mut r = Recovery::new(&cfg);
2267 assert_eq!(r.cwnd(), 12000);
2268
2269 let mut now = Instant::now();
2270
2271 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2272
2273 let p = Sent {
2275 pkt_num: 0,
2276 frames: smallvec![],
2277 time_sent: now,
2278 time_acked: None,
2279 time_lost: None,
2280 size: 1000,
2281 ack_eliciting: true,
2282 in_flight: true,
2283 delivered: 0,
2284 delivered_time: now,
2285 first_sent_time: now,
2286 is_app_limited: false,
2287 tx_in_flight: 0,
2288 lost: 0,
2289 has_data: false,
2290 is_pmtud_probe: false,
2291 };
2292
2293 r.on_packet_sent(
2294 p,
2295 packet::Epoch::Application,
2296 HandshakeStatus::default(),
2297 now,
2298 "",
2299 );
2300
2301 assert_eq!(r.in_flight_count(packet::Epoch::Application), 1);
2302 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
2303 assert_eq!(r.bytes_in_flight(), 1000);
2304 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2305
2306 let p = Sent {
2307 pkt_num: 1,
2308 frames: smallvec![],
2309 time_sent: now,
2310 time_acked: None,
2311 time_lost: None,
2312 size: 1000,
2313 ack_eliciting: true,
2314 in_flight: true,
2315 delivered: 0,
2316 delivered_time: now,
2317 first_sent_time: now,
2318 is_app_limited: false,
2319 tx_in_flight: 0,
2320 lost: 0,
2321 has_data: false,
2322 is_pmtud_probe: true,
2323 };
2324
2325 r.on_packet_sent(
2326 p,
2327 packet::Epoch::Application,
2328 HandshakeStatus::default(),
2329 now,
2330 "",
2331 );
2332
2333 assert_eq!(r.in_flight_count(packet::Epoch::Application), 2);
2334
2335 let p = Sent {
2336 pkt_num: 2,
2337 frames: smallvec![],
2338 time_sent: now,
2339 time_acked: None,
2340 time_lost: None,
2341 size: 1000,
2342 ack_eliciting: true,
2343 in_flight: true,
2344 delivered: 0,
2345 delivered_time: now,
2346 first_sent_time: now,
2347 is_app_limited: false,
2348 tx_in_flight: 0,
2349 lost: 0,
2350 has_data: false,
2351 is_pmtud_probe: false,
2352 };
2353
2354 r.on_packet_sent(
2355 p,
2356 packet::Epoch::Application,
2357 HandshakeStatus::default(),
2358 now,
2359 "",
2360 );
2361
2362 assert_eq!(r.in_flight_count(packet::Epoch::Application), 3);
2363
2364 now += Duration::from_millis(10);
2366
2367 let mut acked = RangeSet::default();
2369 acked.insert(0..1);
2370 acked.insert(2..3);
2371
2372 assert_eq!(
2373 r.on_ack_received(
2374 &acked,
2375 25,
2376 packet::Epoch::Application,
2377 HandshakeStatus::default(),
2378 now,
2379 None,
2380 "",
2381 )
2382 .unwrap(),
2383 OnAckReceivedOutcome {
2384 lost_packets: 0,
2385 lost_bytes: 0,
2386 acked_bytes: 2 * 1000,
2387 spurious_losses: 0,
2388 }
2389 );
2390
2391 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2392 assert_eq!(r.bytes_in_flight(), 1000);
2393 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
2394 assert_eq!(r.lost_count(), 0);
2395
2396 now = r.loss_detection_timer().unwrap();
2398
2399 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
2401 assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
2402
2403 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2404 assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
2405 assert_eq!(r.bytes_in_flight(), 0);
2406 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
2407 assert_eq!(r.cwnd(), 12000);
2408
2409 assert_eq!(r.lost_count(), 0);
2410
2411 now += r.rtt();
2413
2414 assert_eq!(
2415 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
2416 (0, 0)
2417 );
2418
2419 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2420 assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
2421 assert_eq!(r.bytes_in_flight(), 0);
2422 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
2423 assert_eq!(r.lost_count(), 0);
2424 assert_eq!(r.startup_exit(), None);
2425 }
2426
2427 #[rstest]
2430 fn congestion_delivery_rate(
2431 #[values("reno", "cubic", "bbr2")] cc_algorithm_name: &str,
2432 ) {
2433 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2434 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2435
2436 let mut r = Recovery::new(&cfg);
2437 assert_eq!(r.cwnd(), 12000);
2438
2439 let now = Instant::now();
2440
2441 let mut total_bytes_sent = 0;
2442 for pn in 0..10 {
2443 let bytes = 1000;
2445 let sent = test_utils::helper_packet_sent(pn, now, bytes);
2446 r.on_packet_sent(
2447 sent,
2448 packet::Epoch::Application,
2449 HandshakeStatus::default(),
2450 now,
2451 "",
2452 );
2453
2454 total_bytes_sent += bytes;
2455 }
2456
2457 let interval = Duration::from_secs(10);
2459 let mut acked = RangeSet::default();
2460 acked.insert(0..10);
2461 assert_eq!(
2462 r.on_ack_received(
2463 &acked,
2464 25,
2465 packet::Epoch::Application,
2466 HandshakeStatus::default(),
2467 now + interval,
2468 None,
2469 "",
2470 )
2471 .unwrap(),
2472 OnAckReceivedOutcome {
2473 lost_packets: 0,
2474 lost_bytes: 0,
2475 acked_bytes: total_bytes_sent,
2476 spurious_losses: 0,
2477 }
2478 );
2479 assert_eq!(r.delivery_rate().to_bytes_per_second(), 1000);
2480 assert_eq!(r.min_rtt().unwrap(), interval);
2481 assert_eq!(
2483 total_bytes_sent as u64 / interval.as_secs(),
2484 r.delivery_rate().to_bytes_per_second()
2485 );
2486 assert_eq!(r.startup_exit(), None);
2487 }
2488
2489 #[rstest]
2490 fn acks_with_no_retransmittable_data(
2491 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
2492 ) {
2493 let rtt = Duration::from_millis(100);
2494
2495 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2496 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2497
2498 let mut r = Recovery::new(&cfg);
2499
2500 let mut now = Instant::now();
2501
2502 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2503
2504 let mut next_packet = 0;
2505 for _ in 0..3 {
2507 let p = test_utils::helper_packet_sent(next_packet, now, 1200);
2508 next_packet += 1;
2509 r.on_packet_sent(
2510 p,
2511 packet::Epoch::Application,
2512 HandshakeStatus::default(),
2513 now,
2514 "",
2515 );
2516 }
2517
2518 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
2519 assert_eq!(r.bytes_in_flight(), 3600);
2520 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2521
2522 assert_eq!(
2523 r.pacing_rate(),
2524 if cc_algorithm_name == "bbr2_gcongestion" {
2525 103963
2526 } else {
2527 0
2528 },
2529 );
2530 assert_eq!(r.get_packet_send_time(now), now);
2531 assert_eq!(r.cwnd(), 12000);
2532 assert_eq!(r.cwnd_available(), 8400);
2533
2534 now += rtt;
2536
2537 let mut acked = RangeSet::default();
2538 acked.insert(0..3);
2539
2540 assert_eq!(
2541 r.on_ack_received(
2542 &acked,
2543 10,
2544 packet::Epoch::Application,
2545 HandshakeStatus::default(),
2546 now,
2547 None,
2548 "",
2549 )
2550 .unwrap(),
2551 OnAckReceivedOutcome {
2552 lost_packets: 0,
2553 lost_bytes: 0,
2554 acked_bytes: 3600,
2555 spurious_losses: 0,
2556 }
2557 );
2558
2559 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2560 assert_eq!(r.bytes_in_flight(), 0);
2561 assert_eq!(r.bytes_in_flight_duration(), rtt);
2562 assert_eq!(r.rtt(), rtt);
2563
2564 assert_eq!(
2567 r.pacing_rate(),
2568 if cc_algorithm_name == "bbr2_gcongestion" {
2569 120000
2570 } else {
2571 0
2572 },
2573 );
2574
2575 for iter in 3..1000 {
2577 let mut p = test_utils::helper_packet_sent(next_packet, now, 1200);
2578 p.in_flight = false;
2581 next_packet += 1;
2582 r.on_packet_sent(
2583 p,
2584 packet::Epoch::Application,
2585 HandshakeStatus::default(),
2586 now,
2587 "",
2588 );
2589
2590 now += rtt;
2591
2592 let mut acked = RangeSet::default();
2593 acked.insert(iter..(iter + 1));
2594
2595 assert_eq!(
2596 r.on_ack_received(
2597 &acked,
2598 10,
2599 packet::Epoch::Application,
2600 HandshakeStatus::default(),
2601 now,
2602 None,
2603 "",
2604 )
2605 .unwrap(),
2606 OnAckReceivedOutcome {
2607 lost_packets: 0,
2608 lost_bytes: 0,
2609 acked_bytes: 0,
2610 spurious_losses: 0,
2611 }
2612 );
2613
2614 assert_eq!(r.startup_exit(), None, "{iter}");
2616
2617 assert_eq!(
2619 r.sent_packets_len(packet::Epoch::Application),
2620 0,
2621 "{iter}"
2622 );
2623 assert_eq!(r.bytes_in_flight(), 0, "{iter}");
2624 assert_eq!(r.bytes_in_flight_duration(), rtt, "{iter}");
2625 assert_eq!(
2626 r.pacing_rate(),
2627 if cc_algorithm_name == "bbr2_gcongestion" ||
2628 cc_algorithm_name == "bbr2"
2629 {
2630 120000
2631 } else {
2632 0
2633 },
2634 "{iter}"
2635 );
2636 }
2637 }
2638}
2639
2640mod bandwidth;
2641mod bytes_in_flight;
2642mod congestion;
2643mod gcongestion;
2644mod rtt;