Skip to content

Commit b531036

Browse files
committed
feat(congestion control): Migrate the BBR implementation of quinn into smoltcp
1 parent e1ed3d6 commit b531036

File tree

6 files changed

+1330
-1
lines changed

6 files changed

+1330
-1
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ defmt = ["dep:defmt", "heapless/defmt"]
9393
# Enable Reno TCP congestion control algorithm, and it is used as a default congestion controller.
9494
"socket-tcp-reno" = []
9595

96+
# Enable BBR TCP congestion control algorithm, and it is used as a default congestion controller.
97+
"socket-tcp-bbr" = []
98+
9699
"packetmeta-id" = []
97100

98101
"async" = []

src/socket/tcp.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ impl RttEstimator {
197197
Duration::from_millis(self.rto as _)
198198
}
199199

200+
pub(super) fn min_rtt(&self) -> Duration {
201+
Duration::from_millis(self.srtt as _)
202+
}
203+
200204
fn sample(&mut self, new_rtt: u32) {
201205
if self.have_measurement {
202206
// RFC 6298 (2.3) When a subsequent RTT measurement R' is made, a host MUST set (...)
@@ -454,6 +458,9 @@ pub enum CongestionControl {
454458

455459
#[cfg(feature = "socket-tcp-cubic")]
456460
Cubic,
461+
462+
#[cfg(feature = "socket-tcp-bbr")]
463+
Bbr,
457464
}
458465

459466
/// A Transmission Control Protocol socket.
@@ -657,6 +664,9 @@ impl<'a> Socket<'a> {
657664

658665
#[cfg(feature = "socket-tcp-cubic")]
659666
CongestionControl::Cubic => AnyController::Cubic(cubic::Cubic::new()),
667+
668+
#[cfg(feature = "socket-tcp-bbr")]
669+
CongestionControl::Bbr => AnyController::Bbr(bbr::Bbr::new()),
660670
}
661671
}
662672

@@ -672,6 +682,9 @@ impl<'a> Socket<'a> {
672682

673683
#[cfg(feature = "socket-tcp-cubic")]
674684
AnyController::Cubic(_) => CongestionControl::Cubic,
685+
686+
#[cfg(feature = "socket-tcp-bbr")]
687+
AnyController::Bbr(_) => CongestionControl::Bbr,
675688
}
676689
}
677690

@@ -2368,6 +2381,12 @@ impl<'a> Socket<'a> {
23682381
.inner_mut()
23692382
.pre_transmit(cx.now());
23702383

2384+
// Notify congestion controller about available data for app-limited tracking
2385+
let bytes_available = self.tx_buffer.len();
2386+
self.congestion_controller
2387+
.inner_mut()
2388+
.on_send_ready(cx.now(), bytes_available);
2389+
23712390
// Check if any state needs to be changed because of a timer.
23722391
if self.timed_out(cx.now()) {
23732392
// If a timeout expires, we should abort the connection.

src/socket/tcp/congestion.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ pub(super) mod cubic;
1010
#[cfg(feature = "socket-tcp-reno")]
1111
pub(super) mod reno;
1212

13+
#[cfg(feature = "socket-tcp-bbr")]
14+
pub(super) mod bbr;
15+
1316
#[allow(unused_variables)]
1417
pub(super) trait Controller {
1518
/// Returns the number of bytes that can be sent.
@@ -30,6 +33,12 @@ pub(super) trait Controller {
3033

3134
/// Set the maximum segment size.
3235
fn set_mss(&mut self, mss: usize) {}
36+
37+
/// Called when the socket is about to send data.
38+
/// `bytes_available` indicates how many bytes are waiting in the send buffer.
39+
/// This allows the congestion controller to track whether the application
40+
/// is app-limited (not enough data to send) or cwnd-limited.
41+
fn on_send_ready(&mut self, now: Instant, bytes_available: usize) {}
3342
}
3443

3544
#[derive(Debug)]
@@ -42,15 +51,20 @@ pub(super) enum AnyController {
4251

4352
#[cfg(feature = "socket-tcp-cubic")]
4453
Cubic(cubic::Cubic),
54+
55+
#[cfg(feature = "socket-tcp-bbr")]
56+
Bbr(bbr::Bbr),
4557
}
4658

4759
impl AnyController {
4860
/// Create a new congestion controller.
4961
/// `AnyController::new()` selects the best congestion controller based on the features.
5062
///
63+
/// - If `socket-tcp-bbr` feature is enabled, it will use `Bbr`.
5164
/// - If `socket-tcp-cubic` feature is enabled, it will use `Cubic`.
5265
/// - If `socket-tcp-reno` feature is enabled, it will use `Reno`.
53-
/// - If both `socket-tcp-cubic` and `socket-tcp-reno` features are enabled, it will use `Cubic`.
66+
/// - Priority: BBR > Cubic > Reno > NoControl
67+
/// - `BBR` is optimized for high bandwidth-delay product networks.
5468
/// - `Cubic` is more efficient regarding throughput.
5569
/// - `Reno` is more conservative and is suitable for low-power devices.
5670
/// - If no congestion controller is available, it will use `NoControl`.
@@ -60,6 +74,11 @@ impl AnyController {
6074
#[allow(unreachable_code)]
6175
#[inline]
6276
pub fn new() -> Self {
77+
#[cfg(feature = "socket-tcp-bbr")]
78+
{
79+
return AnyController::Bbr(bbr::Bbr::new());
80+
}
81+
6382
#[cfg(feature = "socket-tcp-cubic")]
6483
{
6584
return AnyController::Cubic(cubic::Cubic::new());
@@ -83,6 +102,9 @@ impl AnyController {
83102

84103
#[cfg(feature = "socket-tcp-cubic")]
85104
AnyController::Cubic(c) => c,
105+
106+
#[cfg(feature = "socket-tcp-bbr")]
107+
AnyController::Bbr(b) => b,
86108
}
87109
}
88110

@@ -96,6 +118,9 @@ impl AnyController {
96118

97119
#[cfg(feature = "socket-tcp-cubic")]
98120
AnyController::Cubic(c) => c,
121+
122+
#[cfg(feature = "socket-tcp-bbr")]
123+
AnyController::Bbr(b) => b,
99124
}
100125
}
101126
}

0 commit comments

Comments
 (0)