Skip to content

Commit c900b6c

Browse files
committed
congestion: saturate CUBIC window increment to avoid overflow
1 parent fec2f89 commit c900b6c

1 file changed

Lines changed: 23 additions & 1 deletion

File tree

quinn-proto/src/congestion/cubic.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,9 @@ impl Controller for Cubic {
158158
let cubic_inc =
159159
(w_cubic - cubic_cwnd as f64) / cubic_cwnd as f64 * self.current_mtu as f64;
160160

161-
cubic_cwnd += cubic_inc as u64;
161+
// w_cubic grows cubically with the time since the last congestion
162+
// event and can exceed `u64::MAX` after a long lossless period.
163+
cubic_cwnd = cubic_cwnd.saturating_add(cubic_inc as u64);
162164
}
163165

164166
// Update the increment and increase cwnd by MSS.
@@ -356,4 +358,24 @@ mod tests {
356358
assert_eq!(cubic.state.window, window + BASE_DATAGRAM_SIZE);
357359
assert_eq!(cubic.state.cwnd_inc, BASE_DATAGRAM_SIZE + 1);
358360
}
361+
362+
#[test]
363+
fn congestion_avoidance_does_not_overflow_after_long_lossless_period() {
364+
let now = Instant::now();
365+
let rtt = RttEstimator::new(Duration::from_millis(100));
366+
let config = Arc::new(CubicConfig::default());
367+
let mut cubic = Cubic::new(config, now, BASE_DATAGRAM_SIZE as u16);
368+
369+
// Put CUBIC directly into congestion avoidance.
370+
cubic.state.ssthresh = cubic.state.window;
371+
cubic.state.recovery_start_time = Some(now);
372+
let window = cubic.state.window;
373+
374+
// After ten days without a congestion event, w_cubic exceeds u64::MAX.
375+
// Before this fix, computing the window increment overflowed.
376+
let later = now + Duration::from_secs(10 * 24 * 60 * 60);
377+
cubic.on_ack(later, later, BASE_DATAGRAM_SIZE, false, &rtt);
378+
379+
assert_eq!(cubic.state.window, window + BASE_DATAGRAM_SIZE);
380+
}
359381
}

0 commit comments

Comments
 (0)