quiche/recovery/
mod.rs

1// Copyright (C) 2018-2019, Cloudflare, Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright notice,
9//       this list of conditions and the following disclaimer.
10//
11//     * Redistributions in binary form must reproduce the above copyright
12//       notice, this list of conditions and the following disclaimer in the
13//       documentation and/or other materials provided with the distribution.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27use std::str::FromStr;
28use std::time::Duration;
29use std::time::Instant;
30
31use crate::frame;
32use crate::packet;
33use crate::ranges::RangeSet;
34pub(crate) use crate::recovery::bandwidth::Bandwidth;
35use crate::Config;
36use crate::Result;
37
38#[cfg(feature = "qlog")]
39use qlog::events::EventData;
40
41use smallvec::SmallVec;
42
43use self::congestion::recovery::LegacyRecovery;
44use self::gcongestion::GRecovery;
45pub use gcongestion::BbrBwLoReductionStrategy;
46pub use gcongestion::BbrParams;
47
48// Loss Recovery
49const INITIAL_PACKET_THRESHOLD: u64 = 3;
50
51const MAX_PACKET_THRESHOLD: u64 = 20;
52
53// Time threshold used to calculate the loss time.
54//
55// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.2
56const INITIAL_TIME_THRESHOLD: f64 = 9.0 / 8.0;
57
58// Reduce the sensitivity to packet reordering after the first reordering event.
59//
60// Packet reorder is not a real loss event so quickly reduce the sensitivity to
61// avoid penializing subsequent packet reordering.
62//
63// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.2
64//
65// Implementations MAY experiment with absolute thresholds, thresholds from
66// previous connections, adaptive thresholds, or the including of RTT variation.
67// Smaller thresholds reduce reordering resilience and increase spurious
68// retransmissions, and larger thresholds increase loss detection delay.
69const PACKET_REORDER_TIME_THRESHOLD: f64 = 5.0 / 4.0;
70
71// # Experiment: enable_relaxed_loss_threshold
72//
73// Time threshold overhead used to calculate the loss time.
74//
75// The actual threshold is calcualted as 1 + INITIAL_TIME_THRESHOLD_OVERHEAD and
76// equivalent to INITIAL_TIME_THRESHOLD.
77const INITIAL_TIME_THRESHOLD_OVERHEAD: f64 = 1.0 / 8.0;
78// # Experiment: enable_relaxed_loss_threshold
79//
80// The factor by which to increase the time threshold on spurious loss.
81const TIME_THRESHOLD_OVERHEAD_MULTIPLIER: f64 = 2.0;
82
83const GRANULARITY: Duration = Duration::from_millis(1);
84
85const MAX_PTO_PROBES_COUNT: usize = 2;
86
87const MINIMUM_WINDOW_PACKETS: usize = 2;
88
89const LOSS_REDUCTION_FACTOR: f64 = 0.5;
90
91// How many non ACK eliciting packets we send before including a PING to solicit
92// an ACK.
93pub(super) const MAX_OUTSTANDING_NON_ACK_ELICITING: usize = 24;
94
95#[derive(Default)]
96struct LossDetectionTimer {
97    time: Option<Instant>,
98}
99
100impl LossDetectionTimer {
101    fn update(&mut self, timeout: Instant) {
102        self.time = Some(timeout);
103    }
104
105    fn clear(&mut self) {
106        self.time = None;
107    }
108}
109
110impl std::fmt::Debug for LossDetectionTimer {
111    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
112        match self.time {
113            Some(v) => {
114                let now = Instant::now();
115                if v > now {
116                    let d = v.duration_since(now);
117                    write!(f, "{d:?}")
118                } else {
119                    write!(f, "exp")
120                }
121            },
122            None => write!(f, "none"),
123        }
124    }
125}
126
127#[derive(Clone, Copy, PartialEq)]
128pub struct RecoveryConfig {
129    pub initial_rtt: Duration,
130    pub max_send_udp_payload_size: usize,
131    pub max_ack_delay: Duration,
132    pub cc_algorithm: CongestionControlAlgorithm,
133    pub custom_bbr_params: Option<BbrParams>,
134    pub hystart: bool,
135    pub pacing: bool,
136    pub max_pacing_rate: Option<u64>,
137    pub initial_congestion_window_packets: usize,
138    pub enable_relaxed_loss_threshold: bool,
139}
140
141impl RecoveryConfig {
142    pub fn from_config(config: &Config) -> Self {
143        Self {
144            initial_rtt: config.initial_rtt,
145            max_send_udp_payload_size: config.max_send_udp_payload_size,
146            max_ack_delay: Duration::ZERO,
147            cc_algorithm: config.cc_algorithm,
148            custom_bbr_params: config.custom_bbr_params,
149            hystart: config.hystart,
150            pacing: config.pacing,
151            max_pacing_rate: config.max_pacing_rate,
152            initial_congestion_window_packets: config
153                .initial_congestion_window_packets,
154            enable_relaxed_loss_threshold: config.enable_relaxed_loss_threshold,
155        }
156    }
157}
158
159#[enum_dispatch::enum_dispatch(RecoveryOps)]
160#[allow(clippy::large_enum_variant)]
161#[derive(Debug)]
162pub(crate) enum Recovery {
163    Legacy(LegacyRecovery),
164    GCongestion(GRecovery),
165}
166
167#[derive(Debug, Default, PartialEq)]
168pub struct OnAckReceivedOutcome {
169    pub lost_packets: usize,
170    pub lost_bytes: usize,
171    pub acked_bytes: usize,
172    pub spurious_losses: usize,
173}
174
175#[derive(Debug, Default)]
176pub struct OnLossDetectionTimeoutOutcome {
177    pub lost_packets: usize,
178    pub lost_bytes: usize,
179}
180
181#[enum_dispatch::enum_dispatch]
182/// Api for the Recovery implementation
183pub trait RecoveryOps {
184    fn lost_count(&self) -> usize;
185    fn bytes_lost(&self) -> u64;
186
187    /// Returns whether or not we should elicit an ACK even if we wouldn't
188    /// otherwise have constructed an ACK eliciting packet.
189    fn should_elicit_ack(&self, epoch: packet::Epoch) -> bool;
190
191    fn next_acked_frame(&mut self, epoch: packet::Epoch) -> Option<frame::Frame>;
192
193    fn next_lost_frame(&mut self, epoch: packet::Epoch) -> Option<frame::Frame>;
194
195    fn get_largest_acked_on_epoch(&self, epoch: packet::Epoch) -> Option<u64>;
196    fn has_lost_frames(&self, epoch: packet::Epoch) -> bool;
197    fn loss_probes(&self, epoch: packet::Epoch) -> usize;
198    #[cfg(test)]
199    fn inc_loss_probes(&mut self, epoch: packet::Epoch);
200
201    fn ping_sent(&mut self, epoch: packet::Epoch);
202
203    fn on_packet_sent(
204        &mut self, pkt: Sent, epoch: packet::Epoch,
205        handshake_status: HandshakeStatus, now: Instant, trace_id: &str,
206    );
207    fn get_packet_send_time(&self, now: Instant) -> Instant;
208
209    #[allow(clippy::too_many_arguments)]
210    fn on_ack_received(
211        &mut self, ranges: &RangeSet, ack_delay: u64, epoch: packet::Epoch,
212        handshake_status: HandshakeStatus, now: Instant, skip_pn: Option<u64>,
213        trace_id: &str,
214    ) -> Result<OnAckReceivedOutcome>;
215
216    fn on_loss_detection_timeout(
217        &mut self, handshake_status: HandshakeStatus, now: Instant,
218        trace_id: &str,
219    ) -> OnLossDetectionTimeoutOutcome;
220    fn on_pkt_num_space_discarded(
221        &mut self, epoch: packet::Epoch, handshake_status: HandshakeStatus,
222        now: Instant,
223    );
224    fn on_path_change(
225        &mut self, epoch: packet::Epoch, now: Instant, _trace_id: &str,
226    ) -> (usize, usize);
227    fn loss_detection_timer(&self) -> Option<Instant>;
228    fn cwnd(&self) -> usize;
229    fn cwnd_available(&self) -> usize;
230    fn rtt(&self) -> Duration;
231
232    fn min_rtt(&self) -> Option<Duration>;
233
234    fn max_rtt(&self) -> Option<Duration>;
235
236    fn rttvar(&self) -> Duration;
237
238    fn pto(&self) -> Duration;
239
240    /// The most recent data delivery rate estimate.
241    fn delivery_rate(&self) -> Bandwidth;
242
243    /// Maximum bandwidth estimate, if one is available.
244    fn max_bandwidth(&self) -> Option<Bandwidth>;
245
246    /// Statistics from when a CCA first exited the startup phase.
247    fn startup_exit(&self) -> Option<StartupExit>;
248
249    fn max_datagram_size(&self) -> usize;
250
251    fn pmtud_update_max_datagram_size(&mut self, new_max_datagram_size: usize);
252
253    fn update_max_datagram_size(&mut self, new_max_datagram_size: usize);
254
255    fn on_app_limited(&mut self);
256
257    // Since a recovery module is path specific, this tracks the largest packet
258    // sent per path.
259    #[cfg(test)]
260    fn largest_sent_pkt_num_on_path(&self, epoch: packet::Epoch) -> Option<u64>;
261
262    #[cfg(test)]
263    fn app_limited(&self) -> bool;
264
265    #[cfg(test)]
266    fn sent_packets_len(&self, epoch: packet::Epoch) -> usize;
267
268    fn bytes_in_flight(&self) -> usize;
269
270    fn bytes_in_flight_duration(&self) -> Duration;
271
272    #[cfg(test)]
273    fn in_flight_count(&self, epoch: packet::Epoch) -> usize;
274
275    #[cfg(test)]
276    fn pacing_rate(&self) -> u64;
277
278    #[cfg(test)]
279    fn pto_count(&self) -> u32;
280
281    // This value might be `None` when experiment `enable_relaxed_loss_threshold`
282    // is enabled for gcongestion
283    #[cfg(test)]
284    fn pkt_thresh(&self) -> Option<u64>;
285
286    #[cfg(test)]
287    fn time_thresh(&self) -> f64;
288
289    #[cfg(test)]
290    fn lost_spurious_count(&self) -> usize;
291
292    #[cfg(test)]
293    fn detect_lost_packets_for_test(
294        &mut self, epoch: packet::Epoch, now: Instant,
295    ) -> (usize, usize);
296
297    fn update_app_limited(&mut self, v: bool);
298
299    fn delivery_rate_update_app_limited(&mut self, v: bool);
300
301    fn update_max_ack_delay(&mut self, max_ack_delay: Duration);
302
303    #[cfg(feature = "qlog")]
304    fn state_str(&self, now: Instant) -> &'static str;
305
306    #[cfg(feature = "qlog")]
307    fn get_updated_qlog_event_data(&mut self) -> Option<EventData>;
308
309    #[cfg(feature = "qlog")]
310    fn get_updated_qlog_cc_state(&mut self, now: Instant)
311        -> Option<&'static str>;
312
313    fn send_quantum(&self) -> usize;
314
315    fn get_next_release_time(&self) -> ReleaseDecision;
316
317    fn gcongestion_enabled(&self) -> bool;
318}
319
320impl Recovery {
321    pub fn new_with_config(recovery_config: &RecoveryConfig) -> Self {
322        let grecovery = GRecovery::new(recovery_config);
323        if let Some(grecovery) = grecovery {
324            Recovery::from(grecovery)
325        } else {
326            Recovery::from(LegacyRecovery::new_with_config(recovery_config))
327        }
328    }
329
330    #[cfg(feature = "qlog")]
331    pub fn maybe_qlog(
332        &mut self, qlog: &mut qlog::streamer::QlogStreamer, now: Instant,
333    ) {
334        if let Some(ev_data) = self.get_updated_qlog_event_data() {
335            qlog.add_event_data_with_instant(ev_data, now).ok();
336        }
337
338        if let Some(cc_state) = self.get_updated_qlog_cc_state(now) {
339            let ev_data = EventData::CongestionStateUpdated(
340                qlog::events::quic::CongestionStateUpdated {
341                    old: None,
342                    new: cc_state.to_string(),
343                    trigger: None,
344                },
345            );
346
347            qlog.add_event_data_with_instant(ev_data, now).ok();
348        }
349    }
350
351    #[cfg(test)]
352    pub fn new(config: &Config) -> Self {
353        Self::new_with_config(&RecoveryConfig::from_config(config))
354    }
355}
356
357/// Available congestion control algorithms.
358///
359/// This enum provides currently available list of congestion control
360/// algorithms.
361#[derive(Debug, Copy, Clone, PartialEq, Eq)]
362#[repr(C)]
363pub enum CongestionControlAlgorithm {
364    /// Reno congestion control algorithm. `reno` in a string form.
365    Reno            = 0,
366    /// CUBIC congestion control algorithm (default). `cubic` in a string form.
367    CUBIC           = 1,
368    /// BBRv2 congestion control algorithm implementation from gcongestion
369    /// branch. `bbr2_gcongestion` in a string form.
370    Bbr2Gcongestion = 4,
371}
372
373impl FromStr for CongestionControlAlgorithm {
374    type Err = crate::Error;
375
376    /// Converts a string to `CongestionControlAlgorithm`.
377    ///
378    /// If `name` is not valid, `Error::CongestionControl` is returned.
379    fn from_str(name: &str) -> std::result::Result<Self, Self::Err> {
380        match name {
381            "reno" => Ok(CongestionControlAlgorithm::Reno),
382            "cubic" => Ok(CongestionControlAlgorithm::CUBIC),
383            "bbr" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
384            "bbr2" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
385            "bbr2_gcongestion" => Ok(CongestionControlAlgorithm::Bbr2Gcongestion),
386            _ => Err(crate::Error::CongestionControl),
387        }
388    }
389}
390
391#[derive(Clone)]
392pub struct Sent {
393    pub pkt_num: u64,
394
395    pub frames: SmallVec<[frame::Frame; 1]>,
396
397    pub time_sent: Instant,
398
399    pub time_acked: Option<Instant>,
400
401    pub time_lost: Option<Instant>,
402
403    pub size: usize,
404
405    pub ack_eliciting: bool,
406
407    pub in_flight: bool,
408
409    pub delivered: usize,
410
411    pub delivered_time: Instant,
412
413    pub first_sent_time: Instant,
414
415    pub is_app_limited: bool,
416
417    pub tx_in_flight: usize,
418
419    pub lost: u64,
420
421    pub has_data: bool,
422
423    pub is_pmtud_probe: bool,
424}
425
426impl std::fmt::Debug for Sent {
427    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
428        write!(f, "pkt_num={:?} ", self.pkt_num)?;
429        write!(f, "pkt_sent_time={:?} ", self.time_sent)?;
430        write!(f, "pkt_size={:?} ", self.size)?;
431        write!(f, "delivered={:?} ", self.delivered)?;
432        write!(f, "delivered_time={:?} ", self.delivered_time)?;
433        write!(f, "first_sent_time={:?} ", self.first_sent_time)?;
434        write!(f, "is_app_limited={} ", self.is_app_limited)?;
435        write!(f, "tx_in_flight={} ", self.tx_in_flight)?;
436        write!(f, "lost={} ", self.lost)?;
437        write!(f, "has_data={} ", self.has_data)?;
438        write!(f, "is_pmtud_probe={}", self.is_pmtud_probe)?;
439
440        Ok(())
441    }
442}
443
444#[derive(Clone, Copy, Debug)]
445pub struct HandshakeStatus {
446    pub has_handshake_keys: bool,
447
448    pub peer_verified_address: bool,
449
450    pub completed: bool,
451}
452
453#[cfg(test)]
454impl Default for HandshakeStatus {
455    fn default() -> HandshakeStatus {
456        HandshakeStatus {
457            has_handshake_keys: true,
458
459            peer_verified_address: true,
460
461            completed: true,
462        }
463    }
464}
465
466// We don't need to log all qlog metrics every time there is a recovery event.
467// Instead, we can log only the MetricsUpdated event data fields that we care
468// about, only when they change. To support this, the QLogMetrics structure
469// keeps a running picture of the fields.
470#[derive(Default)]
471#[cfg(feature = "qlog")]
472struct QlogMetrics {
473    min_rtt: Duration,
474    smoothed_rtt: Duration,
475    latest_rtt: Duration,
476    rttvar: Duration,
477    cwnd: u64,
478    bytes_in_flight: u64,
479    ssthresh: Option<u64>,
480    pacing_rate: u64,
481}
482
483#[cfg(feature = "qlog")]
484impl QlogMetrics {
485    // Make a qlog event if the latest instance of QlogMetrics is different.
486    //
487    // This function diffs each of the fields. A qlog MetricsUpdated event is
488    // only generated if at least one field is different. Where fields are
489    // different, the qlog event contains the latest value.
490    fn maybe_update(&mut self, latest: Self) -> Option<EventData> {
491        let mut emit_event = false;
492
493        let new_min_rtt = if self.min_rtt != latest.min_rtt {
494            self.min_rtt = latest.min_rtt;
495            emit_event = true;
496            Some(latest.min_rtt.as_secs_f32() * 1000.0)
497        } else {
498            None
499        };
500
501        let new_smoothed_rtt = if self.smoothed_rtt != latest.smoothed_rtt {
502            self.smoothed_rtt = latest.smoothed_rtt;
503            emit_event = true;
504            Some(latest.smoothed_rtt.as_secs_f32() * 1000.0)
505        } else {
506            None
507        };
508
509        let new_latest_rtt = if self.latest_rtt != latest.latest_rtt {
510            self.latest_rtt = latest.latest_rtt;
511            emit_event = true;
512            Some(latest.latest_rtt.as_secs_f32() * 1000.0)
513        } else {
514            None
515        };
516
517        let new_rttvar = if self.rttvar != latest.rttvar {
518            self.rttvar = latest.rttvar;
519            emit_event = true;
520            Some(latest.rttvar.as_secs_f32() * 1000.0)
521        } else {
522            None
523        };
524
525        let new_cwnd = if self.cwnd != latest.cwnd {
526            self.cwnd = latest.cwnd;
527            emit_event = true;
528            Some(latest.cwnd)
529        } else {
530            None
531        };
532
533        let new_bytes_in_flight =
534            if self.bytes_in_flight != latest.bytes_in_flight {
535                self.bytes_in_flight = latest.bytes_in_flight;
536                emit_event = true;
537                Some(latest.bytes_in_flight)
538            } else {
539                None
540            };
541
542        let new_ssthresh = if self.ssthresh != latest.ssthresh {
543            self.ssthresh = latest.ssthresh;
544            emit_event = true;
545            latest.ssthresh
546        } else {
547            None
548        };
549
550        let new_pacing_rate = if self.pacing_rate != latest.pacing_rate {
551            self.pacing_rate = latest.pacing_rate;
552            emit_event = true;
553            Some(latest.pacing_rate)
554        } else {
555            None
556        };
557
558        if emit_event {
559            // QVis can't use all these fields and they can be large.
560            return Some(EventData::MetricsUpdated(
561                qlog::events::quic::MetricsUpdated {
562                    min_rtt: new_min_rtt,
563                    smoothed_rtt: new_smoothed_rtt,
564                    latest_rtt: new_latest_rtt,
565                    rtt_variance: new_rttvar,
566                    congestion_window: new_cwnd,
567                    bytes_in_flight: new_bytes_in_flight,
568                    ssthresh: new_ssthresh,
569                    pacing_rate: new_pacing_rate,
570                    ..Default::default()
571                },
572            ));
573        }
574
575        None
576    }
577}
578
579/// When the pacer thinks is a good time to release the next packet
580#[derive(Debug, Clone, Copy, PartialEq, Eq)]
581pub enum ReleaseTime {
582    Immediate,
583    At(Instant),
584}
585
586/// When the next packet should be release and if it can be part of a burst
587#[derive(Clone, Copy, Debug, PartialEq, Eq)]
588pub struct ReleaseDecision {
589    time: ReleaseTime,
590    allow_burst: bool,
591}
592
593impl ReleaseTime {
594    /// Add the specific delay to the current time
595    #[allow(dead_code)]
596    fn inc(&mut self, delay: Duration) {
597        match self {
598            ReleaseTime::Immediate => {},
599            ReleaseTime::At(time) => *time += delay,
600        }
601    }
602
603    /// Set the time to the later of two times
604    #[allow(dead_code)]
605    fn set_max(&mut self, other: Instant) {
606        match self {
607            ReleaseTime::Immediate => *self = ReleaseTime::At(other),
608            ReleaseTime::At(time) => *self = ReleaseTime::At(other.max(*time)),
609        }
610    }
611}
612
613impl ReleaseDecision {
614    pub(crate) const EQUAL_THRESHOLD: Duration = Duration::from_micros(50);
615
616    /// Get the [`Instant`] the next packet should be released. It will never be
617    /// in the past.
618    #[allow(dead_code)]
619    #[inline]
620    pub fn time(&self, now: Instant) -> Option<Instant> {
621        match self.time {
622            ReleaseTime::Immediate => None,
623            ReleaseTime::At(other) => other.gt(&now).then_some(other),
624        }
625    }
626
627    /// Can this packet be appended to a previous burst
628    #[allow(dead_code)]
629    #[inline]
630    pub fn can_burst(&self) -> bool {
631        self.allow_burst
632    }
633
634    /// Check if the two packets can be released at the same time
635    #[allow(dead_code)]
636    #[inline]
637    pub fn time_eq(&self, other: &Self, now: Instant) -> bool {
638        let delta = match (self.time(now), other.time(now)) {
639            (None, None) => Duration::ZERO,
640            (Some(t), None) | (None, Some(t)) => t.duration_since(now),
641            (Some(t1), Some(t2)) if t1 < t2 => t2.duration_since(t1),
642            (Some(t1), Some(t2)) => t1.duration_since(t2),
643        };
644
645        delta <= Self::EQUAL_THRESHOLD
646    }
647}
648
649/// Recovery statistics
650#[derive(Default, Debug)]
651pub struct RecoveryStats {
652    startup_exit: Option<StartupExit>,
653}
654
655impl RecoveryStats {
656    // Record statistics when a CCA first exits startup.
657    pub fn set_startup_exit(&mut self, startup_exit: StartupExit) {
658        if self.startup_exit.is_none() {
659            self.startup_exit = Some(startup_exit);
660        }
661    }
662}
663
664/// Statistics from when a CCA first exited the startup phase.
665#[derive(Debug, Clone, Copy, PartialEq)]
666pub struct StartupExit {
667    /// The congestion_window recorded at Startup exit.
668    pub cwnd: usize,
669
670    /// The bandwidth estimate recorded at Startup exit.
671    pub bandwidth: Option<u64>,
672
673    /// The reason a CCA exited the startup phase.
674    pub reason: StartupExitReason,
675}
676
677impl StartupExit {
678    fn new(
679        cwnd: usize, bandwidth: Option<Bandwidth>, reason: StartupExitReason,
680    ) -> Self {
681        let bandwidth = bandwidth.map(Bandwidth::to_bytes_per_second);
682        Self {
683            cwnd,
684            bandwidth,
685            reason,
686        }
687    }
688}
689
690/// The reason a CCA exited the startup phase.
691#[derive(Debug, Clone, Copy, PartialEq)]
692pub enum StartupExitReason {
693    /// Exit startup due to excessive loss
694    Loss,
695
696    /// Exit startup due to bandwidth plateau.
697    BandwidthPlateau,
698
699    /// Exit startup due to persistent queue.
700    PersistentQueue,
701}
702
703#[cfg(test)]
704mod tests {
705    use super::*;
706    use crate::packet;
707    use crate::test_utils;
708    use crate::CongestionControlAlgorithm;
709    use crate::DEFAULT_INITIAL_RTT;
710    use rstest::rstest;
711    use smallvec::smallvec;
712    use std::str::FromStr;
713
714    fn recovery_for_alg(algo: CongestionControlAlgorithm) -> Recovery {
715        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
716        cfg.set_cc_algorithm(algo);
717        Recovery::new(&cfg)
718    }
719
720    #[test]
721    fn lookup_cc_algo_ok() {
722        let algo = CongestionControlAlgorithm::from_str("reno").unwrap();
723        assert_eq!(algo, CongestionControlAlgorithm::Reno);
724        assert!(!recovery_for_alg(algo).gcongestion_enabled());
725
726        let algo = CongestionControlAlgorithm::from_str("cubic").unwrap();
727        assert_eq!(algo, CongestionControlAlgorithm::CUBIC);
728        assert!(!recovery_for_alg(algo).gcongestion_enabled());
729
730        let algo = CongestionControlAlgorithm::from_str("bbr").unwrap();
731        assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
732        assert!(recovery_for_alg(algo).gcongestion_enabled());
733
734        let algo = CongestionControlAlgorithm::from_str("bbr2").unwrap();
735        assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
736        assert!(recovery_for_alg(algo).gcongestion_enabled());
737
738        let algo =
739            CongestionControlAlgorithm::from_str("bbr2_gcongestion").unwrap();
740        assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
741        assert!(recovery_for_alg(algo).gcongestion_enabled());
742    }
743
744    #[test]
745    fn lookup_cc_algo_bad() {
746        assert_eq!(
747            CongestionControlAlgorithm::from_str("???"),
748            Err(crate::Error::CongestionControl)
749        );
750    }
751
752    #[rstest]
753    fn loss_on_pto(
754        #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
755        cc_algorithm_name: &str,
756    ) {
757        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
758        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
759
760        let mut r = Recovery::new(&cfg);
761
762        let mut now = Instant::now();
763
764        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
765
766        // Start by sending a few packets.
767        let p = Sent {
768            pkt_num: 0,
769            frames: smallvec![],
770            time_sent: now,
771            time_acked: None,
772            time_lost: None,
773            size: 1000,
774            ack_eliciting: true,
775            in_flight: true,
776            delivered: 0,
777            delivered_time: now,
778            first_sent_time: now,
779            is_app_limited: false,
780            tx_in_flight: 0,
781            lost: 0,
782            has_data: false,
783            is_pmtud_probe: false,
784        };
785
786        r.on_packet_sent(
787            p,
788            packet::Epoch::Application,
789            HandshakeStatus::default(),
790            now,
791            "",
792        );
793
794        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
795        assert_eq!(r.bytes_in_flight(), 1000);
796        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
797
798        let p = Sent {
799            pkt_num: 1,
800            frames: smallvec![],
801            time_sent: now,
802            time_acked: None,
803            time_lost: None,
804            size: 1000,
805            ack_eliciting: true,
806            in_flight: true,
807            delivered: 0,
808            delivered_time: now,
809            first_sent_time: now,
810            is_app_limited: false,
811            tx_in_flight: 0,
812            lost: 0,
813            has_data: false,
814            is_pmtud_probe: false,
815        };
816
817        r.on_packet_sent(
818            p,
819            packet::Epoch::Application,
820            HandshakeStatus::default(),
821            now,
822            "",
823        );
824
825        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
826        assert_eq!(r.bytes_in_flight(), 2000);
827        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
828
829        let p = Sent {
830            pkt_num: 2,
831            frames: smallvec![],
832            time_sent: now,
833            time_acked: None,
834            time_lost: None,
835            size: 1000,
836            ack_eliciting: true,
837            in_flight: true,
838            delivered: 0,
839            delivered_time: now,
840            first_sent_time: now,
841            is_app_limited: false,
842            tx_in_flight: 0,
843            lost: 0,
844            has_data: false,
845            is_pmtud_probe: false,
846        };
847
848        r.on_packet_sent(
849            p,
850            packet::Epoch::Application,
851            HandshakeStatus::default(),
852            now,
853            "",
854        );
855        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
856        assert_eq!(r.bytes_in_flight(), 3000);
857        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
858
859        let p = Sent {
860            pkt_num: 3,
861            frames: smallvec![],
862            time_sent: now,
863            time_acked: None,
864            time_lost: None,
865            size: 1000,
866            ack_eliciting: true,
867            in_flight: true,
868            delivered: 0,
869            delivered_time: now,
870            first_sent_time: now,
871            is_app_limited: false,
872            tx_in_flight: 0,
873            lost: 0,
874            has_data: false,
875            is_pmtud_probe: false,
876        };
877
878        r.on_packet_sent(
879            p,
880            packet::Epoch::Application,
881            HandshakeStatus::default(),
882            now,
883            "",
884        );
885        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
886        assert_eq!(r.bytes_in_flight(), 4000);
887        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
888
889        // Wait for 10ms.
890        now += Duration::from_millis(10);
891
892        // Only the first 2 packets are acked.
893        let mut acked = RangeSet::default();
894        acked.insert(0..2);
895
896        assert_eq!(
897            r.on_ack_received(
898                &acked,
899                25,
900                packet::Epoch::Application,
901                HandshakeStatus::default(),
902                now,
903                None,
904                "",
905            )
906            .unwrap(),
907            OnAckReceivedOutcome {
908                lost_packets: 0,
909                lost_bytes: 0,
910                acked_bytes: 2 * 1000,
911                spurious_losses: 0,
912            }
913        );
914
915        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
916        assert_eq!(r.bytes_in_flight(), 2000);
917        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
918        assert_eq!(r.lost_count(), 0);
919
920        // Wait until loss detection timer expires.
921        now = r.loss_detection_timer().unwrap();
922
923        // PTO.
924        r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
925        assert_eq!(r.loss_probes(packet::Epoch::Application), 1);
926        assert_eq!(r.lost_count(), 0);
927        assert_eq!(r.pto_count(), 1);
928
929        let p = Sent {
930            pkt_num: 4,
931            frames: smallvec![],
932            time_sent: now,
933            time_acked: None,
934            time_lost: None,
935            size: 1000,
936            ack_eliciting: true,
937            in_flight: true,
938            delivered: 0,
939            delivered_time: now,
940            first_sent_time: now,
941            is_app_limited: false,
942            tx_in_flight: 0,
943            lost: 0,
944            has_data: false,
945            is_pmtud_probe: false,
946        };
947
948        r.on_packet_sent(
949            p,
950            packet::Epoch::Application,
951            HandshakeStatus::default(),
952            now,
953            "",
954        );
955        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
956        assert_eq!(r.bytes_in_flight(), 3000);
957        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(30));
958
959        let p = Sent {
960            pkt_num: 5,
961            frames: smallvec![],
962            time_sent: now,
963            time_acked: None,
964            time_lost: None,
965            size: 1000,
966            ack_eliciting: true,
967            in_flight: true,
968            delivered: 0,
969            delivered_time: now,
970            first_sent_time: now,
971            is_app_limited: false,
972            tx_in_flight: 0,
973            lost: 0,
974            has_data: false,
975            is_pmtud_probe: false,
976        };
977
978        r.on_packet_sent(
979            p,
980            packet::Epoch::Application,
981            HandshakeStatus::default(),
982            now,
983            "",
984        );
985        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
986        assert_eq!(r.bytes_in_flight(), 4000);
987        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(30));
988        assert_eq!(r.lost_count(), 0);
989
990        // Wait for 10ms.
991        now += Duration::from_millis(10);
992
993        // PTO packets are acked.
994        let mut acked = RangeSet::default();
995        acked.insert(4..6);
996
997        assert_eq!(
998            r.on_ack_received(
999                &acked,
1000                25,
1001                packet::Epoch::Application,
1002                HandshakeStatus::default(),
1003                now,
1004                None,
1005                "",
1006            )
1007            .unwrap(),
1008            OnAckReceivedOutcome {
1009                lost_packets: 2,
1010                lost_bytes: 2000,
1011                acked_bytes: 2 * 1000,
1012                spurious_losses: 0,
1013            }
1014        );
1015
1016        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1017        assert_eq!(r.bytes_in_flight(), 0);
1018        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(40));
1019
1020        assert_eq!(r.lost_count(), 2);
1021
1022        // Wait 1 RTT.
1023        now += r.rtt();
1024
1025        assert_eq!(
1026            r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1027            (0, 0)
1028        );
1029
1030        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1031        if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1032            assert!(r.startup_exit().is_some());
1033            assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1034        } else {
1035            assert_eq!(r.startup_exit(), None);
1036        }
1037    }
1038
1039    #[rstest]
1040    fn loss_on_timer(
1041        #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
1042        cc_algorithm_name: &str,
1043    ) {
1044        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1045        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1046
1047        let mut r = Recovery::new(&cfg);
1048
1049        let mut now = Instant::now();
1050
1051        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1052
1053        // Start by sending a few packets.
1054        let p = Sent {
1055            pkt_num: 0,
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), 1);
1081        assert_eq!(r.bytes_in_flight(), 1000);
1082        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1083
1084        let p = Sent {
1085            pkt_num: 1,
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), 2);
1111        assert_eq!(r.bytes_in_flight(), 2000);
1112        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
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            is_pmtud_probe: 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        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1143
1144        let p = Sent {
1145            pkt_num: 3,
1146            frames: smallvec![],
1147            time_sent: now,
1148            time_acked: None,
1149            time_lost: None,
1150            size: 1000,
1151            ack_eliciting: true,
1152            in_flight: true,
1153            delivered: 0,
1154            delivered_time: now,
1155            first_sent_time: now,
1156            is_app_limited: false,
1157            tx_in_flight: 0,
1158            lost: 0,
1159            has_data: false,
1160            is_pmtud_probe: false,
1161        };
1162
1163        r.on_packet_sent(
1164            p,
1165            packet::Epoch::Application,
1166            HandshakeStatus::default(),
1167            now,
1168            "",
1169        );
1170        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1171        assert_eq!(r.bytes_in_flight(), 4000);
1172        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1173
1174        // Wait for 10ms.
1175        now += Duration::from_millis(10);
1176
1177        // Only the first 2 packets and the last one are acked.
1178        let mut acked = RangeSet::default();
1179        acked.insert(0..2);
1180        acked.insert(3..4);
1181
1182        assert_eq!(
1183            r.on_ack_received(
1184                &acked,
1185                25,
1186                packet::Epoch::Application,
1187                HandshakeStatus::default(),
1188                now,
1189                None,
1190                "",
1191            )
1192            .unwrap(),
1193            OnAckReceivedOutcome {
1194                lost_packets: 0,
1195                lost_bytes: 0,
1196                acked_bytes: 3 * 1000,
1197                spurious_losses: 0,
1198            }
1199        );
1200
1201        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1202        assert_eq!(r.bytes_in_flight(), 1000);
1203        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
1204        assert_eq!(r.lost_count(), 0);
1205
1206        // Wait until loss detection timer expires.
1207        now = r.loss_detection_timer().unwrap();
1208
1209        // Packet is declared lost.
1210        r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
1211        assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
1212
1213        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1214        assert_eq!(r.bytes_in_flight(), 0);
1215        assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
1216
1217        assert_eq!(r.lost_count(), 1);
1218
1219        // Wait 1 RTT.
1220        now += r.rtt();
1221
1222        assert_eq!(
1223            r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1224            (0, 0)
1225        );
1226
1227        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1228        if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1229            assert!(r.startup_exit().is_some());
1230            assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1231        } else {
1232            assert_eq!(r.startup_exit(), None);
1233        }
1234    }
1235
1236    #[rstest]
1237    fn loss_on_reordering(
1238        #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
1239        cc_algorithm_name: &str,
1240    ) {
1241        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1242        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1243
1244        let mut r = Recovery::new(&cfg);
1245
1246        let mut now = Instant::now();
1247
1248        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1249
1250        // Start by sending a few packets.
1251        //
1252        // pkt number: [0, 1, 2, 3]
1253        for i in 0..4 {
1254            let p = test_utils::helper_packet_sent(i, now, 1000);
1255            r.on_packet_sent(
1256                p,
1257                packet::Epoch::Application,
1258                HandshakeStatus::default(),
1259                now,
1260                "",
1261            );
1262
1263            let pkt_count = (i + 1) as usize;
1264            assert_eq!(r.sent_packets_len(packet::Epoch::Application), pkt_count);
1265            assert_eq!(r.bytes_in_flight(), pkt_count * 1000);
1266            assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1267        }
1268
1269        // Wait for 10ms after sending.
1270        now += Duration::from_millis(10);
1271
1272        // Recieve reordered ACKs, i.e. pkt_num [2, 3]
1273        let mut acked = RangeSet::default();
1274        acked.insert(2..4);
1275        assert_eq!(
1276            r.on_ack_received(
1277                &acked,
1278                25,
1279                packet::Epoch::Application,
1280                HandshakeStatus::default(),
1281                now,
1282                None,
1283                "",
1284            )
1285            .unwrap(),
1286            OnAckReceivedOutcome {
1287                lost_packets: 1,
1288                lost_bytes: 1000,
1289                acked_bytes: 1000 * 2,
1290                spurious_losses: 0,
1291            }
1292        );
1293        // Since we only remove packets from the back to avoid compaction, the
1294        // send length remains the same after receiving reordered ACKs
1295        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1296        assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1297        assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1298
1299        // Wait for 10ms after receiving first set of ACKs.
1300        now += Duration::from_millis(10);
1301
1302        // Recieve remaining ACKs, i.e. pkt_num [0, 1]
1303        let mut acked = RangeSet::default();
1304        acked.insert(0..2);
1305        assert_eq!(
1306            r.on_ack_received(
1307                &acked,
1308                25,
1309                packet::Epoch::Application,
1310                HandshakeStatus::default(),
1311                now,
1312                None,
1313                "",
1314            )
1315            .unwrap(),
1316            OnAckReceivedOutcome {
1317                lost_packets: 0,
1318                lost_bytes: 0,
1319                acked_bytes: 1000,
1320                spurious_losses: 1,
1321            }
1322        );
1323        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1324        assert_eq!(r.bytes_in_flight(), 0);
1325        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(20));
1326
1327        // Spurious loss.
1328        assert_eq!(r.lost_count(), 1);
1329        assert_eq!(r.lost_spurious_count(), 1);
1330
1331        // Packet threshold was increased.
1332        assert_eq!(r.pkt_thresh().unwrap(), 4);
1333        assert_eq!(r.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1334
1335        // Wait 1 RTT.
1336        now += r.rtt();
1337
1338        // All packets have been ACKed so dont expect additional lost packets
1339        assert_eq!(
1340            r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1341            (0, 0)
1342        );
1343        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1344
1345        if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1346            assert!(r.startup_exit().is_some());
1347            assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1348        } else {
1349            assert_eq!(r.startup_exit(), None);
1350        }
1351    }
1352
1353    // TODO: This should run agains both `congestion` and `gcongestion`.
1354    // `congestion` and `gcongestion` behave differently. That might be ok
1355    // given the different algorithms but it would be ideal to merge and share
1356    // the logic.
1357    #[rstest]
1358    fn time_thresholds_on_reordering(
1359        #[values("bbr2_gcongestion")] cc_algorithm_name: &str,
1360    ) {
1361        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1362        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1363
1364        let mut now = Instant::now();
1365        let mut r = Recovery::new(&cfg);
1366        assert_eq!(r.rtt(), DEFAULT_INITIAL_RTT);
1367
1368        // Pick time between and above thresholds for testing threshold increase.
1369        //
1370        //```
1371        //              between_thresh_ms
1372        //                         |
1373        //    initial_thresh_ms    |     spurious_thresh_ms
1374        //      v                  v             v
1375        // --------------------------------------------------
1376        //      | ................ | ..................... |
1377        //            THRESH_GAP         THRESH_GAP
1378        // ```
1379        // 
1380        // Threshold gap time.
1381        const THRESH_GAP: Duration = Duration::from_millis(30);
1382        // Initial time theshold based on inital RTT.
1383        let initial_thresh_ms =
1384            DEFAULT_INITIAL_RTT.mul_f64(INITIAL_TIME_THRESHOLD);
1385        // The time threshold after spurious loss.
1386        let spurious_thresh_ms: Duration =
1387            DEFAULT_INITIAL_RTT.mul_f64(PACKET_REORDER_TIME_THRESHOLD);
1388        // Time between the two thresholds
1389        let between_thresh_ms = initial_thresh_ms + THRESH_GAP;
1390        assert!(between_thresh_ms > initial_thresh_ms);
1391        assert!(between_thresh_ms < spurious_thresh_ms);
1392        assert!(between_thresh_ms + THRESH_GAP > spurious_thresh_ms);
1393
1394        for i in 0..6 {
1395            let send_time = now + i * between_thresh_ms;
1396
1397            let p = test_utils::helper_packet_sent(i.into(), send_time, 1000);
1398            r.on_packet_sent(
1399                p,
1400                packet::Epoch::Application,
1401                HandshakeStatus::default(),
1402                send_time,
1403                "",
1404            );
1405        }
1406
1407        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 6);
1408        assert_eq!(r.bytes_in_flight(), 6 * 1000);
1409        assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1410        assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1411
1412        // Wait for `between_thresh_ms` after sending to trigger loss based on
1413        // loss threshold.
1414        now += between_thresh_ms;
1415
1416        // Ack packet: 1
1417        //
1418        // [0, 1, 2, 3, 4, 5]
1419        //     ^
1420        let mut acked = RangeSet::default();
1421        acked.insert(1..2);
1422        assert_eq!(
1423            r.on_ack_received(
1424                &acked,
1425                25,
1426                packet::Epoch::Application,
1427                HandshakeStatus::default(),
1428                now,
1429                None,
1430                "",
1431            )
1432            .unwrap(),
1433            OnAckReceivedOutcome {
1434                lost_packets: 1,
1435                lost_bytes: 1000,
1436                acked_bytes: 1000,
1437                spurious_losses: 0,
1438            }
1439        );
1440        assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1441        assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1442
1443        // Ack packet: 0
1444        //
1445        // [0, 1, 2, 3, 4, 5]
1446        //  ^  x
1447        let mut acked = RangeSet::default();
1448        acked.insert(0..1);
1449        assert_eq!(
1450            r.on_ack_received(
1451                &acked,
1452                25,
1453                packet::Epoch::Application,
1454                HandshakeStatus::default(),
1455                now,
1456                None,
1457                "",
1458            )
1459            .unwrap(),
1460            OnAckReceivedOutcome {
1461                lost_packets: 0,
1462                lost_bytes: 0,
1463                acked_bytes: 0,
1464                spurious_losses: 1,
1465            }
1466        );
1467        // The time_thresh after spurious loss
1468        assert_eq!(r.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1469
1470        // Wait for `between_thresh_ms` after sending. However, since the
1471        // threshold has increased, we do not expect loss.
1472        now += between_thresh_ms;
1473
1474        // Ack packet: 3
1475        //
1476        // [2, 3, 4, 5]
1477        //     ^
1478        let mut acked = RangeSet::default();
1479        acked.insert(3..4);
1480        assert_eq!(
1481            r.on_ack_received(
1482                &acked,
1483                25,
1484                packet::Epoch::Application,
1485                HandshakeStatus::default(),
1486                now,
1487                None,
1488                "",
1489            )
1490            .unwrap(),
1491            OnAckReceivedOutcome {
1492                lost_packets: 0,
1493                lost_bytes: 0,
1494                acked_bytes: 1000,
1495                spurious_losses: 0,
1496            }
1497        );
1498
1499        // Wait for and additional `plus_overhead` to trigger loss based on the
1500        // new time threshold.
1501        now += THRESH_GAP;
1502
1503        // Ack packet: 4
1504        //
1505        // [2, 3, 4, 5]
1506        //     x  ^
1507        let mut acked = RangeSet::default();
1508        acked.insert(4..5);
1509        assert_eq!(
1510            r.on_ack_received(
1511                &acked,
1512                25,
1513                packet::Epoch::Application,
1514                HandshakeStatus::default(),
1515                now,
1516                None,
1517                "",
1518            )
1519            .unwrap(),
1520            OnAckReceivedOutcome {
1521                lost_packets: 1,
1522                lost_bytes: 1000,
1523                acked_bytes: 1000,
1524                spurious_losses: 0,
1525            }
1526        );
1527    }
1528
1529    // TODO: Implement enable_relaxed_loss_threshold and enable this test for the
1530    // congestion module.
1531    #[rstest]
1532    fn relaxed_thresholds_on_reordering(
1533        #[values("bbr2_gcongestion")] cc_algorithm_name: &str,
1534    ) {
1535        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1536        cfg.enable_relaxed_loss_threshold = true;
1537        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1538
1539        let mut now = Instant::now();
1540        let mut r = Recovery::new(&cfg);
1541        assert_eq!(r.rtt(), DEFAULT_INITIAL_RTT);
1542
1543        // Pick time between and above thresholds for testing threshold increase.
1544        //
1545        //```
1546        //              between_thresh_ms
1547        //                         |
1548        //    initial_thresh_ms    |     spurious_thresh_ms
1549        //      v                  v             v
1550        // --------------------------------------------------
1551        //      | ................ | ..................... |
1552        //            THRESH_GAP         THRESH_GAP
1553        // ```
1554        // Threshold gap time.
1555        const THRESH_GAP: Duration = Duration::from_millis(30);
1556        // Initial time theshold based on inital RTT.
1557        let initial_thresh_ms =
1558            DEFAULT_INITIAL_RTT.mul_f64(INITIAL_TIME_THRESHOLD);
1559        // The time threshold after spurious loss.
1560        let spurious_thresh_ms: Duration =
1561            DEFAULT_INITIAL_RTT.mul_f64(PACKET_REORDER_TIME_THRESHOLD);
1562        // Time between the two thresholds
1563        let between_thresh_ms = initial_thresh_ms + THRESH_GAP;
1564        assert!(between_thresh_ms > initial_thresh_ms);
1565        assert!(between_thresh_ms < spurious_thresh_ms);
1566        assert!(between_thresh_ms + THRESH_GAP > spurious_thresh_ms);
1567
1568        for i in 0..6 {
1569            let send_time = now + i * between_thresh_ms;
1570
1571            let p = test_utils::helper_packet_sent(i.into(), send_time, 1000);
1572            r.on_packet_sent(
1573                p,
1574                packet::Epoch::Application,
1575                HandshakeStatus::default(),
1576                send_time,
1577                "",
1578            );
1579        }
1580
1581        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 6);
1582        assert_eq!(r.bytes_in_flight(), 6 * 1000);
1583        // Intitial thresholds
1584        assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1585        assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1586
1587        // Wait for `between_thresh_ms` after sending to trigger loss based on
1588        // loss threshold.
1589        now += between_thresh_ms;
1590
1591        // Ack packet: 1
1592        //
1593        // [0, 1, 2, 3, 4, 5]
1594        //     ^
1595        let mut acked = RangeSet::default();
1596        acked.insert(1..2);
1597        assert_eq!(
1598            r.on_ack_received(
1599                &acked,
1600                25,
1601                packet::Epoch::Application,
1602                HandshakeStatus::default(),
1603                now,
1604                None,
1605                "",
1606            )
1607            .unwrap(),
1608            OnAckReceivedOutcome {
1609                lost_packets: 1,
1610                lost_bytes: 1000,
1611                acked_bytes: 1000,
1612                spurious_losses: 0,
1613            }
1614        );
1615        // Thresholds after 1st loss
1616        assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1617        assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1618
1619        // Ack packet: 0
1620        //
1621        // [0, 1, 2, 3, 4, 5]
1622        //  ^  x
1623        let mut acked = RangeSet::default();
1624        acked.insert(0..1);
1625        assert_eq!(
1626            r.on_ack_received(
1627                &acked,
1628                25,
1629                packet::Epoch::Application,
1630                HandshakeStatus::default(),
1631                now,
1632                None,
1633                "",
1634            )
1635            .unwrap(),
1636            OnAckReceivedOutcome {
1637                lost_packets: 0,
1638                lost_bytes: 0,
1639                acked_bytes: 0,
1640                spurious_losses: 1,
1641            }
1642        );
1643        // Thresholds after 1st spurious loss
1644        //
1645        // Packet threshold should be disabled. Time threshold overhead should
1646        // stay the same.
1647        assert_eq!(r.pkt_thresh(), None);
1648        assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1649
1650        // Set now to send time of packet 2 so we can trigger spurious loss for
1651        // packet 2.
1652        now += between_thresh_ms;
1653        // Then wait for `between_thresh_ms` after sending packet 2 to trigger
1654        // loss. Since the time threshold has NOT increased, expect a
1655        // loss.
1656        now += between_thresh_ms;
1657
1658        // Ack packet: 3
1659        //
1660        // [2, 3, 4, 5]
1661        //     ^
1662        let mut acked = RangeSet::default();
1663        acked.insert(3..4);
1664        assert_eq!(
1665            r.on_ack_received(
1666                &acked,
1667                25,
1668                packet::Epoch::Application,
1669                HandshakeStatus::default(),
1670                now,
1671                None,
1672                "",
1673            )
1674            .unwrap(),
1675            OnAckReceivedOutcome {
1676                lost_packets: 1,
1677                lost_bytes: 1000,
1678                acked_bytes: 1000,
1679                spurious_losses: 0,
1680            }
1681        );
1682        // Thresholds after 2nd loss.
1683        assert_eq!(r.pkt_thresh(), None);
1684        assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1685
1686        // Wait for and additional `plus_overhead` to trigger loss based on the
1687        // new time threshold.
1688        // now += THRESH_GAP;
1689
1690        // Ack packet: 2
1691        //
1692        // [2, 3, 4, 5]
1693        //  ^  x
1694        let mut acked = RangeSet::default();
1695        acked.insert(2..3);
1696        assert_eq!(
1697            r.on_ack_received(
1698                &acked,
1699                25,
1700                packet::Epoch::Application,
1701                HandshakeStatus::default(),
1702                now,
1703                None,
1704                "",
1705            )
1706            .unwrap(),
1707            OnAckReceivedOutcome {
1708                lost_packets: 0,
1709                lost_bytes: 0,
1710                acked_bytes: 0,
1711                spurious_losses: 1,
1712            }
1713        );
1714        // Thresholds after 2nd spurious loss.
1715        //
1716        // Time threshold overhead should double.
1717        assert_eq!(r.pkt_thresh(), None);
1718        let double_time_thresh_overhead =
1719            1.0 + 2.0 * INITIAL_TIME_THRESHOLD_OVERHEAD;
1720        assert_eq!(r.time_thresh(), double_time_thresh_overhead);
1721    }
1722
1723    #[rstest]
1724    fn pacing(
1725        #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
1726        cc_algorithm_name: &str,
1727    ) {
1728        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1729        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1730
1731        let mut r = Recovery::new(&cfg);
1732
1733        let mut now = Instant::now();
1734
1735        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1736
1737        // send out first packet burst (a full initcwnd).
1738        for i in 0..10 {
1739            let p = Sent {
1740                pkt_num: i,
1741                frames: smallvec![],
1742                time_sent: now,
1743                time_acked: None,
1744                time_lost: None,
1745                size: 1200,
1746                ack_eliciting: true,
1747                in_flight: true,
1748                delivered: 0,
1749                delivered_time: now,
1750                first_sent_time: now,
1751                is_app_limited: false,
1752                tx_in_flight: 0,
1753                lost: 0,
1754                has_data: true,
1755                is_pmtud_probe: false,
1756            };
1757
1758            r.on_packet_sent(
1759                p,
1760                packet::Epoch::Application,
1761                HandshakeStatus::default(),
1762                now,
1763                "",
1764            );
1765        }
1766
1767        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 10);
1768        assert_eq!(r.bytes_in_flight(), 12000);
1769        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1770
1771        // Next packet will be sent out immediately.
1772        if cc_algorithm_name == "cubic" || cc_algorithm_name == "reno" {
1773            assert_eq!(r.pacing_rate(), 0);
1774        } else {
1775            assert_eq!(r.pacing_rate(), 103963);
1776        }
1777        assert_eq!(r.get_packet_send_time(now), now);
1778
1779        assert_eq!(r.cwnd(), 12000);
1780        assert_eq!(r.cwnd_available(), 0);
1781
1782        // Wait 50ms for ACK.
1783        now += Duration::from_millis(50);
1784
1785        let mut acked = RangeSet::default();
1786        acked.insert(0..10);
1787
1788        assert_eq!(
1789            r.on_ack_received(
1790                &acked,
1791                10,
1792                packet::Epoch::Application,
1793                HandshakeStatus::default(),
1794                now,
1795                None,
1796                "",
1797            )
1798            .unwrap(),
1799            OnAckReceivedOutcome {
1800                lost_packets: 0,
1801                lost_bytes: 0,
1802                acked_bytes: 12000,
1803                spurious_losses: 0,
1804            }
1805        );
1806
1807        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1808        assert_eq!(r.bytes_in_flight(), 0);
1809        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(50));
1810        assert_eq!(r.rtt(), Duration::from_millis(50));
1811
1812        // 10 MSS increased due to acks.
1813        assert_eq!(r.cwnd(), 12000 + 1200 * 10);
1814
1815        // Send the second packet burst.
1816        let p = Sent {
1817            pkt_num: 10,
1818            frames: smallvec![],
1819            time_sent: now,
1820            time_acked: None,
1821            time_lost: None,
1822            size: 6000,
1823            ack_eliciting: true,
1824            in_flight: true,
1825            delivered: 0,
1826            delivered_time: now,
1827            first_sent_time: now,
1828            is_app_limited: false,
1829            tx_in_flight: 0,
1830            lost: 0,
1831            has_data: true,
1832            is_pmtud_probe: false,
1833        };
1834
1835        r.on_packet_sent(
1836            p,
1837            packet::Epoch::Application,
1838            HandshakeStatus::default(),
1839            now,
1840            "",
1841        );
1842
1843        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1844        assert_eq!(r.bytes_in_flight(), 6000);
1845        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(50));
1846
1847        if cc_algorithm_name == "cubic" || cc_algorithm_name == "reno" {
1848            // Pacing is disabled.
1849            assert_eq!(r.get_packet_send_time(now), now);
1850        } else {
1851            // Pacing is done from the beginning.
1852            assert_ne!(r.get_packet_send_time(now), now);
1853        }
1854
1855        // Send the third packet burst.
1856        let p = Sent {
1857            pkt_num: 11,
1858            frames: smallvec![],
1859            time_sent: now,
1860            time_acked: None,
1861            time_lost: None,
1862            size: 6000,
1863            ack_eliciting: true,
1864            in_flight: true,
1865            delivered: 0,
1866            delivered_time: now,
1867            first_sent_time: now,
1868            is_app_limited: false,
1869            tx_in_flight: 0,
1870            lost: 0,
1871            has_data: true,
1872            is_pmtud_probe: false,
1873        };
1874
1875        r.on_packet_sent(
1876            p,
1877            packet::Epoch::Application,
1878            HandshakeStatus::default(),
1879            now,
1880            "",
1881        );
1882
1883        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1884        assert_eq!(r.bytes_in_flight(), 12000);
1885        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(50));
1886
1887        // Send the fourth packet burst.
1888        let p = Sent {
1889            pkt_num: 12,
1890            frames: smallvec![],
1891            time_sent: now,
1892            time_acked: None,
1893            time_lost: None,
1894            size: 1000,
1895            ack_eliciting: true,
1896            in_flight: true,
1897            delivered: 0,
1898            delivered_time: now,
1899            first_sent_time: now,
1900            is_app_limited: false,
1901            tx_in_flight: 0,
1902            lost: 0,
1903            has_data: true,
1904            is_pmtud_probe: false,
1905        };
1906
1907        r.on_packet_sent(
1908            p,
1909            packet::Epoch::Application,
1910            HandshakeStatus::default(),
1911            now,
1912            "",
1913        );
1914
1915        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1916        assert_eq!(r.bytes_in_flight(), 13000);
1917        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(50));
1918
1919        // We pace this outgoing packet. as all conditions for pacing
1920        // are passed.
1921        let pacing_rate = match cc_algorithm_name {
1922            "bbr2_gcongestion" | "bbr2" => {
1923                let cwnd_gain: f64 = 2.0;
1924                // Adjust for cwnd_gain.  BW estimate was made before the CWND
1925                // increase.
1926                let bw = r.cwnd() as f64 /
1927                    cwnd_gain /
1928                    Duration::from_millis(50).as_secs_f64();
1929                bw as u64
1930            },
1931            _ => 0,
1932        };
1933        assert_eq!(r.pacing_rate(), pacing_rate);
1934
1935        let scale_factor = if cc_algorithm_name == "bbr2_gcongestion" ||
1936            cc_algorithm_name == "bbr2"
1937        {
1938            // For bbr2_gcongestion, send time is almost 13000 / pacing_rate.
1939            // Don't know where 13000 comes from.
1940            1.08333332
1941        } else {
1942            1.0
1943        };
1944        assert_eq!(
1945            r.get_packet_send_time(now) - now,
1946            if cc_algorithm_name == "bbr2_gcongestion" ||
1947                cc_algorithm_name == "bbr2"
1948            {
1949                Duration::from_secs_f64(
1950                    scale_factor * 12000.0 / pacing_rate as f64,
1951                )
1952            } else {
1953                Duration::ZERO
1954            }
1955        );
1956        assert_eq!(r.startup_exit(), None);
1957    }
1958
1959    #[rstest]
1960    // initial_cwnd / first_rtt == initial_pacing_rate.  Pacing is 1.0 * bw before
1961    // and after.
1962    #[case::bw_estimate_equal_after_first_rtt(1.0, 1.0)]
1963    // initial_cwnd / first_rtt < initial_pacing_rate.  Pacing decreases from 2 *
1964    // bw to 1.0 * bw.
1965    #[case::bw_estimate_decrease_after_first_rtt(2.0, 1.0)]
1966    // initial_cwnd / first_rtt > initial_pacing_rate from 0.5 * bw to 1.0 * bw.
1967    // Initial pacing remains 0.5 * bw because the initial_pacing_rate parameter
1968    // is used an upper bound for the pacing rate after the first RTT.
1969    // Pacing rate after the first ACK should be:
1970    // min(initial_pacing_rate_bytes_per_second, init_cwnd / first_rtt)
1971    #[case::bw_estimate_increase_after_first_rtt(0.5, 0.5)]
1972    #[cfg(feature = "internal")]
1973    fn initial_pacing_rate_override(
1974        #[case] initial_multipler: f64, #[case] expected_multiplier: f64,
1975    ) {
1976        let rtt = Duration::from_millis(50);
1977        let bw = Bandwidth::from_bytes_and_time_delta(12000, rtt);
1978        let initial_pacing_rate_hint = bw * initial_multipler;
1979        let expected_pacing_with_rtt_measurement = bw * expected_multiplier;
1980
1981        let cc_algorithm_name = "bbr2_gcongestion";
1982        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1983        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1984        cfg.set_custom_bbr_params(BbrParams {
1985            initial_pacing_rate_bytes_per_second: Some(
1986                initial_pacing_rate_hint.to_bytes_per_second(),
1987            ),
1988            ..Default::default()
1989        });
1990
1991        let mut r = Recovery::new(&cfg);
1992
1993        let mut now = Instant::now();
1994
1995        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1996
1997        // send some packets.
1998        for i in 0..2 {
1999            let p = test_utils::helper_packet_sent(i, now, 1200);
2000            r.on_packet_sent(
2001                p,
2002                packet::Epoch::Application,
2003                HandshakeStatus::default(),
2004                now,
2005                "",
2006            );
2007        }
2008
2009        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2010        assert_eq!(r.bytes_in_flight(), 2400);
2011        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2012
2013        // Initial pacing rate matches the override value.
2014        assert_eq!(
2015            r.pacing_rate(),
2016            initial_pacing_rate_hint.to_bytes_per_second()
2017        );
2018        assert_eq!(r.get_packet_send_time(now), now);
2019
2020        assert_eq!(r.cwnd(), 12000);
2021        assert_eq!(r.cwnd_available(), 9600);
2022
2023        // Wait 1 rtt for ACK.
2024        now += rtt;
2025
2026        let mut acked = RangeSet::default();
2027        acked.insert(0..2);
2028
2029        assert_eq!(
2030            r.on_ack_received(
2031                &acked,
2032                10,
2033                packet::Epoch::Application,
2034                HandshakeStatus::default(),
2035                now,
2036                None,
2037                "",
2038            )
2039            .unwrap(),
2040            OnAckReceivedOutcome {
2041                lost_packets: 0,
2042                lost_bytes: 0,
2043                acked_bytes: 2400,
2044                spurious_losses: 0,
2045            }
2046        );
2047
2048        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2049        assert_eq!(r.bytes_in_flight(), 0);
2050        assert_eq!(r.bytes_in_flight_duration(), rtt);
2051        assert_eq!(r.rtt(), rtt);
2052
2053        // Pacing rate is recalculated based on initial cwnd when the
2054        // first RTT estimate is available.
2055        assert_eq!(
2056            r.pacing_rate(),
2057            expected_pacing_with_rtt_measurement.to_bytes_per_second()
2058        );
2059    }
2060
2061    #[rstest]
2062    fn validate_ack_range_on_ack_received(
2063        #[values("cubic", "bbr2", "bbr2_gcongestion")] cc_algorithm_name: &str,
2064    ) {
2065        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2066        cfg.set_cc_algorithm_name(cc_algorithm_name).unwrap();
2067
2068        let epoch = packet::Epoch::Application;
2069        let mut r = Recovery::new(&cfg);
2070        let mut now = Instant::now();
2071        assert_eq!(r.sent_packets_len(epoch), 0);
2072
2073        // Send 4 packets
2074        let pkt_size = 1000;
2075        let pkt_count = 4;
2076        for pkt_num in 0..pkt_count {
2077            let sent = test_utils::helper_packet_sent(pkt_num, now, pkt_size);
2078            r.on_packet_sent(sent, epoch, HandshakeStatus::default(), now, "");
2079        }
2080        assert_eq!(r.sent_packets_len(epoch), pkt_count as usize);
2081        assert_eq!(r.bytes_in_flight(), pkt_count as usize * pkt_size);
2082        assert!(r.get_largest_acked_on_epoch(epoch).is_none());
2083        assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2084
2085        // Wait for 10ms.
2086        now += Duration::from_millis(10);
2087
2088        // ACK 2 packets
2089        let mut acked = RangeSet::default();
2090        acked.insert(0..2);
2091
2092        assert_eq!(
2093            r.on_ack_received(
2094                &acked,
2095                25,
2096                epoch,
2097                HandshakeStatus::default(),
2098                now,
2099                None,
2100                "",
2101            )
2102            .unwrap(),
2103            OnAckReceivedOutcome {
2104                lost_packets: 0,
2105                lost_bytes: 0,
2106                acked_bytes: 2 * 1000,
2107                spurious_losses: 0,
2108            }
2109        );
2110
2111        assert_eq!(r.sent_packets_len(epoch), 2);
2112        assert_eq!(r.bytes_in_flight(), 2 * 1000);
2113
2114        assert_eq!(r.get_largest_acked_on_epoch(epoch).unwrap(), 1);
2115        assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2116
2117        // ACK large range
2118        let mut acked = RangeSet::default();
2119        acked.insert(0..10);
2120        assert_eq!(
2121            r.on_ack_received(
2122                &acked,
2123                25,
2124                epoch,
2125                HandshakeStatus::default(),
2126                now,
2127                None,
2128                "",
2129            )
2130            .unwrap(),
2131            OnAckReceivedOutcome {
2132                lost_packets: 0,
2133                lost_bytes: 0,
2134                acked_bytes: 2 * 1000,
2135                spurious_losses: 0,
2136            }
2137        );
2138        assert_eq!(r.sent_packets_len(epoch), 0);
2139        assert_eq!(r.bytes_in_flight(), 0);
2140
2141        assert_eq!(r.get_largest_acked_on_epoch(epoch).unwrap(), 3);
2142        assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2143    }
2144
2145    #[rstest]
2146    fn pmtud_loss_on_timer(
2147        #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
2148        cc_algorithm_name: &str,
2149    ) {
2150        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2151        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2152
2153        let mut r = Recovery::new(&cfg);
2154        assert_eq!(r.cwnd(), 12000);
2155
2156        let mut now = Instant::now();
2157
2158        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2159
2160        // Start by sending a few packets.
2161        let p = Sent {
2162            pkt_num: 0,
2163            frames: smallvec![],
2164            time_sent: now,
2165            time_acked: None,
2166            time_lost: None,
2167            size: 1000,
2168            ack_eliciting: true,
2169            in_flight: true,
2170            delivered: 0,
2171            delivered_time: now,
2172            first_sent_time: now,
2173            is_app_limited: false,
2174            tx_in_flight: 0,
2175            lost: 0,
2176            has_data: false,
2177            is_pmtud_probe: false,
2178        };
2179
2180        r.on_packet_sent(
2181            p,
2182            packet::Epoch::Application,
2183            HandshakeStatus::default(),
2184            now,
2185            "",
2186        );
2187
2188        assert_eq!(r.in_flight_count(packet::Epoch::Application), 1);
2189        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
2190        assert_eq!(r.bytes_in_flight(), 1000);
2191        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2192
2193        let p = Sent {
2194            pkt_num: 1,
2195            frames: smallvec![],
2196            time_sent: now,
2197            time_acked: None,
2198            time_lost: None,
2199            size: 1000,
2200            ack_eliciting: true,
2201            in_flight: true,
2202            delivered: 0,
2203            delivered_time: now,
2204            first_sent_time: now,
2205            is_app_limited: false,
2206            tx_in_flight: 0,
2207            lost: 0,
2208            has_data: false,
2209            is_pmtud_probe: true,
2210        };
2211
2212        r.on_packet_sent(
2213            p,
2214            packet::Epoch::Application,
2215            HandshakeStatus::default(),
2216            now,
2217            "",
2218        );
2219
2220        assert_eq!(r.in_flight_count(packet::Epoch::Application), 2);
2221
2222        let p = Sent {
2223            pkt_num: 2,
2224            frames: smallvec![],
2225            time_sent: now,
2226            time_acked: None,
2227            time_lost: None,
2228            size: 1000,
2229            ack_eliciting: true,
2230            in_flight: true,
2231            delivered: 0,
2232            delivered_time: now,
2233            first_sent_time: now,
2234            is_app_limited: false,
2235            tx_in_flight: 0,
2236            lost: 0,
2237            has_data: false,
2238            is_pmtud_probe: false,
2239        };
2240
2241        r.on_packet_sent(
2242            p,
2243            packet::Epoch::Application,
2244            HandshakeStatus::default(),
2245            now,
2246            "",
2247        );
2248
2249        assert_eq!(r.in_flight_count(packet::Epoch::Application), 3);
2250
2251        // Wait for 10ms.
2252        now += Duration::from_millis(10);
2253
2254        // Only the first  packets and the last one are acked.
2255        let mut acked = RangeSet::default();
2256        acked.insert(0..1);
2257        acked.insert(2..3);
2258
2259        assert_eq!(
2260            r.on_ack_received(
2261                &acked,
2262                25,
2263                packet::Epoch::Application,
2264                HandshakeStatus::default(),
2265                now,
2266                None,
2267                "",
2268            )
2269            .unwrap(),
2270            OnAckReceivedOutcome {
2271                lost_packets: 0,
2272                lost_bytes: 0,
2273                acked_bytes: 2 * 1000,
2274                spurious_losses: 0,
2275            }
2276        );
2277
2278        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2279        assert_eq!(r.bytes_in_flight(), 1000);
2280        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
2281        assert_eq!(r.lost_count(), 0);
2282
2283        // Wait until loss detection timer expires.
2284        now = r.loss_detection_timer().unwrap();
2285
2286        // Packet is declared lost.
2287        r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
2288        assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
2289
2290        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2291        assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
2292        assert_eq!(r.bytes_in_flight(), 0);
2293        assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
2294        assert_eq!(r.cwnd(), 12000);
2295
2296        assert_eq!(r.lost_count(), 0);
2297
2298        // Wait 1 RTT.
2299        now += r.rtt();
2300
2301        assert_eq!(
2302            r.detect_lost_packets_for_test(packet::Epoch::Application, now),
2303            (0, 0)
2304        );
2305
2306        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2307        assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
2308        assert_eq!(r.bytes_in_flight(), 0);
2309        assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
2310        assert_eq!(r.lost_count(), 0);
2311        assert_eq!(r.startup_exit(), None);
2312    }
2313
2314    // Modeling delivery_rate for gcongestion is non-trivial so we only test the
2315    // congestion specific algorithms.
2316    #[rstest]
2317    fn congestion_delivery_rate(
2318        #[values("reno", "cubic", "bbr2")] cc_algorithm_name: &str,
2319    ) {
2320        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2321        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2322
2323        let mut r = Recovery::new(&cfg);
2324        assert_eq!(r.cwnd(), 12000);
2325
2326        let now = Instant::now();
2327
2328        let mut total_bytes_sent = 0;
2329        for pn in 0..10 {
2330            // Start by sending a few packets.
2331            let bytes = 1000;
2332            let sent = test_utils::helper_packet_sent(pn, now, bytes);
2333            r.on_packet_sent(
2334                sent,
2335                packet::Epoch::Application,
2336                HandshakeStatus::default(),
2337                now,
2338                "",
2339            );
2340
2341            total_bytes_sent += bytes;
2342        }
2343
2344        // Ack
2345        let interval = Duration::from_secs(10);
2346        let mut acked = RangeSet::default();
2347        acked.insert(0..10);
2348        assert_eq!(
2349            r.on_ack_received(
2350                &acked,
2351                25,
2352                packet::Epoch::Application,
2353                HandshakeStatus::default(),
2354                now + interval,
2355                None,
2356                "",
2357            )
2358            .unwrap(),
2359            OnAckReceivedOutcome {
2360                lost_packets: 0,
2361                lost_bytes: 0,
2362                acked_bytes: total_bytes_sent,
2363                spurious_losses: 0,
2364            }
2365        );
2366        assert_eq!(r.delivery_rate().to_bytes_per_second(), 1000);
2367        assert_eq!(r.min_rtt().unwrap(), interval);
2368        // delivery rate should be in units bytes/sec
2369        assert_eq!(
2370            total_bytes_sent as u64 / interval.as_secs(),
2371            r.delivery_rate().to_bytes_per_second()
2372        );
2373        assert_eq!(r.startup_exit(), None);
2374    }
2375
2376    #[rstest]
2377    fn acks_with_no_retransmittable_data(
2378        #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
2379    ) {
2380        let rtt = Duration::from_millis(100);
2381
2382        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2383        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2384
2385        let mut r = Recovery::new(&cfg);
2386
2387        let mut now = Instant::now();
2388
2389        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2390
2391        let mut next_packet = 0;
2392        // send some packets.
2393        for _ in 0..3 {
2394            let p = test_utils::helper_packet_sent(next_packet, now, 1200);
2395            next_packet += 1;
2396            r.on_packet_sent(
2397                p,
2398                packet::Epoch::Application,
2399                HandshakeStatus::default(),
2400                now,
2401                "",
2402            );
2403        }
2404
2405        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
2406        assert_eq!(r.bytes_in_flight(), 3600);
2407        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2408
2409        assert_eq!(
2410            r.pacing_rate(),
2411            if cc_algorithm_name == "bbr2_gcongestion" {
2412                103963
2413            } else {
2414                0
2415            },
2416        );
2417        assert_eq!(r.get_packet_send_time(now), now);
2418        assert_eq!(r.cwnd(), 12000);
2419        assert_eq!(r.cwnd_available(), 8400);
2420
2421        // Wait 1 rtt for ACK.
2422        now += rtt;
2423
2424        let mut acked = RangeSet::default();
2425        acked.insert(0..3);
2426
2427        assert_eq!(
2428            r.on_ack_received(
2429                &acked,
2430                10,
2431                packet::Epoch::Application,
2432                HandshakeStatus::default(),
2433                now,
2434                None,
2435                "",
2436            )
2437            .unwrap(),
2438            OnAckReceivedOutcome {
2439                lost_packets: 0,
2440                lost_bytes: 0,
2441                acked_bytes: 3600,
2442                spurious_losses: 0,
2443            }
2444        );
2445
2446        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2447        assert_eq!(r.bytes_in_flight(), 0);
2448        assert_eq!(r.bytes_in_flight_duration(), rtt);
2449        assert_eq!(r.rtt(), rtt);
2450
2451        // Pacing rate is recalculated based on initial cwnd when the
2452        // first RTT estimate is available.
2453        assert_eq!(
2454            r.pacing_rate(),
2455            if cc_algorithm_name == "bbr2_gcongestion" {
2456                120000
2457            } else {
2458                0
2459            },
2460        );
2461
2462        // Send some no "in_flight" packets
2463        for iter in 3..1000 {
2464            let mut p = test_utils::helper_packet_sent(next_packet, now, 1200);
2465            // `in_flight = false` marks packets as if they only contained ACK
2466            // frames.
2467            p.in_flight = false;
2468            next_packet += 1;
2469            r.on_packet_sent(
2470                p,
2471                packet::Epoch::Application,
2472                HandshakeStatus::default(),
2473                now,
2474                "",
2475            );
2476
2477            now += rtt;
2478
2479            let mut acked = RangeSet::default();
2480            acked.insert(iter..(iter + 1));
2481
2482            assert_eq!(
2483                r.on_ack_received(
2484                    &acked,
2485                    10,
2486                    packet::Epoch::Application,
2487                    HandshakeStatus::default(),
2488                    now,
2489                    None,
2490                    "",
2491                )
2492                .unwrap(),
2493                OnAckReceivedOutcome {
2494                    lost_packets: 0,
2495                    lost_bytes: 0,
2496                    acked_bytes: 0,
2497                    spurious_losses: 0,
2498                }
2499            );
2500
2501            // Verify that connection has not exited startup.
2502            assert_eq!(r.startup_exit(), None, "{iter}");
2503
2504            // Unchanged metrics.
2505            assert_eq!(
2506                r.sent_packets_len(packet::Epoch::Application),
2507                0,
2508                "{iter}"
2509            );
2510            assert_eq!(r.bytes_in_flight(), 0, "{iter}");
2511            assert_eq!(r.bytes_in_flight_duration(), rtt, "{iter}");
2512            assert_eq!(
2513                r.pacing_rate(),
2514                if cc_algorithm_name == "bbr2_gcongestion" ||
2515                    cc_algorithm_name == "bbr2"
2516                {
2517                    120000
2518                } else {
2519                    0
2520                },
2521                "{iter}"
2522            );
2523        }
2524    }
2525}
2526
2527mod bandwidth;
2528mod bytes_in_flight;
2529mod congestion;
2530mod gcongestion;
2531mod rtt;