Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(s2n-quic): expose configuration options for congestion control #2228

Merged
merged 7 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dc/s2n-quic-dc/src/congestion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub struct Controller {
impl Controller {
#[inline]
pub fn new(mtu: u16) -> Self {
let mut controller = BbrCongestionController::new(mtu);
let mut controller = BbrCongestionController::new(mtu, Default::default());
let publisher = &mut NoopPublisher;
controller.on_mtu_update(mtu, publisher);
Self { controller }
Expand Down
184 changes: 156 additions & 28 deletions quic/s2n-quic-core/src/recovery/bbr.rs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions quic/s2n-quic-core/src/recovery/bbr/drain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ mod tests {

#[test]
fn enter_drain() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE);
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
let mut publisher = event::testing::Publisher::snapshot();
let mut publisher = PathPublisher::new(&mut publisher, path::Id::test_id());

Expand All @@ -106,7 +106,7 @@ mod tests {
//# BBREnterProbeBW() /* BBR estimates the queue was drained */
#[test]
fn check_drain_done() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE);
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
let now = NoopClock.get_time();
let mut rng = random::testing::Generator::default();
let mut publisher = event::testing::Publisher::snapshot();
Expand Down
52 changes: 44 additions & 8 deletions quic/s2n-quic-core/src/recovery/bbr/full_pipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

use crate::{
counter::{Counter, Saturating},
recovery::{bandwidth, bandwidth::Bandwidth, bbr::BbrCongestionController},
recovery::{
bandwidth,
bandwidth::Bandwidth,
bbr::{ApplicationSettings, BbrCongestionController},
},
};
use num_rational::Ratio;

Expand Down Expand Up @@ -65,13 +69,18 @@ impl Estimator {
rate_sample: bandwidth::RateSample,
loss_bursts_in_round: u8,
max_datagram_size: u16,
app_settings: &ApplicationSettings,
) {
if self.filled_pipe {
return;
}

self.filled_pipe =
self.excessive_inflight(rate_sample, loss_bursts_in_round, max_datagram_size);
self.filled_pipe = self.excessive_inflight(
rate_sample,
loss_bursts_in_round,
max_datagram_size,
app_settings,
);
}

/// Determines if the rate of increase of bandwidth has decreased enough to estimate the
Expand Down Expand Up @@ -135,6 +144,7 @@ impl Estimator {
rate_sample: bandwidth::RateSample,
loss_bursts_in_round: u8,
max_datagram_size: u16,
app_settings: &ApplicationSettings,
) -> bool {
//= https://tools.ietf.org/id/draft-cardwell-iccrg-bbr-congestion-control-02#4.3.1.3
//# A second method BBR uses for estimating the bottleneck is full is by looking at sustained
Expand Down Expand Up @@ -176,6 +186,7 @@ impl Estimator {
max_datagram_size,
loss_bursts_in_round,
STARTUP_FULL_LOSS_COUNT,
app_settings,
)
}

Expand Down Expand Up @@ -266,12 +277,22 @@ mod tests {
};

// Only 7 loss bursts, not enough to be considered excessive loss
fp_estimator.on_loss_round_start(rate_sample, 7, MINIMUM_MAX_DATAGRAM_SIZE);
fp_estimator.on_loss_round_start(
rate_sample,
7,
MINIMUM_MAX_DATAGRAM_SIZE,
&Default::default(),
);
// The pipe has not been filled yet since there were only 2 loss bursts
assert!(!fp_estimator.filled_pipe());

// 3 loss bursts, enough to be considered excessive loss
fp_estimator.on_loss_round_start(rate_sample, 8, MINIMUM_MAX_DATAGRAM_SIZE);
fp_estimator.on_loss_round_start(
rate_sample,
8,
MINIMUM_MAX_DATAGRAM_SIZE,
&Default::default(),
);
// The pipe has been filled due to loss
assert!(fp_estimator.filled_pipe());
}
Expand All @@ -289,9 +310,19 @@ mod tests {
};

// Only 7 loss bursts, not enough to be considered excessive loss
fp_estimator.on_loss_round_start(rate_sample, 7, MINIMUM_MAX_DATAGRAM_SIZE);
fp_estimator.on_loss_round_start(
rate_sample,
7,
MINIMUM_MAX_DATAGRAM_SIZE,
&Default::default(),
);

fp_estimator.on_loss_round_start(rate_sample, 8, MINIMUM_MAX_DATAGRAM_SIZE);
fp_estimator.on_loss_round_start(
rate_sample,
8,
MINIMUM_MAX_DATAGRAM_SIZE,
&Default::default(),
);
// The pipe has been filled due to ECN
assert!(fp_estimator.filled_pipe());
}
Expand All @@ -308,7 +339,12 @@ mod tests {
..Default::default()
};
// 8 loss bursts, enough to be considered excessive loss
fp_estimator.on_loss_round_start(rate_sample, 8, MINIMUM_MAX_DATAGRAM_SIZE);
fp_estimator.on_loss_round_start(
rate_sample,
8,
MINIMUM_MAX_DATAGRAM_SIZE,
&Default::default(),
);
// The pipe has not been filled yet since the loss rate was not high enough
assert!(!fp_estimator.filled_pipe());
}
Expand Down
31 changes: 19 additions & 12 deletions quic/s2n-quic-core/src/recovery/bbr/pacing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
counter::{Counter, Saturating},
recovery::{
bandwidth::Bandwidth,
bbr::{BbrCongestionController, State},
bbr::{ApplicationSettings, BbrCongestionController, State},
congestion_controller::Publisher,
pacing::{INITIAL_INTERVAL, MINIMUM_PACING_RTT},
MAX_BURST_PACKETS,
Expand All @@ -28,15 +28,17 @@ pub struct Pacer {
}

impl Pacer {
pub(super) fn new(max_datagram_size: u16) -> Self {
pub(super) fn new(max_datagram_size: u16, app_settings: &ApplicationSettings) -> Self {
//= https://tools.ietf.org/id/draft-cardwell-iccrg-bbr-congestion-control-02#4.6.2
//# BBRInitPacingRate():
//# nominal_bandwidth = InitialCwnd / (SRTT ? SRTT : 1ms)
//# BBR.pacing_rate = BBRStartupPacingGain * nominal_bandwidth
let initial_cwnd = BbrCongestionController::initial_window(max_datagram_size);
let initial_cwnd = BbrCongestionController::initial_window(max_datagram_size, app_settings);
let nominal_bandwidth = Bandwidth::new(initial_cwnd as u64, Duration::from_millis(1));
let pacing_rate =
Self::bandwidth_to_pacing_rate(nominal_bandwidth, State::Startup.pacing_gain());
let pacing_rate = Self::bandwidth_to_pacing_rate(
nominal_bandwidth,
State::Startup.pacing_gain(app_settings),
);

Self {
capacity: Default::default(),
Expand Down Expand Up @@ -212,7 +214,7 @@ mod tests {
// nominal_bandwidth = 12_000 / 1ms = ~83.3333nanos/byte
// pacing_rate = 2.77 * 83.333nanos/byte * 99% = ~30.388nanos/byte

let pacer = Pacer::new(MINIMUM_MAX_DATAGRAM_SIZE);
let pacer = Pacer::new(MINIMUM_MAX_DATAGRAM_SIZE, &Default::default());

assert_eq!(
Bandwidth::new(1000, Duration::from_nanos(30388)),
Expand Down Expand Up @@ -241,7 +243,7 @@ mod tests {
//# BBR.pacing_rate = rate
#[test]
fn set_pacing_rate() {
let mut pacer = Pacer::new(MINIMUM_MAX_DATAGRAM_SIZE);
let mut pacer = Pacer::new(MINIMUM_MAX_DATAGRAM_SIZE, &Default::default());
let mut publisher = event::testing::Publisher::snapshot();
let mut publisher = PathPublisher::new(&mut publisher, path::Id::test_id());
let bandwidth = Bandwidth::new(1000, Duration::from_millis(1));
Expand All @@ -258,15 +260,15 @@ mod tests {

#[test]
fn initialize_pacing_rate() {
let mut pacer = Pacer::new(MINIMUM_MAX_DATAGRAM_SIZE);
let mut pacer = Pacer::new(MINIMUM_MAX_DATAGRAM_SIZE, &Default::default());
let mut publisher = event::testing::Publisher::snapshot();
let mut publisher = PathPublisher::new(&mut publisher, path::Id::test_id());

// pacing_rate = 14_000/100ms * 2.77 * .99 = 383_922 bytes/sec
pacer.initialize_pacing_rate(
14_000,
Duration::from_millis(100),
Startup.pacing_gain(),
Startup.pacing_gain(&Default::default()),
&mut publisher,
);
assert_eq!(
Expand All @@ -285,7 +287,7 @@ mod tests {
//# BBR.send_quantum = max(BBR.send_quantum, floor)
#[test]
fn set_send_quantum() {
let mut pacer = Pacer::new(MINIMUM_MAX_DATAGRAM_SIZE);
let mut pacer = Pacer::new(MINIMUM_MAX_DATAGRAM_SIZE, &Default::default());
// pacing_rate < 1.2 Mbps, floor = MINIMUM_MAX_DATAGRAM_SIZE
pacer.pacing_rate = Bandwidth::new(1_100_000 / 8, Duration::from_secs(1));
pacer.set_send_quantum(MINIMUM_MAX_DATAGRAM_SIZE);
Expand Down Expand Up @@ -321,15 +323,20 @@ mod tests {

#[test]
fn test_one_rtt() {
let mut pacer = Pacer::new(MINIMUM_MAX_DATAGRAM_SIZE);
let mut pacer = Pacer::new(MINIMUM_MAX_DATAGRAM_SIZE, &Default::default());
let now = NoopClock.get_time();
let mut publisher = event::testing::Publisher::snapshot();
let mut publisher = PathPublisher::new(&mut publisher, path::Id::test_id());

let rtt = Duration::from_millis(100);
let bw = Bandwidth::new(100_000, rtt);

pacer.set_pacing_rate(bw, State::Startup.pacing_gain(), true, &mut publisher);
pacer.set_pacing_rate(
bw,
State::Startup.pacing_gain(&Default::default()),
true,
&mut publisher,
);

let bytes_to_send = pacer.pacing_rate * rtt;

Expand Down
Loading
Loading