Skip to content

Commit 27c7804

Browse files
bbr2: fix probe_up_acked adjustment in probe_inflight_high_upward to match the BBR RFC draft
probe_up_acked was expected to be in [0, probe_up_bytes) but could end up larger than probe_up_bytes in cases where delta > 1. The effect of this is that inflight_hi would be adjusted upwards too fast in cases where delta > 1.
1 parent c6a0d4c commit 27c7804

File tree

1 file changed

+91
-4
lines changed

1 file changed

+91
-4
lines changed

quiche/src/recovery/gcongestion/bbr2/probe_bw.rs

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -613,10 +613,13 @@ impl ProbeBW {
613613
self.cycle.probe_up_acked += congestion_event.bytes_acked;
614614
}
615615

616-
if let Some(probe_up_bytes) = self.cycle.probe_up_bytes.as_mut() {
617-
if self.cycle.probe_up_acked >= *probe_up_bytes {
618-
let delta = self.cycle.probe_up_acked / *probe_up_bytes;
619-
self.cycle.probe_up_acked -= *probe_up_bytes;
616+
if let Some(probe_up_bytes) = self.cycle.probe_up_bytes {
617+
if self.cycle.probe_up_acked >= probe_up_bytes {
618+
let delta = self.cycle.probe_up_acked / probe_up_bytes;
619+
// probe_up_acked is set to the remainder mod probe_up_bytes;
620+
// probe_up_acked >= delta * probe_up_bytes so this
621+
// can't underflow.
622+
self.cycle.probe_up_acked -= delta * probe_up_bytes;
620623
let new_inflight_hi =
621624
self.model.inflight_hi() + delta * DEFAULT_MSS;
622625
if new_inflight_hi > self.model.inflight_hi() {
@@ -640,3 +643,87 @@ impl ProbeBW {
640643
next_mode
641644
}
642645
}
646+
647+
#[cfg(test)]
648+
mod tests {
649+
use rstest::rstest;
650+
651+
use super::*;
652+
use crate::recovery::gcongestion::bbr2::SendTimeState;
653+
use crate::recovery::gcongestion::bbr2::DEFAULT_PARAMS;
654+
655+
#[rstest]
656+
fn probe_upward(#[values(100, 10_000, 65_536, 300_000)] step: usize) {
657+
let test_event =
658+
|probe_bw: &ProbeBW, bytes_acked: usize, end_of_round_trip: bool| {
659+
BBRv2CongestionEvent {
660+
event_time: probe_bw.cycle.start_time,
661+
prior_cwnd: probe_bw.model.inflight_hi(),
662+
prior_bytes_in_flight: probe_bw.model.inflight_hi(),
663+
bytes_in_flight: 0,
664+
bytes_acked,
665+
bytes_lost: 0,
666+
end_of_round_trip,
667+
is_probing_for_bandwidth: true,
668+
sample_max_bandwidth: None,
669+
sample_min_rtt: None,
670+
last_packet_send_state: SendTimeState::default(),
671+
}
672+
};
673+
674+
let do_probe_up = |probe_bw: &mut ProbeBW,
675+
params: &Params,
676+
total_bytes: usize| {
677+
let mut remaining = total_bytes;
678+
loop {
679+
let congestion_event =
680+
test_event(probe_bw, step.min(remaining), false);
681+
682+
probe_bw.probe_inflight_high_upward(&congestion_event, params);
683+
684+
if remaining > step {
685+
remaining -= step;
686+
} else {
687+
break;
688+
}
689+
}
690+
};
691+
692+
let params = &DEFAULT_PARAMS;
693+
let model = BBRv2NetworkModel::new(&params, Duration::from_millis(333));
694+
let cycle = Cycle::default();
695+
let mut probe_bw = ProbeBW { model, cycle };
696+
probe_bw.model.set_inflight_hi(100_000);
697+
probe_bw.raise_inflight_high_slope(100_000);
698+
assert_eq!(probe_bw.cycle.probe_up_rounds, 1);
699+
assert_eq!(probe_bw.cycle.probe_up_bytes, Some(100_000));
700+
701+
assert_eq!(probe_bw.model.inflight_hi(), 100_000);
702+
do_probe_up(&mut probe_bw, &params, 1_000_000);
703+
// End inflight_hi should be independent of step size.
704+
assert_eq!(probe_bw.model.inflight_hi(), 113_000);
705+
706+
// Slope is increased at the end of round by decreasing probe_up_bytes.
707+
probe_bw.probe_inflight_high_upward(
708+
&test_event(&probe_bw, 10_000, true),
709+
params,
710+
);
711+
assert_eq!(probe_bw.cycle.probe_up_rounds, 2);
712+
assert_eq!(probe_bw.cycle.probe_up_bytes, Some(56500));
713+
714+
do_probe_up(&mut probe_bw, &params, 1_000_000);
715+
// End inflight_hi should be independent of step size.
716+
assert_eq!(probe_bw.model.inflight_hi(), 135_100);
717+
718+
probe_bw.probe_inflight_high_upward(
719+
&test_event(&probe_bw, 10_000, true),
720+
params,
721+
);
722+
assert_eq!(probe_bw.cycle.probe_up_rounds, 3);
723+
assert_eq!(probe_bw.cycle.probe_up_bytes, Some(33775));
724+
725+
do_probe_up(&mut probe_bw, &params, 1_000_000);
726+
// End inflight_hi should be independent of step size.
727+
assert_eq!(probe_bw.model.inflight_hi(), 174_100);
728+
}
729+
}

0 commit comments

Comments
 (0)