quiche/recovery/congestion/bbr2/
per_loss.rs1use super::*;
28
29pub fn bbr2_update_on_loss(
33 r: &mut Congestion, packet: &Sent, lost_bytes: usize, now: Instant,
34) {
35 bbr2_handle_lost_packet(r, packet, lost_bytes, now);
36}
37
38pub fn bbr2_check_inflight_too_high(r: &mut Congestion, now: Instant) -> bool {
41 if bbr2_is_inflight_too_high(r) {
42 if r.bbr2_state.bw_probe_samples {
43 bbr2_handle_inflight_too_high(r, now);
44 }
45
46 return true;
48 }
49
50 false
52}
53
54pub fn bbr2_is_inflight_too_high(r: &mut Congestion) -> bool {
55 r.bbr2_state.lost > (r.bbr2_state.tx_in_flight as f64 * LOSS_THRESH) as usize
56}
57
58fn bbr2_handle_inflight_too_high(r: &mut Congestion, now: Instant) {
59 r.bbr2_state.bw_probe_samples = false;
61
62 if !r.delivery_rate.sample_is_app_limited() {
63 r.bbr2_state.inflight_hi = r
64 .bbr2_state
65 .tx_in_flight
66 .max((per_ack::bbr2_target_inflight(r) as f64 * BETA) as usize);
67 }
68
69 if r.bbr2_state.state == BBR2StateMachine::ProbeBWUP {
70 per_ack::bbr2_start_probe_bw_down(r, now);
71 }
72}
73
74fn bbr2_handle_lost_packet(
75 r: &mut Congestion, packet: &Sent, lost_bytes: usize, now: Instant,
76) {
77 if !r.bbr2_state.bw_probe_samples {
78 return;
79 }
80
81 r.bbr2_state.tx_in_flight = packet.tx_in_flight;
82 r.bbr2_state.lost = lost_bytes;
83
84 r.delivery_rate.update_app_limited(packet.is_app_limited);
85
86 if bbr2_is_inflight_too_high(r) {
87 r.bbr2_state.tx_in_flight = bbr2_inflight_hi_from_lost_packet(r, packet);
88
89 bbr2_handle_inflight_too_high(r, now);
90 }
91}
92
93fn bbr2_inflight_hi_from_lost_packet(r: &mut Congestion, packet: &Sent) -> usize {
94 let size = packet.size;
95 let inflight_prev = r.bbr2_state.tx_in_flight - size;
96 let lost_prev = r.bbr2_state.lost - size;
97 let lost_prefix = (LOSS_THRESH * inflight_prev as f64 - lost_prev as f64) /
98 (1.0 - LOSS_THRESH);
99
100 inflight_prev + lost_prefix as usize
101}
102
103pub fn bbr2_update_latest_delivery_signals(r: &mut Congestion) {
105 let bbr = &mut r.bbr2_state;
106
107 bbr.loss_round_start = false;
109 bbr.bw_latest = bbr
110 .bw_latest
111 .max(r.delivery_rate.sample_delivery_rate().to_bytes_per_second());
112 bbr.inflight_latest =
113 bbr.inflight_latest.max(r.delivery_rate.sample_delivered());
114
115 if r.delivery_rate.sample_prior_delivered() >= bbr.loss_round_delivered {
116 bbr.loss_round_delivered = r.delivery_rate.delivered();
117 bbr.loss_round_start = true;
118 }
119}
120
121pub fn bbr2_advance_latest_delivery_signals(r: &mut Congestion) {
122 let bbr = &mut r.bbr2_state;
123
124 if bbr.loss_round_start {
126 bbr.bw_latest =
127 r.delivery_rate.sample_delivery_rate().to_bytes_per_second();
128 bbr.inflight_latest = r.delivery_rate.sample_delivered();
129 }
130}
131
132pub fn bbr2_reset_congestion_signals(r: &mut Congestion) {
133 let bbr = &mut r.bbr2_state;
134
135 bbr.loss_in_round = false;
136 bbr.loss_events_in_round = 0;
137 bbr.bw_latest = 0;
138 bbr.inflight_latest = 0;
139}
140
141pub fn bbr2_update_congestion_signals(r: &mut Congestion, packet: &Acked) {
142 per_ack::bbr2_update_max_bw(r, packet);
144
145 if r.bbr2_state.lost > 0 {
146 r.bbr2_state.loss_in_round = true;
147 r.bbr2_state.loss_events_in_round += 1;
148 }
149
150 if !r.bbr2_state.loss_round_start {
151 return;
153 }
154
155 bbr2_adapt_lower_bounds_from_congestion(r);
156
157 r.bbr2_state.loss_in_round = false;
158 r.bbr2_state.loss_events_in_round = 0;
159}
160
161fn bbr2_adapt_lower_bounds_from_congestion(r: &mut Congestion) {
162 if bbr2_is_probing_bw(r) {
164 return;
165 }
166
167 if r.bbr2_state.loss_in_round {
168 bbr2_init_lower_bounds(r);
169 bbr2_loss_lower_bounds(r);
170 }
171}
172
173fn bbr2_init_lower_bounds(r: &mut Congestion) {
174 let bbr = &mut r.bbr2_state;
175
176 if bbr.bw_lo == u64::MAX {
178 bbr.bw_lo = bbr.max_bw;
179 }
180
181 if bbr.inflight_lo == usize::MAX {
182 bbr.inflight_lo = r.congestion_window;
183 }
184}
185
186fn bbr2_loss_lower_bounds(r: &mut Congestion) {
187 let bbr = &mut r.bbr2_state;
188
189 bbr.bw_lo = bbr.bw_latest.max((bbr.bw_lo as f64 * BETA) as u64);
191 bbr.inflight_lo = bbr
192 .inflight_latest
193 .max((bbr.inflight_lo as f64 * BETA) as usize);
194}
195
196pub fn bbr2_reset_lower_bounds(r: &mut Congestion) {
197 let bbr = &mut r.bbr2_state;
198
199 bbr.bw_lo = u64::MAX;
200 bbr.inflight_lo = usize::MAX;
201}
202
203pub fn bbr2_bound_bw_for_model(r: &mut Congestion) {
204 let bbr = &mut r.bbr2_state;
205
206 bbr.bw = bbr.max_bw.min(bbr.bw_lo.min(bbr.bw_hi));
207}
208
209fn bbr2_is_probing_bw(r: &mut Congestion) -> bool {
211 let state = r.bbr2_state.state;
212
213 state == BBR2StateMachine::Startup ||
214 state == BBR2StateMachine::ProbeBWREFILL ||
215 state == BBR2StateMachine::ProbeBWUP
216}