quiche/recovery/gcongestion/bbr2/
probe_rtt.rs1use 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(params.probe_rtt_pacing_gain);
142 self.model.set_cwnd_gain(params.probe_rtt_cwnd_gain);
143 self.exit_time = None;
144 }
145
146 fn leave(
147 &mut self, _now: Instant,
148 _congestion_event: Option<&BBRv2CongestionEvent>,
149 ) {
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156 use crate::recovery::gcongestion::bbr2::DEFAULT_PARAMS;
157 use crate::BbrParams;
158 use std::time::Duration;
159
160 #[test]
161 fn probe_rtt_params() {
162 let custom_bbr_settings = BbrParams {
163 probe_rtt_pacing_gain: Some(0.8),
164 probe_rtt_cwnd_gain: Some(0.5),
165 ..Default::default()
166 };
167 let params = &DEFAULT_PARAMS.with_overrides(&custom_bbr_settings);
168
169 let model = BBRv2NetworkModel::new(params, Duration::from_millis(333));
170 let mut probe_rtt = ProbeRTT::new(model, Cycle::default());
171 probe_rtt.enter(Instant::now(), None, params);
172 assert_eq!(probe_rtt.model.pacing_gain(), 0.8);
173 assert_eq!(probe_rtt.model.cwnd_gain(), 0.5);
174 }
175}