Skip to main content

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    fn inc(&mut self, delay: Duration) {
596        match self {
597            ReleaseTime::Immediate => {},
598            ReleaseTime::At(time) => *time += delay,
599        }
600    }
601
602    /// Set the time to the later of two times
603    fn set_max(&mut self, other: Instant) {
604        match self {
605            ReleaseTime::Immediate => *self = ReleaseTime::At(other),
606            ReleaseTime::At(time) => *self = ReleaseTime::At(other.max(*time)),
607        }
608    }
609}
610
611impl ReleaseDecision {
612    pub(crate) const EQUAL_THRESHOLD: Duration = Duration::from_micros(50);
613
614    /// Get the [`Instant`] the next packet should be released. It will never be
615    /// in the past.
616    #[inline]
617    pub fn time(&self, now: Instant) -> Option<Instant> {
618        match self.time {
619            ReleaseTime::Immediate => None,
620            ReleaseTime::At(other) => other.gt(&now).then_some(other),
621        }
622    }
623
624    /// Can this packet be appended to a previous burst
625    #[inline]
626    pub fn can_burst(&self) -> bool {
627        self.allow_burst
628    }
629
630    /// Check if the two packets can be released at the same time
631    #[inline]
632    pub fn time_eq(&self, other: &Self, now: Instant) -> bool {
633        let delta = match (self.time(now), other.time(now)) {
634            (None, None) => Duration::ZERO,
635            (Some(t), None) | (None, Some(t)) => t.duration_since(now),
636            (Some(t1), Some(t2)) if t1 < t2 => t2.duration_since(t1),
637            (Some(t1), Some(t2)) => t1.duration_since(t2),
638        };
639
640        delta <= Self::EQUAL_THRESHOLD
641    }
642}
643
644/// Recovery statistics
645#[derive(Default, Debug)]
646pub struct RecoveryStats {
647    startup_exit: Option<StartupExit>,
648}
649
650impl RecoveryStats {
651    // Record statistics when a CCA first exits startup.
652    pub fn set_startup_exit(&mut self, startup_exit: StartupExit) {
653        if self.startup_exit.is_none() {
654            self.startup_exit = Some(startup_exit);
655        }
656    }
657}
658
659/// Statistics from when a CCA first exited the startup phase.
660#[derive(Debug, Clone, Copy, PartialEq)]
661pub struct StartupExit {
662    /// The congestion_window recorded at Startup exit.
663    pub cwnd: usize,
664
665    /// The bandwidth estimate recorded at Startup exit.
666    pub bandwidth: Option<u64>,
667
668    /// The reason a CCA exited the startup phase.
669    pub reason: StartupExitReason,
670}
671
672impl StartupExit {
673    fn new(
674        cwnd: usize, bandwidth: Option<Bandwidth>, reason: StartupExitReason,
675    ) -> Self {
676        let bandwidth = bandwidth.map(Bandwidth::to_bytes_per_second);
677        Self {
678            cwnd,
679            bandwidth,
680            reason,
681        }
682    }
683}
684
685/// The reason a CCA exited the startup phase.
686#[derive(Debug, Clone, Copy, PartialEq)]
687pub enum StartupExitReason {
688    /// Exit startup due to excessive loss
689    Loss,
690
691    /// Exit startup due to bandwidth plateau.
692    BandwidthPlateau,
693
694    /// Exit startup due to persistent queue.
695    PersistentQueue,
696}
697
698#[cfg(test)]
699mod tests {
700    use super::*;
701    use crate::packet;
702    use crate::test_utils;
703    use crate::CongestionControlAlgorithm;
704    use crate::DEFAULT_INITIAL_RTT;
705    use rstest::rstest;
706    use smallvec::smallvec;
707    use std::str::FromStr;
708
709    fn recovery_for_alg(algo: CongestionControlAlgorithm) -> Recovery {
710        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
711        cfg.set_cc_algorithm(algo);
712        Recovery::new(&cfg)
713    }
714
715    #[test]
716    fn lookup_cc_algo_ok() {
717        let algo = CongestionControlAlgorithm::from_str("reno").unwrap();
718        assert_eq!(algo, CongestionControlAlgorithm::Reno);
719        assert!(!recovery_for_alg(algo).gcongestion_enabled());
720
721        let algo = CongestionControlAlgorithm::from_str("cubic").unwrap();
722        assert_eq!(algo, CongestionControlAlgorithm::CUBIC);
723        assert!(!recovery_for_alg(algo).gcongestion_enabled());
724
725        let algo = CongestionControlAlgorithm::from_str("bbr").unwrap();
726        assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
727        assert!(recovery_for_alg(algo).gcongestion_enabled());
728
729        let algo = CongestionControlAlgorithm::from_str("bbr2").unwrap();
730        assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
731        assert!(recovery_for_alg(algo).gcongestion_enabled());
732
733        let algo =
734            CongestionControlAlgorithm::from_str("bbr2_gcongestion").unwrap();
735        assert_eq!(algo, CongestionControlAlgorithm::Bbr2Gcongestion);
736        assert!(recovery_for_alg(algo).gcongestion_enabled());
737    }
738
739    #[test]
740    fn lookup_cc_algo_bad() {
741        assert_eq!(
742            CongestionControlAlgorithm::from_str("???"),
743            Err(crate::Error::CongestionControl)
744        );
745    }
746
747    #[rstest]
748    fn loss_on_pto(
749        #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
750        cc_algorithm_name: &str,
751    ) {
752        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
753        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
754
755        let mut r = Recovery::new(&cfg);
756
757        let mut now = Instant::now();
758
759        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
760
761        // Start by sending a few packets.
762        let p = Sent {
763            pkt_num: 0,
764            frames: smallvec![],
765            time_sent: now,
766            time_acked: None,
767            time_lost: None,
768            size: 1000,
769            ack_eliciting: true,
770            in_flight: true,
771            delivered: 0,
772            delivered_time: now,
773            first_sent_time: now,
774            is_app_limited: false,
775            tx_in_flight: 0,
776            lost: 0,
777            has_data: false,
778            is_pmtud_probe: false,
779        };
780
781        r.on_packet_sent(
782            p,
783            packet::Epoch::Application,
784            HandshakeStatus::default(),
785            now,
786            "",
787        );
788
789        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
790        assert_eq!(r.bytes_in_flight(), 1000);
791        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
792
793        let p = Sent {
794            pkt_num: 1,
795            frames: smallvec![],
796            time_sent: now,
797            time_acked: None,
798            time_lost: None,
799            size: 1000,
800            ack_eliciting: true,
801            in_flight: true,
802            delivered: 0,
803            delivered_time: now,
804            first_sent_time: now,
805            is_app_limited: false,
806            tx_in_flight: 0,
807            lost: 0,
808            has_data: false,
809            is_pmtud_probe: false,
810        };
811
812        r.on_packet_sent(
813            p,
814            packet::Epoch::Application,
815            HandshakeStatus::default(),
816            now,
817            "",
818        );
819
820        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
821        assert_eq!(r.bytes_in_flight(), 2000);
822        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
823
824        let p = Sent {
825            pkt_num: 2,
826            frames: smallvec![],
827            time_sent: now,
828            time_acked: None,
829            time_lost: None,
830            size: 1000,
831            ack_eliciting: true,
832            in_flight: true,
833            delivered: 0,
834            delivered_time: now,
835            first_sent_time: now,
836            is_app_limited: false,
837            tx_in_flight: 0,
838            lost: 0,
839            has_data: false,
840            is_pmtud_probe: false,
841        };
842
843        r.on_packet_sent(
844            p,
845            packet::Epoch::Application,
846            HandshakeStatus::default(),
847            now,
848            "",
849        );
850        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
851        assert_eq!(r.bytes_in_flight(), 3000);
852        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
853
854        let p = Sent {
855            pkt_num: 3,
856            frames: smallvec![],
857            time_sent: now,
858            time_acked: None,
859            time_lost: None,
860            size: 1000,
861            ack_eliciting: true,
862            in_flight: true,
863            delivered: 0,
864            delivered_time: now,
865            first_sent_time: now,
866            is_app_limited: false,
867            tx_in_flight: 0,
868            lost: 0,
869            has_data: false,
870            is_pmtud_probe: false,
871        };
872
873        r.on_packet_sent(
874            p,
875            packet::Epoch::Application,
876            HandshakeStatus::default(),
877            now,
878            "",
879        );
880        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
881        assert_eq!(r.bytes_in_flight(), 4000);
882        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
883
884        // Wait for 10ms.
885        now += Duration::from_millis(10);
886
887        // Only the first 2 packets are acked.
888        let mut acked = RangeSet::default();
889        acked.insert(0..2);
890
891        assert_eq!(
892            r.on_ack_received(
893                &acked,
894                25,
895                packet::Epoch::Application,
896                HandshakeStatus::default(),
897                now,
898                None,
899                "",
900            )
901            .unwrap(),
902            OnAckReceivedOutcome {
903                lost_packets: 0,
904                lost_bytes: 0,
905                acked_bytes: 2 * 1000,
906                spurious_losses: 0,
907            }
908        );
909
910        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
911        assert_eq!(r.bytes_in_flight(), 2000);
912        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
913        assert_eq!(r.lost_count(), 0);
914
915        // Wait until loss detection timer expires.
916        now = r.loss_detection_timer().unwrap();
917
918        // PTO.
919        r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
920        assert_eq!(r.loss_probes(packet::Epoch::Application), 1);
921        assert_eq!(r.lost_count(), 0);
922        assert_eq!(r.pto_count(), 1);
923
924        let p = Sent {
925            pkt_num: 4,
926            frames: smallvec![],
927            time_sent: now,
928            time_acked: None,
929            time_lost: None,
930            size: 1000,
931            ack_eliciting: true,
932            in_flight: true,
933            delivered: 0,
934            delivered_time: now,
935            first_sent_time: now,
936            is_app_limited: false,
937            tx_in_flight: 0,
938            lost: 0,
939            has_data: false,
940            is_pmtud_probe: false,
941        };
942
943        r.on_packet_sent(
944            p,
945            packet::Epoch::Application,
946            HandshakeStatus::default(),
947            now,
948            "",
949        );
950        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
951        assert_eq!(r.bytes_in_flight(), 3000);
952        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(30));
953
954        let p = Sent {
955            pkt_num: 5,
956            frames: smallvec![],
957            time_sent: now,
958            time_acked: None,
959            time_lost: None,
960            size: 1000,
961            ack_eliciting: true,
962            in_flight: true,
963            delivered: 0,
964            delivered_time: now,
965            first_sent_time: now,
966            is_app_limited: false,
967            tx_in_flight: 0,
968            lost: 0,
969            has_data: false,
970            is_pmtud_probe: false,
971        };
972
973        r.on_packet_sent(
974            p,
975            packet::Epoch::Application,
976            HandshakeStatus::default(),
977            now,
978            "",
979        );
980        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
981        assert_eq!(r.bytes_in_flight(), 4000);
982        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(30));
983        assert_eq!(r.lost_count(), 0);
984
985        // Wait for 10ms.
986        now += Duration::from_millis(10);
987
988        // PTO packets are acked.
989        let mut acked = RangeSet::default();
990        acked.insert(4..6);
991
992        assert_eq!(
993            r.on_ack_received(
994                &acked,
995                25,
996                packet::Epoch::Application,
997                HandshakeStatus::default(),
998                now,
999                None,
1000                "",
1001            )
1002            .unwrap(),
1003            OnAckReceivedOutcome {
1004                lost_packets: 2,
1005                lost_bytes: 2000,
1006                acked_bytes: 2 * 1000,
1007                spurious_losses: 0,
1008            }
1009        );
1010
1011        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1012        assert_eq!(r.bytes_in_flight(), 0);
1013        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(40));
1014
1015        assert_eq!(r.lost_count(), 2);
1016
1017        // Wait 1 RTT.
1018        now += r.rtt();
1019
1020        assert_eq!(
1021            r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1022            (0, 0)
1023        );
1024
1025        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1026        if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1027            assert!(r.startup_exit().is_some());
1028            assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1029        } else {
1030            assert_eq!(r.startup_exit(), None);
1031        }
1032    }
1033
1034    #[rstest]
1035    fn loss_on_timer(
1036        #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
1037        cc_algorithm_name: &str,
1038    ) {
1039        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1040        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1041
1042        let mut r = Recovery::new(&cfg);
1043
1044        let mut now = Instant::now();
1045
1046        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1047
1048        // Start by sending a few packets.
1049        let p = Sent {
1050            pkt_num: 0,
1051            frames: smallvec![],
1052            time_sent: now,
1053            time_acked: None,
1054            time_lost: None,
1055            size: 1000,
1056            ack_eliciting: true,
1057            in_flight: true,
1058            delivered: 0,
1059            delivered_time: now,
1060            first_sent_time: now,
1061            is_app_limited: false,
1062            tx_in_flight: 0,
1063            lost: 0,
1064            has_data: false,
1065            is_pmtud_probe: false,
1066        };
1067
1068        r.on_packet_sent(
1069            p,
1070            packet::Epoch::Application,
1071            HandshakeStatus::default(),
1072            now,
1073            "",
1074        );
1075        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1076        assert_eq!(r.bytes_in_flight(), 1000);
1077        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1078
1079        let p = Sent {
1080            pkt_num: 1,
1081            frames: smallvec![],
1082            time_sent: now,
1083            time_acked: None,
1084            time_lost: None,
1085            size: 1000,
1086            ack_eliciting: true,
1087            in_flight: true,
1088            delivered: 0,
1089            delivered_time: now,
1090            first_sent_time: now,
1091            is_app_limited: false,
1092            tx_in_flight: 0,
1093            lost: 0,
1094            has_data: false,
1095            is_pmtud_probe: false,
1096        };
1097
1098        r.on_packet_sent(
1099            p,
1100            packet::Epoch::Application,
1101            HandshakeStatus::default(),
1102            now,
1103            "",
1104        );
1105        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1106        assert_eq!(r.bytes_in_flight(), 2000);
1107        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1108
1109        let p = Sent {
1110            pkt_num: 2,
1111            frames: smallvec![],
1112            time_sent: now,
1113            time_acked: None,
1114            time_lost: None,
1115            size: 1000,
1116            ack_eliciting: true,
1117            in_flight: true,
1118            delivered: 0,
1119            delivered_time: now,
1120            first_sent_time: now,
1121            is_app_limited: false,
1122            tx_in_flight: 0,
1123            lost: 0,
1124            has_data: false,
1125            is_pmtud_probe: false,
1126        };
1127
1128        r.on_packet_sent(
1129            p,
1130            packet::Epoch::Application,
1131            HandshakeStatus::default(),
1132            now,
1133            "",
1134        );
1135        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1136        assert_eq!(r.bytes_in_flight(), 3000);
1137        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1138
1139        let p = Sent {
1140            pkt_num: 3,
1141            frames: smallvec![],
1142            time_sent: now,
1143            time_acked: None,
1144            time_lost: None,
1145            size: 1000,
1146            ack_eliciting: true,
1147            in_flight: true,
1148            delivered: 0,
1149            delivered_time: now,
1150            first_sent_time: now,
1151            is_app_limited: false,
1152            tx_in_flight: 0,
1153            lost: 0,
1154            has_data: false,
1155            is_pmtud_probe: false,
1156        };
1157
1158        r.on_packet_sent(
1159            p,
1160            packet::Epoch::Application,
1161            HandshakeStatus::default(),
1162            now,
1163            "",
1164        );
1165        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1166        assert_eq!(r.bytes_in_flight(), 4000);
1167        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1168
1169        // Wait for 10ms.
1170        now += Duration::from_millis(10);
1171
1172        // Only the first 2 packets and the last one are acked.
1173        let mut acked = RangeSet::default();
1174        acked.insert(0..2);
1175        acked.insert(3..4);
1176
1177        assert_eq!(
1178            r.on_ack_received(
1179                &acked,
1180                25,
1181                packet::Epoch::Application,
1182                HandshakeStatus::default(),
1183                now,
1184                None,
1185                "",
1186            )
1187            .unwrap(),
1188            OnAckReceivedOutcome {
1189                lost_packets: 0,
1190                lost_bytes: 0,
1191                acked_bytes: 3 * 1000,
1192                spurious_losses: 0,
1193            }
1194        );
1195
1196        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1197        assert_eq!(r.bytes_in_flight(), 1000);
1198        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
1199        assert_eq!(r.lost_count(), 0);
1200
1201        // Wait until loss detection timer expires.
1202        now = r.loss_detection_timer().unwrap();
1203
1204        // Packet is declared lost.
1205        r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
1206        assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
1207
1208        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1209        assert_eq!(r.bytes_in_flight(), 0);
1210        assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
1211
1212        assert_eq!(r.lost_count(), 1);
1213
1214        // Wait 1 RTT.
1215        now += r.rtt();
1216
1217        assert_eq!(
1218            r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1219            (0, 0)
1220        );
1221
1222        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1223        if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1224            assert!(r.startup_exit().is_some());
1225            assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1226        } else {
1227            assert_eq!(r.startup_exit(), None);
1228        }
1229    }
1230
1231    #[rstest]
1232    fn loss_on_reordering(
1233        #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
1234        cc_algorithm_name: &str,
1235    ) {
1236        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1237        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1238
1239        let mut r = Recovery::new(&cfg);
1240
1241        let mut now = Instant::now();
1242
1243        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1244
1245        // Start by sending a few packets.
1246        //
1247        // pkt number: [0, 1, 2, 3]
1248        for i in 0..4 {
1249            let p = test_utils::helper_packet_sent(i, now, 1000);
1250            r.on_packet_sent(
1251                p,
1252                packet::Epoch::Application,
1253                HandshakeStatus::default(),
1254                now,
1255                "",
1256            );
1257
1258            let pkt_count = (i + 1) as usize;
1259            assert_eq!(r.sent_packets_len(packet::Epoch::Application), pkt_count);
1260            assert_eq!(r.bytes_in_flight(), pkt_count * 1000);
1261            assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1262        }
1263
1264        // Wait for 10ms after sending.
1265        now += Duration::from_millis(10);
1266
1267        // Recieve reordered ACKs, i.e. pkt_num [2, 3]
1268        let mut acked = RangeSet::default();
1269        acked.insert(2..4);
1270        assert_eq!(
1271            r.on_ack_received(
1272                &acked,
1273                25,
1274                packet::Epoch::Application,
1275                HandshakeStatus::default(),
1276                now,
1277                None,
1278                "",
1279            )
1280            .unwrap(),
1281            OnAckReceivedOutcome {
1282                lost_packets: 1,
1283                lost_bytes: 1000,
1284                acked_bytes: 1000 * 2,
1285                spurious_losses: 0,
1286            }
1287        );
1288        // Since we only remove packets from the back to avoid compaction, the
1289        // send length remains the same after receiving reordered ACKs
1290        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 4);
1291        assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1292        assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1293
1294        // Wait for 10ms after receiving first set of ACKs.
1295        now += Duration::from_millis(10);
1296
1297        // Recieve remaining ACKs, i.e. pkt_num [0, 1]
1298        let mut acked = RangeSet::default();
1299        acked.insert(0..2);
1300        assert_eq!(
1301            r.on_ack_received(
1302                &acked,
1303                25,
1304                packet::Epoch::Application,
1305                HandshakeStatus::default(),
1306                now,
1307                None,
1308                "",
1309            )
1310            .unwrap(),
1311            OnAckReceivedOutcome {
1312                lost_packets: 0,
1313                lost_bytes: 0,
1314                acked_bytes: 1000,
1315                spurious_losses: 1,
1316            }
1317        );
1318        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1319        assert_eq!(r.bytes_in_flight(), 0);
1320        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(20));
1321
1322        // Spurious loss.
1323        assert_eq!(r.lost_count(), 1);
1324        assert_eq!(r.lost_spurious_count(), 1);
1325
1326        // Packet threshold was increased.
1327        assert_eq!(r.pkt_thresh().unwrap(), 4);
1328        assert_eq!(r.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1329
1330        // Wait 1 RTT.
1331        now += r.rtt();
1332
1333        // All packets have been ACKed so dont expect additional lost packets
1334        assert_eq!(
1335            r.detect_lost_packets_for_test(packet::Epoch::Application, now),
1336            (0, 0)
1337        );
1338        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1339
1340        if cc_algorithm_name == "reno" || cc_algorithm_name == "cubic" {
1341            assert!(r.startup_exit().is_some());
1342            assert_eq!(r.startup_exit().unwrap().reason, StartupExitReason::Loss);
1343        } else {
1344            assert_eq!(r.startup_exit(), None);
1345        }
1346    }
1347
1348    // TODO: This should run agains both `congestion` and `gcongestion`.
1349    // `congestion` and `gcongestion` behave differently. That might be ok
1350    // given the different algorithms but it would be ideal to merge and share
1351    // the logic.
1352    #[rstest]
1353    fn time_thresholds_on_reordering(
1354        #[values("bbr2_gcongestion")] cc_algorithm_name: &str,
1355    ) {
1356        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1357        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1358
1359        let mut now = Instant::now();
1360        let mut r = Recovery::new(&cfg);
1361        assert_eq!(r.rtt(), DEFAULT_INITIAL_RTT);
1362
1363        // Pick time between and above thresholds for testing threshold increase.
1364        //
1365        //```
1366        //              between_thresh_ms
1367        //                         |
1368        //    initial_thresh_ms    |     spurious_thresh_ms
1369        //      v                  v             v
1370        // --------------------------------------------------
1371        //      | ................ | ..................... |
1372        //            THRESH_GAP         THRESH_GAP
1373        // ```
1374        // 
1375        // Threshold gap time.
1376        const THRESH_GAP: Duration = Duration::from_millis(30);
1377        // Initial time theshold based on inital RTT.
1378        let initial_thresh_ms =
1379            DEFAULT_INITIAL_RTT.mul_f64(INITIAL_TIME_THRESHOLD);
1380        // The time threshold after spurious loss.
1381        let spurious_thresh_ms: Duration =
1382            DEFAULT_INITIAL_RTT.mul_f64(PACKET_REORDER_TIME_THRESHOLD);
1383        // Time between the two thresholds
1384        let between_thresh_ms = initial_thresh_ms + THRESH_GAP;
1385        assert!(between_thresh_ms > initial_thresh_ms);
1386        assert!(between_thresh_ms < spurious_thresh_ms);
1387        assert!(between_thresh_ms + THRESH_GAP > spurious_thresh_ms);
1388
1389        for i in 0..6 {
1390            let send_time = now + i * between_thresh_ms;
1391
1392            let p = test_utils::helper_packet_sent(i.into(), send_time, 1000);
1393            r.on_packet_sent(
1394                p,
1395                packet::Epoch::Application,
1396                HandshakeStatus::default(),
1397                send_time,
1398                "",
1399            );
1400        }
1401
1402        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 6);
1403        assert_eq!(r.bytes_in_flight(), 6 * 1000);
1404        assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1405        assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1406
1407        // Wait for `between_thresh_ms` after sending to trigger loss based on
1408        // loss threshold.
1409        now += between_thresh_ms;
1410
1411        // Ack packet: 1
1412        //
1413        // [0, 1, 2, 3, 4, 5]
1414        //     ^
1415        let mut acked = RangeSet::default();
1416        acked.insert(1..2);
1417        assert_eq!(
1418            r.on_ack_received(
1419                &acked,
1420                25,
1421                packet::Epoch::Application,
1422                HandshakeStatus::default(),
1423                now,
1424                None,
1425                "",
1426            )
1427            .unwrap(),
1428            OnAckReceivedOutcome {
1429                lost_packets: 1,
1430                lost_bytes: 1000,
1431                acked_bytes: 1000,
1432                spurious_losses: 0,
1433            }
1434        );
1435        assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1436        assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1437
1438        // Ack packet: 0
1439        //
1440        // [0, 1, 2, 3, 4, 5]
1441        //  ^  x
1442        let mut acked = RangeSet::default();
1443        acked.insert(0..1);
1444        assert_eq!(
1445            r.on_ack_received(
1446                &acked,
1447                25,
1448                packet::Epoch::Application,
1449                HandshakeStatus::default(),
1450                now,
1451                None,
1452                "",
1453            )
1454            .unwrap(),
1455            OnAckReceivedOutcome {
1456                lost_packets: 0,
1457                lost_bytes: 0,
1458                acked_bytes: 0,
1459                spurious_losses: 1,
1460            }
1461        );
1462        // The time_thresh after spurious loss
1463        assert_eq!(r.time_thresh(), PACKET_REORDER_TIME_THRESHOLD);
1464
1465        // Wait for `between_thresh_ms` after sending. However, since the
1466        // threshold has increased, we do not expect loss.
1467        now += between_thresh_ms;
1468
1469        // Ack packet: 3
1470        //
1471        // [2, 3, 4, 5]
1472        //     ^
1473        let mut acked = RangeSet::default();
1474        acked.insert(3..4);
1475        assert_eq!(
1476            r.on_ack_received(
1477                &acked,
1478                25,
1479                packet::Epoch::Application,
1480                HandshakeStatus::default(),
1481                now,
1482                None,
1483                "",
1484            )
1485            .unwrap(),
1486            OnAckReceivedOutcome {
1487                lost_packets: 0,
1488                lost_bytes: 0,
1489                acked_bytes: 1000,
1490                spurious_losses: 0,
1491            }
1492        );
1493
1494        // Wait for and additional `plus_overhead` to trigger loss based on the
1495        // new time threshold.
1496        now += THRESH_GAP;
1497
1498        // Ack packet: 4
1499        //
1500        // [2, 3, 4, 5]
1501        //     x  ^
1502        let mut acked = RangeSet::default();
1503        acked.insert(4..5);
1504        assert_eq!(
1505            r.on_ack_received(
1506                &acked,
1507                25,
1508                packet::Epoch::Application,
1509                HandshakeStatus::default(),
1510                now,
1511                None,
1512                "",
1513            )
1514            .unwrap(),
1515            OnAckReceivedOutcome {
1516                lost_packets: 1,
1517                lost_bytes: 1000,
1518                acked_bytes: 1000,
1519                spurious_losses: 0,
1520            }
1521        );
1522    }
1523
1524    // TODO: Implement enable_relaxed_loss_threshold and enable this test for the
1525    // congestion module.
1526    #[rstest]
1527    fn relaxed_thresholds_on_reordering(
1528        #[values("bbr2_gcongestion")] cc_algorithm_name: &str,
1529    ) {
1530        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1531        cfg.enable_relaxed_loss_threshold = true;
1532        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1533
1534        let mut now = Instant::now();
1535        let mut r = Recovery::new(&cfg);
1536        assert_eq!(r.rtt(), DEFAULT_INITIAL_RTT);
1537
1538        // Pick time between and above thresholds for testing threshold increase.
1539        //
1540        //```
1541        //              between_thresh_ms
1542        //                         |
1543        //    initial_thresh_ms    |     spurious_thresh_ms
1544        //      v                  v             v
1545        // --------------------------------------------------
1546        //      | ................ | ..................... |
1547        //            THRESH_GAP         THRESH_GAP
1548        // ```
1549        // Threshold gap time.
1550        const THRESH_GAP: Duration = Duration::from_millis(30);
1551        // Initial time theshold based on inital RTT.
1552        let initial_thresh_ms =
1553            DEFAULT_INITIAL_RTT.mul_f64(INITIAL_TIME_THRESHOLD);
1554        // The time threshold after spurious loss.
1555        let spurious_thresh_ms: Duration =
1556            DEFAULT_INITIAL_RTT.mul_f64(PACKET_REORDER_TIME_THRESHOLD);
1557        // Time between the two thresholds
1558        let between_thresh_ms = initial_thresh_ms + THRESH_GAP;
1559        assert!(between_thresh_ms > initial_thresh_ms);
1560        assert!(between_thresh_ms < spurious_thresh_ms);
1561        assert!(between_thresh_ms + THRESH_GAP > spurious_thresh_ms);
1562
1563        for i in 0..6 {
1564            let send_time = now + i * between_thresh_ms;
1565
1566            let p = test_utils::helper_packet_sent(i.into(), send_time, 1000);
1567            r.on_packet_sent(
1568                p,
1569                packet::Epoch::Application,
1570                HandshakeStatus::default(),
1571                send_time,
1572                "",
1573            );
1574        }
1575
1576        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 6);
1577        assert_eq!(r.bytes_in_flight(), 6 * 1000);
1578        // Intitial thresholds
1579        assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1580        assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1581
1582        // Wait for `between_thresh_ms` after sending to trigger loss based on
1583        // loss threshold.
1584        now += between_thresh_ms;
1585
1586        // Ack packet: 1
1587        //
1588        // [0, 1, 2, 3, 4, 5]
1589        //     ^
1590        let mut acked = RangeSet::default();
1591        acked.insert(1..2);
1592        assert_eq!(
1593            r.on_ack_received(
1594                &acked,
1595                25,
1596                packet::Epoch::Application,
1597                HandshakeStatus::default(),
1598                now,
1599                None,
1600                "",
1601            )
1602            .unwrap(),
1603            OnAckReceivedOutcome {
1604                lost_packets: 1,
1605                lost_bytes: 1000,
1606                acked_bytes: 1000,
1607                spurious_losses: 0,
1608            }
1609        );
1610        // Thresholds after 1st loss
1611        assert_eq!(r.pkt_thresh().unwrap(), INITIAL_PACKET_THRESHOLD);
1612        assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1613
1614        // Ack packet: 0
1615        //
1616        // [0, 1, 2, 3, 4, 5]
1617        //  ^  x
1618        let mut acked = RangeSet::default();
1619        acked.insert(0..1);
1620        assert_eq!(
1621            r.on_ack_received(
1622                &acked,
1623                25,
1624                packet::Epoch::Application,
1625                HandshakeStatus::default(),
1626                now,
1627                None,
1628                "",
1629            )
1630            .unwrap(),
1631            OnAckReceivedOutcome {
1632                lost_packets: 0,
1633                lost_bytes: 0,
1634                acked_bytes: 0,
1635                spurious_losses: 1,
1636            }
1637        );
1638        // Thresholds after 1st spurious loss
1639        //
1640        // Packet threshold should be disabled. Time threshold overhead should
1641        // stay the same.
1642        assert_eq!(r.pkt_thresh(), None);
1643        assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1644
1645        // Set now to send time of packet 2 so we can trigger spurious loss for
1646        // packet 2.
1647        now += between_thresh_ms;
1648        // Then wait for `between_thresh_ms` after sending packet 2 to trigger
1649        // loss. Since the time threshold has NOT increased, expect a
1650        // loss.
1651        now += between_thresh_ms;
1652
1653        // Ack packet: 3
1654        //
1655        // [2, 3, 4, 5]
1656        //     ^
1657        let mut acked = RangeSet::default();
1658        acked.insert(3..4);
1659        assert_eq!(
1660            r.on_ack_received(
1661                &acked,
1662                25,
1663                packet::Epoch::Application,
1664                HandshakeStatus::default(),
1665                now,
1666                None,
1667                "",
1668            )
1669            .unwrap(),
1670            OnAckReceivedOutcome {
1671                lost_packets: 1,
1672                lost_bytes: 1000,
1673                acked_bytes: 1000,
1674                spurious_losses: 0,
1675            }
1676        );
1677        // Thresholds after 2nd loss.
1678        assert_eq!(r.pkt_thresh(), None);
1679        assert_eq!(r.time_thresh(), INITIAL_TIME_THRESHOLD);
1680
1681        // Wait for and additional `plus_overhead` to trigger loss based on the
1682        // new time threshold.
1683        // now += THRESH_GAP;
1684
1685        // Ack packet: 2
1686        //
1687        // [2, 3, 4, 5]
1688        //  ^  x
1689        let mut acked = RangeSet::default();
1690        acked.insert(2..3);
1691        assert_eq!(
1692            r.on_ack_received(
1693                &acked,
1694                25,
1695                packet::Epoch::Application,
1696                HandshakeStatus::default(),
1697                now,
1698                None,
1699                "",
1700            )
1701            .unwrap(),
1702            OnAckReceivedOutcome {
1703                lost_packets: 0,
1704                lost_bytes: 0,
1705                acked_bytes: 0,
1706                spurious_losses: 1,
1707            }
1708        );
1709        // Thresholds after 2nd spurious loss.
1710        //
1711        // Time threshold overhead should double.
1712        assert_eq!(r.pkt_thresh(), None);
1713        let double_time_thresh_overhead =
1714            1.0 + 2.0 * INITIAL_TIME_THRESHOLD_OVERHEAD;
1715        assert_eq!(r.time_thresh(), double_time_thresh_overhead);
1716    }
1717
1718    #[rstest]
1719    fn pacing(
1720        #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
1721        cc_algorithm_name: &str,
1722        #[values(false, true)] time_sent_set_to_now: bool,
1723    ) {
1724        let pacing_enabled = cc_algorithm_name == "bbr2" ||
1725            cc_algorithm_name == "bbr2_gcongestion";
1726
1727        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
1728        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
1729
1730        #[cfg(feature = "internal")]
1731        cfg.set_custom_bbr_params(BbrParams {
1732            time_sent_set_to_now: Some(time_sent_set_to_now),
1733            ..Default::default()
1734        });
1735
1736        let mut r = Recovery::new(&cfg);
1737
1738        let mut now = Instant::now();
1739
1740        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1741
1742        // send out first packet burst (a full initcwnd).
1743        for i in 0..10 {
1744            let p = Sent {
1745                pkt_num: i,
1746                frames: smallvec![],
1747                time_sent: now,
1748                time_acked: None,
1749                time_lost: None,
1750                size: 1200,
1751                ack_eliciting: true,
1752                in_flight: true,
1753                delivered: 0,
1754                delivered_time: now,
1755                first_sent_time: now,
1756                is_app_limited: false,
1757                tx_in_flight: 0,
1758                lost: 0,
1759                has_data: true,
1760                is_pmtud_probe: false,
1761            };
1762
1763            r.on_packet_sent(
1764                p,
1765                packet::Epoch::Application,
1766                HandshakeStatus::default(),
1767                now,
1768                "",
1769            );
1770        }
1771
1772        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 10);
1773        assert_eq!(r.bytes_in_flight(), 12000);
1774        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
1775
1776        if !pacing_enabled {
1777            assert_eq!(r.pacing_rate(), 0);
1778        } else {
1779            assert_eq!(r.pacing_rate(), 103963);
1780        }
1781        assert_eq!(r.get_packet_send_time(now), now);
1782
1783        assert_eq!(r.cwnd(), 12000);
1784        assert_eq!(r.cwnd_available(), 0);
1785
1786        // Wait 50ms for ACK.
1787        let initial_rtt = Duration::from_millis(50);
1788        now += initial_rtt;
1789
1790        let mut acked = RangeSet::default();
1791        acked.insert(0..10);
1792
1793        assert_eq!(
1794            r.on_ack_received(
1795                &acked,
1796                10,
1797                packet::Epoch::Application,
1798                HandshakeStatus::default(),
1799                now,
1800                None,
1801                "",
1802            )
1803            .unwrap(),
1804            OnAckReceivedOutcome {
1805                lost_packets: 0,
1806                lost_bytes: 0,
1807                acked_bytes: 12000,
1808                spurious_losses: 0,
1809            }
1810        );
1811
1812        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
1813        assert_eq!(r.bytes_in_flight(), 0);
1814        assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
1815        assert_eq!(r.min_rtt(), Some(initial_rtt));
1816        assert_eq!(r.rtt(), initial_rtt);
1817
1818        // 10 MSS increased due to acks.
1819        assert_eq!(r.cwnd(), 12000 + 1200 * 10);
1820
1821        // Send the second packet burst.
1822        let p = Sent {
1823            pkt_num: 10,
1824            frames: smallvec![],
1825            time_sent: now,
1826            time_acked: None,
1827            time_lost: None,
1828            size: 6000,
1829            ack_eliciting: true,
1830            in_flight: true,
1831            delivered: 0,
1832            delivered_time: now,
1833            first_sent_time: now,
1834            is_app_limited: false,
1835            tx_in_flight: 0,
1836            lost: 0,
1837            has_data: true,
1838            is_pmtud_probe: false,
1839        };
1840
1841        r.on_packet_sent(
1842            p,
1843            packet::Epoch::Application,
1844            HandshakeStatus::default(),
1845            now,
1846            "",
1847        );
1848
1849        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
1850        assert_eq!(r.bytes_in_flight(), 6000);
1851        assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
1852
1853        if !pacing_enabled {
1854            // Pacing is disabled.
1855            assert_eq!(r.get_packet_send_time(now), now);
1856        } else {
1857            // Pacing is done from the beginning.
1858            assert_ne!(r.get_packet_send_time(now), now);
1859        }
1860
1861        // Send the third and fourth packet bursts together.
1862        let p = Sent {
1863            pkt_num: 11,
1864            frames: smallvec![],
1865            time_sent: now,
1866            time_acked: None,
1867            time_lost: None,
1868            size: 6000,
1869            ack_eliciting: true,
1870            in_flight: true,
1871            delivered: 0,
1872            delivered_time: now,
1873            first_sent_time: now,
1874            is_app_limited: false,
1875            tx_in_flight: 0,
1876            lost: 0,
1877            has_data: true,
1878            is_pmtud_probe: false,
1879        };
1880
1881        r.on_packet_sent(
1882            p,
1883            packet::Epoch::Application,
1884            HandshakeStatus::default(),
1885            now,
1886            "",
1887        );
1888
1889        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1890        assert_eq!(r.bytes_in_flight(), 12000);
1891        assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
1892
1893        // Send the fourth packet burst.
1894        let p = Sent {
1895            pkt_num: 12,
1896            frames: smallvec![],
1897            time_sent: now,
1898            time_acked: None,
1899            time_lost: None,
1900            size: 1000,
1901            ack_eliciting: true,
1902            in_flight: true,
1903            delivered: 0,
1904            delivered_time: now,
1905            first_sent_time: now,
1906            is_app_limited: false,
1907            tx_in_flight: 0,
1908            lost: 0,
1909            has_data: true,
1910            is_pmtud_probe: false,
1911        };
1912
1913        r.on_packet_sent(
1914            p,
1915            packet::Epoch::Application,
1916            HandshakeStatus::default(),
1917            now,
1918            "",
1919        );
1920
1921        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
1922        assert_eq!(r.bytes_in_flight(), 13000);
1923        assert_eq!(r.bytes_in_flight_duration(), initial_rtt);
1924
1925        // We pace this outgoing packet. as all conditions for pacing
1926        // are passed.
1927        let pacing_rate = if pacing_enabled {
1928            let cwnd_gain: f64 = 2.0;
1929            // Adjust for cwnd_gain.  BW estimate was made before the CWND
1930            // increase.
1931            let bw = r.cwnd() as f64 / cwnd_gain / initial_rtt.as_secs_f64();
1932            bw as u64
1933        } else {
1934            0
1935        };
1936        assert_eq!(r.pacing_rate(), pacing_rate);
1937
1938        let scale_factor = if pacing_enabled {
1939            // For bbr2_gcongestion, send time is almost 13000 / pacing_rate.
1940            // Don't know where 13000 comes from.
1941            1.08333332
1942        } else {
1943            1.0
1944        };
1945        assert_eq!(
1946            r.get_packet_send_time(now) - now,
1947            if pacing_enabled {
1948                Duration::from_secs_f64(
1949                    scale_factor * 12000.0 / pacing_rate as f64,
1950                )
1951            } else {
1952                Duration::ZERO
1953            }
1954        );
1955        assert_eq!(r.startup_exit(), None);
1956
1957        let reduced_rtt = Duration::from_millis(40);
1958        now += reduced_rtt;
1959
1960        let mut acked = RangeSet::default();
1961        acked.insert(10..11);
1962
1963        assert_eq!(
1964            r.on_ack_received(
1965                &acked,
1966                0,
1967                packet::Epoch::Application,
1968                HandshakeStatus::default(),
1969                now,
1970                None,
1971                "",
1972            )
1973            .unwrap(),
1974            OnAckReceivedOutcome {
1975                lost_packets: 0,
1976                lost_bytes: 0,
1977                acked_bytes: 6000,
1978                spurious_losses: 0,
1979            }
1980        );
1981
1982        let expected_srtt = (7 * initial_rtt + reduced_rtt) / 8;
1983        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
1984        assert_eq!(r.bytes_in_flight(), 7000);
1985        assert_eq!(r.bytes_in_flight_duration(), initial_rtt + reduced_rtt);
1986        assert_eq!(r.min_rtt(), Some(reduced_rtt));
1987        assert_eq!(r.rtt(), expected_srtt);
1988
1989        let mut acked = RangeSet::default();
1990        acked.insert(11..12);
1991
1992        assert_eq!(
1993            r.on_ack_received(
1994                &acked,
1995                0,
1996                packet::Epoch::Application,
1997                HandshakeStatus::default(),
1998                now,
1999                None,
2000                "",
2001            )
2002            .unwrap(),
2003            OnAckReceivedOutcome {
2004                lost_packets: 0,
2005                lost_bytes: 0,
2006                acked_bytes: 6000,
2007                spurious_losses: 0,
2008            }
2009        );
2010
2011        // When enabled, the pacer adds a 25msec delay to the packet
2012        // sends which will be applied to the sent times tracked by
2013        // the recovery module, bringing down RTT to 15msec.
2014        let expected_min_rtt = if pacing_enabled &&
2015            !time_sent_set_to_now &&
2016            cfg!(feature = "internal")
2017        {
2018            reduced_rtt - Duration::from_millis(25)
2019        } else {
2020            reduced_rtt
2021        };
2022
2023        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
2024        assert_eq!(r.bytes_in_flight(), 1000);
2025        assert_eq!(r.bytes_in_flight_duration(), initial_rtt + reduced_rtt);
2026        assert_eq!(r.min_rtt(), Some(expected_min_rtt));
2027
2028        let expected_srtt = (7 * expected_srtt + expected_min_rtt) / 8;
2029        assert_eq!(r.rtt(), expected_srtt);
2030
2031        let mut acked = RangeSet::default();
2032        acked.insert(12..13);
2033
2034        assert_eq!(
2035            r.on_ack_received(
2036                &acked,
2037                0,
2038                packet::Epoch::Application,
2039                HandshakeStatus::default(),
2040                now,
2041                None,
2042                "",
2043            )
2044            .unwrap(),
2045            OnAckReceivedOutcome {
2046                lost_packets: 0,
2047                lost_bytes: 0,
2048                acked_bytes: 1000,
2049                spurious_losses: 0,
2050            }
2051        );
2052
2053        // Pacer adds 50msec delay to the second packet, resulting in
2054        // an effective RTT of 0.
2055        let expected_min_rtt = if pacing_enabled &&
2056            !time_sent_set_to_now &&
2057            cfg!(feature = "internal")
2058        {
2059            Duration::from_millis(0)
2060        } else {
2061            reduced_rtt
2062        };
2063        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2064        assert_eq!(r.bytes_in_flight(), 0);
2065        assert_eq!(r.bytes_in_flight_duration(), initial_rtt + reduced_rtt);
2066        assert_eq!(r.min_rtt(), Some(expected_min_rtt));
2067
2068        let expected_srtt = (7 * expected_srtt + expected_min_rtt) / 8;
2069        assert_eq!(r.rtt(), expected_srtt);
2070    }
2071
2072    #[rstest]
2073    // initial_cwnd / first_rtt == initial_pacing_rate.  Pacing is 1.0 * bw before
2074    // and after.
2075    #[case::bw_estimate_equal_after_first_rtt(1.0, 1.0)]
2076    // initial_cwnd / first_rtt < initial_pacing_rate.  Pacing decreases from 2 *
2077    // bw to 1.0 * bw.
2078    #[case::bw_estimate_decrease_after_first_rtt(2.0, 1.0)]
2079    // initial_cwnd / first_rtt > initial_pacing_rate from 0.5 * bw to 1.0 * bw.
2080    // Initial pacing remains 0.5 * bw because the initial_pacing_rate parameter
2081    // is used an upper bound for the pacing rate after the first RTT.
2082    // Pacing rate after the first ACK should be:
2083    // min(initial_pacing_rate_bytes_per_second, init_cwnd / first_rtt)
2084    #[case::bw_estimate_increase_after_first_rtt(0.5, 0.5)]
2085    #[cfg(feature = "internal")]
2086    fn initial_pacing_rate_override(
2087        #[case] initial_multipler: f64, #[case] expected_multiplier: f64,
2088    ) {
2089        let rtt = Duration::from_millis(50);
2090        let bw = Bandwidth::from_bytes_and_time_delta(12000, rtt);
2091        let initial_pacing_rate_hint = bw * initial_multipler;
2092        let expected_pacing_with_rtt_measurement = bw * expected_multiplier;
2093
2094        let cc_algorithm_name = "bbr2_gcongestion";
2095        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2096        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2097        cfg.set_custom_bbr_params(BbrParams {
2098            initial_pacing_rate_bytes_per_second: Some(
2099                initial_pacing_rate_hint.to_bytes_per_second(),
2100            ),
2101            ..Default::default()
2102        });
2103
2104        let mut r = Recovery::new(&cfg);
2105
2106        let mut now = Instant::now();
2107
2108        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2109
2110        // send some packets.
2111        for i in 0..2 {
2112            let p = test_utils::helper_packet_sent(i, now, 1200);
2113            r.on_packet_sent(
2114                p,
2115                packet::Epoch::Application,
2116                HandshakeStatus::default(),
2117                now,
2118                "",
2119            );
2120        }
2121
2122        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2123        assert_eq!(r.bytes_in_flight(), 2400);
2124        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2125
2126        // Initial pacing rate matches the override value.
2127        assert_eq!(
2128            r.pacing_rate(),
2129            initial_pacing_rate_hint.to_bytes_per_second()
2130        );
2131        assert_eq!(r.get_packet_send_time(now), now);
2132
2133        assert_eq!(r.cwnd(), 12000);
2134        assert_eq!(r.cwnd_available(), 9600);
2135
2136        // Wait 1 rtt for ACK.
2137        now += rtt;
2138
2139        let mut acked = RangeSet::default();
2140        acked.insert(0..2);
2141
2142        assert_eq!(
2143            r.on_ack_received(
2144                &acked,
2145                10,
2146                packet::Epoch::Application,
2147                HandshakeStatus::default(),
2148                now,
2149                None,
2150                "",
2151            )
2152            .unwrap(),
2153            OnAckReceivedOutcome {
2154                lost_packets: 0,
2155                lost_bytes: 0,
2156                acked_bytes: 2400,
2157                spurious_losses: 0,
2158            }
2159        );
2160
2161        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2162        assert_eq!(r.bytes_in_flight(), 0);
2163        assert_eq!(r.bytes_in_flight_duration(), rtt);
2164        assert_eq!(r.rtt(), rtt);
2165
2166        // Pacing rate is recalculated based on initial cwnd when the
2167        // first RTT estimate is available.
2168        assert_eq!(
2169            r.pacing_rate(),
2170            expected_pacing_with_rtt_measurement.to_bytes_per_second()
2171        );
2172    }
2173
2174    #[rstest]
2175    fn validate_ack_range_on_ack_received(
2176        #[values("cubic", "bbr2", "bbr2_gcongestion")] cc_algorithm_name: &str,
2177    ) {
2178        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2179        cfg.set_cc_algorithm_name(cc_algorithm_name).unwrap();
2180
2181        let epoch = packet::Epoch::Application;
2182        let mut r = Recovery::new(&cfg);
2183        let mut now = Instant::now();
2184        assert_eq!(r.sent_packets_len(epoch), 0);
2185
2186        // Send 4 packets
2187        let pkt_size = 1000;
2188        let pkt_count = 4;
2189        for pkt_num in 0..pkt_count {
2190            let sent = test_utils::helper_packet_sent(pkt_num, now, pkt_size);
2191            r.on_packet_sent(sent, epoch, HandshakeStatus::default(), now, "");
2192        }
2193        assert_eq!(r.sent_packets_len(epoch), pkt_count as usize);
2194        assert_eq!(r.bytes_in_flight(), pkt_count as usize * pkt_size);
2195        assert!(r.get_largest_acked_on_epoch(epoch).is_none());
2196        assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2197
2198        // Wait for 10ms.
2199        now += Duration::from_millis(10);
2200
2201        // ACK 2 packets
2202        let mut acked = RangeSet::default();
2203        acked.insert(0..2);
2204
2205        assert_eq!(
2206            r.on_ack_received(
2207                &acked,
2208                25,
2209                epoch,
2210                HandshakeStatus::default(),
2211                now,
2212                None,
2213                "",
2214            )
2215            .unwrap(),
2216            OnAckReceivedOutcome {
2217                lost_packets: 0,
2218                lost_bytes: 0,
2219                acked_bytes: 2 * 1000,
2220                spurious_losses: 0,
2221            }
2222        );
2223
2224        assert_eq!(r.sent_packets_len(epoch), 2);
2225        assert_eq!(r.bytes_in_flight(), 2 * 1000);
2226
2227        assert_eq!(r.get_largest_acked_on_epoch(epoch).unwrap(), 1);
2228        assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2229
2230        // ACK large range
2231        let mut acked = RangeSet::default();
2232        acked.insert(0..10);
2233        assert_eq!(
2234            r.on_ack_received(
2235                &acked,
2236                25,
2237                epoch,
2238                HandshakeStatus::default(),
2239                now,
2240                None,
2241                "",
2242            )
2243            .unwrap(),
2244            OnAckReceivedOutcome {
2245                lost_packets: 0,
2246                lost_bytes: 0,
2247                acked_bytes: 2 * 1000,
2248                spurious_losses: 0,
2249            }
2250        );
2251        assert_eq!(r.sent_packets_len(epoch), 0);
2252        assert_eq!(r.bytes_in_flight(), 0);
2253
2254        assert_eq!(r.get_largest_acked_on_epoch(epoch).unwrap(), 3);
2255        assert_eq!(r.largest_sent_pkt_num_on_path(epoch).unwrap(), 3);
2256    }
2257
2258    #[rstest]
2259    fn pmtud_loss_on_timer(
2260        #[values("reno", "cubic", "bbr2", "bbr2_gcongestion")]
2261        cc_algorithm_name: &str,
2262    ) {
2263        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2264        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2265
2266        let mut r = Recovery::new(&cfg);
2267        assert_eq!(r.cwnd(), 12000);
2268
2269        let mut now = Instant::now();
2270
2271        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2272
2273        // Start by sending a few packets.
2274        let p = Sent {
2275            pkt_num: 0,
2276            frames: smallvec![],
2277            time_sent: now,
2278            time_acked: None,
2279            time_lost: None,
2280            size: 1000,
2281            ack_eliciting: true,
2282            in_flight: true,
2283            delivered: 0,
2284            delivered_time: now,
2285            first_sent_time: now,
2286            is_app_limited: false,
2287            tx_in_flight: 0,
2288            lost: 0,
2289            has_data: false,
2290            is_pmtud_probe: false,
2291        };
2292
2293        r.on_packet_sent(
2294            p,
2295            packet::Epoch::Application,
2296            HandshakeStatus::default(),
2297            now,
2298            "",
2299        );
2300
2301        assert_eq!(r.in_flight_count(packet::Epoch::Application), 1);
2302        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 1);
2303        assert_eq!(r.bytes_in_flight(), 1000);
2304        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2305
2306        let p = Sent {
2307            pkt_num: 1,
2308            frames: smallvec![],
2309            time_sent: now,
2310            time_acked: None,
2311            time_lost: None,
2312            size: 1000,
2313            ack_eliciting: true,
2314            in_flight: true,
2315            delivered: 0,
2316            delivered_time: now,
2317            first_sent_time: now,
2318            is_app_limited: false,
2319            tx_in_flight: 0,
2320            lost: 0,
2321            has_data: false,
2322            is_pmtud_probe: true,
2323        };
2324
2325        r.on_packet_sent(
2326            p,
2327            packet::Epoch::Application,
2328            HandshakeStatus::default(),
2329            now,
2330            "",
2331        );
2332
2333        assert_eq!(r.in_flight_count(packet::Epoch::Application), 2);
2334
2335        let p = Sent {
2336            pkt_num: 2,
2337            frames: smallvec![],
2338            time_sent: now,
2339            time_acked: None,
2340            time_lost: None,
2341            size: 1000,
2342            ack_eliciting: true,
2343            in_flight: true,
2344            delivered: 0,
2345            delivered_time: now,
2346            first_sent_time: now,
2347            is_app_limited: false,
2348            tx_in_flight: 0,
2349            lost: 0,
2350            has_data: false,
2351            is_pmtud_probe: false,
2352        };
2353
2354        r.on_packet_sent(
2355            p,
2356            packet::Epoch::Application,
2357            HandshakeStatus::default(),
2358            now,
2359            "",
2360        );
2361
2362        assert_eq!(r.in_flight_count(packet::Epoch::Application), 3);
2363
2364        // Wait for 10ms.
2365        now += Duration::from_millis(10);
2366
2367        // Only the first  packets and the last one are acked.
2368        let mut acked = RangeSet::default();
2369        acked.insert(0..1);
2370        acked.insert(2..3);
2371
2372        assert_eq!(
2373            r.on_ack_received(
2374                &acked,
2375                25,
2376                packet::Epoch::Application,
2377                HandshakeStatus::default(),
2378                now,
2379                None,
2380                "",
2381            )
2382            .unwrap(),
2383            OnAckReceivedOutcome {
2384                lost_packets: 0,
2385                lost_bytes: 0,
2386                acked_bytes: 2 * 1000,
2387                spurious_losses: 0,
2388            }
2389        );
2390
2391        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2392        assert_eq!(r.bytes_in_flight(), 1000);
2393        assert_eq!(r.bytes_in_flight_duration(), Duration::from_millis(10));
2394        assert_eq!(r.lost_count(), 0);
2395
2396        // Wait until loss detection timer expires.
2397        now = r.loss_detection_timer().unwrap();
2398
2399        // Packet is declared lost.
2400        r.on_loss_detection_timeout(HandshakeStatus::default(), now, "");
2401        assert_eq!(r.loss_probes(packet::Epoch::Application), 0);
2402
2403        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 2);
2404        assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
2405        assert_eq!(r.bytes_in_flight(), 0);
2406        assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
2407        assert_eq!(r.cwnd(), 12000);
2408
2409        assert_eq!(r.lost_count(), 0);
2410
2411        // Wait 1 RTT.
2412        now += r.rtt();
2413
2414        assert_eq!(
2415            r.detect_lost_packets_for_test(packet::Epoch::Application, now),
2416            (0, 0)
2417        );
2418
2419        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2420        assert_eq!(r.in_flight_count(packet::Epoch::Application), 0);
2421        assert_eq!(r.bytes_in_flight(), 0);
2422        assert_eq!(r.bytes_in_flight_duration(), Duration::from_micros(11250));
2423        assert_eq!(r.lost_count(), 0);
2424        assert_eq!(r.startup_exit(), None);
2425    }
2426
2427    // Modeling delivery_rate for gcongestion is non-trivial so we only test the
2428    // congestion specific algorithms.
2429    #[rstest]
2430    fn congestion_delivery_rate(
2431        #[values("reno", "cubic", "bbr2")] cc_algorithm_name: &str,
2432    ) {
2433        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2434        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2435
2436        let mut r = Recovery::new(&cfg);
2437        assert_eq!(r.cwnd(), 12000);
2438
2439        let now = Instant::now();
2440
2441        let mut total_bytes_sent = 0;
2442        for pn in 0..10 {
2443            // Start by sending a few packets.
2444            let bytes = 1000;
2445            let sent = test_utils::helper_packet_sent(pn, now, bytes);
2446            r.on_packet_sent(
2447                sent,
2448                packet::Epoch::Application,
2449                HandshakeStatus::default(),
2450                now,
2451                "",
2452            );
2453
2454            total_bytes_sent += bytes;
2455        }
2456
2457        // Ack
2458        let interval = Duration::from_secs(10);
2459        let mut acked = RangeSet::default();
2460        acked.insert(0..10);
2461        assert_eq!(
2462            r.on_ack_received(
2463                &acked,
2464                25,
2465                packet::Epoch::Application,
2466                HandshakeStatus::default(),
2467                now + interval,
2468                None,
2469                "",
2470            )
2471            .unwrap(),
2472            OnAckReceivedOutcome {
2473                lost_packets: 0,
2474                lost_bytes: 0,
2475                acked_bytes: total_bytes_sent,
2476                spurious_losses: 0,
2477            }
2478        );
2479        assert_eq!(r.delivery_rate().to_bytes_per_second(), 1000);
2480        assert_eq!(r.min_rtt().unwrap(), interval);
2481        // delivery rate should be in units bytes/sec
2482        assert_eq!(
2483            total_bytes_sent as u64 / interval.as_secs(),
2484            r.delivery_rate().to_bytes_per_second()
2485        );
2486        assert_eq!(r.startup_exit(), None);
2487    }
2488
2489    #[rstest]
2490    fn acks_with_no_retransmittable_data(
2491        #[values("reno", "cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
2492    ) {
2493        let rtt = Duration::from_millis(100);
2494
2495        let mut cfg = Config::new(crate::PROTOCOL_VERSION).unwrap();
2496        assert_eq!(cfg.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
2497
2498        let mut r = Recovery::new(&cfg);
2499
2500        let mut now = Instant::now();
2501
2502        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2503
2504        let mut next_packet = 0;
2505        // send some packets.
2506        for _ in 0..3 {
2507            let p = test_utils::helper_packet_sent(next_packet, now, 1200);
2508            next_packet += 1;
2509            r.on_packet_sent(
2510                p,
2511                packet::Epoch::Application,
2512                HandshakeStatus::default(),
2513                now,
2514                "",
2515            );
2516        }
2517
2518        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 3);
2519        assert_eq!(r.bytes_in_flight(), 3600);
2520        assert_eq!(r.bytes_in_flight_duration(), Duration::ZERO);
2521
2522        assert_eq!(
2523            r.pacing_rate(),
2524            if cc_algorithm_name == "bbr2_gcongestion" {
2525                103963
2526            } else {
2527                0
2528            },
2529        );
2530        assert_eq!(r.get_packet_send_time(now), now);
2531        assert_eq!(r.cwnd(), 12000);
2532        assert_eq!(r.cwnd_available(), 8400);
2533
2534        // Wait 1 rtt for ACK.
2535        now += rtt;
2536
2537        let mut acked = RangeSet::default();
2538        acked.insert(0..3);
2539
2540        assert_eq!(
2541            r.on_ack_received(
2542                &acked,
2543                10,
2544                packet::Epoch::Application,
2545                HandshakeStatus::default(),
2546                now,
2547                None,
2548                "",
2549            )
2550            .unwrap(),
2551            OnAckReceivedOutcome {
2552                lost_packets: 0,
2553                lost_bytes: 0,
2554                acked_bytes: 3600,
2555                spurious_losses: 0,
2556            }
2557        );
2558
2559        assert_eq!(r.sent_packets_len(packet::Epoch::Application), 0);
2560        assert_eq!(r.bytes_in_flight(), 0);
2561        assert_eq!(r.bytes_in_flight_duration(), rtt);
2562        assert_eq!(r.rtt(), rtt);
2563
2564        // Pacing rate is recalculated based on initial cwnd when the
2565        // first RTT estimate is available.
2566        assert_eq!(
2567            r.pacing_rate(),
2568            if cc_algorithm_name == "bbr2_gcongestion" {
2569                120000
2570            } else {
2571                0
2572            },
2573        );
2574
2575        // Send some no "in_flight" packets
2576        for iter in 3..1000 {
2577            let mut p = test_utils::helper_packet_sent(next_packet, now, 1200);
2578            // `in_flight = false` marks packets as if they only contained ACK
2579            // frames.
2580            p.in_flight = false;
2581            next_packet += 1;
2582            r.on_packet_sent(
2583                p,
2584                packet::Epoch::Application,
2585                HandshakeStatus::default(),
2586                now,
2587                "",
2588            );
2589
2590            now += rtt;
2591
2592            let mut acked = RangeSet::default();
2593            acked.insert(iter..(iter + 1));
2594
2595            assert_eq!(
2596                r.on_ack_received(
2597                    &acked,
2598                    10,
2599                    packet::Epoch::Application,
2600                    HandshakeStatus::default(),
2601                    now,
2602                    None,
2603                    "",
2604                )
2605                .unwrap(),
2606                OnAckReceivedOutcome {
2607                    lost_packets: 0,
2608                    lost_bytes: 0,
2609                    acked_bytes: 0,
2610                    spurious_losses: 0,
2611                }
2612            );
2613
2614            // Verify that connection has not exited startup.
2615            assert_eq!(r.startup_exit(), None, "{iter}");
2616
2617            // Unchanged metrics.
2618            assert_eq!(
2619                r.sent_packets_len(packet::Epoch::Application),
2620                0,
2621                "{iter}"
2622            );
2623            assert_eq!(r.bytes_in_flight(), 0, "{iter}");
2624            assert_eq!(r.bytes_in_flight_duration(), rtt, "{iter}");
2625            assert_eq!(
2626                r.pacing_rate(),
2627                if cc_algorithm_name == "bbr2_gcongestion" ||
2628                    cc_algorithm_name == "bbr2"
2629                {
2630                    120000
2631                } else {
2632                    0
2633                },
2634                "{iter}"
2635            );
2636        }
2637    }
2638}
2639
2640mod bandwidth;
2641mod bytes_in_flight;
2642mod congestion;
2643mod gcongestion;
2644mod rtt;