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::Config;
35
36#[cfg(feature = "qlog")]
37use qlog::events::EventData;
38
39use smallvec::SmallVec;
40
41use self::congestion::recovery::LegacyRecovery;
42use self::gcongestion::GRecovery;
43pub use gcongestion::BbrBwLoReductionStrategy;
44pub use gcongestion::BbrParams;
45
46const INITIAL_PACKET_THRESHOLD: u64 = 3;
48
49const MAX_PACKET_THRESHOLD: u64 = 20;
50
51const INITIAL_TIME_THRESHOLD: f64 = 9.0 / 8.0;
52
53const GRANULARITY: Duration = Duration::from_millis(1);
54
55const MAX_PTO_PROBES_COUNT: usize = 2;
56
57const MINIMUM_WINDOW_PACKETS: usize = 2;
58
59const LOSS_REDUCTION_FACTOR: f64 = 0.5;
60
61pub(super) const MAX_OUTSTANDING_NON_ACK_ELICITING: usize = 24;
64
65#[derive(Default)]
66struct LossDetectionTimer {
67 time: Option<Instant>,
68}
69
70impl LossDetectionTimer {
71 fn update(&mut self, timeout: Instant) {
72 self.time = Some(timeout);
73 }
74
75 fn clear(&mut self) {
76 self.time = None;
77 }
78}
79
80impl std::fmt::Debug for LossDetectionTimer {
81 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
82 match self.time {
83 Some(v) => {
84 let now = Instant::now();
85 if v > now {
86 let d = v.duration_since(now);
87 write!(f, "{d:?}")
88 } else {
89 write!(f, "exp")
90 }
91 },
92 None => write!(f, "none"),
93 }
94 }
95}
96
97#[derive(Clone, Copy, PartialEq)]
98pub struct RecoveryConfig {
99 pub max_send_udp_payload_size: usize,
100 pub max_ack_delay: Duration,
101 pub cc_algorithm: CongestionControlAlgorithm,
102 pub custom_bbr_params: Option<BbrParams>,
103 pub hystart: bool,
104 pub pacing: bool,
105 pub max_pacing_rate: Option<u64>,
106 pub initial_congestion_window_packets: usize,
107}
108
109impl RecoveryConfig {
110 pub fn from_config(config: &Config) -> Self {
111 Self {
112 max_send_udp_payload_size: config.max_send_udp_payload_size,
113 max_ack_delay: Duration::ZERO,
114 cc_algorithm: config.cc_algorithm,
115 custom_bbr_params: config.custom_bbr_params,
116 hystart: config.hystart,
117 pacing: config.pacing,
118 max_pacing_rate: config.max_pacing_rate,
119 initial_congestion_window_packets: config
120 .initial_congestion_window_packets,
121 }
122 }
123}
124
125#[enum_dispatch::enum_dispatch(RecoveryOps)]
126#[allow(clippy::large_enum_variant)]
127#[derive(Debug)]
128pub(crate) enum Recovery {
129 Legacy(LegacyRecovery),
130 GCongestion(GRecovery),
131}
132
133#[enum_dispatch::enum_dispatch]
134pub trait RecoveryOps {
136 fn lost_count(&self) -> usize;
137 fn bytes_lost(&self) -> u64;
138
139 fn should_elicit_ack(&self, epoch: packet::Epoch) -> bool;
142
143 fn get_acked_frames(&mut self, epoch: packet::Epoch) -> Vec<frame::Frame>;
144
145 fn get_lost_frames(&mut self, epoch: packet::Epoch) -> Vec<frame::Frame>;
146
147 fn get_largest_acked_on_epoch(&self, epoch: packet::Epoch) -> Option<u64>;
148 fn has_lost_frames(&self, epoch: packet::Epoch) -> bool;
149 fn loss_probes(&self, epoch: packet::Epoch) -> usize;
150 #[cfg(test)]
151 fn inc_loss_probes(&mut self, epoch: packet::Epoch);
152
153 fn ping_sent(&mut self, epoch: packet::Epoch);
154
155 fn on_packet_sent(
156 &mut self, pkt: Sent, epoch: packet::Epoch,
157 handshake_status: HandshakeStatus, now: Instant, trace_id: &str,
158 );
159 fn get_packet_send_time(&self) -> Instant;
160
161 fn on_ack_received(
162 &mut self, ranges: &RangeSet, ack_delay: u64, epoch: packet::Epoch,
163 handshake_status: HandshakeStatus, now: Instant, trace_id: &str,
164 ) -> (usize, usize, usize);
165
166 fn on_loss_detection_timeout(
167 &mut self, handshake_status: HandshakeStatus, now: Instant,
168 trace_id: &str,
169 ) -> (usize, usize);
170 fn on_pkt_num_space_discarded(
171 &mut self, epoch: packet::Epoch, handshake_status: HandshakeStatus,
172 now: Instant,
173 );
174 fn on_path_change(
175 &mut self, epoch: packet::Epoch, now: Instant, _trace_id: &str,
176 ) -> (usize, usize);
177 fn loss_detection_timer(&self) -> Option<Instant>;
178 fn cwnd(&self) -> usize;
179 fn cwnd_available(&self) -> usize;
180 fn rtt(&self) -> Duration;
181
182 fn min_rtt(&self) -> Option<Duration>;
183
184 fn rttvar(&self) -> Duration;
185
186 fn pto(&self) -> Duration;
187
188 fn delivery_rate(&self) -> u64;
189
190 fn max_datagram_size(&self) -> usize;
191
192 fn pmtud_update_max_datagram_size(&mut self, new_max_datagram_size: usize);
193
194 fn update_max_datagram_size(&mut self, new_max_datagram_size: usize);
195
196 fn on_app_limited(&mut self);
197
198 #[cfg(test)]
199 fn app_limited(&self) -> bool;
200
201 #[cfg(test)]
202 fn sent_packets_len(&self, epoch: packet::Epoch) -> usize;
203
204 #[cfg(test)]
205 fn bytes_in_flight(&self) -> usize;
206
207 #[cfg(test)]
208 fn in_flight_count(&self, epoch: packet::Epoch) -> usize;
209
210 #[cfg(test)]
211 fn pacing_rate(&self) -> u64;
212
213 #[cfg(test)]
214 fn pto_count(&self) -> u32;
215
216 #[cfg(test)]
217 fn pkt_thresh(&self) -> u64;
218
219 #[cfg(test)]
220 fn lost_spurious_count(&self) -> usize;
221
222 #[cfg(test)]
223 fn detect_lost_packets_for_test(
224 &mut self, epoch: packet::Epoch, now: Instant,
225 ) -> (usize, usize);
226
227 fn update_app_limited(&mut self, v: bool);
228
229 fn delivery_rate_update_app_limited(&mut self, v: bool);
230
231 fn update_max_ack_delay(&mut self, max_ack_delay: Duration);
232
233 #[cfg(feature = "qlog")]
234 fn maybe_qlog(&mut self) -> Option<EventData>;
235 fn send_quantum(&self) -> usize;
236
237 fn get_next_release_time(&self) -> ReleaseDecision;
238
239 fn gcongestion_enabled(&self) -> bool;
240}
241
242impl Recovery {
243 pub fn new_with_config(recovery_config: &RecoveryConfig) -> Self {
244 let grecovery = GRecovery::new(recovery_config);
245 if let Some(grecovery) = grecovery {
246 Recovery::from(grecovery)
247 } else {
248 Recovery::from(LegacyRecovery::new_with_config(recovery_config))
249 }
250 }
251
252 #[cfg(test)]
253 pub fn new(config: &crate::Config) -> Self {
254 Self::new_with_config(&RecoveryConfig::from_config(config))
255 }
256}
257
258#[derive(Debug, Copy, Clone, PartialEq, Eq)]
263#[repr(C)]
264pub enum CongestionControlAlgorithm {
265 Reno = 0,
267 CUBIC = 1,
269 BBR = 2,
271 BBR2 = 3,
273 Bbr2Gcongestion = 4,
276}
277
278impl FromStr for CongestionControlAlgorithm {
279 type Err = crate::Error;
280
281 fn from_str(name: &str) -> std::result::Result<Self, Self::Err> {
285 match name {
286 "reno" => Ok(CongestionControlAlgorithm::Reno),
287 "cubic" => Ok(CongestionControlAlgorithm::CUBIC),
288 "bbr" => Ok(CongestionControlAlgorithm::BBR),
289 #[cfg(not(feature = "gcongestion"))]
290 "bbr2" => Ok(CongestionControlAlgorithm::BBR2),
291 #[cfg(feature = "gcongestion")]
292 "bbr2" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
293 "bbr2_gcongestion" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
294 _ => Err(crate::Error::CongestionControl),
295 }
296 }
297}
298
299#[derive(Clone)]
300pub struct Sent {
301 pub pkt_num: u64,
302
303 pub frames: SmallVec<[frame::Frame; 1]>,
304
305 pub time_sent: Instant,
306
307 pub time_acked: Option<Instant>,
308
309 pub time_lost: Option<Instant>,
310
311 pub size: usize,
312
313 pub ack_eliciting: bool,
314
315 pub in_flight: bool,
316
317 pub delivered: usize,
318
319 pub delivered_time: Instant,
320
321 pub first_sent_time: Instant,
322
323 pub is_app_limited: bool,
324
325 pub tx_in_flight: usize,
326
327 pub lost: u64,
328
329 pub has_data: bool,
330
331 pub pmtud: bool,
332}
333
334impl std::fmt::Debug for Sent {
335 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
336 write!(f, "pkt_num={:?} ", self.pkt_num)?;
337 write!(f, "pkt_sent_time={:?} ", self.time_sent)?;
338 write!(f, "pkt_size={:?} ", self.size)?;
339 write!(f, "delivered={:?} ", self.delivered)?;
340 write!(f, "delivered_time={:?} ", self.delivered_time)?;
341 write!(f, "first_sent_time={:?} ", self.first_sent_time)?;
342 write!(f, "is_app_limited={} ", self.is_app_limited)?;
343 write!(f, "tx_in_flight={} ", self.tx_in_flight)?;
344 write!(f, "lost={} ", self.lost)?;
345 write!(f, "has_data={} ", self.has_data)?;
346 write!(f, "pmtud={}", self.pmtud)?;
347
348 Ok(())
349 }
350}
351
352#[derive(Clone, Copy, Debug)]
353pub struct HandshakeStatus {
354 pub has_handshake_keys: bool,
355
356 pub peer_verified_address: bool,
357
358 pub completed: bool,
359}
360
361#[cfg(test)]
362impl Default for HandshakeStatus {
363 fn default() -> HandshakeStatus {
364 HandshakeStatus {
365 has_handshake_keys: true,
366
367 peer_verified_address: true,
368
369 completed: true,
370 }
371 }
372}
373
374#[derive(Default)]
379#[cfg(feature = "qlog")]
380struct QlogMetrics {
381 min_rtt: Duration,
382 smoothed_rtt: Duration,
383 latest_rtt: Duration,
384 rttvar: Duration,
385 cwnd: u64,
386 bytes_in_flight: u64,
387 ssthresh: Option<u64>,
388 pacing_rate: u64,
389}
390
391#[cfg(feature = "qlog")]
392impl QlogMetrics {
393 fn maybe_update(&mut self, latest: Self) -> Option<EventData> {
399 let mut emit_event = false;
400
401 let new_min_rtt = if self.min_rtt != latest.min_rtt {
402 self.min_rtt = latest.min_rtt;
403 emit_event = true;
404 Some(latest.min_rtt.as_secs_f32() * 1000.0)
405 } else {
406 None
407 };
408
409 let new_smoothed_rtt = if self.smoothed_rtt != latest.smoothed_rtt {
410 self.smoothed_rtt = latest.smoothed_rtt;
411 emit_event = true;
412 Some(latest.smoothed_rtt.as_secs_f32() * 1000.0)
413 } else {
414 None
415 };
416
417 let new_latest_rtt = if self.latest_rtt != latest.latest_rtt {
418 self.latest_rtt = latest.latest_rtt;
419 emit_event = true;
420 Some(latest.latest_rtt.as_secs_f32() * 1000.0)
421 } else {
422 None
423 };
424
425 let new_rttvar = if self.rttvar != latest.rttvar {
426 self.rttvar = latest.rttvar;
427 emit_event = true;
428 Some(latest.rttvar.as_secs_f32() * 1000.0)
429 } else {
430 None
431 };
432
433 let new_cwnd = if self.cwnd != latest.cwnd {
434 self.cwnd = latest.cwnd;
435 emit_event = true;
436 Some(latest.cwnd)
437 } else {
438 None
439 };
440
441 let new_bytes_in_flight =
442 if self.bytes_in_flight != latest.bytes_in_flight {
443 self.bytes_in_flight = latest.bytes_in_flight;
444 emit_event = true;
445 Some(latest.bytes_in_flight)
446 } else {
447 None
448 };
449
450 let new_ssthresh = if self.ssthresh != latest.ssthresh {
451 self.ssthresh = latest.ssthresh;
452 emit_event = true;
453 latest.ssthresh
454 } else {
455 None
456 };
457
458 let new_pacing_rate = if self.pacing_rate != latest.pacing_rate {
459 self.pacing_rate = latest.pacing_rate;
460 emit_event = true;
461 Some(latest.pacing_rate)
462 } else {
463 None
464 };
465
466 if emit_event {
467 return Some(EventData::MetricsUpdated(
469 qlog::events::quic::MetricsUpdated {
470 min_rtt: new_min_rtt,
471 smoothed_rtt: new_smoothed_rtt,
472 latest_rtt: new_latest_rtt,
473 rtt_variance: new_rttvar,
474 congestion_window: new_cwnd,
475 bytes_in_flight: new_bytes_in_flight,
476 ssthresh: new_ssthresh,
477 pacing_rate: new_pacing_rate,
478 ..Default::default()
479 },
480 ));
481 }
482
483 None
484 }
485}
486
487#[derive(Debug, Clone, Copy, PartialEq, Eq)]
489pub enum ReleaseTime {
490 Immediate,
491 At(Instant),
492}
493
494#[derive(Clone, Copy, Debug, PartialEq, Eq)]
496pub struct ReleaseDecision {
497 time: ReleaseTime,
498 allow_burst: bool,
499}
500
501impl ReleaseTime {
502 #[allow(dead_code)]
504 fn inc(&mut self, delay: Duration) {
505 match self {
506 ReleaseTime::Immediate => {},
507 ReleaseTime::At(time) => *time += delay,
508 }
509 }
510
511 #[allow(dead_code)]
513 fn set_max(&mut self, other: Instant) {
514 match self {
515 ReleaseTime::Immediate => *self = ReleaseTime::At(other),
516 ReleaseTime::At(time) => *self = ReleaseTime::At(other.max(*time)),
517 }
518 }
519}
520
521impl ReleaseDecision {
522 pub(crate) const EQUAL_THRESHOLD: Duration = Duration::from_micros(50);
523
524 #[allow(dead_code)]
527 #[inline]
528 pub fn time(&self, now: Instant) -> Option<Instant> {
529 match self.time {
530 ReleaseTime::Immediate => None,
531 ReleaseTime::At(other) => other.gt(&now).then_some(other),
532 }
533 }
534
535 #[allow(dead_code)]
537 #[inline]
538 pub fn can_burst(&self) -> bool {
539 self.allow_burst
540 }
541
542 #[allow(dead_code)]
544 #[inline]
545 pub fn time_eq(&self, other: &Self, now: Instant) -> bool {
546 let delta = match (self.time(now), other.time(now)) {
547 (None, None) => Duration::ZERO,
548 (Some(t), None) | (None, Some(t)) => t.duration_since(now),
549 (Some(t1), Some(t2)) if t1 < t2 => t2.duration_since(t1),
550 (Some(t1), Some(t2)) => t1.duration_since(t2),
551 };
552
553 delta <= Self::EQUAL_THRESHOLD
554 }
555}
556
557#[cfg(test)]
558mod tests {
559 use super::*;
560 use crate::packet;
561 use crate::ranges;
562 use crate::recovery::congestion::PACING_MULTIPLIER;
563 use crate::CongestionControlAlgorithm;
564 use smallvec::smallvec;
565 use std::str::FromStr;
566
567 fn recovery_for_alg(algo: CongestionControlAlgorithm) -> Recovery {
568 let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
569 cfg.set_cc_algorithm(algo);
570 Recovery::new(&cfg)
571 }
572
573 #[test]
574 fn lookup_cc_algo_ok() {
575 let algo = CongestionControlAlgorithm::from_str("reno").unwrap();
576 assert_eq!(algo, CongestionControlAlgorithm::Reno);
577 assert!(!recovery_for_alg(algo).gcongestion_enabled());
578
579 let algo = CongestionControlAlgorithm::from_str("cubic").unwrap();
580 assert_eq!(algo, CongestionControlAlgorithm::CUBIC);
581 assert!(!recovery_for_alg(algo).gcongestion_enabled());
582
583 let algo = CongestionControlAlgorithm::from_str("bbr").unwrap();
584 assert_eq!(algo, CongestionControlAlgorithm::BBR);
585 assert!(!recovery_for_alg(algo).gcongestion_enabled());
586
587 let algo = CongestionControlAlgorithm::from_str("bbr2").unwrap();
588 #[cfg(not(feature = "gcongestion"))]
589 {
590 assert_eq!(algo, CongestionControlAlgorithm::BBR2);
591 assert!(!recovery_for_alg(algo).gcongestion_enabled());
592 }
593 #[cfg(feature = "gcongestion")]
594 {
595 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
596 assert!(recovery_for_alg(algo).gcongestion_enabled());
597 }
598
599 let algo =
600 CongestionControlAlgorithm::from_str("bbr2_gcongestion").unwrap();
601 assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
602 assert!(recovery_for_alg(algo).gcongestion_enabled());
603 }
604
605 #[test]
606 fn lookup_cc_algo_bad() {
607 assert_eq!(
608 CongestionControlAlgorithm::from_str("???"),
609 Err(crate::Error::CongestionControl)
610 );
611 }
612
613 #[test]
614 fn loss_on_pto() {
615 let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
616 cfg.set_cc_algorithm(CongestionControlAlgorithm::Reno);
617
618 let mut r = Recovery::new(&cfg);
619
620 let mut now = Instant::now();
621
622 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
623
624 let p = Sent {
626 pkt_num: 0,
627 frames: smallvec![],
628 time_sent: now,
629 time_acked: None,
630 time_lost: None,
631 size: 1000,
632 ack_eliciting: true,
633 in_flight: true,
634 delivered: 0,
635 delivered_time: now,
636 first_sent_time: now,
637 is_app_limited: false,
638 tx_in_flight: 0,
639 lost: 0,
640 has_data: false,
641 pmtud: false,
642 };
643
644 r.on_packet_sent(
645 p,
646 packet::Epoch::Application,
647 HandshakeStatus::default(),
648 now,
649 "",
650 );
651
652 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
653 assert_eq!(r.bytes_in_flight(), 1000);
654
655 let p = Sent {
656 pkt_num: 1,
657 frames: smallvec![],
658 time_sent: now,
659 time_acked: None,
660 time_lost: None,
661 size: 1000,
662 ack_eliciting: true,
663 in_flight: true,
664 delivered: 0,
665 delivered_time: now,
666 first_sent_time: now,
667 is_app_limited: false,
668 tx_in_flight: 0,
669 lost: 0,
670 has_data: false,
671 pmtud: false,
672 };
673
674 r.on_packet_sent(
675 p,
676 packet::Epoch::Application,
677 HandshakeStatus::default(),
678 now,
679 "",
680 );
681
682 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
683 assert_eq!(r.bytes_in_flight(), 2000);
684
685 let p = Sent {
686 pkt_num: 2,
687 frames: smallvec![],
688 time_sent: now,
689 time_acked: None,
690 time_lost: None,
691 size: 1000,
692 ack_eliciting: true,
693 in_flight: true,
694 delivered: 0,
695 delivered_time: now,
696 first_sent_time: now,
697 is_app_limited: false,
698 tx_in_flight: 0,
699 lost: 0,
700 has_data: false,
701 pmtud: false,
702 };
703
704 r.on_packet_sent(
705 p,
706 packet::Epoch::Application,
707 HandshakeStatus::default(),
708 now,
709 "",
710 );
711 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
712 assert_eq!(r.bytes_in_flight(), 3000);
713
714 let p = Sent {
715 pkt_num: 3,
716 frames: smallvec![],
717 time_sent: now,
718 time_acked: None,
719 time_lost: None,
720 size: 1000,
721 ack_eliciting: true,
722 in_flight: true,
723 delivered: 0,
724 delivered_time: now,
725 first_sent_time: now,
726 is_app_limited: false,
727 tx_in_flight: 0,
728 lost: 0,
729 has_data: false,
730 pmtud: false,
731 };
732
733 r.on_packet_sent(
734 p,
735 packet::Epoch::Application,
736 HandshakeStatus::default(),
737 now,
738 "",
739 );
740 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
741 assert_eq!(r.bytes_in_flight(), 4000);
742
743 now += Duration::from_millis(10);
745
746 let mut acked = ranges::RangeSet::default();
748 acked.insert(0..2);
749
750 assert_eq!(
751 r.on_ack_received(
752 &acked,
753 25,
754 packet::Epoch::Application,
755 HandshakeStatus::default(),
756 now,
757 "",
758 ),
759 (0, 0, 2 * 1000)
760 );
761
762 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
763 assert_eq!(r.bytes_in_flight(), 2000);
764 assert_eq!(r.lost_count(), 0);
765
766 now = r.loss_detection_timer().unwrap();
768
769 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
771 assert_eq!(r.loss_probes(packet::Epoch::Application), 1);
772 assert_eq!(r.lost_count(), 0);
773 assert_eq!(r.pto_count(), 1);
774
775 let p = Sent {
776 pkt_num: 4,
777 frames: smallvec![],
778 time_sent: now,
779 time_acked: None,
780 time_lost: None,
781 size: 1000,
782 ack_eliciting: true,
783 in_flight: true,
784 delivered: 0,
785 delivered_time: now,
786 first_sent_time: now,
787 is_app_limited: false,
788 tx_in_flight: 0,
789 lost: 0,
790 has_data: false,
791 pmtud: false,
792 };
793
794 r.on_packet_sent(
795 p,
796 packet::Epoch::Application,
797 HandshakeStatus::default(),
798 now,
799 "",
800 );
801 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
802 assert_eq!(r.bytes_in_flight(), 3000);
803
804 let p = Sent {
805 pkt_num: 5,
806 frames: smallvec![],
807 time_sent: now,
808 time_acked: None,
809 time_lost: None,
810 size: 1000,
811 ack_eliciting: true,
812 in_flight: true,
813 delivered: 0,
814 delivered_time: now,
815 first_sent_time: now,
816 is_app_limited: false,
817 tx_in_flight: 0,
818 lost: 0,
819 has_data: false,
820 pmtud: false,
821 };
822
823 r.on_packet_sent(
824 p,
825 packet::Epoch::Application,
826 HandshakeStatus::default(),
827 now,
828 "",
829 );
830 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
831 assert_eq!(r.bytes_in_flight(), 4000);
832 assert_eq!(r.lost_count(), 0);
833
834 now += Duration::from_millis(10);
836
837 let mut acked = ranges::RangeSet::default();
839 acked.insert(4..6);
840
841 assert_eq!(
842 r.on_ack_received(
843 &acked,
844 25,
845 packet::Epoch::Application,
846 HandshakeStatus::default(),
847 now,
848 "",
849 ),
850 (2, 2000, 2 * 1000)
851 );
852
853 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
854 assert_eq!(r.bytes_in_flight(), 0);
855
856 assert_eq!(r.lost_count(), 2);
857
858 now += r.rtt();
860
861 assert_eq!(
862 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
863 (0, 0)
864 );
865
866 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
867 }
868
869 #[test]
870 fn loss_on_timer() {
871 let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
872 cfg.set_cc_algorithm(CongestionControlAlgorithm::Reno);
873
874 let mut r = Recovery::new(&cfg);
875
876 let mut now = Instant::now();
877
878 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
879
880 let p = Sent {
882 pkt_num: 0,
883 frames: smallvec![],
884 time_sent: now,
885 time_acked: None,
886 time_lost: None,
887 size: 1000,
888 ack_eliciting: true,
889 in_flight: true,
890 delivered: 0,
891 delivered_time: now,
892 first_sent_time: now,
893 is_app_limited: false,
894 tx_in_flight: 0,
895 lost: 0,
896 has_data: false,
897 pmtud: false,
898 };
899
900 r.on_packet_sent(
901 p,
902 packet::Epoch::Application,
903 HandshakeStatus::default(),
904 now,
905 "",
906 );
907 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
908 assert_eq!(r.bytes_in_flight(), 1000);
909
910 let p = Sent {
911 pkt_num: 1,
912 frames: smallvec![],
913 time_sent: now,
914 time_acked: None,
915 time_lost: None,
916 size: 1000,
917 ack_eliciting: true,
918 in_flight: true,
919 delivered: 0,
920 delivered_time: now,
921 first_sent_time: now,
922 is_app_limited: false,
923 tx_in_flight: 0,
924 lost: 0,
925 has_data: false,
926 pmtud: false,
927 };
928
929 r.on_packet_sent(
930 p,
931 packet::Epoch::Application,
932 HandshakeStatus::default(),
933 now,
934 "",
935 );
936 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
937 assert_eq!(r.bytes_in_flight(), 2000);
938
939 let p = Sent {
940 pkt_num: 2,
941 frames: smallvec![],
942 time_sent: now,
943 time_acked: None,
944 time_lost: None,
945 size: 1000,
946 ack_eliciting: true,
947 in_flight: true,
948 delivered: 0,
949 delivered_time: now,
950 first_sent_time: now,
951 is_app_limited: false,
952 tx_in_flight: 0,
953 lost: 0,
954 has_data: false,
955 pmtud: false,
956 };
957
958 r.on_packet_sent(
959 p,
960 packet::Epoch::Application,
961 HandshakeStatus::default(),
962 now,
963 "",
964 );
965 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
966 assert_eq!(r.bytes_in_flight(), 3000);
967
968 let p = Sent {
969 pkt_num: 3,
970 frames: smallvec![],
971 time_sent: now,
972 time_acked: None,
973 time_lost: None,
974 size: 1000,
975 ack_eliciting: true,
976 in_flight: true,
977 delivered: 0,
978 delivered_time: now,
979 first_sent_time: now,
980 is_app_limited: false,
981 tx_in_flight: 0,
982 lost: 0,
983 has_data: false,
984 pmtud: false,
985 };
986
987 r.on_packet_sent(
988 p,
989 packet::Epoch::Application,
990 HandshakeStatus::default(),
991 now,
992 "",
993 );
994 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
995 assert_eq!(r.bytes_in_flight(), 4000);
996
997 now += Duration::from_millis(10);
999
1000 let mut acked = ranges::RangeSet::default();
1002 acked.insert(0..2);
1003 acked.insert(3..4);
1004
1005 assert_eq!(
1006 r.on_ack_received(
1007 &acked,
1008 25,
1009 packet::Epoch::Application,
1010 HandshakeStatus::default(),
1011 now,
1012 "",
1013 ),
1014 (0, 0, 3 * 1000)
1015 );
1016
1017 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1018 assert_eq!(r.bytes_in_flight(), 1000);
1019 assert_eq!(r.lost_count(), 0);
1020
1021 now = r.loss_detection_timer().unwrap();
1023
1024 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
1026 assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
1027
1028 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1029 assert_eq!(r.bytes_in_flight(), 0);
1030
1031 assert_eq!(r.lost_count(), 1);
1032
1033 now += r.rtt();
1035
1036 assert_eq!(
1037 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1038 (0, 0)
1039 );
1040
1041 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1042 }
1043
1044 #[test]
1045 fn loss_on_reordering() {
1046 let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
1047 cfg.set_cc_algorithm(CongestionControlAlgorithm::Reno);
1048
1049 let mut r = Recovery::new(&cfg);
1050
1051 let mut now = Instant::now();
1052
1053 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1054
1055 let p = Sent {
1057 pkt_num: 0,
1058 frames: smallvec![],
1059 time_sent: now,
1060 time_acked: None,
1061 time_lost: None,
1062 size: 1000,
1063 ack_eliciting: true,
1064 in_flight: true,
1065 delivered: 0,
1066 delivered_time: now,
1067 first_sent_time: now,
1068 is_app_limited: false,
1069 tx_in_flight: 0,
1070 lost: 0,
1071 has_data: false,
1072 pmtud: false,
1073 };
1074
1075 r.on_packet_sent(
1076 p,
1077 packet::Epoch::Application,
1078 HandshakeStatus::default(),
1079 now,
1080 "",
1081 );
1082 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1083 assert_eq!(r.bytes_in_flight(), 1000);
1084
1085 let p = Sent {
1086 pkt_num: 1,
1087 frames: smallvec![],
1088 time_sent: now,
1089 time_acked: None,
1090 time_lost: None,
1091 size: 1000,
1092 ack_eliciting: true,
1093 in_flight: true,
1094 delivered: 0,
1095 delivered_time: now,
1096 first_sent_time: now,
1097 is_app_limited: false,
1098 tx_in_flight: 0,
1099 lost: 0,
1100 has_data: false,
1101 pmtud: false,
1102 };
1103
1104 r.on_packet_sent(
1105 p,
1106 packet::Epoch::Application,
1107 HandshakeStatus::default(),
1108 now,
1109 "",
1110 );
1111 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1112 assert_eq!(r.bytes_in_flight(), 2000);
1113
1114 let p = Sent {
1115 pkt_num: 2,
1116 frames: smallvec![],
1117 time_sent: now,
1118 time_acked: None,
1119 time_lost: None,
1120 size: 1000,
1121 ack_eliciting: true,
1122 in_flight: true,
1123 delivered: 0,
1124 delivered_time: now,
1125 first_sent_time: now,
1126 is_app_limited: false,
1127 tx_in_flight: 0,
1128 lost: 0,
1129 has_data: false,
1130 pmtud: false,
1131 };
1132
1133 r.on_packet_sent(
1134 p,
1135 packet::Epoch::Application,
1136 HandshakeStatus::default(),
1137 now,
1138 "",
1139 );
1140 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1141 assert_eq!(r.bytes_in_flight(), 3000);
1142
1143 let p = Sent {
1144 pkt_num: 3,
1145 frames: smallvec![],
1146 time_sent: now,
1147 time_acked: None,
1148 time_lost: None,
1149 size: 1000,
1150 ack_eliciting: true,
1151 in_flight: true,
1152 delivered: 0,
1153 delivered_time: now,
1154 first_sent_time: now,
1155 is_app_limited: false,
1156 tx_in_flight: 0,
1157 lost: 0,
1158 has_data: false,
1159 pmtud: false,
1160 };
1161
1162 r.on_packet_sent(
1163 p,
1164 packet::Epoch::Application,
1165 HandshakeStatus::default(),
1166 now,
1167 "",
1168 );
1169 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1170 assert_eq!(r.bytes_in_flight(), 4000);
1171
1172 now += Duration::from_millis(10);
1174
1175 let mut acked = ranges::RangeSet::default();
1177 acked.insert(2..4);
1178
1179 assert_eq!(
1180 r.on_ack_received(
1181 &acked,
1182 25,
1183 packet::Epoch::Application,
1184 HandshakeStatus::default(),
1185 now,
1186 "",
1187 ),
1188 (1, 1000, 1000 * 2)
1189 );
1190
1191 now += Duration::from_millis(10);
1192
1193 let mut acked = ranges::RangeSet::default();
1194 acked.insert(0..2);
1195
1196 assert_eq!(r.pkt_thresh(), INITIAL_PACKET_THRESHOLD);
1197
1198 assert_eq!(
1199 r.on_ack_received(
1200 &acked,
1201 25,
1202 packet::Epoch::Application,
1203 HandshakeStatus::default(),
1204 now,
1205 "",
1206 ),
1207 (0, 0, 1000)
1208 );
1209
1210 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1211 assert_eq!(r.bytes_in_flight(), 0);
1212
1213 assert_eq!(r.lost_count(), 1);
1215 assert_eq!(r.lost_spurious_count(), 1);
1216
1217 assert_eq!(r.pkt_thresh(), 4);
1219
1220 now += r.rtt();
1222
1223 assert_eq!(
1224 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1225 (0, 0)
1226 );
1227
1228 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1229 }
1230
1231 #[test]
1232 fn pacing() {
1233 let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
1234 cfg.set_cc_algorithm(CongestionControlAlgorithm::CUBIC);
1235
1236 let mut r = Recovery::new(&cfg);
1237
1238 let mut now = Instant::now();
1239
1240 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1241
1242 let p = Sent {
1244 pkt_num: 0,
1245 frames: smallvec![],
1246 time_sent: now,
1247 time_acked: None,
1248 time_lost: None,
1249 size: 12000,
1250 ack_eliciting: true,
1251 in_flight: true,
1252 delivered: 0,
1253 delivered_time: now,
1254 first_sent_time: now,
1255 is_app_limited: false,
1256 tx_in_flight: 0,
1257 lost: 0,
1258 has_data: false,
1259 pmtud: false,
1260 };
1261
1262 r.on_packet_sent(
1263 p,
1264 packet::Epoch::Application,
1265 HandshakeStatus::default(),
1266 now,
1267 "",
1268 );
1269
1270 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1271 assert_eq!(r.bytes_in_flight(), 12000);
1272
1273 assert_eq!(r.pacing_rate(), 0);
1275 assert_eq!(r.get_packet_send_time(), now);
1276
1277 now += Duration::from_millis(50);
1279
1280 let mut acked = ranges::RangeSet::default();
1281 acked.insert(0..1);
1282
1283 assert_eq!(
1284 r.on_ack_received(
1285 &acked,
1286 10,
1287 packet::Epoch::Application,
1288 HandshakeStatus::default(),
1289 now,
1290 "",
1291 ),
1292 (0, 0, 12000)
1293 );
1294
1295 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1296 assert_eq!(r.bytes_in_flight(), 0);
1297 assert_eq!(r.rtt(), Duration::from_millis(50));
1298
1299 assert_eq!(r.cwnd(), 12000 + 1200);
1301
1302 let p = Sent {
1304 pkt_num: 1,
1305 frames: smallvec![],
1306 time_sent: now,
1307 time_acked: None,
1308 time_lost: None,
1309 size: 6000,
1310 ack_eliciting: true,
1311 in_flight: true,
1312 delivered: 0,
1313 delivered_time: now,
1314 first_sent_time: now,
1315 is_app_limited: false,
1316 tx_in_flight: 0,
1317 lost: 0,
1318 has_data: false,
1319 pmtud: false,
1320 };
1321
1322 r.on_packet_sent(
1323 p,
1324 packet::Epoch::Application,
1325 HandshakeStatus::default(),
1326 now,
1327 "",
1328 );
1329
1330 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1331 assert_eq!(r.bytes_in_flight(), 6000);
1332
1333 assert_eq!(r.get_packet_send_time(), now);
1335
1336 let p = Sent {
1338 pkt_num: 2,
1339 frames: smallvec![],
1340 time_sent: now,
1341 time_acked: None,
1342 time_lost: None,
1343 size: 6000,
1344 ack_eliciting: true,
1345 in_flight: true,
1346 delivered: 0,
1347 delivered_time: now,
1348 first_sent_time: now,
1349 is_app_limited: false,
1350 tx_in_flight: 0,
1351 lost: 0,
1352 has_data: false,
1353 pmtud: false,
1354 };
1355
1356 r.on_packet_sent(
1357 p,
1358 packet::Epoch::Application,
1359 HandshakeStatus::default(),
1360 now,
1361 "",
1362 );
1363
1364 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1365 assert_eq!(r.bytes_in_flight(), 12000);
1366
1367 let p = Sent {
1369 pkt_num: 3,
1370 frames: smallvec![],
1371 time_sent: now,
1372 time_acked: None,
1373 time_lost: None,
1374 size: 1000,
1375 ack_eliciting: true,
1376 in_flight: true,
1377 delivered: 0,
1378 delivered_time: now,
1379 first_sent_time: now,
1380 is_app_limited: false,
1381 tx_in_flight: 0,
1382 lost: 0,
1383 has_data: false,
1384 pmtud: false,
1385 };
1386
1387 r.on_packet_sent(
1388 p,
1389 packet::Epoch::Application,
1390 HandshakeStatus::default(),
1391 now,
1392 "",
1393 );
1394
1395 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1396 assert_eq!(r.bytes_in_flight(), 13000);
1397
1398 let pacing_rate = (r.cwnd() as f64 * PACING_MULTIPLIER / 0.05) as u64;
1401 assert_eq!(r.pacing_rate(), pacing_rate);
1402
1403 assert_eq!(
1404 r.get_packet_send_time(),
1405 now + Duration::from_secs_f64(12000.0 / pacing_rate as f64)
1406 );
1407 }
1408
1409 #[test]
1410 fn pmtud_loss_on_timer() {
1411 let mut cfg = crate::Config::new(crate::PROTOCOL_VERSION).unwrap();
1412 cfg.set_cc_algorithm(CongestionControlAlgorithm::Reno);
1413
1414 let mut r = Recovery::new(&cfg);
1415
1416 let mut now = Instant::now();
1417
1418 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1419
1420 let p = Sent {
1422 pkt_num: 0,
1423 frames: smallvec![],
1424 time_sent: now,
1425 time_acked: None,
1426 time_lost: None,
1427 size: 1000,
1428 ack_eliciting: true,
1429 in_flight: true,
1430 delivered: 0,
1431 delivered_time: now,
1432 first_sent_time: now,
1433 is_app_limited: false,
1434 tx_in_flight: 0,
1435 lost: 0,
1436 has_data: false,
1437 pmtud: false,
1438 };
1439
1440 r.on_packet_sent(
1441 p,
1442 packet::Epoch::Application,
1443 HandshakeStatus::default(),
1444 now,
1445 "",
1446 );
1447
1448 assert_eq!(r.in_flight_count(packet::Epoch::Application), 1);
1449 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1450 assert_eq!(r.bytes_in_flight(), 1000);
1451
1452 let p = Sent {
1453 pkt_num: 1,
1454 frames: smallvec![],
1455 time_sent: now,
1456 time_acked: None,
1457 time_lost: None,
1458 size: 1000,
1459 ack_eliciting: true,
1460 in_flight: true,
1461 delivered: 0,
1462 delivered_time: now,
1463 first_sent_time: now,
1464 is_app_limited: false,
1465 tx_in_flight: 0,
1466 lost: 0,
1467 has_data: false,
1468 pmtud: true,
1469 };
1470
1471 r.on_packet_sent(
1472 p,
1473 packet::Epoch::Application,
1474 HandshakeStatus::default(),
1475 now,
1476 "",
1477 );
1478
1479 assert_eq!(r.in_flight_count(packet::Epoch::Application), 2);
1480
1481 let p = Sent {
1482 pkt_num: 2,
1483 frames: smallvec![],
1484 time_sent: now,
1485 time_acked: None,
1486 time_lost: None,
1487 size: 1000,
1488 ack_eliciting: true,
1489 in_flight: true,
1490 delivered: 0,
1491 delivered_time: now,
1492 first_sent_time: now,
1493 is_app_limited: false,
1494 tx_in_flight: 0,
1495 lost: 0,
1496 has_data: false,
1497 pmtud: false,
1498 };
1499
1500 r.on_packet_sent(
1501 p,
1502 packet::Epoch::Application,
1503 HandshakeStatus::default(),
1504 now,
1505 "",
1506 );
1507
1508 assert_eq!(r.in_flight_count(packet::Epoch::Application), 3);
1509
1510 now += Duration::from_millis(10);
1512
1513 let mut acked = ranges::RangeSet::default();
1515 acked.insert(0..1);
1516 acked.insert(2..3);
1517
1518 assert_eq!(
1519 r.on_ack_received(
1520 &acked,
1521 25,
1522 packet::Epoch::Application,
1523 HandshakeStatus::default(),
1524 now,
1525 "",
1526 ),
1527 (0, 0, 2 * 1000)
1528 );
1529
1530 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1531 assert_eq!(r.bytes_in_flight(), 1000);
1532 assert_eq!(r.lost_count(), 0);
1533
1534 now = r.loss_detection_timer().unwrap();
1536
1537 r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
1539 assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
1540
1541 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1542 assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
1543 assert_eq!(r.bytes_in_flight(), 0);
1544 assert_eq!(r.cwnd(), 12000);
1545
1546 assert_eq!(r.lost_count(), 0);
1547
1548 now += r.rtt();
1550
1551 assert_eq!(
1552 r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1553 (0, 0)
1554 );
1555
1556 assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1557 assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
1558 assert_eq!(r.bytes_in_flight(), 0);
1559 assert_eq!(r.lost_count(), 0);
1560 }
1561}
1562
1563mod congestion;
1564mod gcongestion;
1565mod rtt;