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