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.bw_latest.max(r.delivery_rate.sample_delivery_rate());
110 bbr.inflight_latest =
111 bbr.inflight_latest.max(r.delivery_rate.sample_delivered());
112
113 if r.delivery_rate.sample_prior_delivered() >= bbr.loss_round_delivered {
114 bbr.loss_round_delivered = r.delivery_rate.delivered();
115 bbr.loss_round_start = true;
116 }
117}
118
119pub fn bbr2_advance_latest_delivery_signals(r: &mut Congestion) {
120 let bbr = &mut r.bbr2_state;
121
122 if bbr.loss_round_start {
124 bbr.bw_latest = r.delivery_rate.sample_delivery_rate();
125 bbr.inflight_latest = r.delivery_rate.sample_delivered();
126 }
127}
128
129pub fn bbr2_reset_congestion_signals(r: &mut Congestion) {
130 let bbr = &mut r.bbr2_state;
131
132 bbr.loss_in_round = false;
133 bbr.loss_events_in_round = 0;
134 bbr.bw_latest = 0;
135 bbr.inflight_latest = 0;
136}
137
138pub fn bbr2_update_congestion_signals(r: &mut Congestion, packet: &Acked) {
139 per_ack::bbr2_update_max_bw(r, packet);
141
142 if r.bbr2_state.lost > 0 {
143 r.bbr2_state.loss_in_round = true;
144 r.bbr2_state.loss_events_in_round += 1;
145 }
146
147 if !r.bbr2_state.loss_round_start {
148 return;
150 }
151
152 bbr2_adapt_lower_bounds_from_congestion(r);
153
154 r.bbr2_state.loss_in_round = false;
155 r.bbr2_state.loss_events_in_round = 0;
156}
157
158fn bbr2_adapt_lower_bounds_from_congestion(r: &mut Congestion) {
159 if bbr2_is_probing_bw(r) {
161 return;
162 }
163
164 if r.bbr2_state.loss_in_round {
165 bbr2_init_lower_bounds(r);
166 bbr2_loss_lower_bounds(r);
167 }
168}
169
170fn bbr2_init_lower_bounds(r: &mut Congestion) {
171 let bbr = &mut r.bbr2_state;
172
173 if bbr.bw_lo == u64::MAX {
175 bbr.bw_lo = bbr.max_bw;
176 }
177
178 if bbr.inflight_lo == usize::MAX {
179 bbr.inflight_lo = r.congestion_window;
180 }
181}
182
183fn bbr2_loss_lower_bounds(r: &mut Congestion) {
184 let bbr = &mut r.bbr2_state;
185
186 bbr.bw_lo = bbr.bw_latest.max((bbr.bw_lo as f64 * BETA) as u64);
188 bbr.inflight_lo = bbr
189 .inflight_latest
190 .max((bbr.inflight_lo as f64 * BETA) as usize);
191}
192
193pub fn bbr2_reset_lower_bounds(r: &mut Congestion) {
194 let bbr = &mut r.bbr2_state;
195
196 bbr.bw_lo = u64::MAX;
197 bbr.inflight_lo = usize::MAX;
198}
199
200pub fn bbr2_bound_bw_for_model(r: &mut Congestion) {
201 let bbr = &mut r.bbr2_state;
202
203 bbr.bw = bbr.max_bw.min(bbr.bw_lo.min(bbr.bw_hi));
204}
205
206fn bbr2_is_probing_bw(r: &mut Congestion) -> bool {
208 let state = r.bbr2_state.state;
209
210 state == BBR2StateMachine::Startup ||
211 state == BBR2StateMachine::ProbeBWREFILL ||
212 state == BBR2StateMachine::ProbeBWUP
213}