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: Option<u64>,
481 delivery_rate: Option<u64>,
482 send_rate: Option<u64>,
483 ack_rate: Option<u64>,
484}
485
486#[cfg(feature = "qlog")]
487impl QlogMetrics {
488 fn maybe_update(&mut self, latest: Self) -> Option<EventData> {
494 let mut emit_event = false;
495
496 let new_min_rtt = if self.min_rtt != latest.min_rtt {
497 self.min_rtt = latest.min_rtt;
498 emit_event = true;
499 Some(latest.min_rtt.as_secs_f32() * 1000.0)
500 } else {
501 None
502 };
503
504 let new_smoothed_rtt = if self.smoothed_rtt != latest.smoothed_rtt {
505 self.smoothed_rtt = latest.smoothed_rtt;
506 emit_event = true;
507 Some(latest.smoothed_rtt.as_secs_f32() * 1000.0)
508 } else {
509 None
510 };
511
512 let new_latest_rtt = if self.latest_rtt != latest.latest_rtt {
513 self.latest_rtt = latest.latest_rtt;
514 emit_event = true;
515 Some(latest.latest_rtt.as_secs_f32() * 1000.0)
516 } else {
517 None
518 };
519
520 let new_rttvar = if self.rttvar != latest.rttvar {
521 self.rttvar = latest.rttvar;
522 emit_event = true;
523 Some(latest.rttvar.as_secs_f32() * 1000.0)
524 } else {
525 None
526 };
527
528 let new_cwnd = if self.cwnd != latest.cwnd {
529 self.cwnd = latest.cwnd;
530 emit_event = true;
531 Some(latest.cwnd)
532 } else {
533 None
534 };
535
536 let new_bytes_in_flight =
537 if self.bytes_in_flight != latest.bytes_in_flight {
538 self.bytes_in_flight = latest.bytes_in_flight;
539 emit_event = true;
540 Some(latest.bytes_in_flight)
541 } else {
542 None
543 };
544
545 let new_ssthresh = if self.ssthresh != latest.ssthresh {
546 self.ssthresh = latest.ssthresh;
547 emit_event = true;
548 latest.ssthresh
549 } else {
550 None
551 };
552
553 let new_pacing_rate = if self.pacing_rate != latest.pacing_rate {
554 self.pacing_rate = latest.pacing_rate;
555 emit_event = true;
556 latest.pacing_rate
557 } else {
558 None
559 };
560
561 let mut ex_data = qlog::events::ExData::new();
563 if self.delivery_rate != latest.delivery_rate {
564 if let Some(rate) = latest.delivery_rate {
565 self.delivery_rate = latest.delivery_rate;
566 emit_event = true;
567 ex_data.insert(
568 "cf_delivery_rate".to_string(),
569 serde_json::json!(rate),
570 );
571 }
572 }
573 if self.send_rate != latest.send_rate {
574 if let Some(rate) = latest.send_rate {
575 self.send_rate = latest.send_rate;
576 emit_event = true;
577 ex_data
578 .insert("cf_send_rate".to_string(), serde_json::json!(rate));
579 }
580 }
581 if self.ack_rate != latest.ack_rate {
582 if let Some(rate) = latest.ack_rate {
583 self.ack_rate = latest.ack_rate;
584 emit_event = true;
585 ex_data
586 .insert("cf_ack_rate".to_string(), serde_json::json!(rate));
587 }
588 }
589
590 if emit_event {
591 return Some(EventData::MetricsUpdated(
592 qlog::events::quic::MetricsUpdated {
593 min_rtt: new_min_rtt,
594 smoothed_rtt: new_smoothed_rtt,
595 latest_rtt: new_latest_rtt,
596 rtt_variance: new_rttvar,
597 congestion_window: new_cwnd,
598 bytes_in_flight: new_bytes_in_flight,
599 ssthresh: new_ssthresh,
600 pacing_rate: new_pacing_rate,
601 ex_data,
602 ..Default::default()
603 },
604 ));
605 }
606
607 None
608 }
609}
610
611#[derive(Debug, Clone, Copy, PartialEq, Eq)]
613pub enum ReleaseTime {
614 Immediate,
615 At(Instant),
616}
617
618#[derive(Clone, Copy, Debug, PartialEq, Eq)]
620pub struct ReleaseDecision {
621 time: ReleaseTime,
622 allow_burst: bool,
623}
624
625impl ReleaseTime {
626 fn inc(&mut self, delay: Duration) {
628 match self {
629 ReleaseTime::Immediate => {},
630 ReleaseTime::At(time) => *time += delay,
631 }
632 }
633
634 fn set_max(&mut self, other: Instant) {
636 match self {
637 ReleaseTime::Immediate => *self = ReleaseTime::At(other),
638 ReleaseTime::At(time) => *self = ReleaseTime::At(other.max(*time)),
639 }
640 }
641}
642
643impl ReleaseDecision {
644 pub(crate) const EQUAL_THRESHOLD: Duration = Duration::from_micros(50);
645
646 #[inline]
649 pub fn time(&self, now: Instant) -> Option<Instant> {
650 match self.time {
651 ReleaseTime::Immediate => None,
652 ReleaseTime::At(other) => other.gt(&now).then_some(other),
653 }
654 }
655
656 #[inline]
658 pub fn can_burst(&self) -> bool {
659 self.allow_burst
660 }
661
662 #[inline]
664 pub fn time_eq(&self, other: &Self, now: Instant) -> bool {
665 let delta = match (self.time(now), other.time(now)) {
666 (None, None) => Duration::ZERO,
667 (Some(t), None) | (None, Some(t)) => t.duration_since(now),
668 (Some(t1), Some(t2)) if t1 < t2 => t2.duration_since(t1),
669 (Some(t1), Some(t2)) => t1.duration_since(t2),
670 };
671
672 delta <= Self::EQUAL_THRESHOLD
673 }
674}
675
676#[derive(Default, Debug)]
678pub struct RecoveryStats {
679 startup_exit: Option<StartupExit>,
680}
681
682impl RecoveryStats {
683 pub fn set_startup_exit(&mut self, startup_exit: StartupExit) {
685 if self.startup_exit.is_none() {
686 self.startup_exit = Some(startup_exit);
687 }
688 }
689}
690
691#[derive(Debug, Clone, Copy, PartialEq)]
693pub struct StartupExit {
694 pub cwnd: usize,
696
697 pub bandwidth: Option<u64>,
699
700 pub reason: StartupExitReason,
702}
703
704impl StartupExit {
705 fn new(
706 cwnd: usize, bandwidth: Option<Bandwidth>, reason: StartupExitReason,
707 ) -> Self {
708 let bandwidth = bandwidth.map(Bandwidth::to_bytes_per_second);
709 Self {
710 cwnd,
711 bandwidth,
712 reason,
713 }
714 }
715}
716
717#[derive(Debug, Clone, Copy, PartialEq)]
719pub enum StartupExitReason {
720 Loss,
722
723 BandwidthPlateau,
725
726 PersistentQueue,
728
729 ConservativeSlowStartRounds,
731}
732
733#[cfg(test)]
734mod tests {
735 use super::*;
736 use crate::packet;
737 use crate::test_utils;
738 use crate::CongestionControlAlgorithm;
739 use crate::DEFAULT_INITIAL_RTT;
740 use rstest::rstest;
741 use smallvec::smallvec;
742 use std::str::FromStr;
743
744 fn recovery_for_alg(algo: CongestionControlAlgorithm) -> Recovery {
745 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
746 cfg.set_cc_algorithm(algo);
747 Recovery::new(&cfg)
748 }
749
750 #[test]
751 fn lookup_cc_algo_ok() {
752 let algo = CongestionControlAlgorithm::from_str("reno").unwrap();
753 assert_eq!(algo, CongestionControlAlgorithm::Reno);
754 assert!(!recovery_for_alg(algo).gcongestion_enabled());
755
756 let algo = CongestionControlAlgorithm::from_str("cubic").unwrap();
757 assert_eq!(algo, CongestionControlAlgorithm::CUBIC);
758 assert!(!recovery_for_alg(algo).gcongestion_enabled());
759
760 let algo = CongestionControlAlgorithm::from_str("bbr").unwrap();
761 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
762 assert!(recovery_for_alg(algo).gcongestion_enabled());
763
764 let algo = CongestionControlAlgorithm::from_str("bbr2").unwrap();
765 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
766 assert!(recovery_for_alg(algo).gcongestion_enabled());
767
768 let algo =
769 CongestionControlAlgorithm::from_str("bbr2_gcongestion").unwrap();
770 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
771 assert!(recovery_for_alg(algo).gcongestion_enabled());
772 }
773
774 #[test]
775 fn lookup_cc_algo_bad() {
776 assert_eq!(
777 CongestionControlAlgorithm::from_str("???"),
778 Err(crate::Error::CongestionControl)
779 );
780 }
781
782 #[rstest]
783 fn loss_on_pto(
784 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
785 ) {
786 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
787 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
788
789 let mut r = Recovery::new(&cfg);
790
791 let mut now = Instant::now();
792
793 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
794
795 let p = Sent {
797 pkt_num: 0,
798 frames: smallvec![],
799 time_sent: now,
800 time_acked: None,
801 time_lost: None,
802 size: 1000,
803 ack_eliciting: true,
804 in_flight: true,
805 delivered: 0,
806 delivered_time: now,
807 first_sent_time: now,
808 is_app_limited: false,
809 tx_in_flight: 0,
810 lost: 0,
811 has_data: false,
812 is_pmtud_probe: false,
813 };
814
815 r.on_packet_sent(
816 p,
817 packet::Epoch::Application,
818 HandshakeStatus::default(),
819 now,
820 "",
821 );
822
823 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
824 assert_eq!(r.bytes_in_flight(), 1000);
825 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
826
827 let p = Sent {
828 pkt_num: 1,
829 frames: smallvec![],
830 time_sent: now,
831 time_acked: None,
832 time_lost: None,
833 size: 1000,
834 ack_eliciting: true,
835 in_flight: true,
836 delivered: 0,
837 delivered_time: now,
838 first_sent_time: now,
839 is_app_limited: false,
840 tx_in_flight: 0,
841 lost: 0,
842 has_data: false,
843 is_pmtud_probe: false,
844 };
845
846 r.on_packet_sent(
847 p,
848 packet::Epoch::Application,
849 HandshakeStatus::default(),
850 now,
851 "",
852 );
853
854 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
855 assert_eq!(r.bytes_in_flight(), 2000);
856 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
857
858 let p = Sent {
859 pkt_num: 2,
860 frames: smallvec![],
861 time_sent: now,
862 time_acked: None,
863 time_lost: None,
864 size: 1000,
865 ack_eliciting: true,
866 in_flight: true,
867 delivered: 0,
868 delivered_time: now,
869 first_sent_time: now,
870 is_app_limited: false,
871 tx_in_flight: 0,
872 lost: 0,
873 has_data: false,
874 is_pmtud_probe: false,
875 };
876
877 r.on_packet_sent(
878 p,
879 packet::Epoch::Application,
880 HandshakeStatus::default(),
881 now,
882 "",
883 );
884 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
885 assert_eq!(r.bytes_in_flight(), 3000);
886 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
887
888 let p = Sent {
889 pkt_num: 3,
890 frames: smallvec![],
891 time_sent: now,
892 time_acked: None,
893 time_lost: None,
894 size: 1000,
895 ack_eliciting: true,
896 in_flight: true,
897 delivered: 0,
898 delivered_time: now,
899 first_sent_time: now,
900 is_app_limited: false,
901 tx_in_flight: 0,
902 lost: 0,
903 has_data: false,
904 is_pmtud_probe: false,
905 };
906
907 r.on_packet_sent(
908 p,
909 packet::Epoch::Application,
910 HandshakeStatus::default(),
911 now,
912 "",
913 );
914 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
915 assert_eq!(r.bytes_in_flight(), 4000);
916 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
917
918 now += Duration::from_millis(10);
920
921 let mut acked = RangeSet::default();
923 acked.insert(0..2);
924
925 assert_eq!(
926 r.on_ack_received(
927 &acked,
928 25,
929 packet::Epoch::Application,
930 HandshakeStatus::default(),
931 now,
932 None,
933 "",
934 )
935 .unwrap(),
936 OnAckReceivedOutcome {
937 lost_packets: 0,
938 lost_bytes: 0,
939 acked_bytes: 2 * 1000,
940 spurious_losses: 0,
941 }
942 );
943
944 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
945 assert_eq!(r.bytes_in_flight(), 2000);
946 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
947 assert_eq!(r.lost_count(), 0);
948
949 now = r.loss_detection_timer().unwrap();
951
952 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
954 assert_eq!(r.loss_probes(packet::Epoch::Application), 1);
955 assert_eq!(r.lost_count(), 0);
956 assert_eq!(r.pto_count(), 1);
957
958 let p = Sent {
959 pkt_num: 4,
960 frames: smallvec![],
961 time_sent: now,
962 time_acked: None,
963 time_lost: None,
964 size: 1000,
965 ack_eliciting: true,
966 in_flight: true,
967 delivered: 0,
968 delivered_time: now,
969 first_sent_time: now,
970 is_app_limited: false,
971 tx_in_flight: 0,
972 lost: 0,
973 has_data: false,
974 is_pmtud_probe: false,
975 };
976
977 r.on_packet_sent(
978 p,
979 packet::Epoch::Application,
980 HandshakeStatus::default(),
981 now,
982 "",
983 );
984 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
985 assert_eq!(r.bytes_in_flight(), 3000);
986 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(30));
987
988 let p = Sent {
989 pkt_num: 5,
990 frames: smallvec![],
991 time_sent: now,
992 time_acked: None,
993 time_lost: None,
994 size: 1000,
995 ack_eliciting: true,
996 in_flight: true,
997 delivered: 0,
998 delivered_time: now,
999 first_sent_time: now,
1000 is_app_limited: false,
1001 tx_in_flight: 0,
1002 lost: 0,
1003 has_data: false,
1004 is_pmtud_probe: false,
1005 };
1006
1007 r.on_packet_sent(
1008 p,
1009 packet::Epoch::Application,
1010 HandshakeStatus::default(),
1011 now,
1012 "",
1013 );
1014 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1015 assert_eq!(r.bytes_in_flight(), 4000);
1016 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(30));
1017 assert_eq!(r.lost_count(), 0);
1018
1019 now += Duration::from_millis(10);
1021
1022 let mut acked = RangeSet::default();
1024 acked.insert(4..6);
1025
1026 assert_eq!(
1027 r.on_ack_received(
1028 &acked,
1029 25,
1030 packet::Epoch::Application,
1031 HandshakeStatus::default(),
1032 now,
1033 None,
1034 "",
1035 )
1036 .unwrap(),
1037 OnAckReceivedOutcome {
1038 lost_packets: 2,
1039 lost_bytes: 2000,
1040 acked_bytes: 2 * 1000,
1041 spurious_losses: 0,
1042 }
1043 );
1044
1045 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1046 assert_eq!(r.bytes_in_flight(), 0);
1047 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(40));
1048
1049 assert_eq!(r.lost_count(), 2);
1050
1051 now += r.rtt();
1053
1054 assert_eq!(
1055 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1056 (0, 0)
1057 );
1058
1059 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1060 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1061 assert!(r.startup_exit().is_some());
1062 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1063 } else {
1064 assert_eq!(r.startup_exit(), None);
1065 }
1066 }
1067
1068 #[rstest]
1069 fn loss_on_timer(
1070 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
1071 ) {
1072 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1073 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1074
1075 let mut r = Recovery::new(&cfg);
1076
1077 let mut now = Instant::now();
1078
1079 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1080
1081 let p = Sent {
1083 pkt_num: 0,
1084 frames: smallvec![],
1085 time_sent: now,
1086 time_acked: None,
1087 time_lost: None,
1088 size: 1000,
1089 ack_eliciting: true,
1090 in_flight: true,
1091 delivered: 0,
1092 delivered_time: now,
1093 first_sent_time: now,
1094 is_app_limited: false,
1095 tx_in_flight: 0,
1096 lost: 0,
1097 has_data: false,
1098 is_pmtud_probe: false,
1099 };
1100
1101 r.on_packet_sent(
1102 p,
1103 packet::Epoch::Application,
1104 HandshakeStatus::default(),
1105 now,
1106 "",
1107 );
1108 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1109 assert_eq!(r.bytes_in_flight(), 1000);
1110 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1111
1112 let p = Sent {
1113 pkt_num: 1,
1114 frames: smallvec![],
1115 time_sent: now,
1116 time_acked: None,
1117 time_lost: None,
1118 size: 1000,
1119 ack_eliciting: true,
1120 in_flight: true,
1121 delivered: 0,
1122 delivered_time: now,
1123 first_sent_time: now,
1124 is_app_limited: false,
1125 tx_in_flight: 0,
1126 lost: 0,
1127 has_data: false,
1128 is_pmtud_probe: false,
1129 };
1130
1131 r.on_packet_sent(
1132 p,
1133 packet::Epoch::Application,
1134 HandshakeStatus::default(),
1135 now,
1136 "",
1137 );
1138 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1139 assert_eq!(r.bytes_in_flight(), 2000);
1140 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1141
1142 let p = Sent {
1143 pkt_num: 2,
1144 frames: smallvec![],
1145 time_sent: now,
1146 time_acked: None,
1147 time_lost: None,
1148 size: 1000,
1149 ack_eliciting: true,
1150 in_flight: true,
1151 delivered: 0,
1152 delivered_time: now,
1153 first_sent_time: now,
1154 is_app_limited: false,
1155 tx_in_flight: 0,
1156 lost: 0,
1157 has_data: false,
1158 is_pmtud_probe: false,
1159 };
1160
1161 r.on_packet_sent(
1162 p,
1163 packet::Epoch::Application,
1164 HandshakeStatus::default(),
1165 now,
1166 "",
1167 );
1168 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1169 assert_eq!(r.bytes_in_flight(), 3000);
1170 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1171
1172 let p = Sent {
1173 pkt_num: 3,
1174 frames: smallvec![],
1175 time_sent: now,
1176 time_acked: None,
1177 time_lost: None,
1178 size: 1000,
1179 ack_eliciting: true,
1180 in_flight: true,
1181 delivered: 0,
1182 delivered_time: now,
1183 first_sent_time: now,
1184 is_app_limited: false,
1185 tx_in_flight: 0,
1186 lost: 0,
1187 has_data: false,
1188 is_pmtud_probe: false,
1189 };
1190
1191 r.on_packet_sent(
1192 p,
1193 packet::Epoch::Application,
1194 HandshakeStatus::default(),
1195 now,
1196 "",
1197 );
1198 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1199 assert_eq!(r.bytes_in_flight(), 4000);
1200 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1201
1202 now += Duration::from_millis(10);
1204
1205 let mut acked = RangeSet::default();
1207 acked.insert(0..2);
1208 acked.insert(3..4);
1209
1210 assert_eq!(
1211 r.on_ack_received(
1212 &acked,
1213 25,
1214 packet::Epoch::Application,
1215 HandshakeStatus::default(),
1216 now,
1217 None,
1218 "",
1219 )
1220 .unwrap(),
1221 OnAckReceivedOutcome {
1222 lost_packets: 0,
1223 lost_bytes: 0,
1224 acked_bytes: 3 * 1000,
1225 spurious_losses: 0,
1226 }
1227 );
1228
1229 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1230 assert_eq!(r.bytes_in_flight(), 1000);
1231 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
1232 assert_eq!(r.lost_count(), 0);
1233
1234 now = r.loss_detection_timer().unwrap();
1236
1237 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
1239 assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
1240
1241 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1242 assert_eq!(r.bytes_in_flight(), 0);
1243 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
1244
1245 assert_eq!(r.lost_count(), 1);
1246
1247 now += r.rtt();
1249
1250 assert_eq!(
1251 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1252 (0, 0)
1253 );
1254
1255 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1256 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1257 assert!(r.startup_exit().is_some());
1258 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1259 } else {
1260 assert_eq!(r.startup_exit(), None);
1261 }
1262 }
1263
1264 #[rstest]
1265 fn loss_on_reordering(
1266 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
1267 ) {
1268 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1269 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1270
1271 let mut r = Recovery::new(&cfg);
1272
1273 let mut now = Instant::now();
1274
1275 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1276
1277 for i in 0..4 {
1281 let p = test_utils::helper_packet_sent(i, now, 1000);
1282 r.on_packet_sent(
1283 p,
1284 packet::Epoch::Application,
1285 HandshakeStatus::default(),
1286 now,
1287 "",
1288 );
1289
1290 let pkt_count = (i + 1) as usize;
1291 assert_eq!(r.sent_packets_len(packet::Epoch::Application), pkt_count);
1292 assert_eq!(r.bytes_in_flight(), pkt_count * 1000);
1293 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1294 }
1295
1296 now += Duration::from_millis(10);
1298
1299 let mut acked = RangeSet::default();
1301 acked.insert(2..4);
1302 assert_eq!(
1303 r.on_ack_received(
1304 &acked,
1305 25,
1306 packet::Epoch::Application,
1307 HandshakeStatus::default(),
1308 now,
1309 None,
1310 "",
1311 )
1312 .unwrap(),
1313 OnAckReceivedOutcome {
1314 lost_packets: 1,
1315 lost_bytes: 1000,
1316 acked_bytes: 1000 * 2,
1317 spurious_losses: 0,
1318 }
1319 );
1320 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1323 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1324 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1325
1326 now += Duration::from_millis(10);
1328
1329 let mut acked = RangeSet::default();
1331 acked.insert(0..2);
1332 assert_eq!(
1333 r.on_ack_received(
1334 &acked,
1335 25,
1336 packet::Epoch::Application,
1337 HandshakeStatus::default(),
1338 now,
1339 None,
1340 "",
1341 )
1342 .unwrap(),
1343 OnAckReceivedOutcome {
1344 lost_packets: 0,
1345 lost_bytes: 0,
1346 acked_bytes: 1000,
1347 spurious_losses: 1,
1348 }
1349 );
1350 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1351 assert_eq!(r.bytes_in_flight(), 0);
1352 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(20));
1353
1354 assert_eq!(r.lost_count(), 1);
1356 assert_eq!(r.lost_spurious_count(), 1);
1357
1358 assert_eq!(r.pkt_thresh().unwrap(), 4);
1360 assert_eq!(r.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1361
1362 now += r.rtt();
1364
1365 assert_eq!(
1367 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1368 (0, 0)
1369 );
1370 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1371
1372 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1373 assert!(r.startup_exit().is_some());
1374 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1375 } else {
1376 assert_eq!(r.startup_exit(), None);
1377 }
1378 }
1379
1380 #[rstest]
1385 fn time_thresholds_on_reordering(
1386 #[values("bbr2_gcongestion")] cc_algorithm_name: &str,
1387 ) {
1388 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1389 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1390
1391 let mut now = Instant::now();
1392 let mut r = Recovery::new(&cfg);
1393 assert_eq!(r.rtt(), DEFAULT_INITIAL_RTT);
1394
1395 const THRESH_GAP: Duration = Duration::from_millis(30);
1409 let initial_thresh_ms =
1411 DEFAULT_INITIAL_RTT.mul_f64(INITIAL_TIME_THRESHOLD);
1412 let spurious_thresh_ms: Duration =
1414 DEFAULT_INITIAL_RTT.mul_f64(PACKET_REORDER_TIME_THRESHOLD);
1415 let between_thresh_ms = initial_thresh_ms + THRESH_GAP;
1417 assert!(between_thresh_ms > initial_thresh_ms);
1418 assert!(between_thresh_ms < spurious_thresh_ms);
1419 assert!(between_thresh_ms + THRESH_GAP > spurious_thresh_ms);
1420
1421 for i in 0..6 {
1422 let send_time = now + i * between_thresh_ms;
1423
1424 let p = test_utils::helper_packet_sent(i.into(), send_time, 1000);
1425 r.on_packet_sent(
1426 p,
1427 packet::Epoch::Application,
1428 HandshakeStatus::default(),
1429 send_time,
1430 "",
1431 );
1432 }
1433
1434 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 6);
1435 assert_eq!(r.bytes_in_flight(), 6 * 1000);
1436 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1437 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1438
1439 now += between_thresh_ms;
1442
1443 let mut acked = RangeSet::default();
1448 acked.insert(1..2);
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: 1,
1462 lost_bytes: 1000,
1463 acked_bytes: 1000,
1464 spurious_losses: 0,
1465 }
1466 );
1467 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1468 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1469
1470 let mut acked = RangeSet::default();
1475 acked.insert(0..1);
1476 assert_eq!(
1477 r.on_ack_received(
1478 &acked,
1479 25,
1480 packet::Epoch::Application,
1481 HandshakeStatus::default(),
1482 now,
1483 None,
1484 "",
1485 )
1486 .unwrap(),
1487 OnAckReceivedOutcome {
1488 lost_packets: 0,
1489 lost_bytes: 0,
1490 acked_bytes: 0,
1491 spurious_losses: 1,
1492 }
1493 );
1494 assert_eq!(r.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1496
1497 now += between_thresh_ms;
1500
1501 let mut acked = RangeSet::default();
1506 acked.insert(3..4);
1507 assert_eq!(
1508 r.on_ack_received(
1509 &acked,
1510 25,
1511 packet::Epoch::Application,
1512 HandshakeStatus::default(),
1513 now,
1514 None,
1515 "",
1516 )
1517 .unwrap(),
1518 OnAckReceivedOutcome {
1519 lost_packets: 0,
1520 lost_bytes: 0,
1521 acked_bytes: 1000,
1522 spurious_losses: 0,
1523 }
1524 );
1525
1526 now += THRESH_GAP;
1529
1530 let mut acked = RangeSet::default();
1535 acked.insert(4..5);
1536 assert_eq!(
1537 r.on_ack_received(
1538 &acked,
1539 25,
1540 packet::Epoch::Application,
1541 HandshakeStatus::default(),
1542 now,
1543 None,
1544 "",
1545 )
1546 .unwrap(),
1547 OnAckReceivedOutcome {
1548 lost_packets: 1,
1549 lost_bytes: 1000,
1550 acked_bytes: 1000,
1551 spurious_losses: 0,
1552 }
1553 );
1554 }
1555
1556 #[rstest]
1559 fn relaxed_thresholds_on_reordering(
1560 #[values("bbr2_gcongestion")] cc_algorithm_name: &str,
1561 ) {
1562 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1563 cfg.enable_relaxed_loss_threshold = true;
1564 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1565
1566 let mut now = Instant::now();
1567 let mut r = Recovery::new(&cfg);
1568 assert_eq!(r.rtt(), DEFAULT_INITIAL_RTT);
1569
1570 const THRESH_GAP: Duration = Duration::from_millis(30);
1583 let initial_thresh_ms =
1585 DEFAULT_INITIAL_RTT.mul_f64(INITIAL_TIME_THRESHOLD);
1586 let spurious_thresh_ms: Duration =
1588 DEFAULT_INITIAL_RTT.mul_f64(PACKET_REORDER_TIME_THRESHOLD);
1589 let between_thresh_ms = initial_thresh_ms + THRESH_GAP;
1591 assert!(between_thresh_ms > initial_thresh_ms);
1592 assert!(between_thresh_ms < spurious_thresh_ms);
1593 assert!(between_thresh_ms + THRESH_GAP > spurious_thresh_ms);
1594
1595 for i in 0..6 {
1596 let send_time = now + i * between_thresh_ms;
1597
1598 let p = test_utils::helper_packet_sent(i.into(), send_time, 1000);
1599 r.on_packet_sent(
1600 p,
1601 packet::Epoch::Application,
1602 HandshakeStatus::default(),
1603 send_time,
1604 "",
1605 );
1606 }
1607
1608 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 6);
1609 assert_eq!(r.bytes_in_flight(), 6 * 1000);
1610 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1612 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1613
1614 now += between_thresh_ms;
1617
1618 let mut acked = RangeSet::default();
1623 acked.insert(1..2);
1624 assert_eq!(
1625 r.on_ack_received(
1626 &acked,
1627 25,
1628 packet::Epoch::Application,
1629 HandshakeStatus::default(),
1630 now,
1631 None,
1632 "",
1633 )
1634 .unwrap(),
1635 OnAckReceivedOutcome {
1636 lost_packets: 1,
1637 lost_bytes: 1000,
1638 acked_bytes: 1000,
1639 spurious_losses: 0,
1640 }
1641 );
1642 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1644 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1645
1646 let mut acked = RangeSet::default();
1651 acked.insert(0..1);
1652 assert_eq!(
1653 r.on_ack_received(
1654 &acked,
1655 25,
1656 packet::Epoch::Application,
1657 HandshakeStatus::default(),
1658 now,
1659 None,
1660 "",
1661 )
1662 .unwrap(),
1663 OnAckReceivedOutcome {
1664 lost_packets: 0,
1665 lost_bytes: 0,
1666 acked_bytes: 0,
1667 spurious_losses: 1,
1668 }
1669 );
1670 assert_eq!(r.pkt_thresh(), None);
1675 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1676
1677 now += between_thresh_ms;
1680 now += between_thresh_ms;
1684
1685 let mut acked = RangeSet::default();
1690 acked.insert(3..4);
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: 1,
1704 lost_bytes: 1000,
1705 acked_bytes: 1000,
1706 spurious_losses: 0,
1707 }
1708 );
1709 assert_eq!(r.pkt_thresh(), None);
1711 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1712
1713 let mut acked = RangeSet::default();
1722 acked.insert(2..3);
1723 assert_eq!(
1724 r.on_ack_received(
1725 &acked,
1726 25,
1727 packet::Epoch::Application,
1728 HandshakeStatus::default(),
1729 now,
1730 None,
1731 "",
1732 )
1733 .unwrap(),
1734 OnAckReceivedOutcome {
1735 lost_packets: 0,
1736 lost_bytes: 0,
1737 acked_bytes: 0,
1738 spurious_losses: 1,
1739 }
1740 );
1741 assert_eq!(r.pkt_thresh(), None);
1745 let double_time_thresh_overhead =
1746 1.0 + 2.0 * INITIAL_TIME_THRESHOLD_OVERHEAD;
1747 assert_eq!(r.time_thresh(), double_time_thresh_overhead);
1748 }
1749
1750 #[rstest]
1751 fn pacing(
1752 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
1753 #[values(false, true)] time_sent_set_to_now: bool,
1754 ) {
1755 let pacing_enabled = cc_algorithm_name == "bbr2" ||
1756 cc_algorithm_name == "bbr2_gcongestion";
1757
1758 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1759 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1760
1761 #[cfg(feature = "internal")]
1762 cfg.set_custom_bbr_params(BbrParams {
1763 time_sent_set_to_now: Some(time_sent_set_to_now),
1764 ..Default::default()
1765 });
1766
1767 let mut r = Recovery::new(&cfg);
1768
1769 let mut now = Instant::now();
1770
1771 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1772
1773 for i in 0..10 {
1775 let p = Sent {
1776 pkt_num: i,
1777 frames: smallvec![],
1778 time_sent: now,
1779 time_acked: None,
1780 time_lost: None,
1781 size: 1200,
1782 ack_eliciting: true,
1783 in_flight: true,
1784 delivered: 0,
1785 delivered_time: now,
1786 first_sent_time: now,
1787 is_app_limited: false,
1788 tx_in_flight: 0,
1789 lost: 0,
1790 has_data: true,
1791 is_pmtud_probe: false,
1792 };
1793
1794 r.on_packet_sent(
1795 p,
1796 packet::Epoch::Application,
1797 HandshakeStatus::default(),
1798 now,
1799 "",
1800 );
1801 }
1802
1803 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 10);
1804 assert_eq!(r.bytes_in_flight(), 12000);
1805 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1806
1807 if !pacing_enabled {
1808 assert_eq!(r.pacing_rate(), 0);
1809 } else {
1810 assert_eq!(r.pacing_rate(), 103963);
1811 }
1812 assert_eq!(r.get_packet_send_time(now), now);
1813
1814 assert_eq!(r.cwnd(), 12000);
1815 assert_eq!(r.cwnd_available(), 0);
1816
1817 let initial_rtt = Duration::from_millis(50);
1819 now += initial_rtt;
1820
1821 let mut acked = RangeSet::default();
1822 acked.insert(0..10);
1823
1824 assert_eq!(
1825 r.on_ack_received(
1826 &acked,
1827 10,
1828 packet::Epoch::Application,
1829 HandshakeStatus::default(),
1830 now,
1831 None,
1832 "",
1833 )
1834 .unwrap(),
1835 OnAckReceivedOutcome {
1836 lost_packets: 0,
1837 lost_bytes: 0,
1838 acked_bytes: 12000,
1839 spurious_losses: 0,
1840 }
1841 );
1842
1843 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1844 assert_eq!(r.bytes_in_flight(), 0);
1845 assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
1846 assert_eq!(r.min_rtt(), Some(initial_rtt));
1847 assert_eq!(r.rtt(), initial_rtt);
1848
1849 assert_eq!(r.cwnd(), 12000 + 1200 * 10);
1851
1852 let p = Sent {
1854 pkt_num: 10,
1855 frames: smallvec![],
1856 time_sent: now,
1857 time_acked: None,
1858 time_lost: None,
1859 size: 6000,
1860 ack_eliciting: true,
1861 in_flight: true,
1862 delivered: 0,
1863 delivered_time: now,
1864 first_sent_time: now,
1865 is_app_limited: false,
1866 tx_in_flight: 0,
1867 lost: 0,
1868 has_data: true,
1869 is_pmtud_probe: false,
1870 };
1871
1872 r.on_packet_sent(
1873 p,
1874 packet::Epoch::Application,
1875 HandshakeStatus::default(),
1876 now,
1877 "",
1878 );
1879
1880 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1881 assert_eq!(r.bytes_in_flight(), 6000);
1882 assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
1883
1884 if !pacing_enabled {
1885 assert_eq!(r.get_packet_send_time(now), now);
1887 } else {
1888 assert_ne!(r.get_packet_send_time(now), now);
1890 }
1891
1892 let p = Sent {
1894 pkt_num: 11,
1895 frames: smallvec![],
1896 time_sent: now,
1897 time_acked: None,
1898 time_lost: None,
1899 size: 6000,
1900 ack_eliciting: true,
1901 in_flight: true,
1902 delivered: 0,
1903 delivered_time: now,
1904 first_sent_time: now,
1905 is_app_limited: false,
1906 tx_in_flight: 0,
1907 lost: 0,
1908 has_data: true,
1909 is_pmtud_probe: false,
1910 };
1911
1912 r.on_packet_sent(
1913 p,
1914 packet::Epoch::Application,
1915 HandshakeStatus::default(),
1916 now,
1917 "",
1918 );
1919
1920 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1921 assert_eq!(r.bytes_in_flight(), 12000);
1922 assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
1923
1924 let p = Sent {
1926 pkt_num: 12,
1927 frames: smallvec![],
1928 time_sent: now,
1929 time_acked: None,
1930 time_lost: None,
1931 size: 1000,
1932 ack_eliciting: true,
1933 in_flight: true,
1934 delivered: 0,
1935 delivered_time: now,
1936 first_sent_time: now,
1937 is_app_limited: false,
1938 tx_in_flight: 0,
1939 lost: 0,
1940 has_data: true,
1941 is_pmtud_probe: false,
1942 };
1943
1944 r.on_packet_sent(
1945 p,
1946 packet::Epoch::Application,
1947 HandshakeStatus::default(),
1948 now,
1949 "",
1950 );
1951
1952 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1953 assert_eq!(r.bytes_in_flight(), 13000);
1954 assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
1955
1956 let pacing_rate = if pacing_enabled {
1959 let cwnd_gain: f64 = 2.0;
1960 let bw = r.cwnd() as f64 / cwnd_gain / initial_rtt.as_secs_f64();
1963 bw as u64
1964 } else {
1965 0
1966 };
1967 assert_eq!(r.pacing_rate(), pacing_rate);
1968
1969 let scale_factor = if pacing_enabled {
1970 1.08333332
1973 } else {
1974 1.0
1975 };
1976 assert_eq!(
1977 r.get_packet_send_time(now) - now,
1978 if pacing_enabled {
1979 Duration::from_secs_f64(
1980 scale_factor * 12000.0 / pacing_rate as f64,
1981 )
1982 } else {
1983 Duration::ZERO
1984 }
1985 );
1986 assert_eq!(r.startup_exit(), None);
1987
1988 let reduced_rtt = Duration::from_millis(40);
1989 now += reduced_rtt;
1990
1991 let mut acked = RangeSet::default();
1992 acked.insert(10..11);
1993
1994 assert_eq!(
1995 r.on_ack_received(
1996 &acked,
1997 0,
1998 packet::Epoch::Application,
1999 HandshakeStatus::default(),
2000 now,
2001 None,
2002 "",
2003 )
2004 .unwrap(),
2005 OnAckReceivedOutcome {
2006 lost_packets: 0,
2007 lost_bytes: 0,
2008 acked_bytes: 6000,
2009 spurious_losses: 0,
2010 }
2011 );
2012
2013 let expected_srtt = (7 * initial_rtt + reduced_rtt) / 8;
2014 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2015 assert_eq!(r.bytes_in_flight(), 7000);
2016 assert_eq!(r.bytes_in_flight_duration(), initial_rtt + reduced_rtt);
2017 assert_eq!(r.min_rtt(), Some(reduced_rtt));
2018 assert_eq!(r.rtt(), expected_srtt);
2019
2020 let mut acked = RangeSet::default();
2021 acked.insert(11..12);
2022
2023 assert_eq!(
2024 r.on_ack_received(
2025 &acked,
2026 0,
2027 packet::Epoch::Application,
2028 HandshakeStatus::default(),
2029 now,
2030 None,
2031 "",
2032 )
2033 .unwrap(),
2034 OnAckReceivedOutcome {
2035 lost_packets: 0,
2036 lost_bytes: 0,
2037 acked_bytes: 6000,
2038 spurious_losses: 0,
2039 }
2040 );
2041
2042 let expected_min_rtt = if pacing_enabled &&
2046 !time_sent_set_to_now &&
2047 cfg!(feature = "internal")
2048 {
2049 reduced_rtt - Duration::from_millis(25)
2050 } else {
2051 reduced_rtt
2052 };
2053
2054 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
2055 assert_eq!(r.bytes_in_flight(), 1000);
2056 assert_eq!(r.bytes_in_flight_duration(), initial_rtt + reduced_rtt);
2057 assert_eq!(r.min_rtt(), Some(expected_min_rtt));
2058
2059 let expected_srtt = (7 * expected_srtt + expected_min_rtt) / 8;
2060 assert_eq!(r.rtt(), expected_srtt);
2061
2062 let mut acked = RangeSet::default();
2063 acked.insert(12..13);
2064
2065 assert_eq!(
2066 r.on_ack_received(
2067 &acked,
2068 0,
2069 packet::Epoch::Application,
2070 HandshakeStatus::default(),
2071 now,
2072 None,
2073 "",
2074 )
2075 .unwrap(),
2076 OnAckReceivedOutcome {
2077 lost_packets: 0,
2078 lost_bytes: 0,
2079 acked_bytes: 1000,
2080 spurious_losses: 0,
2081 }
2082 );
2083
2084 let expected_min_rtt = if pacing_enabled &&
2087 !time_sent_set_to_now &&
2088 cfg!(feature = "internal")
2089 {
2090 Duration::from_millis(0)
2091 } else {
2092 reduced_rtt
2093 };
2094 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2095 assert_eq!(r.bytes_in_flight(), 0);
2096 assert_eq!(r.bytes_in_flight_duration(), initial_rtt + reduced_rtt);
2097 assert_eq!(r.min_rtt(), Some(expected_min_rtt));
2098
2099 let expected_srtt = (7 * expected_srtt + expected_min_rtt) / 8;
2100 assert_eq!(r.rtt(), expected_srtt);
2101 }
2102
2103 #[rstest]
2104 #[case::bw_estimate_equal_after_first_rtt(1.0, 1.0)]
2107 #[case::bw_estimate_decrease_after_first_rtt(2.0, 1.0)]
2110 #[case::bw_estimate_increase_after_first_rtt(0.5, 0.5)]
2116 #[cfg(feature = "internal")]
2117 fn initial_pacing_rate_override(
2118 #[case] initial_multipler: f64, #[case] expected_multiplier: f64,
2119 ) {
2120 let rtt = Duration::from_millis(50);
2121 let bw = Bandwidth::from_bytes_and_time_delta(12000, rtt);
2122 let initial_pacing_rate_hint = bw * initial_multipler;
2123 let expected_pacing_with_rtt_measurement = bw * expected_multiplier;
2124
2125 let cc_algorithm_name = "bbr2_gcongestion";
2126 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2127 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2128 cfg.set_custom_bbr_params(BbrParams {
2129 initial_pacing_rate_bytes_per_second: Some(
2130 initial_pacing_rate_hint.to_bytes_per_second(),
2131 ),
2132 ..Default::default()
2133 });
2134
2135 let mut r = Recovery::new(&cfg);
2136
2137 let mut now = Instant::now();
2138
2139 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2140
2141 for i in 0..2 {
2143 let p = test_utils::helper_packet_sent(i, now, 1200);
2144 r.on_packet_sent(
2145 p,
2146 packet::Epoch::Application,
2147 HandshakeStatus::default(),
2148 now,
2149 "",
2150 );
2151 }
2152
2153 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2154 assert_eq!(r.bytes_in_flight(), 2400);
2155 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2156
2157 assert_eq!(
2159 r.pacing_rate(),
2160 initial_pacing_rate_hint.to_bytes_per_second()
2161 );
2162 assert_eq!(r.get_packet_send_time(now), now);
2163
2164 assert_eq!(r.cwnd(), 12000);
2165 assert_eq!(r.cwnd_available(), 9600);
2166
2167 now += rtt;
2169
2170 let mut acked = RangeSet::default();
2171 acked.insert(0..2);
2172
2173 assert_eq!(
2174 r.on_ack_received(
2175 &acked,
2176 10,
2177 packet::Epoch::Application,
2178 HandshakeStatus::default(),
2179 now,
2180 None,
2181 "",
2182 )
2183 .unwrap(),
2184 OnAckReceivedOutcome {
2185 lost_packets: 0,
2186 lost_bytes: 0,
2187 acked_bytes: 2400,
2188 spurious_losses: 0,
2189 }
2190 );
2191
2192 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2193 assert_eq!(r.bytes_in_flight(), 0);
2194 assert_eq!(r.bytes_in_flight_duration(), rtt);
2195 assert_eq!(r.rtt(), rtt);
2196
2197 assert_eq!(
2200 r.pacing_rate(),
2201 expected_pacing_with_rtt_measurement.to_bytes_per_second()
2202 );
2203 }
2204
2205 #[rstest]
2206 fn validate_ack_range_on_ack_received(
2207 #[values("cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
2208 ) {
2209 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2210 cfg.set_cc_algorithm_name(cc_algorithm_name).unwrap();
2211
2212 let epoch = packet::Epoch::Application;
2213 let mut r = Recovery::new(&cfg);
2214 let mut now = Instant::now();
2215 assert_eq!(r.sent_packets_len(epoch), 0);
2216
2217 let pkt_size = 1000;
2219 let pkt_count = 4;
2220 for pkt_num in 0..pkt_count {
2221 let sent = test_utils::helper_packet_sent(pkt_num, now, pkt_size);
2222 r.on_packet_sent(sent, epoch, HandshakeStatus::default(), now, "");
2223 }
2224 assert_eq!(r.sent_packets_len(epoch), pkt_count as usize);
2225 assert_eq!(r.bytes_in_flight(), pkt_count as usize * pkt_size);
2226 assert!(r.get_largest_acked_on_epoch(epoch).is_none());
2227 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2228
2229 now += Duration::from_millis(10);
2231
2232 let mut acked = RangeSet::default();
2234 acked.insert(0..2);
2235
2236 assert_eq!(
2237 r.on_ack_received(
2238 &acked,
2239 25,
2240 epoch,
2241 HandshakeStatus::default(),
2242 now,
2243 None,
2244 "",
2245 )
2246 .unwrap(),
2247 OnAckReceivedOutcome {
2248 lost_packets: 0,
2249 lost_bytes: 0,
2250 acked_bytes: 2 * 1000,
2251 spurious_losses: 0,
2252 }
2253 );
2254
2255 assert_eq!(r.sent_packets_len(epoch), 2);
2256 assert_eq!(r.bytes_in_flight(), 2 * 1000);
2257
2258 assert_eq!(r.get_largest_acked_on_epoch(epoch).unwrap(), 1);
2259 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2260
2261 let mut acked = RangeSet::default();
2263 acked.insert(0..10);
2264 assert_eq!(
2265 r.on_ack_received(
2266 &acked,
2267 25,
2268 epoch,
2269 HandshakeStatus::default(),
2270 now,
2271 None,
2272 "",
2273 )
2274 .unwrap(),
2275 OnAckReceivedOutcome {
2276 lost_packets: 0,
2277 lost_bytes: 0,
2278 acked_bytes: 2 * 1000,
2279 spurious_losses: 0,
2280 }
2281 );
2282 assert_eq!(r.sent_packets_len(epoch), 0);
2283 assert_eq!(r.bytes_in_flight(), 0);
2284
2285 assert_eq!(r.get_largest_acked_on_epoch(epoch).unwrap(), 3);
2286 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2287 }
2288
2289 #[rstest]
2290 fn pmtud_loss_on_timer(
2291 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
2292 ) {
2293 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2294 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2295
2296 let mut r = Recovery::new(&cfg);
2297 assert_eq!(r.cwnd(), 12000);
2298
2299 let mut now = Instant::now();
2300
2301 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2302
2303 let p = Sent {
2305 pkt_num: 0,
2306 frames: smallvec![],
2307 time_sent: now,
2308 time_acked: None,
2309 time_lost: None,
2310 size: 1000,
2311 ack_eliciting: true,
2312 in_flight: true,
2313 delivered: 0,
2314 delivered_time: now,
2315 first_sent_time: now,
2316 is_app_limited: false,
2317 tx_in_flight: 0,
2318 lost: 0,
2319 has_data: false,
2320 is_pmtud_probe: false,
2321 };
2322
2323 r.on_packet_sent(
2324 p,
2325 packet::Epoch::Application,
2326 HandshakeStatus::default(),
2327 now,
2328 "",
2329 );
2330
2331 assert_eq!(r.in_flight_count(packet::Epoch::Application), 1);
2332 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
2333 assert_eq!(r.bytes_in_flight(), 1000);
2334 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2335
2336 let p = Sent {
2337 pkt_num: 1,
2338 frames: smallvec![],
2339 time_sent: now,
2340 time_acked: None,
2341 time_lost: None,
2342 size: 1000,
2343 ack_eliciting: true,
2344 in_flight: true,
2345 delivered: 0,
2346 delivered_time: now,
2347 first_sent_time: now,
2348 is_app_limited: false,
2349 tx_in_flight: 0,
2350 lost: 0,
2351 has_data: false,
2352 is_pmtud_probe: true,
2353 };
2354
2355 r.on_packet_sent(
2356 p,
2357 packet::Epoch::Application,
2358 HandshakeStatus::default(),
2359 now,
2360 "",
2361 );
2362
2363 assert_eq!(r.in_flight_count(packet::Epoch::Application), 2);
2364
2365 let p = Sent {
2366 pkt_num: 2,
2367 frames: smallvec![],
2368 time_sent: now,
2369 time_acked: None,
2370 time_lost: None,
2371 size: 1000,
2372 ack_eliciting: true,
2373 in_flight: true,
2374 delivered: 0,
2375 delivered_time: now,
2376 first_sent_time: now,
2377 is_app_limited: false,
2378 tx_in_flight: 0,
2379 lost: 0,
2380 has_data: false,
2381 is_pmtud_probe: false,
2382 };
2383
2384 r.on_packet_sent(
2385 p,
2386 packet::Epoch::Application,
2387 HandshakeStatus::default(),
2388 now,
2389 "",
2390 );
2391
2392 assert_eq!(r.in_flight_count(packet::Epoch::Application), 3);
2393
2394 now += Duration::from_millis(10);
2396
2397 let mut acked = RangeSet::default();
2399 acked.insert(0..1);
2400 acked.insert(2..3);
2401
2402 assert_eq!(
2403 r.on_ack_received(
2404 &acked,
2405 25,
2406 packet::Epoch::Application,
2407 HandshakeStatus::default(),
2408 now,
2409 None,
2410 "",
2411 )
2412 .unwrap(),
2413 OnAckReceivedOutcome {
2414 lost_packets: 0,
2415 lost_bytes: 0,
2416 acked_bytes: 2 * 1000,
2417 spurious_losses: 0,
2418 }
2419 );
2420
2421 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2422 assert_eq!(r.bytes_in_flight(), 1000);
2423 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
2424 assert_eq!(r.lost_count(), 0);
2425
2426 now = r.loss_detection_timer().unwrap();
2428
2429 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
2431 assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
2432
2433 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2434 assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
2435 assert_eq!(r.bytes_in_flight(), 0);
2436 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
2437 assert_eq!(r.cwnd(), 12000);
2438
2439 assert_eq!(r.lost_count(), 0);
2440
2441 now += r.rtt();
2443
2444 assert_eq!(
2445 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
2446 (0, 0)
2447 );
2448
2449 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2450 assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
2451 assert_eq!(r.bytes_in_flight(), 0);
2452 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
2453 assert_eq!(r.lost_count(), 0);
2454 assert_eq!(r.startup_exit(), None);
2455 }
2456
2457 #[rstest]
2460 fn congestion_delivery_rate(
2461 #[values("reno", "cubic", "bbr2")] cc_algorithm_name: &str,
2462 ) {
2463 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2464 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2465
2466 let mut r = Recovery::new(&cfg);
2467 assert_eq!(r.cwnd(), 12000);
2468
2469 let now = Instant::now();
2470
2471 let mut total_bytes_sent = 0;
2472 for pn in 0..10 {
2473 let bytes = 1000;
2475 let sent = test_utils::helper_packet_sent(pn, now, bytes);
2476 r.on_packet_sent(
2477 sent,
2478 packet::Epoch::Application,
2479 HandshakeStatus::default(),
2480 now,
2481 "",
2482 );
2483
2484 total_bytes_sent += bytes;
2485 }
2486
2487 let interval = Duration::from_secs(10);
2489 let mut acked = RangeSet::default();
2490 acked.insert(0..10);
2491 assert_eq!(
2492 r.on_ack_received(
2493 &acked,
2494 25,
2495 packet::Epoch::Application,
2496 HandshakeStatus::default(),
2497 now + interval,
2498 None,
2499 "",
2500 )
2501 .unwrap(),
2502 OnAckReceivedOutcome {
2503 lost_packets: 0,
2504 lost_bytes: 0,
2505 acked_bytes: total_bytes_sent,
2506 spurious_losses: 0,
2507 }
2508 );
2509 assert_eq!(r.delivery_rate().to_bytes_per_second(), 1000);
2510 assert_eq!(r.min_rtt().unwrap(), interval);
2511 assert_eq!(
2513 total_bytes_sent as u64 / interval.as_secs(),
2514 r.delivery_rate().to_bytes_per_second()
2515 );
2516 assert_eq!(r.startup_exit(), None);
2517 }
2518
2519 #[rstest]
2520 fn acks_with_no_retransmittable_data(
2521 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
2522 ) {
2523 let rtt = Duration::from_millis(100);
2524
2525 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2526 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2527
2528 let mut r = Recovery::new(&cfg);
2529
2530 let mut now = Instant::now();
2531
2532 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2533
2534 let mut next_packet = 0;
2535 for _ in 0..3 {
2537 let p = test_utils::helper_packet_sent(next_packet, now, 1200);
2538 next_packet += 1;
2539 r.on_packet_sent(
2540 p,
2541 packet::Epoch::Application,
2542 HandshakeStatus::default(),
2543 now,
2544 "",
2545 );
2546 }
2547
2548 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
2549 assert_eq!(r.bytes_in_flight(), 3600);
2550 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2551
2552 assert_eq!(
2553 r.pacing_rate(),
2554 if cc_algorithm_name == "bbr2_gcongestion" {
2555 103963
2556 } else {
2557 0
2558 },
2559 );
2560 assert_eq!(r.get_packet_send_time(now), now);
2561 assert_eq!(r.cwnd(), 12000);
2562 assert_eq!(r.cwnd_available(), 8400);
2563
2564 now += rtt;
2566
2567 let mut acked = RangeSet::default();
2568 acked.insert(0..3);
2569
2570 assert_eq!(
2571 r.on_ack_received(
2572 &acked,
2573 10,
2574 packet::Epoch::Application,
2575 HandshakeStatus::default(),
2576 now,
2577 None,
2578 "",
2579 )
2580 .unwrap(),
2581 OnAckReceivedOutcome {
2582 lost_packets: 0,
2583 lost_bytes: 0,
2584 acked_bytes: 3600,
2585 spurious_losses: 0,
2586 }
2587 );
2588
2589 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2590 assert_eq!(r.bytes_in_flight(), 0);
2591 assert_eq!(r.bytes_in_flight_duration(), rtt);
2592 assert_eq!(r.rtt(), rtt);
2593
2594 assert_eq!(
2597 r.pacing_rate(),
2598 if cc_algorithm_name == "bbr2_gcongestion" {
2599 120000
2600 } else {
2601 0
2602 },
2603 );
2604
2605 for iter in 3..1000 {
2607 let mut p = test_utils::helper_packet_sent(next_packet, now, 1200);
2608 p.in_flight = false;
2611 next_packet += 1;
2612 r.on_packet_sent(
2613 p,
2614 packet::Epoch::Application,
2615 HandshakeStatus::default(),
2616 now,
2617 "",
2618 );
2619
2620 now += rtt;
2621
2622 let mut acked = RangeSet::default();
2623 acked.insert(iter..(iter + 1));
2624
2625 assert_eq!(
2626 r.on_ack_received(
2627 &acked,
2628 10,
2629 packet::Epoch::Application,
2630 HandshakeStatus::default(),
2631 now,
2632 None,
2633 "",
2634 )
2635 .unwrap(),
2636 OnAckReceivedOutcome {
2637 lost_packets: 0,
2638 lost_bytes: 0,
2639 acked_bytes: 0,
2640 spurious_losses: 0,
2641 }
2642 );
2643
2644 assert_eq!(r.startup_exit(), None, "{iter}");
2646
2647 assert_eq!(
2649 r.sent_packets_len(packet::Epoch::Application),
2650 0,
2651 "{iter}"
2652 );
2653 assert_eq!(r.bytes_in_flight(), 0, "{iter}");
2654 assert_eq!(r.bytes_in_flight_duration(), rtt, "{iter}");
2655 assert_eq!(
2656 r.pacing_rate(),
2657 if cc_algorithm_name == "bbr2_gcongestion" ||
2658 cc_algorithm_name == "bbr2"
2659 {
2660 120000
2661 } else {
2662 0
2663 },
2664 "{iter}"
2665 );
2666 }
2667 }
2668}
2669
2670mod bandwidth;
2671mod bytes_in_flight;
2672mod congestion;
2673mod gcongestion;
2674mod rtt;