use super::core::MTU_ETHERNET;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct LinkImpairment {
pub latency: u32,
pub netem_limit: u32,
pub loss: f64,
pub gap: u32,
pub duplicate: f64,
pub jitter: u32,
pub bandwidth_mbit_s: Option<f64>,
pub burst_kib: Option<u32>,
pub tbf_queue_latency_ms: Option<u32>,
}
impl Default for LinkImpairment {
fn default() -> Self {
Self {
latency: 0,
netem_limit: 1_000,
loss: 0.0,
gap: 0,
duplicate: 0.0,
jitter: 0,
bandwidth_mbit_s: None,
burst_kib: None,
tbf_queue_latency_ms: None,
}
}
}
impl LinkImpairment {
pub fn with_latency(mut self, microseconds: u32) -> Self {
self.latency = microseconds;
self
}
pub fn with_latency_ms(mut self, milliseconds: u32) -> Self {
self.latency = milliseconds * 1_000;
self
}
pub fn with_jitter(mut self, microseconds: u32) -> Self {
self.jitter = microseconds;
self
}
pub fn with_jitter_ms(mut self, milliseconds: u32) -> Self {
self.jitter = milliseconds * 1_000;
self
}
pub fn with_loss(mut self, percent: f64) -> Self {
self.loss = percent;
self
}
pub fn with_duplicate(mut self, percent: f64) -> Self {
self.duplicate = percent;
self
}
pub fn with_gap(mut self, gap: u32) -> Self {
self.gap = gap;
self
}
pub fn with_netem_limit(mut self, limit: u32) -> Self {
self.netem_limit = limit;
self
}
pub fn with_bandwidth_mbit_s(mut self, mbit_s: f64) -> Self {
self.bandwidth_mbit_s = Some(mbit_s);
self
}
pub fn with_burst_kib(mut self, kib: u32) -> Self {
self.burst_kib = Some(kib);
self
}
pub fn with_tbf_queue_latency_ms(mut self, ms: u32) -> Self {
self.tbf_queue_latency_ms = Some(ms);
self
}
pub fn has_bandwidth_limit(&self) -> bool {
self.bandwidth_mbit_s.is_some()
}
pub fn effective_burst_bytes(&self) -> u32 {
if let Some(burst_kib) = self.burst_kib {
burst_kib * 1024
} else if let Some(bandwidth_mbit) = self.bandwidth_mbit_s {
let bandwidth_bytes_per_sec = (bandwidth_mbit * 1_000_000.0 / 8.0) as u32;
let one_eighth_second = bandwidth_bytes_per_sec / 8;
let ten_packets = MTU_ETHERNET * 10;
std::cmp::max(one_eighth_second, ten_packets)
} else {
0
}
}
pub fn effective_tbf_limit_bytes(&self) -> u32 {
let queue_latency_ms = self.tbf_queue_latency_ms.unwrap_or(200);
let burst_bytes = self.effective_burst_bytes();
if let Some(rate_bytes_per_sec) = self.bandwidth_bytes_per_sec() {
let rate_bytes_per_ms = rate_bytes_per_sec / 1000;
rate_bytes_per_ms * queue_latency_ms + burst_bytes
} else {
burst_bytes
}
}
pub fn bandwidth_bytes_per_sec(&self) -> Option<u32> {
self.bandwidth_mbit_s.map(|mbit| (mbit * 1_000_000.0 / 8.0) as u32)
}
}