quiche/recovery/gcongestion/bbr2/
mode.rs1use std::fmt::Debug;
32use std::ops::Deref;
33use std::ops::DerefMut;
34use std::time::Duration;
35use std::time::Instant;
36
37use crate::recovery::gcongestion::Lost;
38
39use super::drain::Drain;
40use super::network_model::BBRv2NetworkModel;
41use super::probe_bw::ProbeBW;
42use super::probe_rtt::ProbeRTT;
43use super::startup::Startup;
44use super::Acked;
45use super::BBRv2CongestionEvent;
46use super::Limits;
47use super::PARAMS;
48
49#[derive(Debug, Default, PartialEq)]
50pub(super) enum CyclePhase {
51 #[default]
52 NotStarted,
53 Up,
54 Down,
55 Cruise,
56 Refill,
57}
58
59impl CyclePhase {
60 pub(super) fn gain(&self) -> f32 {
61 match self {
62 CyclePhase::Up => PARAMS.probe_bw_probe_up_pacing_gain,
63 CyclePhase::Down => PARAMS.probe_bw_probe_down_pacing_gain,
64 _ => PARAMS.probe_bw_default_pacing_gain,
65 }
66 }
67}
68
69#[derive(Debug)]
70pub(super) struct Cycle {
71 pub(super) start_time: Instant,
72 pub(super) phase: CyclePhase,
73 pub(super) rounds_in_phase: usize,
74 pub(super) phase_start_time: Instant,
75 pub(super) rounds_since_probe: usize,
76 pub(super) probe_wait_time: Option<Duration>,
77 pub(super) probe_up_rounds: usize,
78 pub(super) probe_up_bytes: Option<usize>,
79 pub(super) probe_up_acked: usize,
80 pub(super) probe_up_app_limited_since_inflight_hi_limited: bool,
81 pub(super) has_advanced_max_bw: bool,
84 pub(super) is_sample_from_probing: bool,
85
86 pub(super) last_cycle_probed_too_high: bool,
87 pub(super) last_cycle_stopped_risky_probe: bool,
88}
89
90impl Default for Cycle {
91 fn default() -> Self {
92 let now = Instant::now();
93
94 Cycle {
95 start_time: now,
96 phase_start_time: now,
97
98 phase: CyclePhase::NotStarted,
99 rounds_in_phase: 0,
100 rounds_since_probe: 0,
101 probe_wait_time: None,
102 probe_up_rounds: 0,
103 probe_up_bytes: None,
104 probe_up_acked: 0,
105 probe_up_app_limited_since_inflight_hi_limited: false,
106 has_advanced_max_bw: false,
107 is_sample_from_probing: false,
108 last_cycle_probed_too_high: false,
109 last_cycle_stopped_risky_probe: false,
110 }
111 }
112}
113
114#[enum_dispatch::enum_dispatch]
115pub(super) trait ModeImpl: Debug {
116 fn enter(
117 &mut self, now: Instant, congestion_event: Option<&BBRv2CongestionEvent>,
118 );
119
120 fn leave(
121 &mut self, now: Instant, congestion_event: Option<&BBRv2CongestionEvent>,
122 );
123
124 fn is_probing_for_bandwidth(&self) -> bool;
125
126 fn on_congestion_event(
127 self, prior_in_flight: usize, event_time: Instant,
128 acked_packets: &[Acked], lost_packets: &[Lost],
129 congestion_event: &mut BBRv2CongestionEvent,
130 target_bytes_inflight: usize,
131 ) -> Mode;
132
133 fn get_cwnd_limits(&self) -> Limits<usize>;
134
135 fn on_exit_quiescence(
136 self, now: Instant, quiescence_start_time: Instant,
137 ) -> Mode;
138}
139
140#[enum_dispatch::enum_dispatch(ModeImpl)]
141#[derive(Debug)]
142pub(super) enum Mode {
143 Startup(Startup),
144 Drain(Drain),
145 ProbeBW(ProbeBW),
146 ProbeRTT(ProbeRTT),
147 Placheolder(Placeholder),
148}
149
150impl Default for Mode {
151 fn default() -> Self {
152 Mode::Placheolder(Placeholder {})
153 }
154}
155
156impl Mode {
157 pub(super) fn startup(model: BBRv2NetworkModel) -> Self {
158 Mode::Startup(Startup { model })
159 }
160
161 pub(super) fn drain(model: BBRv2NetworkModel) -> Self {
162 Mode::Drain(Drain {
163 model,
164 cycle: Default::default(),
165 })
166 }
167
168 pub(super) fn probe_bw(model: BBRv2NetworkModel, cycle: Cycle) -> Self {
169 Mode::ProbeBW(ProbeBW { model, cycle })
170 }
171
172 pub(super) fn probe_rtt(model: BBRv2NetworkModel, cycle: Cycle) -> Self {
173 Mode::ProbeRTT(ProbeRTT::new(model, cycle))
174 }
175
176 pub(super) fn do_on_congestion_event(
177 &mut self, prior_in_flight: usize, event_time: Instant,
178 acked_packets: &[Acked], lost_packets: &[Lost],
179 congestion_event: &mut BBRv2CongestionEvent,
180 target_bytes_inflight: usize,
181 ) -> bool {
182 let mode_before = std::mem::discriminant(self);
183
184 *self = std::mem::take(self).on_congestion_event(
185 prior_in_flight,
186 event_time,
187 acked_packets,
188 lost_packets,
189 congestion_event,
190 target_bytes_inflight,
191 );
192
193 let mode_after = std::mem::discriminant(self);
194
195 mode_before != mode_after
196 }
197
198 pub(super) fn do_on_exit_quiescence(
199 &mut self, now: Instant, quiescence_start_time: Instant,
200 ) {
201 *self =
202 std::mem::take(self).on_exit_quiescence(now, quiescence_start_time)
203 }
204}
205
206impl Deref for Mode {
207 type Target = BBRv2NetworkModel;
208
209 fn deref(&self) -> &Self::Target {
210 match self {
211 Mode::Startup(Startup { model }) => model,
212 Mode::Drain(Drain { model, .. }) => model,
213 Mode::ProbeBW(ProbeBW { model, .. }) => model,
214 Mode::ProbeRTT(ProbeRTT { model, .. }) => model,
215 Mode::Placheolder(_) => unreachable!(),
216 }
217 }
218}
219
220impl DerefMut for Mode {
221 fn deref_mut(&mut self) -> &mut Self::Target {
222 match self {
223 Mode::Startup(Startup { model }) => model,
224 Mode::Drain(Drain { model, .. }) => model,
225 Mode::ProbeBW(ProbeBW { model, .. }) => model,
226 Mode::ProbeRTT(ProbeRTT { model, .. }) => model,
227 Mode::Placheolder(_) => unreachable!(),
228 }
229 }
230}
231
232#[derive(Debug, Default)]
233pub(super) struct Placeholder {}
234
235impl ModeImpl for Placeholder {
236 fn enter(&mut self, _: Instant, _: Option<&BBRv2CongestionEvent>) {
237 unreachable!()
238 }
239
240 fn leave(&mut self, _: Instant, _: Option<&BBRv2CongestionEvent>) {
241 unreachable!()
242 }
243
244 fn is_probing_for_bandwidth(&self) -> bool {
245 unreachable!()
246 }
247
248 fn on_congestion_event(
249 self, _: usize, _: Instant, _: &[Acked], _: &[Lost],
250 _: &mut BBRv2CongestionEvent, _: usize,
251 ) -> Mode {
252 unreachable!()
253 }
254
255 fn get_cwnd_limits(&self) -> Limits<usize> {
256 unreachable!()
257 }
258
259 fn on_exit_quiescence(self, _: Instant, _: Instant) -> Mode {
260 unreachable!()
261 }
262}