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