Skip to content

Commit 6763027

Browse files
committed
congestion: saturate CUBIC window increment to avoid overflow
1 parent a96949f commit 6763027

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
@@ -146,7 +146,9 @@ impl Controller for Cubic {
146146
let cubic_inc =
147147
(w_cubic - cubic_cwnd as f64) / cubic_cwnd as f64 * self.current_mtu as f64;
148148

149-
cubic_cwnd += cubic_inc as u64;
149+
// w_cubic grows cubically with the time since the last congestion
150+
// event and can exceed `u64::MAX` after a long lossless period.
151+
cubic_cwnd = cubic_cwnd.saturating_add(cubic_inc as u64);
150152
}
151153

152154
// Update the increment and increase cwnd by MSS.
@@ -296,4 +298,24 @@ mod tests {
296298
assert_eq!(cubic.ssthresh, (window as f64 * BETA_CUBIC) as u64);
297299
assert_eq!(cubic.window, cubic.ssthresh);
298300
}
301+
302+
#[test]
303+
fn congestion_avoidance_does_not_overflow_after_long_lossless_period() {
304+
let now = Instant::now();
305+
let rtt = RttEstimator::new(Duration::from_millis(100));
306+
let config = Arc::new(CubicConfig::default());
307+
let mut cubic = Cubic::new(config, now, BASE_DATAGRAM_SIZE as u16);
308+
309+
// Put CUBIC directly into congestion avoidance.
310+
cubic.state.ssthresh = cubic.state.window;
311+
cubic.state.recovery_start_time = Some(now);
312+
let window = cubic.state.window;
313+
314+
// After ten days without a congestion event, w_cubic exceeds u64::MAX.
315+
// Before this fix, computing the window increment overflowed.
316+
let later = now + Duration::from_secs(10 * 24 * 60 * 60);
317+
cubic.on_ack(later, later, BASE_DATAGRAM_SIZE, false, &rtt);
318+
319+
assert_eq!(cubic.state.window, window + BASE_DATAGRAM_SIZE);
320+
}
299321
}

0 commit comments

Comments
 (0)