quiche/recovery/gcongestion/bbr2/
drain.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 Drain {
47    pub(super) model: BBRv2NetworkModel,
48    pub(super) cycle: Cycle,
49}
50
51impl ModeImpl for Drain {
52    #[cfg(feature = "qlog")]
53    fn state_str(&self) -> &'static str {
54        "bbr_drain"
55    }
56
57    fn is_probing_for_bandwidth(&self) -> bool {
58        false
59    }
60
61    fn on_congestion_event(
62        mut self, _prior_in_flight: usize, event_time: Instant,
63        _acked_packets: &[Acked], _lost_packets: &[Lost],
64        congestion_event: &mut BBRv2CongestionEvent,
65        _target_bytes_inflight: usize, params: &Params,
66        _recovery_stats: &mut RecoveryStats, _cwnd: usize,
67    ) -> Mode {
68        self.model.set_pacing_gain(params.drain_pacing_gain);
69        // Only STARTUP can transition to DRAIN, both of them use the same cwnd
70        // gain.
71        self.model.set_cwnd_gain(params.drain_cwnd_gain);
72
73        let drain_target = self.drain_target();
74        if congestion_event.bytes_in_flight <= drain_target {
75            return self.into_probe_bw(
76                event_time,
77                Some(congestion_event),
78                params,
79            );
80        }
81
82        Mode::Drain(self)
83    }
84
85    fn get_cwnd_limits(&self, _params: &Params) -> Limits<usize> {
86        Limits {
87            lo: 0,
88            hi: self.model.inflight_lo(),
89        }
90    }
91
92    fn on_exit_quiescence(
93        self, _now: Instant, _quiescence_start_time: Instant, _params: &Params,
94    ) -> Mode {
95        Mode::Drain(self)
96    }
97
98    fn enter(
99        &mut self, _: Instant, _: Option<&BBRv2CongestionEvent>, _params: &Params,
100    ) {
101    }
102
103    fn leave(&mut self, _: Instant, _: Option<&BBRv2CongestionEvent>) {}
104}
105
106impl Drain {
107    fn into_probe_bw(
108        mut self, now: Instant, congestion_event: Option<&BBRv2CongestionEvent>,
109        params: &Params,
110    ) -> Mode {
111        self.leave(now, congestion_event);
112        let mut next_mode = Mode::probe_bw(self.model, self.cycle);
113        next_mode.enter(now, congestion_event, params);
114        next_mode
115    }
116
117    fn drain_target(&self) -> usize {
118        self.model.bdp0()
119    }
120}