tor_proto/congestion/params.rs
1//! Define the congestion control parameters needed for the algorithms.
2//!
3//! All of these values are taken from the consensus. And so the details of these values can be
4//! found in section 6.5.1. of proposal 324.
5
6use caret::caret_int;
7use derive_builder::Builder;
8
9use tor_config::{impl_standard_builder, ConfigBuildError};
10use tor_units::Percentage;
11
12/// Fixed window parameters that are for the SENDME v0 world of fixed congestion window.
13#[non_exhaustive]
14#[derive(Builder, Copy, Clone, Debug, amplify::Getters)]
15#[builder(build_fn(error = "ConfigBuildError"))]
16pub struct FixedWindowParams {
17 /// Circuit window starting point. From the "circwindow" param.
18 #[getter(as_copy)]
19 circ_window_start: u16,
20 /// Circuit window minimum value.
21 #[getter(as_copy)]
22 circ_window_min: u16,
23 /// Circuit window maximum value.
24 #[getter(as_copy)]
25 circ_window_max: u16,
26}
27impl_standard_builder! { FixedWindowParams: !Deserialize + !Default }
28
29/// Vegas queuing parameters taken from the consensus only which are different depending if the
30/// circuit is an onion service one, an exit or used for SBWS.
31#[non_exhaustive]
32#[derive(Copy, Clone, Debug, amplify::Getters)]
33pub struct VegasQueueParams {
34 /// Alpha parameter is used to know when to increase the window.
35 #[getter(as_copy)]
36 alpha: u32,
37 /// Beta parameter is used to know when to decrease the window
38 #[getter(as_copy)]
39 beta: u32,
40 /// Delta parameter is used as an indicator to drop the window to this considering the current
41 /// BDP value and increment.
42 #[getter(as_copy)]
43 delta: u32,
44 /// Gamma parameter is only used in slow start and used to know when to increase or adjust the
45 /// window with the BDP.
46 #[getter(as_copy)]
47 gamma: u32,
48 /// Parameter describe the RFC3742 'cap', after which congestion window increments are reduced.
49 /// INT32_MAX disables
50 #[getter(as_copy)]
51 ss_cwnd_cap: u32,
52}
53
54/// Used when we parse at once all the specific circuit type vegas queue parameters. They are
55/// bundled in a 5-tuple and transformed with this.
56impl From<(u32, u32, u32, u32, u32)> for VegasQueueParams {
57 fn from(v: (u32, u32, u32, u32, u32)) -> Self {
58 Self {
59 alpha: v.0,
60 beta: v.1,
61 delta: v.2,
62 gamma: v.3,
63 ss_cwnd_cap: v.4,
64 }
65 }
66}
67
68/// Vegas algorithm parameters taken from the consensus.
69#[non_exhaustive]
70#[derive(Builder, Copy, Clone, Debug, amplify::Getters)]
71#[builder(build_fn(error = "ConfigBuildError"))]
72pub struct VegasParams {
73 /// The amount of queued cells that Vegas can tolerate before reacting.
74 cell_in_queue_params: VegasQueueParams,
75 /// A hard-max on the congestion window in Slow Start.
76 #[getter(as_copy)]
77 ss_cwnd_max: u32,
78 /// This parameter defines the integer number of 'cc_sendme_inc' multiples
79 /// of gap allowed between inflight and cwnd, to still declare the cwnd full.
80 #[getter(as_copy)]
81 cwnd_full_gap: u32,
82 /// This parameter defines a low watermark in percent.
83 cwnd_full_min_pct: Percentage<u32>,
84 /// This parameter governs how often a cwnd must be full.
85 #[getter(as_copy)]
86 cwnd_full_per_cwnd: u32,
87}
88impl_standard_builder! { VegasParams: !Deserialize + !Default }
89
90/// The different congestion control algorithms. Each contain their parameters taken from the
91/// consensus.
92#[non_exhaustive]
93#[derive(Clone, Debug)]
94pub enum Algorithm {
95 /// Fixed window algorithm.
96 FixedWindow(FixedWindowParams),
97 /// Vegas algorithm.
98 Vegas(VegasParams),
99}
100
101impl Algorithm {
102 /// Return true if this algorithm can be used along with CGO.
103 ///
104 /// CGO requires the V1 relay cell format, where every relay command
105 /// implies either the presence or absence of a StreamID.
106 /// But that format is not compatible with (legacy) stream-level SENDME messages
107 /// for flow control.
108 pub(crate) fn compatible_with_cgo(&self) -> bool {
109 match self {
110 Algorithm::FixedWindow(_) => false,
111 Algorithm::Vegas(_) => true,
112 }
113 }
114}
115
116caret_int! {
117 /// Congestion control algorithm types defined by numerical values. See "cc_alg" in proposal
118 /// 324 section 6.5.1 for the supported values.
119 ///
120 /// This is a i32 so it is the same type as the consensus supported value type.
121 pub struct AlgorithmType(i32) {
122 /// Fixed window algorithm.
123 FIXED_WINDOW = 0,
124 /// Vegas algorithm.
125 VEGAS = 2,
126 }
127}
128
129/// The round trip estimator parameters taken from consensus and used to estimate the round trip
130/// time on a circuit.
131#[non_exhaustive]
132#[derive(Builder, Clone, Debug, amplify::Getters)]
133#[builder(build_fn(error = "ConfigBuildError"))]
134pub struct RoundTripEstimatorParams {
135 /// The "N" parameter in N-EWMA smoothing of RTT and/or bandwidth estimation, specified as a
136 /// percentage of the number of SENDME acks in a congestion window.
137 ///
138 /// A percentage over 100% indicates smoothing with more than one congestion window's worth
139 /// of SENDMEs.
140 ewma_cwnd_pct: Percentage<u32>,
141 /// The maximum value of the "N" parameter in N-EWMA smoothing of RTT and/or bandwidth
142 /// estimation.
143 #[getter(as_copy)]
144 ewma_max: u32,
145 /// The maximum value of the "N" parameter in N-EWMA smoothing of RTT and/or bandwidth
146 /// estimation but in Slow Start.
147 #[getter(as_copy)]
148 ewma_ss_max: u32,
149 /// Describes a percentile average between min and current ewma, for use to reset RTT_min, when
150 /// the congestion window hits cwnd_min.
151 rtt_reset_pct: Percentage<u32>,
152}
153impl_standard_builder! { RoundTripEstimatorParams: !Deserialize + !Default }
154
155/// The parameters of what constitute a congestion window. This is used by all congestion control
156/// algorithms as in it is not specific to an algorithm.
157#[non_exhaustive]
158#[derive(Builder, Clone, Debug, amplify::Getters)]
159#[builder(build_fn(error = "ConfigBuildError"))]
160pub struct CongestionWindowParams {
161 /// Initial size of the congestion window.
162 #[getter(as_copy)]
163 cwnd_init: u32,
164 /// Percent of cwnd to increment by during slow start.
165 cwnd_inc_pct_ss: Percentage<u32>,
166 /// Number of cells to increment cwnd by during steady state.
167 #[getter(as_copy)]
168 cwnd_inc: u32,
169 /// Number of times per congestion window to update based on congestion signals.
170 #[getter(as_copy)]
171 cwnd_inc_rate: u32,
172 /// Minimum congestion window (must be at least sendme_inc)
173 #[getter(as_copy)]
174 cwnd_min: u32,
175 /// Maximum congestion window
176 #[getter(as_copy)]
177 cwnd_max: u32,
178 /// The SENDME increment as in the number of cells to ACK with every SENDME. This is coming
179 /// from the consensus and negotiated during circuit setup.
180 #[getter(as_copy)]
181 sendme_inc: u32,
182}
183impl_standard_builder! { CongestionWindowParams: !Deserialize + !Default}
184
185impl CongestionWindowParams {
186 /// Set the `sendme_inc` value.
187 ///
188 /// This is used to override the default increment value from when this was constructed with a
189 /// [`CongestionWindowParamsBuilder`].
190 /// Typically the default when built should be from the network parameters from the consensus.
191 pub(crate) fn set_sendme_inc(&mut self, inc: u8) {
192 self.sendme_inc = u32::from(inc);
193 }
194}
195
196/// Global congestion control parameters taken from consensus. These are per-circuit.
197#[non_exhaustive]
198#[derive(Builder, Clone, Debug, amplify::Getters)]
199#[builder(build_fn(error = "ConfigBuildError"))]
200pub struct CongestionControlParams {
201 /// The congestion control algorithm to use.
202 alg: Algorithm,
203 /// Parameters to the fallback fixed-window algorithm, which we use
204 /// when the one in `alg` is not supported by a given relay.
205 ///
206 /// It is put in here because by the time we do path selection, we don't have access to the
207 /// consensus and so we have to keep our fallback ready.
208 fixed_window_params: FixedWindowParams,
209 /// Congestion window parameters.
210 #[getter(as_mut)]
211 cwnd_params: CongestionWindowParams,
212 /// RTT calculation parameters.
213 rtt_params: RoundTripEstimatorParams,
214}
215impl_standard_builder! { CongestionControlParams: !Deserialize + !Default }
216
217impl CongestionControlParams {
218 /// Return true iff congestion control is enabled that is the algorithm is anything other than
219 /// the fixed window SENDMEs.
220 ///
221 /// C-tor ref: congestion_control_enabled()
222 pub(crate) fn is_enabled(&self) -> bool {
223 !matches!(self.alg(), Algorithm::FixedWindow(_))
224 }
225
226 /// Make these parameters to use the fallback algorithm. This can't be reversed.
227 pub(crate) fn use_fallback_alg(&mut self) {
228 self.alg = Algorithm::FixedWindow(self.fixed_window_params);
229 }
230}
231
232/// Return true iff the given sendme increment is valid with regards to the value in the circuit
233/// parameters that is taken from the consensus.
234pub(crate) fn is_sendme_inc_valid(inc: u8, params: &CongestionControlParams) -> bool {
235 // Ease our lives a bit because the consensus value is u32.
236 let inc_u32 = u32::from(inc);
237 // A consensus value of 1 would allow this sendme increment to be 0 and thus
238 // we have to special case it before evaluating.
239 if inc == 0 {
240 return false;
241 }
242 let inc_consensus = params.cwnd_params().sendme_inc();
243 // See prop324 section 10.3
244 if inc_u32 > (inc_consensus.saturating_add(1)) || inc_u32 < (inc_consensus.saturating_sub(1)) {
245 return false;
246 }
247 true
248}
249
250#[cfg(test)]
251mod test {
252 use crate::{
253 ccparams::is_sendme_inc_valid, congestion::test_utils::params::build_cc_vegas_params,
254 };
255
256 #[test]
257 fn test_sendme_inc_valid() {
258 let params = build_cc_vegas_params();
259 let ref_inc = params.cwnd_params().sendme_inc() as u8;
260
261 // In range.
262 assert!(is_sendme_inc_valid(ref_inc, ¶ms));
263 assert!(is_sendme_inc_valid(ref_inc + 1, ¶ms));
264 assert!(is_sendme_inc_valid(ref_inc - 1, ¶ms));
265 // Out of range.
266 assert!(!is_sendme_inc_valid(0, ¶ms));
267 assert!(!is_sendme_inc_valid(ref_inc + 2, ¶ms));
268 assert!(!is_sendme_inc_valid(ref_inc - 2, ¶ms));
269 }
270}