Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ defmt = ["dep:defmt", "heapless/defmt"]
# Enable Reno TCP congestion control algorithm, and it is used as a default congestion controller.
"socket-tcp-reno" = []

# Enable BBR TCP congestion control algorithm, and it is used as a default congestion controller.
"socket-tcp-bbr" = []

"packetmeta-id" = []

"async" = []
Expand Down
20 changes: 20 additions & 0 deletions src/socket/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,11 @@ impl RttEstimator {
Duration::from_millis(self.rto as _)
}

#[cfg(feature = "socket-tcp-bbr")]
pub(super) fn min_rtt(&self) -> Duration {
Duration::from_millis(self.srtt as _)
}

fn sample(&mut self, new_rtt: u32) {
if self.have_measurement {
// RFC 6298 (2.3) When a subsequent RTT measurement R' is made, a host MUST set (...)
Expand Down Expand Up @@ -454,6 +459,9 @@ pub enum CongestionControl {

#[cfg(feature = "socket-tcp-cubic")]
Cubic,

#[cfg(feature = "socket-tcp-bbr")]
Bbr,
}

/// A Transmission Control Protocol socket.
Expand Down Expand Up @@ -657,6 +665,9 @@ impl<'a> Socket<'a> {

#[cfg(feature = "socket-tcp-cubic")]
CongestionControl::Cubic => AnyController::Cubic(cubic::Cubic::new()),

#[cfg(feature = "socket-tcp-bbr")]
CongestionControl::Bbr => AnyController::Bbr(bbr::Bbr::new()),
}
}

Expand All @@ -672,6 +683,9 @@ impl<'a> Socket<'a> {

#[cfg(feature = "socket-tcp-cubic")]
AnyController::Cubic(_) => CongestionControl::Cubic,

#[cfg(feature = "socket-tcp-bbr")]
AnyController::Bbr(_) => CongestionControl::Bbr,
}
}

Expand Down Expand Up @@ -2368,6 +2382,12 @@ impl<'a> Socket<'a> {
.inner_mut()
.pre_transmit(cx.now());

// Notify congestion controller about available data for app-limited tracking
let bytes_available = self.tx_buffer.len();
self.congestion_controller
.inner_mut()
.on_send_ready(cx.now(), bytes_available);

// Check if any state needs to be changed because of a timer.
if self.timed_out(cx.now()) {
// If a timeout expires, we should abort the connection.
Expand Down
28 changes: 27 additions & 1 deletion src/socket/tcp/congestion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ pub(super) mod cubic;
#[cfg(feature = "socket-tcp-reno")]
pub(super) mod reno;

#[cfg(feature = "socket-tcp-bbr")]
pub(super) mod bbr;

#[allow(unused_variables)]
pub(super) trait Controller {
/// Returns the number of bytes that can be sent.
Expand All @@ -30,10 +33,17 @@ pub(super) trait Controller {

/// Set the maximum segment size.
fn set_mss(&mut self, mss: usize) {}

/// Called when the socket is about to send data.
/// `bytes_available` indicates how many bytes are waiting in the send buffer.
/// This allows the congestion controller to track whether the application
/// is app-limited (not enough data to send) or cwnd-limited.
fn on_send_ready(&mut self, now: Instant, bytes_available: usize) {}
}

#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[allow(clippy::large_enum_variant)]
pub(super) enum AnyController {
None(no_control::NoControl),

Expand All @@ -42,15 +52,20 @@ pub(super) enum AnyController {

#[cfg(feature = "socket-tcp-cubic")]
Cubic(cubic::Cubic),

#[cfg(feature = "socket-tcp-bbr")]
Bbr(bbr::Bbr),
}

impl AnyController {
/// Create a new congestion controller.
/// `AnyController::new()` selects the best congestion controller based on the features.
///
/// - If `socket-tcp-bbr` feature is enabled, it will use `Bbr`.
/// - If `socket-tcp-cubic` feature is enabled, it will use `Cubic`.
/// - If `socket-tcp-reno` feature is enabled, it will use `Reno`.
/// - If both `socket-tcp-cubic` and `socket-tcp-reno` features are enabled, it will use `Cubic`.
/// - Priority: BBR > Cubic > Reno > NoControl
/// - `BBR` is optimized for high bandwidth-delay product networks.
/// - `Cubic` is more efficient regarding throughput.
/// - `Reno` is more conservative and is suitable for low-power devices.
/// - If no congestion controller is available, it will use `NoControl`.
Expand All @@ -60,6 +75,11 @@ impl AnyController {
#[allow(unreachable_code)]
#[inline]
pub fn new() -> Self {
#[cfg(feature = "socket-tcp-bbr")]
{
return AnyController::Bbr(bbr::Bbr::new());
}

#[cfg(feature = "socket-tcp-cubic")]
{
return AnyController::Cubic(cubic::Cubic::new());
Expand All @@ -83,6 +103,9 @@ impl AnyController {

#[cfg(feature = "socket-tcp-cubic")]
AnyController::Cubic(c) => c,

#[cfg(feature = "socket-tcp-bbr")]
AnyController::Bbr(b) => b,
}
}

Expand All @@ -96,6 +119,9 @@ impl AnyController {

#[cfg(feature = "socket-tcp-cubic")]
AnyController::Cubic(c) => c,

#[cfg(feature = "socket-tcp-bbr")]
AnyController::Bbr(b) => b,
}
}
}
Loading