1use std::str::FromStr;
28use std::time::Duration;
29use std::time::Instant;
30
31use crate::frame;
32use crate::packet;
33use crate::ranges::RangeSet;
34use 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;
54
55const GRANULARITY: Duration = Duration::from_millis(1);
56
57const MAX_PTO_PROBES_COUNT: usize = 2;
58
59const MINIMUM_WINDOW_PACKETS: usize = 2;
60
61const LOSS_REDUCTION_FACTOR: f64 = 0.5;
62
63pub(super) const MAX_OUTSTANDING_NON_ACK_ELICITING: usize = 24;
66
67#[derive(Default)]
68struct LossDetectionTimer {
69 time: Option<Instant>,
70}
71
72impl LossDetectionTimer {
73 fn update(&mut self, timeout: Instant) {
74 self.time = Some(timeout);
75 }
76
77 fn clear(&mut self) {
78 self.time = None;
79 }
80}
81
82impl std::fmt::Debug for LossDetectionTimer {
83 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
84 match self.time {
85 Some(v) => {
86 let now = Instant::now();
87 if v > now {
88 let d = v.duration_since(now);
89 write!(f, "{d:?}")
90 } else {
91 write!(f, "exp")
92 }
93 },
94 None => write!(f, "none"),
95 }
96 }
97}
98
99#[derive(Clone, Copy, PartialEq)]
100pub struct RecoveryConfig {
101 pub max_send_udp_payload_size: usize,
102 pub max_ack_delay: Duration,
103 pub cc_algorithm: CongestionControlAlgorithm,
104 pub custom_bbr_params: Option<BbrParams>,
105 pub hystart: bool,
106 pub pacing: bool,
107 pub max_pacing_rate: Option<u64>,
108 pub initial_congestion_window_packets: usize,
109}
110
111impl RecoveryConfig {
112 pub fn from_config(config: &Config) -> Self {
113 Self {
114 max_send_udp_payload_size: config.max_send_udp_payload_size,
115 max_ack_delay: Duration::ZERO,
116 cc_algorithm: config.cc_algorithm,
117 custom_bbr_params: config.custom_bbr_params,
118 hystart: config.hystart,
119 pacing: config.pacing,
120 max_pacing_rate: config.max_pacing_rate,
121 initial_congestion_window_packets: config
122 .initial_congestion_window_packets,
123 }
124 }
125}
126
127#[enum_dispatch::enum_dispatch(RecoveryOps)]
128#[allow(clippy::large_enum_variant)]
129#[derive(Debug)]
130pub(crate) enum Recovery {
131 Legacy(LegacyRecovery),
132 GCongestion(GRecovery),
133}
134
135#[derive(Debug, Default, PartialEq)]
136pub struct OnAckReceivedOutcome {
137 pub lost_packets: usize,
138 pub lost_bytes: usize,
139 pub acked_bytes: usize,
140 pub spurious_losses: usize,
141}
142
143#[derive(Debug, Default)]
144pub struct OnLossDetectionTimeoutOutcome {
145 pub lost_packets: usize,
146 pub lost_bytes: usize,
147}
148
149#[enum_dispatch::enum_dispatch]
150pub trait RecoveryOps {
152 fn lost_count(&self) -> usize;
153 fn bytes_lost(&self) -> u64;
154
155 fn should_elicit_ack(&self, epoch: packet::Epoch) -> bool;
158
159 fn get_acked_frames(&mut self, epoch: packet::Epoch) -> Vec<frame::Frame>;
160
161 fn get_lost_frames(&mut self, epoch: packet::Epoch) -> Vec<frame::Frame>;
162
163 fn get_largest_acked_on_epoch(&self, epoch: packet::Epoch) -> Option<u64>;
164 fn has_lost_frames(&self, epoch: packet::Epoch) -> bool;
165 fn loss_probes(&self, epoch: packet::Epoch) -> usize;
166 #[cfg(test)]
167 fn inc_loss_probes(&mut self, epoch: packet::Epoch);
168
169 fn ping_sent(&mut self, epoch: packet::Epoch);
170
171 fn on_packet_sent(
172 &mut self, pkt: Sent, epoch: packet::Epoch,
173 handshake_status: HandshakeStatus, now: Instant, trace_id: &str,
174 );
175 fn get_packet_send_time(&self, now: Instant) -> Instant;
176
177 #[allow(clippy::too_many_arguments)]
178 fn on_ack_received(
179 &mut self, ranges: &RangeSet, ack_delay: u64, epoch: packet::Epoch,
180 handshake_status: HandshakeStatus, now: Instant, skip_pn: Option<u64>,
181 trace_id: &str,
182 ) -> Result<OnAckReceivedOutcome>;
183
184 fn on_loss_detection_timeout(
185 &mut self, handshake_status: HandshakeStatus, now: Instant,
186 trace_id: &str,
187 ) -> OnLossDetectionTimeoutOutcome;
188 fn on_pkt_num_space_discarded(
189 &mut self, epoch: packet::Epoch, handshake_status: HandshakeStatus,
190 now: Instant,
191 );
192 fn on_path_change(
193 &mut self, epoch: packet::Epoch, now: Instant, _trace_id: &str,
194 ) -> (usize, usize);
195 fn loss_detection_timer(&self) -> Option<Instant>;
196 fn cwnd(&self) -> usize;
197 fn cwnd_available(&self) -> usize;
198 fn rtt(&self) -> Duration;
199
200 fn min_rtt(&self) -> Option<Duration>;
201
202 fn max_rtt(&self) -> Option<Duration>;
203
204 fn rttvar(&self) -> Duration;
205
206 fn pto(&self) -> Duration;
207
208 fn delivery_rate(&self) -> Bandwidth;
210
211 fn startup_exit(&self) -> Option<StartupExit>;
213
214 fn max_datagram_size(&self) -> usize;
215
216 fn pmtud_update_max_datagram_size(&mut self, new_max_datagram_size: usize);
217
218 fn update_max_datagram_size(&mut self, new_max_datagram_size: usize);
219
220 fn on_app_limited(&mut self);
221
222 #[cfg(test)]
225 fn largest_sent_pkt_num_on_path(&self, epoch: packet::Epoch) -> Option<u64>;
226
227 #[cfg(test)]
228 fn app_limited(&self) -> bool;
229
230 #[cfg(test)]
231 fn sent_packets_len(&self, epoch: packet::Epoch) -> usize;
232
233 #[cfg(test)]
234 fn bytes_in_flight(&self) -> usize;
235
236 fn bytes_in_flight_duration(&self) -> Duration;
237
238 #[cfg(test)]
239 fn in_flight_count(&self, epoch: packet::Epoch) -> usize;
240
241 #[cfg(test)]
242 fn pacing_rate(&self) -> u64;
243
244 #[cfg(test)]
245 fn pto_count(&self) -> u32;
246
247 #[cfg(test)]
248 fn pkt_thresh(&self) -> u64;
249
250 #[cfg(test)]
251 fn lost_spurious_count(&self) -> usize;
252
253 #[cfg(test)]
254 fn detect_lost_packets_for_test(
255 &mut self, epoch: packet::Epoch, now: Instant,
256 ) -> (usize, usize);
257
258 fn update_app_limited(&mut self, v: bool);
259
260 fn delivery_rate_update_app_limited(&mut self, v: bool);
261
262 fn update_max_ack_delay(&mut self, max_ack_delay: Duration);
263
264 #[cfg(feature = "qlog")]
265 fn state_str(&self, now: Instant) -> &'static str;
266
267 #[cfg(feature = "qlog")]
268 fn get_updated_qlog_event_data(&mut self) -> Option<EventData>;
269
270 #[cfg(feature = "qlog")]
271 fn get_updated_qlog_cc_state(&mut self, now: Instant)
272 -> Option<&'static str>;
273
274 fn send_quantum(&self) -> usize;
275
276 fn get_next_release_time(&self) -> ReleaseDecision;
277
278 fn gcongestion_enabled(&self) -> bool;
279}
280
281impl Recovery {
282 pub fn new_with_config(recovery_config: &RecoveryConfig) -> Self {
283 let grecovery = GRecovery::new(recovery_config);
284 if let Some(grecovery) = grecovery {
285 Recovery::from(grecovery)
286 } else {
287 Recovery::from(LegacyRecovery::new_with_config(recovery_config))
288 }
289 }
290
291 #[cfg(feature = "qlog")]
292 pub fn maybe_qlog(
293 &mut self, qlog: &mut qlog::streamer::QlogStreamer, now: Instant,
294 ) {
295 if let Some(ev_data) = self.get_updated_qlog_event_data() {
296 qlog.add_event_data_with_instant(ev_data, now).ok();
297 }
298
299 if let Some(cc_state) = self.get_updated_qlog_cc_state(now) {
300 let ev_data = EventData::CongestionStateUpdated(
301 qlog::events::quic::CongestionStateUpdated {
302 old: None,
303 new: cc_state.to_string(),
304 trigger: None,
305 },
306 );
307
308 qlog.add_event_data_with_instant(ev_data, now).ok();
309 }
310 }
311
312 #[cfg(test)]
313 pub fn new(config: &crate::Config) -> Self {
314 Self::new_with_config(&RecoveryConfig::from_config(config))
315 }
316}
317
318#[derive(Debug, Copy, Clone, PartialEq, Eq)]
323#[repr(C)]
324pub enum CongestionControlAlgorithm {
325 Reno = 0,
327 CUBIC = 1,
329 BBR = 2,
331 BBR2 = 3,
333 Bbr2Gcongestion = 4,
336}
337
338impl FromStr for CongestionControlAlgorithm {
339 type Err = crate::Error;
340
341 fn from_str(name: &str) -> std::result::Result<Self, Self::Err> {
345 match name {
346 "reno" => Ok(CongestionControlAlgorithm::Reno),
347 "cubic" => Ok(CongestionControlAlgorithm::CUBIC),
348 "bbr" => Ok(CongestionControlAlgorithm::BBR),
349 #[cfg(not(feature = "gcongestion"))]
350 "bbr2" => Ok(CongestionControlAlgorithm::BBR2),
351 #[cfg(feature = "gcongestion")]
352 "bbr2" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
353 "bbr2_gcongestion" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
354 _ => Err(crate::Error::CongestionControl),
355 }
356 }
357}
358
359#[derive(Clone)]
360pub struct Sent {
361 pub pkt_num: u64,
362
363 pub frames: SmallVec<[frame::Frame; 1]>,
364
365 pub time_sent: Instant,
366
367 pub time_acked: Option<Instant>,
368
369 pub time_lost: Option<Instant>,
370
371 pub size: usize,
372
373 pub ack_eliciting: bool,
374
375 pub in_flight: bool,
376
377 pub delivered: usize,
378
379 pub delivered_time: Instant,
380
381 pub first_sent_time: Instant,
382
383 pub is_app_limited: bool,
384
385 pub tx_in_flight: usize,
386
387 pub lost: u64,
388
389 pub has_data: bool,
390
391 pub is_pmtud_probe: bool,
392}
393
394impl std::fmt::Debug for Sent {
395 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
396 write!(f, "pkt_num={:?} ", self.pkt_num)?;
397 write!(f, "pkt_sent_time={:?} ", self.time_sent)?;
398 write!(f, "pkt_size={:?} ", self.size)?;
399 write!(f, "delivered={:?} ", self.delivered)?;
400 write!(f, "delivered_time={:?} ", self.delivered_time)?;
401 write!(f, "first_sent_time={:?} ", self.first_sent_time)?;
402 write!(f, "is_app_limited={} ", self.is_app_limited)?;
403 write!(f, "tx_in_flight={} ", self.tx_in_flight)?;
404 write!(f, "lost={} ", self.lost)?;
405 write!(f, "has_data={} ", self.has_data)?;
406 write!(f, "is_pmtud_probe={}", self.is_pmtud_probe)?;
407
408 Ok(())
409 }
410}
411
412#[derive(Clone, Copy, Debug)]
413pub struct HandshakeStatus {
414 pub has_handshake_keys: bool,
415
416 pub peer_verified_address: bool,
417
418 pub completed: bool,
419}
420
421#[cfg(test)]
422impl Default for HandshakeStatus {
423 fn default() -> HandshakeStatus {
424 HandshakeStatus {
425 has_handshake_keys: true,
426
427 peer_verified_address: true,
428
429 completed: true,
430 }
431 }
432}
433
434#[derive(Default)]
439#[cfg(feature = "qlog")]
440struct QlogMetrics {
441 min_rtt: Duration,
442 smoothed_rtt: Duration,
443 latest_rtt: Duration,
444 rttvar: Duration,
445 cwnd: u64,
446 bytes_in_flight: u64,
447 ssthresh: Option<u64>,
448 pacing_rate: u64,
449}
450
451#[cfg(feature = "qlog")]
452impl QlogMetrics {
453 fn maybe_update(&mut self, latest: Self) -> Option<EventData> {
459 let mut emit_event = false;
460
461 let new_min_rtt = if self.min_rtt != latest.min_rtt {
462 self.min_rtt = latest.min_rtt;
463 emit_event = true;
464 Some(latest.min_rtt.as_secs_f32() * 1000.0)
465 } else {
466 None
467 };
468
469 let new_smoothed_rtt = if self.smoothed_rtt != latest.smoothed_rtt {
470 self.smoothed_rtt = latest.smoothed_rtt;
471 emit_event = true;
472 Some(latest.smoothed_rtt.as_secs_f32() * 1000.0)
473 } else {
474 None
475 };
476
477 let new_latest_rtt = if self.latest_rtt != latest.latest_rtt {
478 self.latest_rtt = latest.latest_rtt;
479 emit_event = true;
480 Some(latest.latest_rtt.as_secs_f32() * 1000.0)
481 } else {
482 None
483 };
484
485 let new_rttvar = if self.rttvar != latest.rttvar {
486 self.rttvar = latest.rttvar;
487 emit_event = true;
488 Some(latest.rttvar.as_secs_f32() * 1000.0)
489 } else {
490 None
491 };
492
493 let new_cwnd = if self.cwnd != latest.cwnd {
494 self.cwnd = latest.cwnd;
495 emit_event = true;
496 Some(latest.cwnd)
497 } else {
498 None
499 };
500
501 let new_bytes_in_flight =
502 if self.bytes_in_flight != latest.bytes_in_flight {
503 self.bytes_in_flight = latest.bytes_in_flight;
504 emit_event = true;
505 Some(latest.bytes_in_flight)
506 } else {
507 None
508 };
509
510 let new_ssthresh = if self.ssthresh != latest.ssthresh {
511 self.ssthresh = latest.ssthresh;
512 emit_event = true;
513 latest.ssthresh
514 } else {
515 None
516 };
517
518 let new_pacing_rate = if self.pacing_rate != latest.pacing_rate {
519 self.pacing_rate = latest.pacing_rate;
520 emit_event = true;
521 Some(latest.pacing_rate)
522 } else {
523 None
524 };
525
526 if emit_event {
527 return Some(EventData::MetricsUpdated(
529 qlog::events::quic::MetricsUpdated {
530 min_rtt: new_min_rtt,
531 smoothed_rtt: new_smoothed_rtt,
532 latest_rtt: new_latest_rtt,
533 rtt_variance: new_rttvar,
534 congestion_window: new_cwnd,
535 bytes_in_flight: new_bytes_in_flight,
536 ssthresh: new_ssthresh,
537 pacing_rate: new_pacing_rate,
538 ..Default::default()
539 },
540 ));
541 }
542
543 None
544 }
545}
546
547#[derive(Debug, Clone, Copy, PartialEq, Eq)]
549pub enum ReleaseTime {
550 Immediate,
551 At(Instant),
552}
553
554#[derive(Clone, Copy, Debug, PartialEq, Eq)]
556pub struct ReleaseDecision {
557 time: ReleaseTime,
558 allow_burst: bool,
559}
560
561impl ReleaseTime {
562 #[allow(dead_code)]
564 fn inc(&mut self, delay: Duration) {
565 match self {
566 ReleaseTime::Immediate => {},
567 ReleaseTime::At(time) => *time += delay,
568 }
569 }
570
571 #[allow(dead_code)]
573 fn set_max(&mut self, other: Instant) {
574 match self {
575 ReleaseTime::Immediate => *self = ReleaseTime::At(other),
576 ReleaseTime::At(time) => *self = ReleaseTime::At(other.max(*time)),
577 }
578 }
579}
580
581impl ReleaseDecision {
582 pub(crate) const EQUAL_THRESHOLD: Duration = Duration::from_micros(50);
583
584 #[allow(dead_code)]
587 #[inline]
588 pub fn time(&self, now: Instant) -> Option<Instant> {
589 match self.time {
590 ReleaseTime::Immediate => None,
591 ReleaseTime::At(other) => other.gt(&now).then_some(other),
592 }
593 }
594
595 #[allow(dead_code)]
597 #[inline]
598 pub fn can_burst(&self) -> bool {
599 self.allow_burst
600 }
601
602 #[allow(dead_code)]
604 #[inline]
605 pub fn time_eq(&self, other: &Self, now: Instant) -> bool {
606 let delta = match (self.time(now), other.time(now)) {
607 (None, None) => Duration::ZERO,
608 (Some(t), None) | (None, Some(t)) => t.duration_since(now),
609 (Some(t1), Some(t2)) if t1 < t2 => t2.duration_since(t1),
610 (Some(t1), Some(t2)) => t1.duration_since(t2),
611 };
612
613 delta <= Self::EQUAL_THRESHOLD
614 }
615}
616
617#[derive(Default, Debug)]
619pub struct RecoveryStats {
620 startup_exit: Option<StartupExit>,
621}
622
623impl RecoveryStats {
624 pub fn set_startup_exit(&mut self, startup_exit: StartupExit) {
626 if self.startup_exit.is_none() {
627 self.startup_exit = Some(startup_exit);
628 }
629 }
630}
631
632#[derive(Debug, Clone, Copy, PartialEq)]
634pub struct StartupExit {
635 pub cwnd: usize,
637
638 pub reason: StartupExitReason,
640}
641
642impl StartupExit {
643 fn new(cwnd: usize, reason: StartupExitReason) -> Self {
644 Self { cwnd, reason }
645 }
646}
647
648#[derive(Debug, Clone, Copy, PartialEq)]
650pub enum StartupExitReason {
651 Loss,
653
654 BandwidthPlateau,
656
657 PersistentQueue,
659}
660
661#[cfg(test)]
662mod tests {
663 use super::*;
664 use crate::packet;
665 use crate::ranges;
666 use crate::recovery::congestion::PACING_MULTIPLIER;
667 use crate::testing;
668 use crate::CongestionControlAlgorithm;
669 use rstest::rstest;
670 use smallvec::smallvec;
671 use std::str::FromStr;
672
673 fn recovery_for_alg(algo: CongestionControlAlgorithm) -> Recovery {
674 let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
675 cfg.set_cc_algorithm(algo);
676 Recovery::new(&cfg)
677 }
678
679 #[test]
680 fn lookup_cc_algo_ok() {
681 let algo = CongestionControlAlgorithm::from_str("reno").unwrap();
682 assert_eq!(algo, CongestionControlAlgorithm::Reno);
683 assert!(!recovery_for_alg(algo).gcongestion_enabled());
684
685 let algo = CongestionControlAlgorithm::from_str("cubic").unwrap();
686 assert_eq!(algo, CongestionControlAlgorithm::CUBIC);
687 assert!(!recovery_for_alg(algo).gcongestion_enabled());
688
689 let algo = CongestionControlAlgorithm::from_str("bbr").unwrap();
690 assert_eq!(algo, CongestionControlAlgorithm::BBR);
691 assert!(!recovery_for_alg(algo).gcongestion_enabled());
692
693 let algo = CongestionControlAlgorithm::from_str("bbr2").unwrap();
694 #[cfg(not(feature = "gcongestion"))]
695 {
696 assert_eq!(algo, CongestionControlAlgorithm::BBR2);
697 assert!(!recovery_for_alg(algo).gcongestion_enabled());
698 }
699 #[cfg(feature = "gcongestion")]
700 {
701 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
702 assert!(recovery_for_alg(algo).gcongestion_enabled());
703 }
704
705 let algo =
706 CongestionControlAlgorithm::from_str("bbr2_gcongestion").unwrap();
707 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
708 assert!(recovery_for_alg(algo).gcongestion_enabled());
709 }
710
711 #[test]
712 fn lookup_cc_algo_bad() {
713 assert_eq!(
714 CongestionControlAlgorithm::from_str("???"),
715 Err(crate::Error::CongestionControl)
716 );
717 }
718
719 #[rstest]
720 fn loss_on_pto(
721 #[values("reno", "cubic", "bbr", "bbr2", "bbr2_gcongestion")]
722 cc_algorithm_name: &str,
723 ) {
724 let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
725 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
726
727 let mut r = Recovery::new(&cfg);
728
729 let mut now = Instant::now();
730
731 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
732
733 let p = Sent {
735 pkt_num: 0,
736 frames: smallvec![],
737 time_sent: now,
738 time_acked: None,
739 time_lost: None,
740 size: 1000,
741 ack_eliciting: true,
742 in_flight: true,
743 delivered: 0,
744 delivered_time: now,
745 first_sent_time: now,
746 is_app_limited: false,
747 tx_in_flight: 0,
748 lost: 0,
749 has_data: false,
750 is_pmtud_probe: false,
751 };
752
753 r.on_packet_sent(
754 p,
755 packet::Epoch::Application,
756 HandshakeStatus::default(),
757 now,
758 "",
759 );
760
761 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
762 assert_eq!(r.bytes_in_flight(), 1000);
763 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
764
765 let p = Sent {
766 pkt_num: 1,
767 frames: smallvec![],
768 time_sent: now,
769 time_acked: None,
770 time_lost: None,
771 size: 1000,
772 ack_eliciting: true,
773 in_flight: true,
774 delivered: 0,
775 delivered_time: now,
776 first_sent_time: now,
777 is_app_limited: false,
778 tx_in_flight: 0,
779 lost: 0,
780 has_data: false,
781 is_pmtud_probe: false,
782 };
783
784 r.on_packet_sent(
785 p,
786 packet::Epoch::Application,
787 HandshakeStatus::default(),
788 now,
789 "",
790 );
791
792 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
793 assert_eq!(r.bytes_in_flight(), 2000);
794 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
795
796 let p = Sent {
797 pkt_num: 2,
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 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
823 assert_eq!(r.bytes_in_flight(), 3000);
824 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
825
826 let p = Sent {
827 pkt_num: 3,
828 frames: smallvec![],
829 time_sent: now,
830 time_acked: None,
831 time_lost: None,
832 size: 1000,
833 ack_eliciting: true,
834 in_flight: true,
835 delivered: 0,
836 delivered_time: now,
837 first_sent_time: now,
838 is_app_limited: false,
839 tx_in_flight: 0,
840 lost: 0,
841 has_data: false,
842 is_pmtud_probe: false,
843 };
844
845 r.on_packet_sent(
846 p,
847 packet::Epoch::Application,
848 HandshakeStatus::default(),
849 now,
850 "",
851 );
852 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
853 assert_eq!(r.bytes_in_flight(), 4000);
854 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
855
856 now += Duration::from_millis(10);
858
859 let mut acked = ranges::RangeSet::default();
861 acked.insert(0..2);
862
863 assert_eq!(
864 r.on_ack_received(
865 &acked,
866 25,
867 packet::Epoch::Application,
868 HandshakeStatus::default(),
869 now,
870 None,
871 "",
872 )
873 .unwrap(),
874 OnAckReceivedOutcome {
875 lost_packets: 0,
876 lost_bytes: 0,
877 acked_bytes: 2 * 1000,
878 spurious_losses: 0,
879 }
880 );
881
882 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
883 assert_eq!(r.bytes_in_flight(), 2000);
884 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
885 assert_eq!(r.lost_count(), 0);
886
887 now = r.loss_detection_timer().unwrap();
889
890 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
892 assert_eq!(r.loss_probes(packet::Epoch::Application), 1);
893 assert_eq!(r.lost_count(), 0);
894 assert_eq!(r.pto_count(), 1);
895
896 let p = Sent {
897 pkt_num: 4,
898 frames: smallvec![],
899 time_sent: now,
900 time_acked: None,
901 time_lost: None,
902 size: 1000,
903 ack_eliciting: true,
904 in_flight: true,
905 delivered: 0,
906 delivered_time: now,
907 first_sent_time: now,
908 is_app_limited: false,
909 tx_in_flight: 0,
910 lost: 0,
911 has_data: false,
912 is_pmtud_probe: false,
913 };
914
915 r.on_packet_sent(
916 p,
917 packet::Epoch::Application,
918 HandshakeStatus::default(),
919 now,
920 "",
921 );
922 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
923 assert_eq!(r.bytes_in_flight(), 3000);
924 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(30));
925
926 let p = Sent {
927 pkt_num: 5,
928 frames: smallvec![],
929 time_sent: now,
930 time_acked: None,
931 time_lost: None,
932 size: 1000,
933 ack_eliciting: true,
934 in_flight: true,
935 delivered: 0,
936 delivered_time: now,
937 first_sent_time: now,
938 is_app_limited: false,
939 tx_in_flight: 0,
940 lost: 0,
941 has_data: false,
942 is_pmtud_probe: false,
943 };
944
945 r.on_packet_sent(
946 p,
947 packet::Epoch::Application,
948 HandshakeStatus::default(),
949 now,
950 "",
951 );
952 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
953 assert_eq!(r.bytes_in_flight(), 4000);
954 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(30));
955 assert_eq!(r.lost_count(), 0);
956
957 now += Duration::from_millis(10);
959
960 let mut acked = ranges::RangeSet::default();
962 acked.insert(4..6);
963
964 assert_eq!(
965 r.on_ack_received(
966 &acked,
967 25,
968 packet::Epoch::Application,
969 HandshakeStatus::default(),
970 now,
971 None,
972 "",
973 )
974 .unwrap(),
975 OnAckReceivedOutcome {
976 lost_packets: 2,
977 lost_bytes: 2000,
978 acked_bytes: 2 * 1000,
979 spurious_losses: 0,
980 }
981 );
982
983 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
984 assert_eq!(r.bytes_in_flight(), 0);
985 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(40));
986
987 assert_eq!(r.lost_count(), 2);
988
989 now += r.rtt();
991
992 assert_eq!(
993 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
994 (0, 0)
995 );
996
997 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
998 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
999 assert!(r.startup_exit().is_some());
1000 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1001 } else {
1002 assert_eq!(r.startup_exit(), None);
1003 }
1004 }
1005
1006 #[rstest]
1007 fn loss_on_timer(
1008 #[values("reno", "cubic", "bbr", "bbr2", "bbr2_gcongestion")]
1009 cc_algorithm_name: &str,
1010 ) {
1011 let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
1012 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1013
1014 let mut r = Recovery::new(&cfg);
1015
1016 let mut now = Instant::now();
1017
1018 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1019
1020 let p = Sent {
1022 pkt_num: 0,
1023 frames: smallvec![],
1024 time_sent: now,
1025 time_acked: None,
1026 time_lost: None,
1027 size: 1000,
1028 ack_eliciting: true,
1029 in_flight: true,
1030 delivered: 0,
1031 delivered_time: now,
1032 first_sent_time: now,
1033 is_app_limited: false,
1034 tx_in_flight: 0,
1035 lost: 0,
1036 has_data: false,
1037 is_pmtud_probe: false,
1038 };
1039
1040 r.on_packet_sent(
1041 p,
1042 packet::Epoch::Application,
1043 HandshakeStatus::default(),
1044 now,
1045 "",
1046 );
1047 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1048 assert_eq!(r.bytes_in_flight(), 1000);
1049 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1050
1051 let p = Sent {
1052 pkt_num: 1,
1053 frames: smallvec![],
1054 time_sent: now,
1055 time_acked: None,
1056 time_lost: None,
1057 size: 1000,
1058 ack_eliciting: true,
1059 in_flight: true,
1060 delivered: 0,
1061 delivered_time: now,
1062 first_sent_time: now,
1063 is_app_limited: false,
1064 tx_in_flight: 0,
1065 lost: 0,
1066 has_data: false,
1067 is_pmtud_probe: false,
1068 };
1069
1070 r.on_packet_sent(
1071 p,
1072 packet::Epoch::Application,
1073 HandshakeStatus::default(),
1074 now,
1075 "",
1076 );
1077 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1078 assert_eq!(r.bytes_in_flight(), 2000);
1079 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1080
1081 let p = Sent {
1082 pkt_num: 2,
1083 frames: smallvec![],
1084 time_sent: now,
1085 time_acked: None,
1086 time_lost: None,
1087 size: 1000,
1088 ack_eliciting: true,
1089 in_flight: true,
1090 delivered: 0,
1091 delivered_time: now,
1092 first_sent_time: now,
1093 is_app_limited: false,
1094 tx_in_flight: 0,
1095 lost: 0,
1096 has_data: false,
1097 is_pmtud_probe: false,
1098 };
1099
1100 r.on_packet_sent(
1101 p,
1102 packet::Epoch::Application,
1103 HandshakeStatus::default(),
1104 now,
1105 "",
1106 );
1107 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1108 assert_eq!(r.bytes_in_flight(), 3000);
1109 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1110
1111 let p = Sent {
1112 pkt_num: 3,
1113 frames: smallvec![],
1114 time_sent: now,
1115 time_acked: None,
1116 time_lost: None,
1117 size: 1000,
1118 ack_eliciting: true,
1119 in_flight: true,
1120 delivered: 0,
1121 delivered_time: now,
1122 first_sent_time: now,
1123 is_app_limited: false,
1124 tx_in_flight: 0,
1125 lost: 0,
1126 has_data: false,
1127 is_pmtud_probe: false,
1128 };
1129
1130 r.on_packet_sent(
1131 p,
1132 packet::Epoch::Application,
1133 HandshakeStatus::default(),
1134 now,
1135 "",
1136 );
1137 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1138 assert_eq!(r.bytes_in_flight(), 4000);
1139 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1140
1141 now += Duration::from_millis(10);
1143
1144 let mut acked = ranges::RangeSet::default();
1146 acked.insert(0..2);
1147 acked.insert(3..4);
1148
1149 assert_eq!(
1150 r.on_ack_received(
1151 &acked,
1152 25,
1153 packet::Epoch::Application,
1154 HandshakeStatus::default(),
1155 now,
1156 None,
1157 "",
1158 )
1159 .unwrap(),
1160 OnAckReceivedOutcome {
1161 lost_packets: 0,
1162 lost_bytes: 0,
1163 acked_bytes: 3 * 1000,
1164 spurious_losses: 0,
1165 }
1166 );
1167
1168 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1169 assert_eq!(r.bytes_in_flight(), 1000);
1170 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
1171 assert_eq!(r.lost_count(), 0);
1172
1173 now = r.loss_detection_timer().unwrap();
1175
1176 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
1178 assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
1179
1180 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1181 assert_eq!(r.bytes_in_flight(), 0);
1182 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
1183
1184 assert_eq!(r.lost_count(), 1);
1185
1186 now += r.rtt();
1188
1189 assert_eq!(
1190 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1191 (0, 0)
1192 );
1193
1194 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1195 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1196 assert!(r.startup_exit().is_some());
1197 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1198 } else {
1199 assert_eq!(r.startup_exit(), None);
1200 }
1201 }
1202
1203 #[rstest]
1204 fn loss_on_reordering(
1205 #[values("reno", "cubic", "bbr", "bbr2", "bbr2_gcongestion")]
1206 cc_algorithm_name: &str,
1207 ) {
1208 let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
1209 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1210
1211 let mut r = Recovery::new(&cfg);
1212
1213 let mut now = Instant::now();
1214
1215 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1216
1217 let p = Sent {
1219 pkt_num: 0,
1220 frames: smallvec![],
1221 time_sent: now,
1222 time_acked: None,
1223 time_lost: None,
1224 size: 1000,
1225 ack_eliciting: true,
1226 in_flight: true,
1227 delivered: 0,
1228 delivered_time: now,
1229 first_sent_time: now,
1230 is_app_limited: false,
1231 tx_in_flight: 0,
1232 lost: 0,
1233 has_data: false,
1234 is_pmtud_probe: false,
1235 };
1236
1237 r.on_packet_sent(
1238 p,
1239 packet::Epoch::Application,
1240 HandshakeStatus::default(),
1241 now,
1242 "",
1243 );
1244 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1245 assert_eq!(r.bytes_in_flight(), 1000);
1246 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1247
1248 let p = Sent {
1249 pkt_num: 1,
1250 frames: smallvec![],
1251 time_sent: now,
1252 time_acked: None,
1253 time_lost: None,
1254 size: 1000,
1255 ack_eliciting: true,
1256 in_flight: true,
1257 delivered: 0,
1258 delivered_time: now,
1259 first_sent_time: now,
1260 is_app_limited: false,
1261 tx_in_flight: 0,
1262 lost: 0,
1263 has_data: false,
1264 is_pmtud_probe: false,
1265 };
1266
1267 r.on_packet_sent(
1268 p,
1269 packet::Epoch::Application,
1270 HandshakeStatus::default(),
1271 now,
1272 "",
1273 );
1274 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1275 assert_eq!(r.bytes_in_flight(), 2000);
1276 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1277
1278 let p = Sent {
1279 pkt_num: 2,
1280 frames: smallvec![],
1281 time_sent: now,
1282 time_acked: None,
1283 time_lost: None,
1284 size: 1000,
1285 ack_eliciting: true,
1286 in_flight: true,
1287 delivered: 0,
1288 delivered_time: now,
1289 first_sent_time: now,
1290 is_app_limited: false,
1291 tx_in_flight: 0,
1292 lost: 0,
1293 has_data: false,
1294 is_pmtud_probe: false,
1295 };
1296
1297 r.on_packet_sent(
1298 p,
1299 packet::Epoch::Application,
1300 HandshakeStatus::default(),
1301 now,
1302 "",
1303 );
1304 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1305 assert_eq!(r.bytes_in_flight(), 3000);
1306 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1307
1308 let p = Sent {
1309 pkt_num: 3,
1310 frames: smallvec![],
1311 time_sent: now,
1312 time_acked: None,
1313 time_lost: None,
1314 size: 1000,
1315 ack_eliciting: true,
1316 in_flight: true,
1317 delivered: 0,
1318 delivered_time: now,
1319 first_sent_time: now,
1320 is_app_limited: false,
1321 tx_in_flight: 0,
1322 lost: 0,
1323 has_data: false,
1324 is_pmtud_probe: false,
1325 };
1326
1327 r.on_packet_sent(
1328 p,
1329 packet::Epoch::Application,
1330 HandshakeStatus::default(),
1331 now,
1332 "",
1333 );
1334 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1335 assert_eq!(r.bytes_in_flight(), 4000);
1336 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1337
1338 now += Duration::from_millis(10);
1340
1341 let mut acked = ranges::RangeSet::default();
1343 acked.insert(2..4);
1344
1345 assert_eq!(
1346 r.on_ack_received(
1347 &acked,
1348 25,
1349 packet::Epoch::Application,
1350 HandshakeStatus::default(),
1351 now,
1352 None,
1353 "",
1354 )
1355 .unwrap(),
1356 OnAckReceivedOutcome {
1357 lost_packets: 1,
1358 lost_bytes: 1000,
1359 acked_bytes: 1000 * 2,
1360 spurious_losses: 0,
1361 }
1362 );
1363
1364 now += Duration::from_millis(10);
1365
1366 let mut acked = ranges::RangeSet::default();
1367 acked.insert(0..2);
1368
1369 assert_eq!(r.pkt_thresh(), INITIAL_PACKET_THRESHOLD);
1370
1371 assert_eq!(
1372 r.on_ack_received(
1373 &acked,
1374 25,
1375 packet::Epoch::Application,
1376 HandshakeStatus::default(),
1377 now,
1378 None,
1379 "",
1380 )
1381 .unwrap(),
1382 OnAckReceivedOutcome {
1383 lost_packets: 0,
1384 lost_bytes: 0,
1385 acked_bytes: 1000,
1386 spurious_losses: 1,
1387 }
1388 );
1389
1390 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1391 assert_eq!(r.bytes_in_flight(), 0);
1392 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(20));
1393
1394 assert_eq!(r.lost_count(), 1);
1396 assert_eq!(r.lost_spurious_count(), 1);
1397
1398 assert_eq!(r.pkt_thresh(), 4);
1400
1401 now += r.rtt();
1403
1404 assert_eq!(
1405 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1406 (0, 0)
1407 );
1408
1409 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1410 if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1411 assert!(r.startup_exit().is_some());
1412 assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1413 } else {
1414 assert_eq!(r.startup_exit(), None);
1415 }
1416 }
1417
1418 #[rstest]
1419 fn pacing(
1420 #[values("reno", "cubic", "bbr", "bbr2", "bbr2_gcongestion")]
1421 cc_algorithm_name: &str,
1422 ) {
1423 let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
1424 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1425
1426 let mut r = Recovery::new(&cfg);
1427
1428 let mut now = Instant::now();
1429
1430 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1431
1432 for i in 0..10 {
1434 let p = Sent {
1435 pkt_num: i,
1436 frames: smallvec![],
1437 time_sent: now,
1438 time_acked: None,
1439 time_lost: None,
1440 size: 1200,
1441 ack_eliciting: true,
1442 in_flight: true,
1443 delivered: 0,
1444 delivered_time: now,
1445 first_sent_time: now,
1446 is_app_limited: false,
1447 tx_in_flight: 0,
1448 lost: 0,
1449 has_data: true,
1450 is_pmtud_probe: false,
1451 };
1452
1453 r.on_packet_sent(
1454 p,
1455 packet::Epoch::Application,
1456 HandshakeStatus::default(),
1457 now,
1458 "",
1459 );
1460 }
1461
1462 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 10);
1463 assert_eq!(r.bytes_in_flight(), 12000);
1464 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1465
1466 if cc_algorithm_name != "bbr2_gcongestion" {
1468 assert_eq!(r.pacing_rate(), 0);
1469 } else {
1470 assert_eq!(r.pacing_rate(), 103963);
1471 }
1472 assert_eq!(r.get_packet_send_time(now), now);
1473
1474 assert_eq!(r.cwnd(), 12000);
1475 assert_eq!(r.cwnd_available(), 0);
1476
1477 now += Duration::from_millis(50);
1479
1480 let mut acked = ranges::RangeSet::default();
1481 acked.insert(0..10);
1482
1483 assert_eq!(
1484 r.on_ack_received(
1485 &acked,
1486 10,
1487 packet::Epoch::Application,
1488 HandshakeStatus::default(),
1489 now,
1490 None,
1491 "",
1492 )
1493 .unwrap(),
1494 OnAckReceivedOutcome {
1495 lost_packets: 0,
1496 lost_bytes: 0,
1497 acked_bytes: 12000,
1498 spurious_losses: 0,
1499 }
1500 );
1501
1502 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1503 assert_eq!(r.bytes_in_flight(), 0);
1504 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(50));
1505 assert_eq!(r.rtt(), Duration::from_millis(50));
1506
1507 assert_eq!(r.cwnd(), 12000 + 1200 * 10);
1509
1510 let p = Sent {
1512 pkt_num: 10,
1513 frames: smallvec![],
1514 time_sent: now,
1515 time_acked: None,
1516 time_lost: None,
1517 size: 6000,
1518 ack_eliciting: true,
1519 in_flight: true,
1520 delivered: 0,
1521 delivered_time: now,
1522 first_sent_time: now,
1523 is_app_limited: false,
1524 tx_in_flight: 0,
1525 lost: 0,
1526 has_data: true,
1527 is_pmtud_probe: false,
1528 };
1529
1530 r.on_packet_sent(
1531 p,
1532 packet::Epoch::Application,
1533 HandshakeStatus::default(),
1534 now,
1535 "",
1536 );
1537
1538 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1539 assert_eq!(r.bytes_in_flight(), 6000);
1540 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(50));
1541
1542 if cc_algorithm_name != "bbr2_gcongestion" {
1543 assert_eq!(r.get_packet_send_time(now), now);
1545 } else {
1546 assert_ne!(r.get_packet_send_time(now), now);
1548 }
1549
1550 let p = Sent {
1552 pkt_num: 11,
1553 frames: smallvec![],
1554 time_sent: now,
1555 time_acked: None,
1556 time_lost: None,
1557 size: 6000,
1558 ack_eliciting: true,
1559 in_flight: true,
1560 delivered: 0,
1561 delivered_time: now,
1562 first_sent_time: now,
1563 is_app_limited: false,
1564 tx_in_flight: 0,
1565 lost: 0,
1566 has_data: true,
1567 is_pmtud_probe: false,
1568 };
1569
1570 r.on_packet_sent(
1571 p,
1572 packet::Epoch::Application,
1573 HandshakeStatus::default(),
1574 now,
1575 "",
1576 );
1577
1578 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1579 assert_eq!(r.bytes_in_flight(), 12000);
1580 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(50));
1581
1582 let p = Sent {
1584 pkt_num: 12,
1585 frames: smallvec![],
1586 time_sent: now,
1587 time_acked: None,
1588 time_lost: None,
1589 size: 1000,
1590 ack_eliciting: true,
1591 in_flight: true,
1592 delivered: 0,
1593 delivered_time: now,
1594 first_sent_time: now,
1595 is_app_limited: false,
1596 tx_in_flight: 0,
1597 lost: 0,
1598 has_data: true,
1599 is_pmtud_probe: false,
1600 };
1601
1602 r.on_packet_sent(
1603 p,
1604 packet::Epoch::Application,
1605 HandshakeStatus::default(),
1606 now,
1607 "",
1608 );
1609
1610 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1611 assert_eq!(r.bytes_in_flight(), 13000);
1612 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(50));
1613
1614 let pacing_rate = match cc_algorithm_name {
1617 "bbr" => {
1618 let cwnd_gain = 2.0;
1620 let startup_pacing_gain = 2.89;
1621 let bw = r.cwnd() as f64 /
1624 cwnd_gain /
1625 Duration::from_millis(50).as_secs_f64();
1626 (bw * startup_pacing_gain) as u64
1627 },
1628 "bbr2_gcongestion" => {
1629 let cwnd_gain: f64 = 2.0;
1630 let bw = r.cwnd() as f64 /
1633 cwnd_gain /
1634 Duration::from_millis(50).as_secs_f64();
1635 bw as u64
1636 },
1637 "bbr2" => {
1638 let cwnd_gain = 2.0;
1640 let startup_pacing_gain = 2.77;
1641 let pacing_margin_percent = 0.01;
1642 let bw = r.cwnd() as f64 /
1645 cwnd_gain /
1646 Duration::from_millis(50).as_secs_f64();
1647 (bw * startup_pacing_gain * (1.0 - pacing_margin_percent)) as u64
1648 },
1649 _ => {
1650 let bw =
1651 r.cwnd() as f64 / Duration::from_millis(50).as_secs_f64();
1652 (bw * PACING_MULTIPLIER) as u64
1653 },
1654 };
1655 assert_eq!(r.pacing_rate(), pacing_rate);
1656
1657 let scale_factor = if cc_algorithm_name == "bbr2_gcongestion" {
1658 1.08333332
1661 } else {
1662 1.0
1663 };
1664 assert_eq!(
1665 r.get_packet_send_time(now) - now,
1666 Duration::from_secs_f64(scale_factor * 12000.0 / pacing_rate as f64)
1667 );
1668 assert_eq!(r.startup_exit(), None);
1669 }
1670
1671 #[rstest]
1672 fn validate_ack_range_on_ack_received(
1673 #[values("cubic", "bbr2", "bbr2_gcongestion")] cc_algorithm_name: &str,
1674 ) {
1675 let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
1676 cfg.set_cc_algorithm_name(cc_algorithm_name).unwrap();
1677
1678 let epoch = packet::Epoch::Application;
1679 let mut r = Recovery::new(&cfg);
1680 let mut now = Instant::now();
1681 assert_eq!(r.sent_packets_len(epoch), 0);
1682
1683 let pkt_size = 1000;
1685 let pkt_count = 4;
1686 for pkt_num in 0..pkt_count {
1687 let sent = crate::testing::helper_packet_sent(pkt_num, now, pkt_size);
1688 r.on_packet_sent(sent, epoch, HandshakeStatus::default(), now, "");
1689 }
1690 assert_eq!(r.sent_packets_len(epoch), pkt_count as usize);
1691 assert_eq!(r.bytes_in_flight(), pkt_count as usize * pkt_size);
1692 assert!(r.get_largest_acked_on_epoch(epoch).is_none());
1693 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
1694
1695 now += Duration::from_millis(10);
1697
1698 let mut acked = ranges::RangeSet::default();
1700 acked.insert(0..2);
1701
1702 assert_eq!(
1703 r.on_ack_received(
1704 &acked,
1705 25,
1706 epoch,
1707 HandshakeStatus::default(),
1708 now,
1709 None,
1710 "",
1711 )
1712 .unwrap(),
1713 OnAckReceivedOutcome {
1714 lost_packets: 0,
1715 lost_bytes: 0,
1716 acked_bytes: 2 * 1000,
1717 spurious_losses: 0,
1718 }
1719 );
1720
1721 assert_eq!(r.sent_packets_len(epoch), 2);
1722 assert_eq!(r.bytes_in_flight(), 2 * 1000);
1723
1724 assert_eq!(r.get_largest_acked_on_epoch(epoch).unwrap(), 1);
1725 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
1726
1727 let mut acked = ranges::RangeSet::default();
1729 acked.insert(0..10);
1730 assert_eq!(
1731 r.on_ack_received(
1732 &acked,
1733 25,
1734 epoch,
1735 HandshakeStatus::default(),
1736 now,
1737 None,
1738 "",
1739 )
1740 .unwrap(),
1741 OnAckReceivedOutcome {
1742 lost_packets: 0,
1743 lost_bytes: 0,
1744 acked_bytes: 2 * 1000,
1745 spurious_losses: 0,
1746 }
1747 );
1748 assert_eq!(r.sent_packets_len(epoch), 0);
1749 assert_eq!(r.bytes_in_flight(), 0);
1750
1751 assert_eq!(r.get_largest_acked_on_epoch(epoch).unwrap(), 3);
1752 assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
1753 }
1754
1755 #[rstest]
1756 fn pmtud_loss_on_timer(
1757 #[values("reno", "cubic", "bbr", "bbr2", "bbr2_gcongestion")]
1758 cc_algorithm_name: &str,
1759 ) {
1760 let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
1761 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1762
1763 let mut r = Recovery::new(&cfg);
1764 assert_eq!(r.cwnd(), 12000);
1765
1766 let mut now = Instant::now();
1767
1768 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1769
1770 let p = Sent {
1772 pkt_num: 0,
1773 frames: smallvec![],
1774 time_sent: now,
1775 time_acked: None,
1776 time_lost: None,
1777 size: 1000,
1778 ack_eliciting: true,
1779 in_flight: true,
1780 delivered: 0,
1781 delivered_time: now,
1782 first_sent_time: now,
1783 is_app_limited: false,
1784 tx_in_flight: 0,
1785 lost: 0,
1786 has_data: false,
1787 is_pmtud_probe: false,
1788 };
1789
1790 r.on_packet_sent(
1791 p,
1792 packet::Epoch::Application,
1793 HandshakeStatus::default(),
1794 now,
1795 "",
1796 );
1797
1798 assert_eq!(r.in_flight_count(packet::Epoch::Application), 1);
1799 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1800 assert_eq!(r.bytes_in_flight(), 1000);
1801 assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1802
1803 let p = Sent {
1804 pkt_num: 1,
1805 frames: smallvec![],
1806 time_sent: now,
1807 time_acked: None,
1808 time_lost: None,
1809 size: 1000,
1810 ack_eliciting: true,
1811 in_flight: true,
1812 delivered: 0,
1813 delivered_time: now,
1814 first_sent_time: now,
1815 is_app_limited: false,
1816 tx_in_flight: 0,
1817 lost: 0,
1818 has_data: false,
1819 is_pmtud_probe: true,
1820 };
1821
1822 r.on_packet_sent(
1823 p,
1824 packet::Epoch::Application,
1825 HandshakeStatus::default(),
1826 now,
1827 "",
1828 );
1829
1830 assert_eq!(r.in_flight_count(packet::Epoch::Application), 2);
1831
1832 let p = Sent {
1833 pkt_num: 2,
1834 frames: smallvec![],
1835 time_sent: now,
1836 time_acked: None,
1837 time_lost: None,
1838 size: 1000,
1839 ack_eliciting: true,
1840 in_flight: true,
1841 delivered: 0,
1842 delivered_time: now,
1843 first_sent_time: now,
1844 is_app_limited: false,
1845 tx_in_flight: 0,
1846 lost: 0,
1847 has_data: false,
1848 is_pmtud_probe: false,
1849 };
1850
1851 r.on_packet_sent(
1852 p,
1853 packet::Epoch::Application,
1854 HandshakeStatus::default(),
1855 now,
1856 "",
1857 );
1858
1859 assert_eq!(r.in_flight_count(packet::Epoch::Application), 3);
1860
1861 now += Duration::from_millis(10);
1863
1864 let mut acked = ranges::RangeSet::default();
1866 acked.insert(0..1);
1867 acked.insert(2..3);
1868
1869 assert_eq!(
1870 r.on_ack_received(
1871 &acked,
1872 25,
1873 packet::Epoch::Application,
1874 HandshakeStatus::default(),
1875 now,
1876 None,
1877 "",
1878 )
1879 .unwrap(),
1880 OnAckReceivedOutcome {
1881 lost_packets: 0,
1882 lost_bytes: 0,
1883 acked_bytes: 2 * 1000,
1884 spurious_losses: 0,
1885 }
1886 );
1887
1888 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1889 assert_eq!(r.bytes_in_flight(), 1000);
1890 assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
1891 assert_eq!(r.lost_count(), 0);
1892
1893 now = r.loss_detection_timer().unwrap();
1895
1896 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
1898 assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
1899
1900 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1901 assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
1902 assert_eq!(r.bytes_in_flight(), 0);
1903 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
1904 assert_eq!(r.cwnd(), match cc_algorithm_name {
1905 "bbr" => 14000,
1906 "bbr2" => 14000,
1907 _ => 12000,
1908 });
1909
1910 assert_eq!(r.lost_count(), 0);
1911
1912 now += r.rtt();
1914
1915 assert_eq!(
1916 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1917 (0, 0)
1918 );
1919
1920 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1921 assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
1922 assert_eq!(r.bytes_in_flight(), 0);
1923 assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
1924 assert_eq!(r.lost_count(), 0);
1925 assert_eq!(r.startup_exit(), None);
1926 }
1927
1928 #[rstest]
1931 fn congestion_delivery_rate(
1932 #[values("reno", "cubic", "bbr", "bbr2")] cc_algorithm_name: &str,
1933 ) {
1934 let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
1935 assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1936
1937 let mut r = Recovery::new(&cfg);
1938 assert_eq!(r.cwnd(), 12000);
1939
1940 let now = Instant::now();
1941
1942 let mut total_bytes_sent = 0;
1943 for pn in 0..10 {
1944 let bytes = 1000;
1946 let sent = testing::helper_packet_sent(pn, now, bytes);
1947 r.on_packet_sent(
1948 sent,
1949 packet::Epoch::Application,
1950 HandshakeStatus::default(),
1951 now,
1952 "",
1953 );
1954
1955 total_bytes_sent += bytes;
1956 }
1957
1958 let interval = Duration::from_secs(10);
1960 let mut acked = ranges::RangeSet::default();
1961 acked.insert(0..10);
1962 assert_eq!(
1963 r.on_ack_received(
1964 &acked,
1965 25,
1966 packet::Epoch::Application,
1967 HandshakeStatus::default(),
1968 now + interval,
1969 None,
1970 "",
1971 )
1972 .unwrap(),
1973 OnAckReceivedOutcome {
1974 lost_packets: 0,
1975 lost_bytes: 0,
1976 acked_bytes: total_bytes_sent,
1977 spurious_losses: 0,
1978 }
1979 );
1980 assert_eq!(r.delivery_rate().to_bytes_per_second(), 1000);
1981 assert_eq!(r.min_rtt().unwrap(), interval);
1982 assert_eq!(
1984 total_bytes_sent as u64 / interval.as_secs(),
1985 r.delivery_rate().to_bytes_per_second()
1986 );
1987 assert_eq!(r.startup_exit(), None);
1988 }
1989}
1990
1991mod bandwidth;
1992mod bytes_in_flight;
1993mod congestion;
1994mod gcongestion;
1995mod rtt;