use std::any::Any;
use std::sync::Arc;
use super::{BASE_DATAGRAM_SIZE, Controller, ControllerFactory};
use crate::Instant;
use crate::connection::RttEstimator;
#[derive(Debug, Clone)]
pub struct NewReno {
config: Arc<NewRenoConfig>,
current_mtu: u64,
window: u64,
ssthresh: u64,
recovery_start_time: Instant,
bytes_acked: u64,
}
impl NewReno {
pub fn new(config: Arc<NewRenoConfig>, now: Instant, current_mtu: u16) -> Self {
Self {
window: config.initial_window,
ssthresh: u64::MAX,
recovery_start_time: now,
current_mtu: current_mtu as u64,
config,
bytes_acked: 0,
}
}
fn minimum_window(&self) -> u64 {
2 * self.current_mtu
}
}
impl Controller for NewReno {
fn on_ack(
&mut self,
_now: Instant,
sent: Instant,
bytes: u64,
app_limited: bool,
_rtt: &RttEstimator,
) {
if app_limited || sent <= self.recovery_start_time {
return;
}
if self.window < self.ssthresh {
self.window += bytes;
if self.window >= self.ssthresh {
self.bytes_acked = self.window - self.ssthresh;
}
} else {
self.bytes_acked += bytes;
if self.bytes_acked >= self.window {
self.bytes_acked -= self.window;
self.window += self.current_mtu;
}
}
}
fn on_congestion_event(
&mut self,
now: Instant,
sent: Instant,
is_persistent_congestion: bool,
_is_ecn: bool,
_lost_bytes: u64,
) {
if sent <= self.recovery_start_time {
return;
}
self.recovery_start_time = now;
self.window = (self.window as f32 * self.config.loss_reduction_factor) as u64;
self.window = self.window.max(self.minimum_window());
self.ssthresh = self.window;
if is_persistent_congestion {
self.window = self.minimum_window();
}
}
fn on_mtu_update(&mut self, new_mtu: u16) {
self.current_mtu = new_mtu as u64;
self.window = self.window.max(self.minimum_window());
}
fn window(&self) -> u64 {
self.window
}
fn metrics(&self) -> super::ControllerMetrics {
super::ControllerMetrics {
congestion_window: self.window(),
ssthresh: Some(self.ssthresh),
pacing_rate: None,
}
}
fn clone_box(&self) -> Box<dyn Controller> {
Box::new(self.clone())
}
fn initial_window(&self) -> u64 {
self.config.initial_window
}
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
}
#[derive(Debug, Clone)]
pub struct NewRenoConfig {
initial_window: u64,
loss_reduction_factor: f32,
}
impl NewRenoConfig {
pub fn initial_window(&mut self, value: u64) -> &mut Self {
self.initial_window = value;
self
}
pub fn loss_reduction_factor(&mut self, value: f32) -> &mut Self {
self.loss_reduction_factor = value;
self
}
}
impl Default for NewRenoConfig {
fn default() -> Self {
Self {
initial_window: 14720.clamp(2 * BASE_DATAGRAM_SIZE, 10 * BASE_DATAGRAM_SIZE),
loss_reduction_factor: 0.5,
}
}
}
impl ControllerFactory for NewRenoConfig {
fn build(self: Arc<Self>, now: Instant, current_mtu: u16) -> Box<dyn Controller> {
Box::new(NewReno::new(self, now, current_mtu))
}
}