quiche/recovery/congestion/bbr2/
per_loss.rsuse super::*;
pub fn bbr2_update_on_loss(
r: &mut Congestion, packet: &Sent, lost_bytes: usize, now: Instant,
) {
bbr2_handle_lost_packet(r, packet, lost_bytes, now);
}
pub fn bbr2_check_inflight_too_high(r: &mut Congestion, now: Instant) -> bool {
if bbr2_is_inflight_too_high(r) {
if r.bbr2_state.bw_probe_samples {
bbr2_handle_inflight_too_high(r, now);
}
return true;
}
false
}
pub fn bbr2_is_inflight_too_high(r: &mut Congestion) -> bool {
r.bbr2_state.lost > (r.bbr2_state.tx_in_flight as f64 * LOSS_THRESH) as usize
}
fn bbr2_handle_inflight_too_high(r: &mut Congestion, now: Instant) {
r.bbr2_state.bw_probe_samples = false;
if !r.delivery_rate.sample_is_app_limited() {
r.bbr2_state.inflight_hi = r
.bbr2_state
.tx_in_flight
.max((per_ack::bbr2_target_inflight(r) as f64 * BETA) as usize);
}
if r.bbr2_state.state == BBR2StateMachine::ProbeBWUP {
per_ack::bbr2_start_probe_bw_down(r, now);
}
}
fn bbr2_handle_lost_packet(
r: &mut Congestion, packet: &Sent, lost_bytes: usize, now: Instant,
) {
if !r.bbr2_state.bw_probe_samples {
return;
}
r.bbr2_state.tx_in_flight = packet.tx_in_flight;
r.bbr2_state.lost = lost_bytes;
r.delivery_rate.update_app_limited(packet.is_app_limited);
if bbr2_is_inflight_too_high(r) {
r.bbr2_state.tx_in_flight = bbr2_inflight_hi_from_lost_packet(r, packet);
bbr2_handle_inflight_too_high(r, now);
}
}
fn bbr2_inflight_hi_from_lost_packet(r: &mut Congestion, packet: &Sent) -> usize {
let size = packet.size;
let inflight_prev = r.bbr2_state.tx_in_flight - size;
let lost_prev = r.bbr2_state.lost - size;
let lost_prefix = (LOSS_THRESH * inflight_prev as f64 - lost_prev as f64) /
(1.0 - LOSS_THRESH);
inflight_prev + lost_prefix as usize
}
pub fn bbr2_update_latest_delivery_signals(r: &mut Congestion) {
let bbr = &mut r.bbr2_state;
bbr.loss_round_start = false;
bbr.bw_latest = bbr.bw_latest.max(r.delivery_rate.sample_delivery_rate());
bbr.inflight_latest =
bbr.inflight_latest.max(r.delivery_rate.sample_delivered());
if r.delivery_rate.sample_prior_delivered() >= bbr.loss_round_delivered {
bbr.loss_round_delivered = r.delivery_rate.delivered();
bbr.loss_round_start = true;
}
}
pub fn bbr2_advance_latest_delivery_signals(r: &mut Congestion) {
let bbr = &mut r.bbr2_state;
if bbr.loss_round_start {
bbr.bw_latest = r.delivery_rate.sample_delivery_rate();
bbr.inflight_latest = r.delivery_rate.sample_delivered();
}
}
pub fn bbr2_reset_congestion_signals(r: &mut Congestion) {
let bbr = &mut r.bbr2_state;
bbr.loss_in_round = false;
bbr.loss_events_in_round = 0;
bbr.bw_latest = 0;
bbr.inflight_latest = 0;
}
pub fn bbr2_update_congestion_signals(r: &mut Congestion, packet: &Acked) {
per_ack::bbr2_update_max_bw(r, packet);
if r.bbr2_state.lost > 0 {
r.bbr2_state.loss_in_round = true;
r.bbr2_state.loss_events_in_round += 1;
}
if !r.bbr2_state.loss_round_start {
return;
}
bbr2_adapt_lower_bounds_from_congestion(r);
r.bbr2_state.loss_in_round = false;
r.bbr2_state.loss_events_in_round = 0;
}
fn bbr2_adapt_lower_bounds_from_congestion(r: &mut Congestion) {
if bbr2_is_probing_bw(r) {
return;
}
if r.bbr2_state.loss_in_round {
bbr2_init_lower_bounds(r);
bbr2_loss_lower_bounds(r);
}
}
fn bbr2_init_lower_bounds(r: &mut Congestion) {
let bbr = &mut r.bbr2_state;
if bbr.bw_lo == u64::MAX {
bbr.bw_lo = bbr.max_bw;
}
if bbr.inflight_lo == usize::MAX {
bbr.inflight_lo = r.congestion_window;
}
}
fn bbr2_loss_lower_bounds(r: &mut Congestion) {
let bbr = &mut r.bbr2_state;
bbr.bw_lo = bbr.bw_latest.max((bbr.bw_lo as f64 * BETA) as u64);
bbr.inflight_lo = bbr
.inflight_latest
.max((bbr.inflight_lo as f64 * BETA) as usize);
}
pub fn bbr2_reset_lower_bounds(r: &mut Congestion) {
let bbr = &mut r.bbr2_state;
bbr.bw_lo = u64::MAX;
bbr.inflight_lo = usize::MAX;
}
pub fn bbr2_bound_bw_for_model(r: &mut Congestion) {
let bbr = &mut r.bbr2_state;
bbr.bw = bbr.max_bw.min(bbr.bw_lo.min(bbr.bw_hi));
}
fn bbr2_is_probing_bw(r: &mut Congestion) -> bool {
let state = r.bbr2_state.state;
state == BBR2StateMachine::Startup ||
state == BBR2StateMachine::ProbeBWREFILL ||
state == BBR2StateMachine::ProbeBWUP
}