quiche/recovery/gcongestion/bbr2/
probe_rtt.rs

1// Copyright (c) 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Copyright (C) 2023, Cloudflare, Inc.
6// All rights reserved.
7//
8// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
11//
12//     * Redistributions of source code must retain the above copyright notice,
13//       this list of conditions and the following disclaimer.
14//
15//     * Redistributions in binary form must reproduce the above copyright
16//       notice, this list of conditions and the following disclaimer in the
17//       documentation and/or other materials provided with the distribution.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31use std::time::Instant;
32
33use crate::recovery::gcongestion::bbr2::Params;
34use crate::recovery::gcongestion::Acked;
35use crate::recovery::gcongestion::Lost;
36use crate::recovery::RecoveryStats;
37
38use super::mode::Cycle;
39use super::mode::Mode;
40use super::mode::ModeImpl;
41use super::network_model::BBRv2NetworkModel;
42use super::BBRv2CongestionEvent;
43use super::Limits;
44
45#[derive(Debug)]
46pub(super) struct ProbeRTT {
47    pub(super) model: BBRv2NetworkModel,
48    pub(super) cycle: Cycle,
49    exit_time: Option<Instant>,
50}
51
52impl ProbeRTT {
53    pub(super) fn new(model: BBRv2NetworkModel, cycle: Cycle) -> Self {
54        ProbeRTT {
55            model,
56            cycle,
57            exit_time: None,
58        }
59    }
60
61    fn into_probe_bw(
62        mut self, now: Instant, congestion_event: Option<&BBRv2CongestionEvent>,
63        params: &Params,
64    ) -> Mode {
65        self.leave(now, congestion_event);
66        let mut next_mode = Mode::probe_bw(self.model, self.cycle);
67        next_mode.enter(now, congestion_event, params);
68        next_mode
69    }
70
71    fn inflight_target(&self, params: &Params) -> usize {
72        self.model.bdp(
73            self.model.max_bandwidth(),
74            params.probe_rtt_inflight_target_bdp_fraction,
75        )
76    }
77}
78
79impl ModeImpl for ProbeRTT {
80    #[cfg(feature = "qlog")]
81    fn state_str(&self) -> &'static str {
82        "bbr_probe_rtt"
83    }
84
85    fn is_probing_for_bandwidth(&self) -> bool {
86        false
87    }
88
89    fn on_congestion_event(
90        mut self, _prior_in_flight: usize, event_time: Instant,
91        _acked_packets: &[Acked], _lost_packets: &[Lost],
92        congestion_event: &mut BBRv2CongestionEvent,
93        _target_bytes_inflight: usize, params: &Params,
94        _recovery_stats: &mut RecoveryStats, _cwnd: usize,
95    ) -> Mode {
96        match self.exit_time {
97            None => {
98                if congestion_event.bytes_in_flight <=
99                    self.inflight_target(params)
100                {
101                    self.exit_time = Some(
102                        congestion_event.event_time + params.probe_rtt_duration,
103                    )
104                }
105                Mode::ProbeRTT(self)
106            },
107            Some(exit_time) =>
108                if congestion_event.event_time > exit_time {
109                    self.into_probe_bw(event_time, Some(congestion_event), params)
110                } else {
111                    Mode::ProbeRTT(self)
112                },
113        }
114    }
115
116    fn get_cwnd_limits(&self, params: &Params) -> Limits<usize> {
117        let inflight_upper_bound = self
118            .model
119            .inflight_lo()
120            .min(self.model.inflight_hi_with_headroom(params));
121        Limits::no_greater_than(
122            inflight_upper_bound.min(self.inflight_target(params)),
123        )
124    }
125
126    fn on_exit_quiescence(
127        self, now: Instant, _quiescence_start_time: Instant, params: &Params,
128    ) -> Mode {
129        match self.exit_time {
130            None => self.into_probe_bw(now, None, params),
131            Some(exit_time) if now > exit_time =>
132                self.into_probe_bw(now, None, params),
133            Some(_) => Mode::ProbeRTT(self),
134        }
135    }
136
137    fn enter(
138        &mut self, _now: Instant,
139        _congestion_event: Option<&BBRv2CongestionEvent>, _params: &Params,
140    ) {
141        self.model.set_pacing_gain(1.0);
142        self.model.set_cwnd_gain(1.0);
143        self.exit_time = None;
144    }
145
146    fn leave(
147        &mut self, _now: Instant,
148        _congestion_event: Option<&BBRv2CongestionEvent>,
149    ) {
150    }
151}