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