1use std::{
2 time::Duration
3};
4use crate::types::*;
5use super::{
6 cc_impl::CcImpl,
7 ledbat::{self, Ledbat},
8 bbr::{self, Bbr},
9};
10
11
12#[derive(Debug)]
13struct EstimateRtt {
14 srtt: i64, mdev: i64, mdev_max: i64, rttvar: i64, min_rtt: i64,
20}
21
22impl EstimateRtt {
23 fn new() -> Self {
24 Self {
25 srtt: 0,
26 mdev: Duration::from_secs(1).as_micros() as i64,
27 mdev_max: 0,
28 rttvar: 0,
29 min_rtt: 0,
31 }
32 }
33
34 fn update(&mut self, config: &Config, rtt: Duration) -> (Duration, Duration) {
35 let mut rtt = rtt.as_micros() as i64;
36 if rtt == 0 {
37 rtt = 1;
38 }
39
40 if self.min_rtt == 0 ||
41 self.min_rtt > rtt {
42 self.min_rtt = rtt;
43 }
44
45 if self.srtt != 0 {
46 rtt -= self.srtt / 8;
47 self.srtt += rtt;
48 if rtt < 0 {
49 rtt = 0 - rtt;
50 rtt -= self.mdev / 4;
51 if rtt > 0 {
52 rtt >>= 3;
53 }
54 } else {
55 rtt -= self.mdev / 4;
56 }
57
58 self.mdev = self.mdev + rtt;
59
60 if self.mdev > self.mdev_max {
61 self.mdev_max = self.mdev;
62 if self.mdev_max > self.rttvar {
63 self.rttvar = self.mdev_max;
64 }
65 }
66 if self.mdev < self.mdev_max {
67 self.rttvar -= (self.rttvar - self.mdev_max) / 4;
68 }
69 self.mdev_max = config.min_rto.as_micros() as i64;
70 } else {
71 self.srtt = rtt * 8;
72 self.mdev = rtt * 2;
73 self.rttvar = std::cmp::max(self.mdev, config.min_rto.as_micros() as i64);
74 self.mdev_max = self.rttvar;
75 }
76 let srtt = (self.srtt / 8) as u64;
77 let rto = (self.srtt / 8 + self.rttvar) as u64;
78 (Duration::from_micros(srtt), Duration::from_micros(rto))
79 }
80}
81
82#[derive(Clone)]
83pub enum ImplConfig {
84 Ledbat(ledbat::Config),
85 BBR(bbr::Config),
86}
87
88#[derive(Clone)]
89pub struct Config {
90 pub init_rto: Duration,
91 pub min_rto: Duration,
92 pub cc_impl: ImplConfig
93}
94
95pub struct CongestionControl {
96 rtt: Duration,
97 rto: Duration,
98 config: Config,
99 est_rtt: EstimateRtt,
100 cc: Box<dyn CcImpl>,
101}
102
103impl CongestionControl {
104 pub fn new(mss: usize, config: &Config) -> Self {
105 Self {
106 rtt: Duration::from_secs(0),
107 rto: config.init_rto,
108 est_rtt: EstimateRtt::new(),
109 cc: match &config.cc_impl {
110 ImplConfig::Ledbat(config) => {
111 Box::new(Ledbat::new(mss, config))
112 },
113 ImplConfig::BBR(config) => {
114 Box::new(Bbr::new(mss, config))
115 }
116 },
117 config: config.clone()
118 }
119 }
120
121 pub fn on_sent(&mut self, now: Timestamp, bytes: u64, last_packet_number: u64) {
122 self.cc.on_sent(now, bytes, last_packet_number);
123 }
124
125 pub fn cwnd(&self) -> u64 {
126 self.cc.cwnd()
127 }
128
129 pub fn rto(&self) -> Duration {
130 self.rto
131 }
132
133 pub fn rtt(&self) -> Duration {
134 self.rtt
135 }
136
137 pub fn on_estimate(&mut self, est_rtt: Duration, est_delay: Duration, app_limited: bool) {
138 let (rtt, rto) = self.est_rtt.update(&self.config, est_rtt);
139 self.rto = rto;
140 self.rtt = rtt;
141 self.cc.on_estimate(Duration::from_micros(self.est_rtt.min_rtt as u64), rto, est_delay, app_limited);
142 }
143
144 pub fn on_ack(&mut self,
145 flight: u64,
146 ack: u64,
147 largest_packet_num_acked: Option<u64>,
148 sent_time: Timestamp,
149 app_limited: bool) {
150 self.cc.on_ack(flight, ack, largest_packet_num_acked, sent_time, app_limited)
151 }
152
153 pub fn on_loss(&mut self, lost: u64) {
154 self.cc.on_loss(lost)
155 }
156
157 pub fn on_no_resp(&mut self, lost: u64) {
158 let rto = self.cc.on_no_resp(self.rto, lost);
159 self.rto = rto;
160 }
161
162 pub fn on_time_escape(&mut self, now: Timestamp) {
163 self.cc.on_time_escape(now)
164 }
165
166 pub fn rate(&self) -> u64 {
167 self.cc.rate()
168 }
169}