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#[cfg(feature = "qlog")]
41use serde::Serialize;
42
43use smallvec::SmallVec;
44
45use self::congestion::recovery::LegacyRecovery;
46use self::gcongestion::GRecovery;
47pub use gcongestion::BbrBwLoReductionStrategy;
48pub use gcongestion::BbrParams;
49
50const INITIAL_PACKET_THRESHOLD: u64 = 3;
52
53const MAX_PACKET_THRESHOLD: u64 = 20;
54
55const INITIAL_TIME_THRESHOLD: f64 = 9.0 / 8.0;
59
60const PACKET_REORDER_TIME_THRESHOLD: f64 = 5.0 / 4.0;
72
73const INITIAL_TIME_THRESHOLD_OVERHEAD: f64 = 1.0 / 8.0;
80const TIME_THRESHOLD_OVERHEAD_MULTIPLIER: f64 = 2.0;
84
85const GRANULARITY: Duration = Duration::from_millis(1);
86
87const MAX_PTO_PROBES_COUNT: usize = 2;
88
89const MINIMUM_WINDOW_PACKETS: usize = 2;
90
91const LOSS_REDUCTION_FACTOR: f64 = 0.5;
92
93pub(super) const MAX_OUTSTANDING_NON_ACK_ELICITING: usize = 24;
96
97const MAX_PTO_EXPONENT: u32 = 5;
101
102#[derive(Default)]
103struct LossDetectionTimer {
104 time: Option<Instant>,
105}
106
107impl LossDetectionTimer {
108 fn update(&mut self, timeout: Instant) {
109 self.time = Some(timeout);
110 }
111
112 fn clear(&mut self) {
113 self.time = None;
114 }
115}
116
117impl std::fmt::Debug for LossDetectionTimer {
118 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
119 match self.time {
120 Some(v) => {
121 let now = Instant::now();
122 if v > now {
123 let d = v.duration_since(now);
124 write!(f, "{d:?}")
125 } else {
126 write!(f, "exp")
127 }
128 },
129 None => write!(f, "none"),
130 }
131 }
132}
133
134#[derive(Clone, Copy, PartialEq)]
135pub struct RecoveryConfig {
136 pub initial_rtt: Duration,
137 pub max_send_udp_payload_size: usize,
138 pub max_ack_delay: Duration,
139 pub cc_algorithm: CongestionControlAlgorithm,
140 pub custom_bbr_params: Option<BbrParams>,
141 pub hystart: bool,
142 pub pacing: bool,
143 pub max_pacing_rate: Option<u64>,
144 pub initial_congestion_window_packets: usize,
145 pub enable_relaxed_loss_threshold: bool,
146 pub enable_cubic_idle_restart_fix: bool,
147}
148
149impl RecoveryConfig {
150 pub fn from_config(config: &Config) -> Self {
151 Self {
152 initial_rtt: config.initial_rtt,
153 max_send_udp_payload_size: config.max_send_udp_payload_size,
154 max_ack_delay: Duration::ZERO,
155 cc_algorithm: config.cc_algorithm,
156 custom_bbr_params: config.custom_bbr_params,
157 hystart: config.hystart,
158 pacing: config.pacing,
159 max_pacing_rate: config.max_pacing_rate,
160 initial_congestion_window_packets: config
161 .initial_congestion_window_packets,
162 enable_relaxed_loss_threshold: config.enable_relaxed_loss_threshold,
163 enable_cubic_idle_restart_fix: config.enable_cubic_idle_restart_fix,
164 }
165 }
166}
167
168#[enum_dispatch::enum_dispatch(RecoveryOps)]
169#[allow(clippy::large_enum_variant)]
170#[derive(Debug)]
171pub(crate) enum Recovery {
172 Legacy(LegacyRecovery),
173 GCongestion(GRecovery),
174}
175
176#[derive(Debug, Default, PartialEq)]
177pub struct OnAckReceivedOutcome {
178 pub lost_packets: usize,
179 pub lost_bytes: usize,
180 pub acked_bytes: usize,
181 pub spurious_losses: usize,
182}
183
184#[derive(Debug, Default)]
185pub struct OnLossDetectionTimeoutOutcome {
186 pub lost_packets: usize,
187 pub lost_bytes: usize,
188}
189
190#[enum_dispatch::enum_dispatch]
191pub trait RecoveryOps {
193 fn lost_count(&self) -> usize;
194 fn bytes_lost(&self) -> u64;
195
196 fn should_elicit_ack(&self, epoch: packet::Epoch) -> bool;
199
200 fn next_acked_frame(&mut self, epoch: packet::Epoch) -> Option<frame::Frame>;
201
202 fn next_lost_frame(&mut self, epoch: packet::Epoch) -> Option<frame::Frame>;
203
204 fn get_largest_acked_on_epoch(&self, epoch: packet::Epoch) -> Option<u64>;
205 fn has_lost_frames(&self, epoch: packet::Epoch) -> bool;
206 fn loss_probes(&self, epoch: packet::Epoch) -> usize;
207 #[cfg(test)]
208 fn inc_loss_probes(&mut self, epoch: packet::Epoch);
209
210 fn ping_sent(&mut self, epoch: packet::Epoch);
211
212 fn on_packet_sent(
213 &mut self, pkt: Sent, epoch: packet::Epoch,
214 handshake_status: HandshakeStatus, now: Instant, trace_id: &str,
215 );
216 fn get_packet_send_time(&self, now: Instant) -> Instant;
217
218 #[allow(clippy::too_many_arguments)]
219 fn on_ack_received(
220 &mut self, ranges: &RangeSet, ack_delay: u64, epoch: packet::Epoch,
221 handshake_status: HandshakeStatus, now: Instant, skip_pn: Option<u64>,
222 trace_id: &str,
223 ) -> Result<OnAckReceivedOutcome>;
224
225 fn on_loss_detection_timeout(
226 &mut self, handshake_status: HandshakeStatus, now: Instant,
227 trace_id: &str,
228 ) -> OnLossDetectionTimeoutOutcome;
229 fn on_pkt_num_space_discarded(
230 &mut self, epoch: packet::Epoch, handshake_status: HandshakeStatus,
231 now: Instant,
232 );
233 fn on_path_change(
234 &mut self, epoch: packet::Epoch, now: Instant, _trace_id: &str,
235 ) -> (usize, usize);
236 fn loss_detection_timer(&self) -> Option<Instant>;
237 fn cwnd(&self) -> usize;
238 fn cwnd_available(&self) -> usize;
239 fn rtt(&self) -> Duration;
240
241 fn min_rtt(&self) -> Option<Duration>;
242
243 fn max_rtt(&self) -> Option<Duration>;
244
245 fn rttvar(&self) -> Duration;
246
247 fn pto(&self) -> Duration;
248
249 fn delivery_rate(&self) -> Bandwidth;
251
252 fn max_bandwidth(&self) -> Option<Bandwidth>;
254
255 fn startup_exit(&self) -> Option<StartupExit>;
257
258 fn max_datagram_size(&self) -> usize;
259
260 fn pmtud_update_max_datagram_size(&mut self, new_max_datagram_size: usize);
261
262 fn update_max_datagram_size(&mut self, new_max_datagram_size: usize);
263
264 fn on_app_limited(&mut self);
265
266 #[cfg(test)]
269 fn largest_sent_pkt_num_on_path(&self, epoch: packet::Epoch) -> Option<u64>;
270
271 #[cfg(test)]
272 fn app_limited(&self) -> bool;
273
274 #[cfg(test)]
275 fn sent_packets_len(&self, epoch: packet::Epoch) -> usize;
276
277 fn bytes_in_flight(&self) -> usize;
278
279 fn bytes_in_flight_duration(&self) -> Duration;
280
281 #[cfg(test)]
282 fn in_flight_count(&self, epoch: packet::Epoch) -> usize;
283
284 #[cfg(test)]
285 fn pacing_rate(&self) -> u64;
286
287 #[cfg(test)]
288 fn pto_count(&self) -> u32;
289
290 #[cfg(test)]
293 fn pkt_thresh(&self) -> Option<u64>;
294
295 #[cfg(test)]
296 fn time_thresh(&self) -> f64;
297
298 #[cfg(test)]
299 fn lost_spurious_count(&self) -> usize;
300
301 #[cfg(test)]
302 fn detect_lost_packets_for_test(
303 &mut self, epoch: packet::Epoch, now: Instant,
304 ) -> (usize, usize);
305
306 fn update_app_limited(&mut self, v: bool);
307
308 fn delivery_rate_update_app_limited(&mut self, v: bool);
309
310 fn update_max_ack_delay(&mut self, max_ack_delay: Duration);
311
312 #[cfg(feature = "qlog")]
313 fn state_str(&self, now: Instant) -> &'static str;
314
315 #[cfg(feature = "qlog")]
316 fn get_updated_qlog_event_data(&mut self) -> Option<EventData>;
317
318 #[cfg(feature = "qlog")]
319 fn get_updated_qlog_cc_state(&mut self, now: Instant)
320 -> Option<&'static str>;
321
322 fn send_quantum(&self) -> usize;
323
324 fn get_next_release_time(&self) -> ReleaseDecision;
325
326 fn gcongestion_enabled(&self) -> bool;
327}
328
329impl Recovery {
330 pub fn new_with_config(recovery_config: &RecoveryConfig) -> Self {
331 let grecovery = GRecovery::new(recovery_config);
332 if let Some(grecovery) = grecovery {
333 Recovery::from(grecovery)
334 } else {
335 Recovery::from(LegacyRecovery::new_with_config(recovery_config))
336 }
337 }
338
339 #[cfg(feature = "qlog")]
340 pub fn maybe_qlog(
341 &mut self, qlog: &mut qlog::streamer::QlogStreamer, now: Instant,
342 ) {
343 if let Some(ev_data) = self.get_updated_qlog_event_data() {
344 qlog.add_event_data_with_instant(ev_data, now).ok();
345 }
346
347 if let Some(cc_state) = self.get_updated_qlog_cc_state(now) {
348 let ev_data = EventData::QuicCongestionStateUpdated(
349 qlog::events::quic::CongestionStateUpdated {
350 old: None,
351 new: cc_state.to_string(),
352 trigger: None,
353 },
354 );
355
356 qlog.add_event_data_with_instant(ev_data, now).ok();
357 }
358 }
359
360 #[cfg(test)]
361 pub fn new(config: &Config) -> Self {
362 Self::new_with_config(&RecoveryConfig::from_config(config))
363 }
364}
365
366#[derive(Debug, Copy, Clone, PartialEq, Eq)]
371#[repr(C)]
372pub enum CongestionControlAlgorithm {
373 Reno = 0,
375 CUBIC = 1,
377 Bbr2Gcongestion = 4,
380}
381
382impl FromStr for CongestionControlAlgorithm {
383 type Err = crate::Error;
384
385 fn from_str(name: &str) -> std::result::Result<Self, Self::Err> {
389 match name {
390 "reno" => Ok(CongestionControlAlgorithm::Reno),
391 "cubic" => Ok(CongestionControlAlgorithm::CUBIC),
392 "bbr" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
393 "bbr2" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
394 "bbr2_gcongestion" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
395 _ => Err(crate::Error::CongestionControl),
396 }
397 }
398}
399
400#[derive(Clone)]
401pub struct Sent {
402 pub pkt_num: u64,
403
404 pub frames: SmallVec<[frame::Frame; 1]>,
405
406 pub time_sent: Instant,
407
408 pub time_acked: Option<Instant>,
409
410 pub time_lost: Option<Instant>,
411
412 pub size: usize,
413
414 pub ack_eliciting: bool,
415
416 pub in_flight: bool,
417
418 pub delivered: usize,
419
420 pub delivered_time: Instant,
421
422 pub first_sent_time: Instant,
423
424 pub is_app_limited: bool,
425
426 pub tx_in_flight: usize,
427
428 pub lost: u64,
429
430 pub has_data: bool,
431
432 pub is_pmtud_probe: bool,
433}
434
435impl std::fmt::Debug for Sent {
436 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
437 write!(f, "pkt_num={:?} ", self.pkt_num)?;
438 write!(f, "pkt_sent_time={:?} ", self.time_sent)?;
439 write!(f, "pkt_size={:?} ", self.size)?;
440 write!(f, "delivered={:?} ", self.delivered)?;
441 write!(f, "delivered_time={:?} ", self.delivered_time)?;
442 write!(f, "first_sent_time={:?} ", self.first_sent_time)?;
443 write!(f, "is_app_limited={} ", self.is_app_limited)?;
444 write!(f, "tx_in_flight={} ", self.tx_in_flight)?;
445 write!(f, "lost={} ", self.lost)?;
446 write!(f, "has_data={} ", self.has_data)?;
447 write!(f, "is_pmtud_probe={}", self.is_pmtud_probe)?;
448
449 Ok(())
450 }
451}
452
453#[derive(Clone, Copy, Debug)]
454pub struct HandshakeStatus {
455 pub has_handshake_keys: bool,
456
457 pub peer_verified_address: bool,
458
459 pub completed: bool,
460}
461
462#[cfg(test)]
463impl Default for HandshakeStatus {
464 fn default() -> HandshakeStatus {
465 HandshakeStatus {
466 has_handshake_keys: true,
467
468 peer_verified_address: true,
469
470 completed: true,
471 }
472 }
473}
474
475#[derive(Default)]
480#[cfg(feature = "qlog")]
481struct QlogMetrics {
482 min_rtt: Duration,
483 smoothed_rtt: Duration,
484 latest_rtt: Duration,
485 rttvar: Duration,
486 cwnd: u64,
487 bytes_in_flight: u64,
488 ssthresh: Option<u64>,
489 pacing_rate: Option<u64>,
490 delivery_rate: Option<u64>,
491 send_rate: Option<u64>,
492 ack_rate: Option<u64>,
493 lost_packets: Option<u64>,
494 lost_bytes: Option<u64>,
495 pto_count: Option<u32>,
496}
497
498#[cfg(feature = "qlog")]
499trait CustomCfQlogField {
500 fn name(&self) -> &'static str;
501 fn as_json_value(&self) -> serde_json::Value;
502}
503
504#[cfg(feature = "qlog")]
505#[serde_with::skip_serializing_none]
506#[derive(Serialize)]
507struct TotalAndDelta {
508 total: Option<u64>,
509 delta: Option<u64>,
510}
511
512#[cfg(feature = "qlog")]
513struct CustomQlogField<T> {
514 name: &'static str,
515 value: T,
516}
517
518#[cfg(feature = "qlog")]
519impl<T> CustomQlogField<T> {
520 fn new(name: &'static str, value: T) -> Self {
521 Self { name, value }
522 }
523}
524
525#[cfg(feature = "qlog")]
526impl<T: Serialize> CustomCfQlogField for CustomQlogField<T> {
527 fn name(&self) -> &'static str {
528 self.name
529 }
530
531 fn as_json_value(&self) -> serde_json::Value {
532 serde_json::json!(&self.value)
533 }
534}
535
536#[cfg(feature = "qlog")]
537struct CfExData(qlog::events::ExData);
538
539#[cfg(feature = "qlog")]
540impl CfExData {
541 fn new() -> Self {
542 Self(qlog::events::ExData::new())
543 }
544
545 fn insert<T: Serialize>(&mut self, name: &'static str, value: T) {
546 let field = CustomQlogField::new(name, value);
547 self.0
548 .insert(field.name().to_string(), field.as_json_value());
549 }
550
551 fn into_inner(self) -> qlog::events::ExData {
552 self.0
553 }
554}
555
556#[cfg(feature = "qlog")]
557impl QlogMetrics {
558 fn maybe_update(&mut self, latest: Self) -> Option<EventData> {
564 let mut emit_event = false;
565
566 let new_min_rtt = if self.min_rtt != latest.min_rtt {
567 self.min_rtt = latest.min_rtt;
568 emit_event = true;
569 Some(latest.min_rtt.as_secs_f32() * 1000.0)
570 } else {
571 None
572 };
573
574 let new_smoothed_rtt = if self.smoothed_rtt != latest.smoothed_rtt {
575 self.smoothed_rtt = latest.smoothed_rtt;
576 emit_event = true;
577 Some(latest.smoothed_rtt.as_secs_f32() * 1000.0)
578 } else {
579 None
580 };
581
582 let new_latest_rtt = if self.latest_rtt != latest.latest_rtt {
583 self.latest_rtt = latest.latest_rtt;
584 emit_event = true;
585 Some(latest.latest_rtt.as_secs_f32() * 1000.0)
586 } else {
587 None
588 };
589
590 let new_rttvar = if self.rttvar != latest.rttvar {
591 self.rttvar = latest.rttvar;
592 emit_event = true;
593 Some(latest.rttvar.as_secs_f32() * 1000.0)
594 } else {
595 None
596 };
597
598 let new_cwnd = if self.cwnd != latest.cwnd {
599 self.cwnd = latest.cwnd;
600 emit_event = true;
601 Some(latest.cwnd)
602 } else {
603 None
604 };
605
606 let new_bytes_in_flight =
607 if self.bytes_in_flight != latest.bytes_in_flight {
608 self.bytes_in_flight = latest.bytes_in_flight;
609 emit_event = true;
610 Some(latest.bytes_in_flight)
611 } else {
612 None
613 };
614
615 let new_ssthresh = if self.ssthresh != latest.ssthresh {
616 self.ssthresh = latest.ssthresh;
617 emit_event = true;
618 latest.ssthresh
619 } else {
620 None
621 };
622
623 let new_pacing_rate = if self.pacing_rate != latest.pacing_rate {
624 self.pacing_rate = latest.pacing_rate;
625 emit_event = true;
626 latest.pacing_rate
627 } else {
628 None
629 };
630
631 let new_pto_count =
632 if latest.pto_count.is_some() && self.pto_count != latest.pto_count {
633 self.pto_count = latest.pto_count;
634 emit_event = true;
635 latest.pto_count.map(|v| v as u16)
636 } else {
637 None
638 };
639
640 let mut ex_data = CfExData::new();
642 if self.delivery_rate != latest.delivery_rate {
643 if let Some(rate) = latest.delivery_rate {
644 self.delivery_rate = latest.delivery_rate;
645 emit_event = true;
646 ex_data.insert("cf_delivery_rate", rate);
647 }
648 }
649 if self.send_rate != latest.send_rate {
650 if let Some(rate) = latest.send_rate {
651 self.send_rate = latest.send_rate;
652 emit_event = true;
653 ex_data.insert("cf_send_rate", rate);
654 }
655 }
656 if self.ack_rate != latest.ack_rate {
657 if let Some(rate) = latest.ack_rate {
658 self.ack_rate = latest.ack_rate;
659 emit_event = true;
660 ex_data.insert("cf_ack_rate", rate);
661 }
662 }
663
664 if self.lost_packets != latest.lost_packets {
665 if let Some(val) = latest.lost_packets {
666 emit_event = true;
667 ex_data.insert("cf_lost_packets", TotalAndDelta {
668 total: latest.lost_packets,
669 delta: Some(val - self.lost_packets.unwrap_or(0)),
670 });
671 self.lost_packets = latest.lost_packets;
672 }
673 }
674 if self.lost_bytes != latest.lost_bytes {
675 if let Some(val) = latest.lost_bytes {
676 emit_event = true;
677 ex_data.insert("cf_lost_bytes", TotalAndDelta {
678 total: latest.lost_bytes,
679 delta: Some(val - self.lost_bytes.unwrap_or(0)),
680 });
681 self.lost_bytes = latest.lost_bytes;
682 }
683 }
684
685 if emit_event {
686 return Some(EventData::QuicMetricsUpdated(
687 qlog::events::quic::RecoveryMetricsUpdated {
688 min_rtt: new_min_rtt,
689 smoothed_rtt: new_smoothed_rtt,
690 latest_rtt: new_latest_rtt,
691 rtt_variance: new_rttvar,
692 congestion_window: new_cwnd,
693 bytes_in_flight: new_bytes_in_flight,
694 ssthresh: new_ssthresh,
695 pacing_rate: new_pacing_rate,
696 pto_count: new_pto_count,
697 ex_data: ex_data.into_inner(),
698 ..Default::default()
699 },
700 ));
701 }
702
703 None
704 }
705}
706
707#[derive(Debug, Clone, Copy, PartialEq, Eq)]
709pub enum ReleaseTime {
710 Immediate,
711 At(Instant),
712}
713
714#[derive(Clone, Copy, Debug, PartialEq, Eq)]
716pub struct ReleaseDecision {
717 time: ReleaseTime,
718 allow_burst: bool,
719}
720
721impl ReleaseTime {
722 fn inc(&mut self, delay: Duration) {
724 match self {
725 ReleaseTime::Immediate => {},
726 ReleaseTime::At(time) => *time += delay,
727 }
728 }
729
730 fn set_max(&mut self, other: Instant) {
732 match self {
733 ReleaseTime::Immediate => *self = ReleaseTime::At(other),
734 ReleaseTime::At(time) => *self = ReleaseTime::At(other.max(*time)),
735 }
736 }
737}
738
739impl ReleaseDecision {
740 pub(crate) const EQUAL_THRESHOLD: Duration = Duration::from_micros(50);
741
742 #[inline]
745 pub fn time(&self, now: Instant) -> Option<Instant> {
746 match self.time {
747 ReleaseTime::Immediate => None,
748 ReleaseTime::At(other) => other.gt(&now).then_some(other),
749 }
750 }
751
752 #[inline]
754 pub fn can_burst(&self) -> bool {
755 self.allow_burst
756 }
757
758 #[inline]
760 pub fn time_eq(&self, other: &Self, now: Instant) -> bool {
761 let delta = match (self.time(now), other.time(now)) {
762 (None, None) => Duration::ZERO,
763 (Some(t), None) | (None, Some(t)) => t.duration_since(now),
764 (Some(t1), Some(t2)) if t1 < t2 => t2.duration_since(t1),
765 (Some(t1), Some(t2)) => t1.duration_since(t2),
766 };
767
768 delta <= Self::EQUAL_THRESHOLD
769 }
770}
771
772#[derive(Default, Debug)]
774pub struct RecoveryStats {
775 startup_exit: Option<StartupExit>,
776}
777
778impl RecoveryStats {
779 pub fn set_startup_exit(&mut self, startup_exit: StartupExit) {
781 if self.startup_exit.is_none() {
782 self.startup_exit = Some(startup_exit);
783 }
784 }
785}
786
787#[derive(Debug, Clone, Copy, PartialEq)]
789pub struct StartupExit {
790 pub cwnd: usize,
792
793 pub bandwidth: Option<u64>,
795
796 pub reason: StartupExitReason,
798}
799
800impl StartupExit {
801 fn new(
802 cwnd: usize, bandwidth: Option<Bandwidth>, reason: StartupExitReason,
803 ) -> Self {
804 let bandwidth = bandwidth.map(Bandwidth::to_bytes_per_second);
805 Self {
806 cwnd,
807 bandwidth,
808 reason,
809 }
810 }
811}
812
813#[derive(Debug, Clone, Copy, PartialEq)]
815pub enum StartupExitReason {
816 Loss,
818
819 BandwidthPlateau,
821
822 PersistentQueue,
824
825 ConservativeSlowStartRounds,
827}
828
829#[cfg(test)]
830mod tests {
831 use super::*;
832 use crate::packet;
833 use crate::test_utils;
834 use crate::CongestionControlAlgorithm;
835 use crate::DEFAULT_INITIAL_RTT;
836 use rstest::rstest;
837 use smallvec::smallvec;
838 use std::str::FromStr;
839
840 fn recovery_for_alg(algo: CongestionControlAlgorithm) -> Recovery {
841 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
842 cfg.set_cc_algorithm(algo);
843 Recovery::new(&cfg)
844 }
845
846 #[test]
847 fn lookup_cc_algo_ok() {
848 let algo = CongestionControlAlgorithm::from_str("reno").unwrap();
849 assert_eq!(algo, CongestionControlAlgorithm::Reno);
850 assert!(!recovery_for_alg(algo).gcongestion_enabled());
851
852 let algo = CongestionControlAlgorithm::from_str("cubic").unwrap();
853 assert_eq!(algo, CongestionControlAlgorithm::CUBIC);
854 assert!(!recovery_for_alg(algo).gcongestion_enabled());
855
856 let algo = CongestionControlAlgorithm::from_str("bbr").unwrap();
857 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
858 assert!(recovery_for_alg(algo).gcongestion_enabled());
859
860 let algo = CongestionControlAlgorithm::from_str("bbr2").unwrap();
861 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
862 assert!(recovery_for_alg(algo).gcongestion_enabled());
863
864 let algo =
865 CongestionControlAlgorithm::from_str("bbr2_gcongestion").unwrap();
866 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
867 assert!(recovery_for_alg(algo).gcongestion_enabled());
868 }
869
870 #[test]
871 fn lookup_cc_algo_bad() {
872 assert_eq!(
873 CongestionControlAlgorithm::from_str("???"),
874 Err(crate::Error::CongestionControl)
875 );
876 }
877
878 #[rstest]
879 fn loss_on_pto(
880 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
881 ) {
882 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
883 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
884
885 let mut r = Recovery::new(&cfg);
886
887 let mut now = Instant::now();
888
889 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
890
891 let p = Sent {
893 pkt_num: 0,
894 frames: smallvec![],
895 time_sent: now,
896 time_acked: None,
897 time_lost: None,
898 size: 1000,
899 ack_eliciting: true,
900 in_flight: true,
901 delivered: 0,
902 delivered_time: now,
903 first_sent_time: now,
904 is_app_limited: false,
905 tx_in_flight: 0,
906 lost: 0,
907 has_data: false,
908 is_pmtud_probe: false,
909 };
910
911 r.on_packet_sent(
912 p,
913 packet::Epoch::Application,
914 HandshakeStatus::default(),
915 now,
916 "",
917 );
918
919 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
920 assert_eq!(r.bytes_in_flight(), 1000);
921 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
922
923 let p = Sent {
924 pkt_num: 1,
925 frames: smallvec![],
926 time_sent: now,
927 time_acked: None,
928 time_lost: None,
929 size: 1000,
930 ack_eliciting: true,
931 in_flight: true,
932 delivered: 0,
933 delivered_time: now,
934 first_sent_time: now,
935 is_app_limited: false,
936 tx_in_flight: 0,
937 lost: 0,
938 has_data: false,
939 is_pmtud_probe: false,
940 };
941
942 r.on_packet_sent(
943 p,
944 packet::Epoch::Application,
945 HandshakeStatus::default(),
946 now,
947 "",
948 );
949
950 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
951 assert_eq!(r.bytes_in_flight(), 2000);
952 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
953
954 let p = Sent {
955 pkt_num: 2,
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), 3);
981 assert_eq!(r.bytes_in_flight(), 3000);
982 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
983
984 let p = Sent {
985 pkt_num: 3,
986 frames: smallvec![],
987 time_sent: now,
988 time_acked: None,
989 time_lost: None,
990 size: 1000,
991 ack_eliciting: true,
992 in_flight: true,
993 delivered: 0,
994 delivered_time: now,
995 first_sent_time: now,
996 is_app_limited: false,
997 tx_in_flight: 0,
998 lost: 0,
999 has_data: false,
1000 is_pmtud_probe: false,
1001 };
1002
1003 r.on_packet_sent(
1004 p,
1005 packet::Epoch::Application,
1006 HandshakeStatus::default(),
1007 now,
1008 "",
1009 );
1010 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1011 assert_eq!(r.bytes_in_flight(), 4000);
1012 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1013
1014 now += Duration::from_millis(10);
1016
1017 let mut acked = RangeSet::default();
1019 acked.insert(0..2);
1020
1021 assert_eq!(
1022 r.on_ack_received(
1023 &acked,
1024 25,
1025 packet::Epoch::Application,
1026 HandshakeStatus::default(),
1027 now,
1028 None,
1029 "",
1030 )
1031 .unwrap(),
1032 OnAckReceivedOutcome {
1033 lost_packets: 0,
1034 lost_bytes: 0,
1035 acked_bytes: 2 * 1000,
1036 spurious_losses: 0,
1037 }
1038 );
1039
1040 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1041 assert_eq!(r.bytes_in_flight(), 2000);
1042 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
1043 assert_eq!(r.lost_count(), 0);
1044
1045 now = r.loss_detection_timer().unwrap();
1047
1048 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
1050 assert_eq!(r.loss_probes(packet::Epoch::Application), 1);
1051 assert_eq!(r.lost_count(), 0);
1052 assert_eq!(r.pto_count(), 1);
1053
1054 let p = Sent {
1055 pkt_num: 4,
1056 frames: smallvec![],
1057 time_sent: now,
1058 time_acked: None,
1059 time_lost: None,
1060 size: 1000,
1061 ack_eliciting: true,
1062 in_flight: true,
1063 delivered: 0,
1064 delivered_time: now,
1065 first_sent_time: now,
1066 is_app_limited: false,
1067 tx_in_flight: 0,
1068 lost: 0,
1069 has_data: false,
1070 is_pmtud_probe: false,
1071 };
1072
1073 r.on_packet_sent(
1074 p,
1075 packet::Epoch::Application,
1076 HandshakeStatus::default(),
1077 now,
1078 "",
1079 );
1080 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1081 assert_eq!(r.bytes_in_flight(), 3000);
1082 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(30));
1083
1084 let p = Sent {
1085 pkt_num: 5,
1086 frames: smallvec![],
1087 time_sent: now,
1088 time_acked: None,
1089 time_lost: None,
1090 size: 1000,
1091 ack_eliciting: true,
1092 in_flight: true,
1093 delivered: 0,
1094 delivered_time: now,
1095 first_sent_time: now,
1096 is_app_limited: false,
1097 tx_in_flight: 0,
1098 lost: 0,
1099 has_data: false,
1100 is_pmtud_probe: false,
1101 };
1102
1103 r.on_packet_sent(
1104 p,
1105 packet::Epoch::Application,
1106 HandshakeStatus::default(),
1107 now,
1108 "",
1109 );
1110 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1111 assert_eq!(r.bytes_in_flight(), 4000);
1112 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(30));
1113 assert_eq!(r.lost_count(), 0);
1114
1115 now += Duration::from_millis(10);
1117
1118 let mut acked = RangeSet::default();
1120 acked.insert(4..6);
1121
1122 assert_eq!(
1123 r.on_ack_received(
1124 &acked,
1125 25,
1126 packet::Epoch::Application,
1127 HandshakeStatus::default(),
1128 now,
1129 None,
1130 "",
1131 )
1132 .unwrap(),
1133 OnAckReceivedOutcome {
1134 lost_packets: 2,
1135 lost_bytes: 2000,
1136 acked_bytes: 2 * 1000,
1137 spurious_losses: 0,
1138 }
1139 );
1140
1141 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1142 assert_eq!(r.bytes_in_flight(), 0);
1143 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(40));
1144
1145 assert_eq!(r.lost_count(), 2);
1146
1147 now += r.rtt();
1149
1150 assert_eq!(
1151 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1152 (0, 0)
1153 );
1154
1155 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1156 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1157 assert!(r.startup_exit().is_some());
1158 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1159 } else {
1160 assert_eq!(r.startup_exit(), None);
1161 }
1162 }
1163
1164 #[rstest]
1165 fn loss_on_timer(
1166 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
1167 ) {
1168 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1169 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1170
1171 let mut r = Recovery::new(&cfg);
1172
1173 let mut now = Instant::now();
1174
1175 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1176
1177 let p = Sent {
1179 pkt_num: 0,
1180 frames: smallvec![],
1181 time_sent: now,
1182 time_acked: None,
1183 time_lost: None,
1184 size: 1000,
1185 ack_eliciting: true,
1186 in_flight: true,
1187 delivered: 0,
1188 delivered_time: now,
1189 first_sent_time: now,
1190 is_app_limited: false,
1191 tx_in_flight: 0,
1192 lost: 0,
1193 has_data: false,
1194 is_pmtud_probe: false,
1195 };
1196
1197 r.on_packet_sent(
1198 p,
1199 packet::Epoch::Application,
1200 HandshakeStatus::default(),
1201 now,
1202 "",
1203 );
1204 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1205 assert_eq!(r.bytes_in_flight(), 1000);
1206 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1207
1208 let p = Sent {
1209 pkt_num: 1,
1210 frames: smallvec![],
1211 time_sent: now,
1212 time_acked: None,
1213 time_lost: None,
1214 size: 1000,
1215 ack_eliciting: true,
1216 in_flight: true,
1217 delivered: 0,
1218 delivered_time: now,
1219 first_sent_time: now,
1220 is_app_limited: false,
1221 tx_in_flight: 0,
1222 lost: 0,
1223 has_data: false,
1224 is_pmtud_probe: false,
1225 };
1226
1227 r.on_packet_sent(
1228 p,
1229 packet::Epoch::Application,
1230 HandshakeStatus::default(),
1231 now,
1232 "",
1233 );
1234 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1235 assert_eq!(r.bytes_in_flight(), 2000);
1236 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1237
1238 let p = Sent {
1239 pkt_num: 2,
1240 frames: smallvec![],
1241 time_sent: now,
1242 time_acked: None,
1243 time_lost: None,
1244 size: 1000,
1245 ack_eliciting: true,
1246 in_flight: true,
1247 delivered: 0,
1248 delivered_time: now,
1249 first_sent_time: now,
1250 is_app_limited: false,
1251 tx_in_flight: 0,
1252 lost: 0,
1253 has_data: false,
1254 is_pmtud_probe: false,
1255 };
1256
1257 r.on_packet_sent(
1258 p,
1259 packet::Epoch::Application,
1260 HandshakeStatus::default(),
1261 now,
1262 "",
1263 );
1264 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1265 assert_eq!(r.bytes_in_flight(), 3000);
1266 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1267
1268 let p = Sent {
1269 pkt_num: 3,
1270 frames: smallvec![],
1271 time_sent: now,
1272 time_acked: None,
1273 time_lost: None,
1274 size: 1000,
1275 ack_eliciting: true,
1276 in_flight: true,
1277 delivered: 0,
1278 delivered_time: now,
1279 first_sent_time: now,
1280 is_app_limited: false,
1281 tx_in_flight: 0,
1282 lost: 0,
1283 has_data: false,
1284 is_pmtud_probe: false,
1285 };
1286
1287 r.on_packet_sent(
1288 p,
1289 packet::Epoch::Application,
1290 HandshakeStatus::default(),
1291 now,
1292 "",
1293 );
1294 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1295 assert_eq!(r.bytes_in_flight(), 4000);
1296 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1297
1298 now += Duration::from_millis(10);
1300
1301 let mut acked = RangeSet::default();
1303 acked.insert(0..2);
1304 acked.insert(3..4);
1305
1306 assert_eq!(
1307 r.on_ack_received(
1308 &acked,
1309 25,
1310 packet::Epoch::Application,
1311 HandshakeStatus::default(),
1312 now,
1313 None,
1314 "",
1315 )
1316 .unwrap(),
1317 OnAckReceivedOutcome {
1318 lost_packets: 0,
1319 lost_bytes: 0,
1320 acked_bytes: 3 * 1000,
1321 spurious_losses: 0,
1322 }
1323 );
1324
1325 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1326 assert_eq!(r.bytes_in_flight(), 1000);
1327 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
1328 assert_eq!(r.lost_count(), 0);
1329
1330 now = r.loss_detection_timer().unwrap();
1332
1333 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
1335 assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
1336
1337 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1338 assert_eq!(r.bytes_in_flight(), 0);
1339 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
1340
1341 assert_eq!(r.lost_count(), 1);
1342
1343 now += r.rtt();
1345
1346 assert_eq!(
1347 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1348 (0, 0)
1349 );
1350
1351 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1352 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1353 assert!(r.startup_exit().is_some());
1354 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1355 } else {
1356 assert_eq!(r.startup_exit(), None);
1357 }
1358 }
1359
1360 #[rstest]
1361 fn loss_on_reordering(
1362 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
1363 ) {
1364 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1365 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1366
1367 let mut r = Recovery::new(&cfg);
1368
1369 let mut now = Instant::now();
1370
1371 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1372
1373 for i in 0..4 {
1377 let p = test_utils::helper_packet_sent(i, now, 1000);
1378 r.on_packet_sent(
1379 p,
1380 packet::Epoch::Application,
1381 HandshakeStatus::default(),
1382 now,
1383 "",
1384 );
1385
1386 let pkt_count = (i + 1) as usize;
1387 assert_eq!(r.sent_packets_len(packet::Epoch::Application), pkt_count);
1388 assert_eq!(r.bytes_in_flight(), pkt_count * 1000);
1389 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1390 }
1391
1392 now += Duration::from_millis(10);
1394
1395 let mut acked = RangeSet::default();
1397 acked.insert(2..4);
1398 assert_eq!(
1399 r.on_ack_received(
1400 &acked,
1401 25,
1402 packet::Epoch::Application,
1403 HandshakeStatus::default(),
1404 now,
1405 None,
1406 "",
1407 )
1408 .unwrap(),
1409 OnAckReceivedOutcome {
1410 lost_packets: 1,
1411 lost_bytes: 1000,
1412 acked_bytes: 1000 * 2,
1413 spurious_losses: 0,
1414 }
1415 );
1416 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1419 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1420 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1421
1422 now += Duration::from_millis(10);
1424
1425 let mut acked = RangeSet::default();
1427 acked.insert(0..2);
1428 assert_eq!(
1429 r.on_ack_received(
1430 &acked,
1431 25,
1432 packet::Epoch::Application,
1433 HandshakeStatus::default(),
1434 now,
1435 None,
1436 "",
1437 )
1438 .unwrap(),
1439 OnAckReceivedOutcome {
1440 lost_packets: 0,
1441 lost_bytes: 0,
1442 acked_bytes: 1000,
1443 spurious_losses: 1,
1444 }
1445 );
1446 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1447 assert_eq!(r.bytes_in_flight(), 0);
1448 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(20));
1449
1450 assert_eq!(r.lost_count(), 1);
1452 assert_eq!(r.lost_spurious_count(), 1);
1453
1454 assert_eq!(r.pkt_thresh().unwrap(), 4);
1456 assert_eq!(r.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1457
1458 now += r.rtt();
1460
1461 assert_eq!(
1463 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1464 (0, 0)
1465 );
1466 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1467
1468 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1469 assert!(r.startup_exit().is_some());
1470 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1471 } else {
1472 assert_eq!(r.startup_exit(), None);
1473 }
1474 }
1475
1476 #[rstest]
1481 fn time_thresholds_on_reordering(
1482 #[values("bbr2_gcongestion")] cc_algorithm_name: &str,
1483 ) {
1484 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1485 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1486
1487 let mut now = Instant::now();
1488 let mut r = Recovery::new(&cfg);
1489 assert_eq!(r.rtt(), DEFAULT_INITIAL_RTT);
1490
1491 const THRESH_GAP: Duration = Duration::from_millis(30);
1505 let initial_thresh_ms =
1507 DEFAULT_INITIAL_RTT.mul_f64(INITIAL_TIME_THRESHOLD);
1508 let spurious_thresh_ms: Duration =
1510 DEFAULT_INITIAL_RTT.mul_f64(PACKET_REORDER_TIME_THRESHOLD);
1511 let between_thresh_ms = initial_thresh_ms + THRESH_GAP;
1513 assert!(between_thresh_ms > initial_thresh_ms);
1514 assert!(between_thresh_ms < spurious_thresh_ms);
1515 assert!(between_thresh_ms + THRESH_GAP > spurious_thresh_ms);
1516
1517 for i in 0..6 {
1518 let send_time = now + i * between_thresh_ms;
1519
1520 let p = test_utils::helper_packet_sent(i.into(), send_time, 1000);
1521 r.on_packet_sent(
1522 p,
1523 packet::Epoch::Application,
1524 HandshakeStatus::default(),
1525 send_time,
1526 "",
1527 );
1528 }
1529
1530 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 6);
1531 assert_eq!(r.bytes_in_flight(), 6 * 1000);
1532 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1533 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1534
1535 now += between_thresh_ms;
1538
1539 let mut acked = RangeSet::default();
1544 acked.insert(1..2);
1545 assert_eq!(
1546 r.on_ack_received(
1547 &acked,
1548 25,
1549 packet::Epoch::Application,
1550 HandshakeStatus::default(),
1551 now,
1552 None,
1553 "",
1554 )
1555 .unwrap(),
1556 OnAckReceivedOutcome {
1557 lost_packets: 1,
1558 lost_bytes: 1000,
1559 acked_bytes: 1000,
1560 spurious_losses: 0,
1561 }
1562 );
1563 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1564 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1565
1566 let mut acked = RangeSet::default();
1571 acked.insert(0..1);
1572 assert_eq!(
1573 r.on_ack_received(
1574 &acked,
1575 25,
1576 packet::Epoch::Application,
1577 HandshakeStatus::default(),
1578 now,
1579 None,
1580 "",
1581 )
1582 .unwrap(),
1583 OnAckReceivedOutcome {
1584 lost_packets: 0,
1585 lost_bytes: 0,
1586 acked_bytes: 0,
1587 spurious_losses: 1,
1588 }
1589 );
1590 assert_eq!(r.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1592
1593 now += between_thresh_ms;
1596
1597 let mut acked = RangeSet::default();
1602 acked.insert(3..4);
1603 assert_eq!(
1604 r.on_ack_received(
1605 &acked,
1606 25,
1607 packet::Epoch::Application,
1608 HandshakeStatus::default(),
1609 now,
1610 None,
1611 "",
1612 )
1613 .unwrap(),
1614 OnAckReceivedOutcome {
1615 lost_packets: 0,
1616 lost_bytes: 0,
1617 acked_bytes: 1000,
1618 spurious_losses: 0,
1619 }
1620 );
1621
1622 now += THRESH_GAP;
1625
1626 let mut acked = RangeSet::default();
1631 acked.insert(4..5);
1632 assert_eq!(
1633 r.on_ack_received(
1634 &acked,
1635 25,
1636 packet::Epoch::Application,
1637 HandshakeStatus::default(),
1638 now,
1639 None,
1640 "",
1641 )
1642 .unwrap(),
1643 OnAckReceivedOutcome {
1644 lost_packets: 1,
1645 lost_bytes: 1000,
1646 acked_bytes: 1000,
1647 spurious_losses: 0,
1648 }
1649 );
1650 }
1651
1652 #[rstest]
1655 fn relaxed_thresholds_on_reordering(
1656 #[values("bbr2_gcongestion")] cc_algorithm_name: &str,
1657 ) {
1658 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1659 cfg.enable_relaxed_loss_threshold = true;
1660 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1661
1662 let mut now = Instant::now();
1663 let mut r = Recovery::new(&cfg);
1664 assert_eq!(r.rtt(), DEFAULT_INITIAL_RTT);
1665
1666 const THRESH_GAP: Duration = Duration::from_millis(30);
1679 let initial_thresh_ms =
1681 DEFAULT_INITIAL_RTT.mul_f64(INITIAL_TIME_THRESHOLD);
1682 let spurious_thresh_ms: Duration =
1684 DEFAULT_INITIAL_RTT.mul_f64(PACKET_REORDER_TIME_THRESHOLD);
1685 let between_thresh_ms = initial_thresh_ms + THRESH_GAP;
1687 assert!(between_thresh_ms > initial_thresh_ms);
1688 assert!(between_thresh_ms < spurious_thresh_ms);
1689 assert!(between_thresh_ms + THRESH_GAP > spurious_thresh_ms);
1690
1691 for i in 0..6 {
1692 let send_time = now + i * between_thresh_ms;
1693
1694 let p = test_utils::helper_packet_sent(i.into(), send_time, 1000);
1695 r.on_packet_sent(
1696 p,
1697 packet::Epoch::Application,
1698 HandshakeStatus::default(),
1699 send_time,
1700 "",
1701 );
1702 }
1703
1704 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 6);
1705 assert_eq!(r.bytes_in_flight(), 6 * 1000);
1706 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1708 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1709
1710 now += between_thresh_ms;
1713
1714 let mut acked = RangeSet::default();
1719 acked.insert(1..2);
1720 assert_eq!(
1721 r.on_ack_received(
1722 &acked,
1723 25,
1724 packet::Epoch::Application,
1725 HandshakeStatus::default(),
1726 now,
1727 None,
1728 "",
1729 )
1730 .unwrap(),
1731 OnAckReceivedOutcome {
1732 lost_packets: 1,
1733 lost_bytes: 1000,
1734 acked_bytes: 1000,
1735 spurious_losses: 0,
1736 }
1737 );
1738 assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1740 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1741
1742 let mut acked = RangeSet::default();
1747 acked.insert(0..1);
1748 assert_eq!(
1749 r.on_ack_received(
1750 &acked,
1751 25,
1752 packet::Epoch::Application,
1753 HandshakeStatus::default(),
1754 now,
1755 None,
1756 "",
1757 )
1758 .unwrap(),
1759 OnAckReceivedOutcome {
1760 lost_packets: 0,
1761 lost_bytes: 0,
1762 acked_bytes: 0,
1763 spurious_losses: 1,
1764 }
1765 );
1766 assert_eq!(r.pkt_thresh(), None);
1771 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1772
1773 now += between_thresh_ms;
1776 now += between_thresh_ms;
1780
1781 let mut acked = RangeSet::default();
1786 acked.insert(3..4);
1787 assert_eq!(
1788 r.on_ack_received(
1789 &acked,
1790 25,
1791 packet::Epoch::Application,
1792 HandshakeStatus::default(),
1793 now,
1794 None,
1795 "",
1796 )
1797 .unwrap(),
1798 OnAckReceivedOutcome {
1799 lost_packets: 1,
1800 lost_bytes: 1000,
1801 acked_bytes: 1000,
1802 spurious_losses: 0,
1803 }
1804 );
1805 assert_eq!(r.pkt_thresh(), None);
1807 assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1808
1809 let mut acked = RangeSet::default();
1818 acked.insert(2..3);
1819 assert_eq!(
1820 r.on_ack_received(
1821 &acked,
1822 25,
1823 packet::Epoch::Application,
1824 HandshakeStatus::default(),
1825 now,
1826 None,
1827 "",
1828 )
1829 .unwrap(),
1830 OnAckReceivedOutcome {
1831 lost_packets: 0,
1832 lost_bytes: 0,
1833 acked_bytes: 0,
1834 spurious_losses: 1,
1835 }
1836 );
1837 assert_eq!(r.pkt_thresh(), None);
1841 let double_time_thresh_overhead =
1842 1.0 + 2.0 * INITIAL_TIME_THRESHOLD_OVERHEAD;
1843 assert_eq!(r.time_thresh(), double_time_thresh_overhead);
1844 }
1845
1846 #[rstest]
1847 fn pacing(
1848 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
1849 #[values(false, true)] time_sent_set_to_now: bool,
1850 ) {
1851 let pacing_enabled = cc_algorithm_name == "bbr2" ||
1852 cc_algorithm_name == "bbr2_gcongestion";
1853
1854 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1855 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1856
1857 #[cfg(feature = "internal")]
1858 cfg.set_custom_bbr_params(BbrParams {
1859 time_sent_set_to_now: Some(time_sent_set_to_now),
1860 ..Default::default()
1861 });
1862
1863 let mut r = Recovery::new(&cfg);
1864
1865 let mut now = Instant::now();
1866
1867 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1868
1869 for i in 0..10 {
1871 let p = Sent {
1872 pkt_num: i,
1873 frames: smallvec![],
1874 time_sent: now,
1875 time_acked: None,
1876 time_lost: None,
1877 size: 1200,
1878 ack_eliciting: true,
1879 in_flight: true,
1880 delivered: 0,
1881 delivered_time: now,
1882 first_sent_time: now,
1883 is_app_limited: false,
1884 tx_in_flight: 0,
1885 lost: 0,
1886 has_data: true,
1887 is_pmtud_probe: false,
1888 };
1889
1890 r.on_packet_sent(
1891 p,
1892 packet::Epoch::Application,
1893 HandshakeStatus::default(),
1894 now,
1895 "",
1896 );
1897 }
1898
1899 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 10);
1900 assert_eq!(r.bytes_in_flight(), 12000);
1901 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1902
1903 if !pacing_enabled {
1904 assert_eq!(r.pacing_rate(), 0);
1905 } else {
1906 assert_eq!(r.pacing_rate(), 103963);
1907 }
1908 assert_eq!(r.get_packet_send_time(now), now);
1909
1910 assert_eq!(r.cwnd(), 12000);
1911 assert_eq!(r.cwnd_available(), 0);
1912
1913 let initial_rtt = Duration::from_millis(50);
1915 now += initial_rtt;
1916
1917 let mut acked = RangeSet::default();
1918 acked.insert(0..10);
1919
1920 assert_eq!(
1921 r.on_ack_received(
1922 &acked,
1923 10,
1924 packet::Epoch::Application,
1925 HandshakeStatus::default(),
1926 now,
1927 None,
1928 "",
1929 )
1930 .unwrap(),
1931 OnAckReceivedOutcome {
1932 lost_packets: 0,
1933 lost_bytes: 0,
1934 acked_bytes: 12000,
1935 spurious_losses: 0,
1936 }
1937 );
1938
1939 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1940 assert_eq!(r.bytes_in_flight(), 0);
1941 assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
1942 assert_eq!(r.min_rtt(), Some(initial_rtt));
1943 assert_eq!(r.rtt(), initial_rtt);
1944
1945 assert_eq!(r.cwnd(), 12000 + 1200 * 10);
1947
1948 let p = Sent {
1950 pkt_num: 10,
1951 frames: smallvec![],
1952 time_sent: now,
1953 time_acked: None,
1954 time_lost: None,
1955 size: 6000,
1956 ack_eliciting: true,
1957 in_flight: true,
1958 delivered: 0,
1959 delivered_time: now,
1960 first_sent_time: now,
1961 is_app_limited: false,
1962 tx_in_flight: 0,
1963 lost: 0,
1964 has_data: true,
1965 is_pmtud_probe: false,
1966 };
1967
1968 r.on_packet_sent(
1969 p,
1970 packet::Epoch::Application,
1971 HandshakeStatus::default(),
1972 now,
1973 "",
1974 );
1975
1976 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1977 assert_eq!(r.bytes_in_flight(), 6000);
1978 assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
1979
1980 if !pacing_enabled {
1981 assert_eq!(r.get_packet_send_time(now), now);
1983 } else {
1984 assert_ne!(r.get_packet_send_time(now), now);
1986 }
1987
1988 let p = Sent {
1990 pkt_num: 11,
1991 frames: smallvec![],
1992 time_sent: now,
1993 time_acked: None,
1994 time_lost: None,
1995 size: 6000,
1996 ack_eliciting: true,
1997 in_flight: true,
1998 delivered: 0,
1999 delivered_time: now,
2000 first_sent_time: now,
2001 is_app_limited: false,
2002 tx_in_flight: 0,
2003 lost: 0,
2004 has_data: true,
2005 is_pmtud_probe: false,
2006 };
2007
2008 r.on_packet_sent(
2009 p,
2010 packet::Epoch::Application,
2011 HandshakeStatus::default(),
2012 now,
2013 "",
2014 );
2015
2016 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2017 assert_eq!(r.bytes_in_flight(), 12000);
2018 assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
2019
2020 let p = Sent {
2022 pkt_num: 12,
2023 frames: smallvec![],
2024 time_sent: now,
2025 time_acked: None,
2026 time_lost: None,
2027 size: 1000,
2028 ack_eliciting: true,
2029 in_flight: true,
2030 delivered: 0,
2031 delivered_time: now,
2032 first_sent_time: now,
2033 is_app_limited: false,
2034 tx_in_flight: 0,
2035 lost: 0,
2036 has_data: true,
2037 is_pmtud_probe: false,
2038 };
2039
2040 r.on_packet_sent(
2041 p,
2042 packet::Epoch::Application,
2043 HandshakeStatus::default(),
2044 now,
2045 "",
2046 );
2047
2048 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
2049 assert_eq!(r.bytes_in_flight(), 13000);
2050 assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
2051
2052 let pacing_rate = if pacing_enabled {
2055 let cwnd_gain: f64 = 2.0;
2056 let bw = r.cwnd() as f64 / cwnd_gain / initial_rtt.as_secs_f64();
2059 bw as u64
2060 } else {
2061 0
2062 };
2063 assert_eq!(r.pacing_rate(), pacing_rate);
2064
2065 let scale_factor = if pacing_enabled {
2066 1.08333332
2069 } else {
2070 1.0
2071 };
2072 assert_eq!(
2073 r.get_packet_send_time(now) - now,
2074 if pacing_enabled {
2075 Duration::from_secs_f64(
2076 scale_factor * 12000.0 / pacing_rate as f64,
2077 )
2078 } else {
2079 Duration::ZERO
2080 }
2081 );
2082 assert_eq!(r.startup_exit(), None);
2083
2084 let reduced_rtt = Duration::from_millis(40);
2085 now += reduced_rtt;
2086
2087 let mut acked = RangeSet::default();
2088 acked.insert(10..11);
2089
2090 assert_eq!(
2091 r.on_ack_received(
2092 &acked,
2093 0,
2094 packet::Epoch::Application,
2095 HandshakeStatus::default(),
2096 now,
2097 None,
2098 "",
2099 )
2100 .unwrap(),
2101 OnAckReceivedOutcome {
2102 lost_packets: 0,
2103 lost_bytes: 0,
2104 acked_bytes: 6000,
2105 spurious_losses: 0,
2106 }
2107 );
2108
2109 let expected_srtt = (7 * initial_rtt + reduced_rtt) / 8;
2110 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2111 assert_eq!(r.bytes_in_flight(), 7000);
2112 assert_eq!(r.bytes_in_flight_duration(), initial_rtt + reduced_rtt);
2113 assert_eq!(r.min_rtt(), Some(reduced_rtt));
2114 assert_eq!(r.rtt(), expected_srtt);
2115
2116 let mut acked = RangeSet::default();
2117 acked.insert(11..12);
2118
2119 assert_eq!(
2120 r.on_ack_received(
2121 &acked,
2122 0,
2123 packet::Epoch::Application,
2124 HandshakeStatus::default(),
2125 now,
2126 None,
2127 "",
2128 )
2129 .unwrap(),
2130 OnAckReceivedOutcome {
2131 lost_packets: 0,
2132 lost_bytes: 0,
2133 acked_bytes: 6000,
2134 spurious_losses: 0,
2135 }
2136 );
2137
2138 let expected_min_rtt = if pacing_enabled &&
2142 !time_sent_set_to_now &&
2143 cfg!(feature = "internal")
2144 {
2145 reduced_rtt - Duration::from_millis(25)
2146 } else {
2147 reduced_rtt
2148 };
2149
2150 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
2151 assert_eq!(r.bytes_in_flight(), 1000);
2152 assert_eq!(r.bytes_in_flight_duration(), initial_rtt + reduced_rtt);
2153 assert_eq!(r.min_rtt(), Some(expected_min_rtt));
2154
2155 let expected_srtt = (7 * expected_srtt + expected_min_rtt) / 8;
2156 assert_eq!(r.rtt(), expected_srtt);
2157
2158 let mut acked = RangeSet::default();
2159 acked.insert(12..13);
2160
2161 assert_eq!(
2162 r.on_ack_received(
2163 &acked,
2164 0,
2165 packet::Epoch::Application,
2166 HandshakeStatus::default(),
2167 now,
2168 None,
2169 "",
2170 )
2171 .unwrap(),
2172 OnAckReceivedOutcome {
2173 lost_packets: 0,
2174 lost_bytes: 0,
2175 acked_bytes: 1000,
2176 spurious_losses: 0,
2177 }
2178 );
2179
2180 let expected_min_rtt = if pacing_enabled &&
2183 !time_sent_set_to_now &&
2184 cfg!(feature = "internal")
2185 {
2186 Duration::from_millis(0)
2187 } else {
2188 reduced_rtt
2189 };
2190 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2191 assert_eq!(r.bytes_in_flight(), 0);
2192 assert_eq!(r.bytes_in_flight_duration(), initial_rtt + reduced_rtt);
2193 assert_eq!(r.min_rtt(), Some(expected_min_rtt));
2194
2195 let expected_srtt = (7 * expected_srtt + expected_min_rtt) / 8;
2196 assert_eq!(r.rtt(), expected_srtt);
2197 }
2198
2199 #[rstest]
2200 #[case::bw_estimate_equal_after_first_rtt(1.0, 1.0)]
2203 #[case::bw_estimate_decrease_after_first_rtt(2.0, 1.0)]
2206 #[case::bw_estimate_increase_after_first_rtt(0.5, 0.5)]
2212 #[cfg(feature = "internal")]
2213 fn initial_pacing_rate_override(
2214 #[case] initial_multipler: f64, #[case] expected_multiplier: f64,
2215 ) {
2216 let rtt = Duration::from_millis(50);
2217 let bw = Bandwidth::from_bytes_and_time_delta(12000, rtt);
2218 let initial_pacing_rate_hint = bw * initial_multipler;
2219 let expected_pacing_with_rtt_measurement = bw * expected_multiplier;
2220
2221 let cc_algorithm_name = "bbr2_gcongestion";
2222 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2223 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2224 cfg.set_custom_bbr_params(BbrParams {
2225 initial_pacing_rate_bytes_per_second: Some(
2226 initial_pacing_rate_hint.to_bytes_per_second(),
2227 ),
2228 ..Default::default()
2229 });
2230
2231 let mut r = Recovery::new(&cfg);
2232
2233 let mut now = Instant::now();
2234
2235 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2236
2237 for i in 0..2 {
2239 let p = test_utils::helper_packet_sent(i, now, 1200);
2240 r.on_packet_sent(
2241 p,
2242 packet::Epoch::Application,
2243 HandshakeStatus::default(),
2244 now,
2245 "",
2246 );
2247 }
2248
2249 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2250 assert_eq!(r.bytes_in_flight(), 2400);
2251 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2252
2253 assert_eq!(
2255 r.pacing_rate(),
2256 initial_pacing_rate_hint.to_bytes_per_second()
2257 );
2258 assert_eq!(r.get_packet_send_time(now), now);
2259
2260 assert_eq!(r.cwnd(), 12000);
2261 assert_eq!(r.cwnd_available(), 9600);
2262
2263 now += rtt;
2265
2266 let mut acked = RangeSet::default();
2267 acked.insert(0..2);
2268
2269 assert_eq!(
2270 r.on_ack_received(
2271 &acked,
2272 10,
2273 packet::Epoch::Application,
2274 HandshakeStatus::default(),
2275 now,
2276 None,
2277 "",
2278 )
2279 .unwrap(),
2280 OnAckReceivedOutcome {
2281 lost_packets: 0,
2282 lost_bytes: 0,
2283 acked_bytes: 2400,
2284 spurious_losses: 0,
2285 }
2286 );
2287
2288 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2289 assert_eq!(r.bytes_in_flight(), 0);
2290 assert_eq!(r.bytes_in_flight_duration(), rtt);
2291 assert_eq!(r.rtt(), rtt);
2292
2293 assert_eq!(
2296 r.pacing_rate(),
2297 expected_pacing_with_rtt_measurement.to_bytes_per_second()
2298 );
2299 }
2300
2301 #[rstest]
2302 fn validate_ack_range_on_ack_received(
2303 #[values("cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
2304 ) {
2305 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2306 cfg.set_cc_algorithm_name(cc_algorithm_name).unwrap();
2307
2308 let epoch = packet::Epoch::Application;
2309 let mut r = Recovery::new(&cfg);
2310 let mut now = Instant::now();
2311 assert_eq!(r.sent_packets_len(epoch), 0);
2312
2313 let pkt_size = 1000;
2315 let pkt_count = 4;
2316 for pkt_num in 0..pkt_count {
2317 let sent = test_utils::helper_packet_sent(pkt_num, now, pkt_size);
2318 r.on_packet_sent(sent, epoch, HandshakeStatus::default(), now, "");
2319 }
2320 assert_eq!(r.sent_packets_len(epoch), pkt_count as usize);
2321 assert_eq!(r.bytes_in_flight(), pkt_count as usize * pkt_size);
2322 assert!(r.get_largest_acked_on_epoch(epoch).is_none());
2323 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2324
2325 now += Duration::from_millis(10);
2327
2328 let mut acked = RangeSet::default();
2330 acked.insert(0..2);
2331
2332 assert_eq!(
2333 r.on_ack_received(
2334 &acked,
2335 25,
2336 epoch,
2337 HandshakeStatus::default(),
2338 now,
2339 None,
2340 "",
2341 )
2342 .unwrap(),
2343 OnAckReceivedOutcome {
2344 lost_packets: 0,
2345 lost_bytes: 0,
2346 acked_bytes: 2 * 1000,
2347 spurious_losses: 0,
2348 }
2349 );
2350
2351 assert_eq!(r.sent_packets_len(epoch), 2);
2352 assert_eq!(r.bytes_in_flight(), 2 * 1000);
2353
2354 assert_eq!(r.get_largest_acked_on_epoch(epoch).unwrap(), 1);
2355 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2356
2357 let mut acked = RangeSet::default();
2359 acked.insert(0..10);
2360 assert_eq!(
2361 r.on_ack_received(
2362 &acked,
2363 25,
2364 epoch,
2365 HandshakeStatus::default(),
2366 now,
2367 None,
2368 "",
2369 )
2370 .unwrap(),
2371 OnAckReceivedOutcome {
2372 lost_packets: 0,
2373 lost_bytes: 0,
2374 acked_bytes: 2 * 1000,
2375 spurious_losses: 0,
2376 }
2377 );
2378 assert_eq!(r.sent_packets_len(epoch), 0);
2379 assert_eq!(r.bytes_in_flight(), 0);
2380
2381 assert_eq!(r.get_largest_acked_on_epoch(epoch).unwrap(), 3);
2382 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2383 }
2384
2385 #[rstest]
2386 fn pmtud_loss_on_timer(
2387 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
2388 ) {
2389 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2390 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2391
2392 let mut r = Recovery::new(&cfg);
2393 assert_eq!(r.cwnd(), 12000);
2394
2395 let mut now = Instant::now();
2396
2397 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2398
2399 let p = Sent {
2401 pkt_num: 0,
2402 frames: smallvec![],
2403 time_sent: now,
2404 time_acked: None,
2405 time_lost: None,
2406 size: 1000,
2407 ack_eliciting: true,
2408 in_flight: true,
2409 delivered: 0,
2410 delivered_time: now,
2411 first_sent_time: now,
2412 is_app_limited: false,
2413 tx_in_flight: 0,
2414 lost: 0,
2415 has_data: false,
2416 is_pmtud_probe: false,
2417 };
2418
2419 r.on_packet_sent(
2420 p,
2421 packet::Epoch::Application,
2422 HandshakeStatus::default(),
2423 now,
2424 "",
2425 );
2426
2427 assert_eq!(r.in_flight_count(packet::Epoch::Application), 1);
2428 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
2429 assert_eq!(r.bytes_in_flight(), 1000);
2430 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2431
2432 let p = Sent {
2433 pkt_num: 1,
2434 frames: smallvec![],
2435 time_sent: now,
2436 time_acked: None,
2437 time_lost: None,
2438 size: 1000,
2439 ack_eliciting: true,
2440 in_flight: true,
2441 delivered: 0,
2442 delivered_time: now,
2443 first_sent_time: now,
2444 is_app_limited: false,
2445 tx_in_flight: 0,
2446 lost: 0,
2447 has_data: false,
2448 is_pmtud_probe: true,
2449 };
2450
2451 r.on_packet_sent(
2452 p,
2453 packet::Epoch::Application,
2454 HandshakeStatus::default(),
2455 now,
2456 "",
2457 );
2458
2459 assert_eq!(r.in_flight_count(packet::Epoch::Application), 2);
2460
2461 let p = Sent {
2462 pkt_num: 2,
2463 frames: smallvec![],
2464 time_sent: now,
2465 time_acked: None,
2466 time_lost: None,
2467 size: 1000,
2468 ack_eliciting: true,
2469 in_flight: true,
2470 delivered: 0,
2471 delivered_time: now,
2472 first_sent_time: now,
2473 is_app_limited: false,
2474 tx_in_flight: 0,
2475 lost: 0,
2476 has_data: false,
2477 is_pmtud_probe: false,
2478 };
2479
2480 r.on_packet_sent(
2481 p,
2482 packet::Epoch::Application,
2483 HandshakeStatus::default(),
2484 now,
2485 "",
2486 );
2487
2488 assert_eq!(r.in_flight_count(packet::Epoch::Application), 3);
2489
2490 now += Duration::from_millis(10);
2492
2493 let mut acked = RangeSet::default();
2495 acked.insert(0..1);
2496 acked.insert(2..3);
2497
2498 assert_eq!(
2499 r.on_ack_received(
2500 &acked,
2501 25,
2502 packet::Epoch::Application,
2503 HandshakeStatus::default(),
2504 now,
2505 None,
2506 "",
2507 )
2508 .unwrap(),
2509 OnAckReceivedOutcome {
2510 lost_packets: 0,
2511 lost_bytes: 0,
2512 acked_bytes: 2 * 1000,
2513 spurious_losses: 0,
2514 }
2515 );
2516
2517 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2518 assert_eq!(r.bytes_in_flight(), 1000);
2519 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
2520 assert_eq!(r.lost_count(), 0);
2521
2522 now = r.loss_detection_timer().unwrap();
2524
2525 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
2527 assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
2528
2529 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2530 assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
2531 assert_eq!(r.bytes_in_flight(), 0);
2532 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
2533 assert_eq!(r.cwnd(), 12000);
2534
2535 assert_eq!(r.lost_count(), 0);
2536
2537 now += r.rtt();
2539
2540 assert_eq!(
2541 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
2542 (0, 0)
2543 );
2544
2545 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2546 assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
2547 assert_eq!(r.bytes_in_flight(), 0);
2548 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
2549 assert_eq!(r.lost_count(), 0);
2550 assert_eq!(r.startup_exit(), None);
2551 }
2552
2553 #[rstest]
2556 fn congestion_delivery_rate(
2557 #[values("reno", "cubic", "bbr2")] cc_algorithm_name: &str,
2558 ) {
2559 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2560 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2561
2562 let mut r = Recovery::new(&cfg);
2563 assert_eq!(r.cwnd(), 12000);
2564
2565 let now = Instant::now();
2566
2567 let mut total_bytes_sent = 0;
2568 for pn in 0..10 {
2569 let bytes = 1000;
2571 let sent = test_utils::helper_packet_sent(pn, now, bytes);
2572 r.on_packet_sent(
2573 sent,
2574 packet::Epoch::Application,
2575 HandshakeStatus::default(),
2576 now,
2577 "",
2578 );
2579
2580 total_bytes_sent += bytes;
2581 }
2582
2583 let interval = Duration::from_secs(10);
2585 let mut acked = RangeSet::default();
2586 acked.insert(0..10);
2587 assert_eq!(
2588 r.on_ack_received(
2589 &acked,
2590 25,
2591 packet::Epoch::Application,
2592 HandshakeStatus::default(),
2593 now + interval,
2594 None,
2595 "",
2596 )
2597 .unwrap(),
2598 OnAckReceivedOutcome {
2599 lost_packets: 0,
2600 lost_bytes: 0,
2601 acked_bytes: total_bytes_sent,
2602 spurious_losses: 0,
2603 }
2604 );
2605 assert_eq!(r.delivery_rate().to_bytes_per_second(), 1000);
2606 assert_eq!(r.min_rtt().unwrap(), interval);
2607 assert_eq!(
2609 total_bytes_sent as u64 / interval.as_secs(),
2610 r.delivery_rate().to_bytes_per_second()
2611 );
2612 assert_eq!(r.startup_exit(), None);
2613 }
2614
2615 #[rstest]
2616 fn acks_with_no_retransmittable_data(
2617 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
2618 ) {
2619 let rtt = Duration::from_millis(100);
2620
2621 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2622 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2623
2624 let mut r = Recovery::new(&cfg);
2625
2626 let mut now = Instant::now();
2627
2628 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2629
2630 let mut next_packet = 0;
2631 for _ in 0..3 {
2633 let p = test_utils::helper_packet_sent(next_packet, now, 1200);
2634 next_packet += 1;
2635 r.on_packet_sent(
2636 p,
2637 packet::Epoch::Application,
2638 HandshakeStatus::default(),
2639 now,
2640 "",
2641 );
2642 }
2643
2644 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
2645 assert_eq!(r.bytes_in_flight(), 3600);
2646 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2647
2648 assert_eq!(
2649 r.pacing_rate(),
2650 if cc_algorithm_name == "bbr2_gcongestion" {
2651 103963
2652 } else {
2653 0
2654 },
2655 );
2656 assert_eq!(r.get_packet_send_time(now), now);
2657 assert_eq!(r.cwnd(), 12000);
2658 assert_eq!(r.cwnd_available(), 8400);
2659
2660 now += rtt;
2662
2663 let mut acked = RangeSet::default();
2664 acked.insert(0..3);
2665
2666 assert_eq!(
2667 r.on_ack_received(
2668 &acked,
2669 10,
2670 packet::Epoch::Application,
2671 HandshakeStatus::default(),
2672 now,
2673 None,
2674 "",
2675 )
2676 .unwrap(),
2677 OnAckReceivedOutcome {
2678 lost_packets: 0,
2679 lost_bytes: 0,
2680 acked_bytes: 3600,
2681 spurious_losses: 0,
2682 }
2683 );
2684
2685 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2686 assert_eq!(r.bytes_in_flight(), 0);
2687 assert_eq!(r.bytes_in_flight_duration(), rtt);
2688 assert_eq!(r.rtt(), rtt);
2689
2690 assert_eq!(
2693 r.pacing_rate(),
2694 if cc_algorithm_name == "bbr2_gcongestion" {
2695 120000
2696 } else {
2697 0
2698 },
2699 );
2700
2701 for iter in 3..1000 {
2703 let mut p = test_utils::helper_packet_sent(next_packet, now, 1200);
2704 p.in_flight = false;
2707 next_packet += 1;
2708 r.on_packet_sent(
2709 p,
2710 packet::Epoch::Application,
2711 HandshakeStatus::default(),
2712 now,
2713 "",
2714 );
2715
2716 now += rtt;
2717
2718 let mut acked = RangeSet::default();
2719 acked.insert(iter..(iter + 1));
2720
2721 assert_eq!(
2722 r.on_ack_received(
2723 &acked,
2724 10,
2725 packet::Epoch::Application,
2726 HandshakeStatus::default(),
2727 now,
2728 None,
2729 "",
2730 )
2731 .unwrap(),
2732 OnAckReceivedOutcome {
2733 lost_packets: 0,
2734 lost_bytes: 0,
2735 acked_bytes: 0,
2736 spurious_losses: 0,
2737 }
2738 );
2739
2740 assert_eq!(r.startup_exit(), None, "{iter}");
2742
2743 assert_eq!(
2745 r.sent_packets_len(packet::Epoch::Application),
2746 0,
2747 "{iter}"
2748 );
2749 assert_eq!(r.bytes_in_flight(), 0, "{iter}");
2750 assert_eq!(r.bytes_in_flight_duration(), rtt, "{iter}");
2751 assert_eq!(
2752 r.pacing_rate(),
2753 if cc_algorithm_name == "bbr2_gcongestion" ||
2754 cc_algorithm_name == "bbr2"
2755 {
2756 120000
2757 } else {
2758 0
2759 },
2760 "{iter}"
2761 );
2762 }
2763 }
2764 #[rstest]
2765 fn pto_overflow_reproduction(
2766 #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
2767 ) {
2768 let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2769 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2770 let mut r = Recovery::new(&cfg);
2771 let now = Instant::now();
2772
2773 let handshake_status = HandshakeStatus {
2775 has_handshake_keys: true,
2776 peer_verified_address: true,
2777 completed: false,
2778 };
2779
2780 let p_initial = Sent {
2782 pkt_num: 0,
2783 frames: smallvec::smallvec![],
2784 time_sent: now,
2785 time_acked: None,
2786 time_lost: None,
2787 size: 1000,
2788 ack_eliciting: true,
2789 in_flight: true,
2790 delivered: 0,
2791 delivered_time: now,
2792 first_sent_time: now,
2793 is_app_limited: false,
2794 tx_in_flight: 0,
2795 lost: 0,
2796 has_data: false,
2797 is_pmtud_probe: false,
2798 };
2799 r.on_packet_sent(
2800 p_initial,
2801 packet::Epoch::Initial,
2802 handshake_status,
2803 now,
2804 "",
2805 );
2806
2807 assert!(r.loss_detection_timer().is_some());
2809
2810 let p_app = Sent {
2812 pkt_num: 0, frames: smallvec::smallvec![],
2814 time_sent: now,
2815 time_acked: None,
2816 time_lost: None,
2817 size: 1000,
2818 ack_eliciting: true,
2819 in_flight: true,
2820 delivered: 0,
2821 delivered_time: now,
2822 first_sent_time: now,
2823 is_app_limited: false,
2824 tx_in_flight: 0,
2825
2826 lost: 0,
2827 has_data: true,
2828 is_pmtud_probe: false,
2829 };
2830 r.on_packet_sent(
2831 p_app,
2832 packet::Epoch::Application,
2833 handshake_status,
2834 now,
2835 "",
2836 );
2837
2838 let mut ranges = RangeSet::default();
2842 ranges.insert(0..1);
2843 r.on_ack_received(
2844 &ranges,
2845 0,
2846 packet::Epoch::Initial,
2847 handshake_status,
2848 now,
2849 None,
2850 "",
2851 )
2852 .unwrap();
2853
2854 assert!(r.loss_detection_timer().is_none());
2860 }
2861}
2862
2863mod bandwidth;
2864mod bytes_in_flight;
2865mod congestion;
2866mod gcongestion;
2867mod rtt;