1 #include "core/or/or.h"
3 #include "test/log_test_helpers.h"
4 #include "lib/testsupport/testsupport.h"
5 #include "test/fakecircs.h"
6 #include "test/rng_test_helpers.h"
8 #include "lib/time/compat_time.h"
10 #include "core/or/circuitlist.h"
11 #include "core/or/circuitmux.h"
12 #include "core/or/channel.h"
14 #define TOR_CONGESTION_CONTROL_COMMON_PRIVATE
15 #define TOR_CONGESTION_CONTROL_PRIVATE
16 #include "core/or/congestion_control_st.h"
17 #include "core/or/congestion_control_common.h"
18 #include "core/or/congestion_control_vegas.h"
20 void test_congestion_control_rtt(void *arg
);
21 void test_congestion_control_clock(void *arg
);
22 void test_congestion_control_vegas_cwnd(void *arg
);
25 circuitmux_attach_circuit_mock(circuitmux_t
*cmux
, circuit_t
*circ
,
26 cell_direction_t direction
);
29 circuitmux_attach_circuit_mock(circuitmux_t
*cmux
, circuit_t
*circ
,
30 cell_direction_t direction
)
39 /* =============== Clock Heuristic Test Vectors =============== */
41 typedef struct clock_vec
43 uint64_t old_delta_in
;
44 uint64_t new_delta_in
;
45 bool in_slow_start_in
;
46 bool cached_result_out
;
51 run_clock_test_vec(congestion_control_t
*cc
,
52 clock_vec_t
*vec
, size_t vec_len
)
54 for (size_t i
= 0; i
< vec_len
; i
++) {
55 cc
->in_slow_start
= vec
[i
].in_slow_start_in
;
56 cc
->ewma_rtt_usec
= vec
[i
].old_delta_in
*1000;
57 bool ret
= time_delta_stalled_or_jumped(cc
,
61 tt_int_op(ret
, OP_EQ
, vec
[i
].result_out
);
62 tt_int_op(is_monotime_clock_broken
, OP_EQ
, vec
[i
].cached_result_out
);
66 is_monotime_clock_broken
= false;
70 * This test verifies the behavior of Section 2.1.1 of
71 * Prop#324 (CLOCK_HEURISTICS).
73 * It checks that we declare the clock value stalled,
74 * and cache that value, on various time deltas.
76 * It also verifies that our heuristics behave correctly
77 * with respect to slow start and large clock jumps/stalls.
80 test_congestion_control_clock(void *arg
)
85 {0, 1, 1, 0, 0}, // old delta 0, slow start -> false
86 {0, 0, 1, 1, 1}, // New delta 0 -> cache true, return true
87 {1, 1, 1, 1, 0}, // In slow start -> keep cache, but return false
88 {1, 4999, 0, 0, 0}, // Not slow start, edge -> update cache, and false
89 {4999, 1, 0, 0, 0}, // Not slow start, other edge -> false
90 {5001, 1, 0, 0, 0}, // Not slow start w/ -5000x -> use cache (false)
91 {5001, 0, 0, 1, 1}, // New delta 0 -> cache true, return true
92 {5001, 1, 0, 1, 1}, // Not slow start w/ -5000x -> use cache (true)
93 {5001, 1, 1, 1, 0}, // In slow start w/ -5000x -> false
94 {0, 5001, 0, 1, 0}, // Not slow start w/ no EWMA -> false
95 {1, 5001, 1, 1, 0}, // In slow start w/ +5000x -> false
96 {1, 1, 0, 0, 0}, // Not slow start -> update cache to false
97 {5001, 1, 0, 0, 0}, // Not slow start w/ -5000x -> use cache (false)
98 {1, 5001, 0, 0, 1}, // Not slow start w/ +5000x -> true
99 {0, 5001, 0, 0, 0}, // Not slow start w/ no EWMA -> false
100 {5001, 1, 1, 0, 0}, // In slow start w/ -5000x change -> false
101 {1, 1, 0, 0, 0} // Not slow start -> false
104 circuit_params_t params
;
106 params
.cc_enabled
= 1;
107 params
.sendme_inc_cells
= TLS_RECORD_MAX_CELLS
;
108 cc_alg
= CC_ALG_VEGAS
;
109 congestion_control_t
*cc
= congestion_control_new(¶ms
, CC_PATH_EXIT
);
111 run_clock_test_vec(cc
, vect1
, sizeof(vect1
)/sizeof(clock_vec_t
));
113 congestion_control_free(cc
);
116 /* =========== RTT Test Vectors ================== */
118 typedef struct rtt_vec
{
119 uint64_t sent_usec_in
;
120 uint64_t got_sendme_usec_in
;
123 uint64_t curr_rtt_usec_out
;
124 uint64_t ewma_rtt_usec_out
;
125 uint64_t min_rtt_usec_out
;
129 run_rtt_test_vec(congestion_control_t
*cc
,
130 rtt_vec_t
*vec
, size_t vec_len
)
132 for (size_t i
= 0; i
< vec_len
; i
++) {
133 enqueue_timestamp(cc
->sendme_pending_timestamps
,
134 vec
[i
].sent_usec_in
);
137 for (size_t i
= 0; i
< vec_len
; i
++) {
138 cc
->cwnd
= vec
[i
].cwnd_in
;
139 cc
->in_slow_start
= vec
[i
].ss_in
;
140 uint64_t curr_rtt_usec
= congestion_control_update_circuit_rtt(cc
,
141 vec
[i
].got_sendme_usec_in
);
143 tt_int_op(curr_rtt_usec
, OP_EQ
, vec
[i
].curr_rtt_usec_out
);
144 tt_int_op(cc
->min_rtt_usec
, OP_EQ
, vec
[i
].min_rtt_usec_out
);
145 tt_int_op(cc
->ewma_rtt_usec
, OP_EQ
, vec
[i
].ewma_rtt_usec_out
);
148 is_monotime_clock_broken
= false;
152 * This test validates current, EWMA, and minRTT calculation
153 * from Sections 2.1 of Prop#324.
155 * We also do NOT exercise the sendme pacing code here. See
156 * test_sendme_is_next() for that, in test_sendme.c.
159 test_congestion_control_rtt(void *arg
)
162 rtt_vec_t vect1
[] = {
163 {100000, 200000, 124, 1, 100000, 100000, 100000},
164 {200000, 300000, 124, 1, 100000, 100000, 100000},
165 {350000, 500000, 124, 1, 150000, 133333, 100000},
166 {500000, 550000, 124, 1, 50000, 77777, 77777},
167 {600000, 700000, 124, 1, 100000, 92592, 77777},
168 {700000, 750000, 124, 1, 50000, 64197, 64197},
169 {750000, 875000, 124, 0, 125000, 104732, 104732},
170 {875000, 900000, 124, 0, 25000, 51577, 104732},
171 {900000, 950000, 200, 0, 50000, 50525, 50525}
174 circuit_params_t params
;
175 congestion_control_t
*cc
= NULL
;
177 params
.cc_enabled
= 1;
178 params
.sendme_inc_cells
= TLS_RECORD_MAX_CELLS
;
179 cc_alg
= CC_ALG_VEGAS
;
181 cc
= congestion_control_new(¶ms
, CC_PATH_EXIT
);
182 run_rtt_test_vec(cc
, vect1
, sizeof(vect1
)/sizeof(rtt_vec_t
));
183 congestion_control_free(cc
);
188 /* =========== Vegas CWND Test Vectors ============== */
190 typedef struct cwnd_vec
{
191 uint64_t sent_usec_in
;
192 uint64_t got_sendme_usec_in
;
193 bool or_conn_blocked_in
;
194 uint64_t inflight_in
;
195 uint64_t ewma_rtt_usec_out
;
196 uint64_t min_rtt_usec_out
;
198 bool in_slow_start_out
;
200 bool blocked_chan_out
;
204 run_vegas_cwnd_test_vec(congestion_control_t
*cc
,
206 cwnd_vec_t
*vec
, size_t vec_len
)
208 for (size_t i
= 0; i
< vec_len
; i
++) {
209 enqueue_timestamp(cc
->sendme_pending_timestamps
,
210 vec
[i
].sent_usec_in
);
213 for (size_t i
= 0; i
< vec_len
; i
++) {
214 log_notice(LD_CIRC
, "Step %d", (int)i
);
215 monotime_set_mock_time_nsec(vec
[i
].got_sendme_usec_in
*1000);
216 circ
->circuit_blocked_on_p_chan
= vec
[i
].or_conn_blocked_in
;
217 cc
->inflight
= vec
[i
].inflight_in
;
219 congestion_control_vegas_process_sendme(cc
, circ
);
221 /* If the or conn was blocked, ensure we updated our
223 if (vec
[i
].or_conn_blocked_in
) {
224 tt_int_op(cc
->next_cc_event
, OP_EQ
, CWND_UPDATE_RATE(cc
));
227 tt_int_op(cc
->ewma_rtt_usec
, OP_EQ
, vec
[i
].ewma_rtt_usec_out
);
228 tt_int_op(cc
->min_rtt_usec
, OP_EQ
, vec
[i
].min_rtt_usec_out
);
229 tt_int_op(cc
->cwnd
, OP_EQ
, vec
[i
].cwnd_out
);
231 tt_int_op(cc
->in_slow_start
, OP_EQ
, vec
[i
].in_slow_start_out
);
232 tt_int_op(cc
->cwnd_full
, OP_EQ
, vec
[i
].cwnd_full_out
);
233 tt_int_op(cc
->blocked_chan
, OP_EQ
, vec
[i
].blocked_chan_out
);
237 is_monotime_clock_broken
= false;
241 * This test validates congestion window updates for the
242 * TOR_VEGAS congestion control algorithm, from Section 3.3
245 * It tests updates as a function of the timestamp of the
246 * cell that would trigger a sendme and the sendme arrival
247 * timestamp, and as a function of orconn blocking.
249 * It ensures that at least one test vector caused a cwnd update
250 * due to a blocked OR connection. The orconn blocking logic is
251 * simulated -- we do NOT actually exercise the orconn code here.
253 * We also do NOT exercise the sendme pacing code here. See
254 * test_sendme_is_next() for that, in test_sendme.c.
256 * We also do NOT exercise the negotiation code here. See
257 * test_ntor3_handshake() for that, in test_ntor_v3.c.
260 test_congestion_control_vegas_cwnd(void *arg
)
263 circuit_params_t params
;
264 /* Replay of RTT edge case checks, plus some extra to exit
265 * slow start via RTT, and exercise full/not full */
266 cwnd_vec_t vect1
[] = {
267 {100000, 200000, 0, 124, 100000, 100000, 155, 1, 0, 0},
268 {200000, 300000, 0, 155, 100000, 100000, 186, 1, 1, 0},
269 {350000, 500000, 0, 186, 133333, 100000, 217, 1, 1, 0},
270 {500000, 550000, 0, 217, 77777, 77777, 248, 1, 1, 0},
271 {600000, 700000, 0, 248, 92592, 77777, 279, 1, 1, 0},
272 {700000, 750000, 0, 279, 64197, 64197, 310, 1, 0, 0}, // Fullness expiry
273 {750000, 875000, 0, 310, 104732, 64197, 341, 1, 1, 0},
274 {875000, 900000, 0, 341, 51577, 51577, 372, 1, 1, 0},
275 {900000, 950000, 0, 279, 50525, 50525, 403, 1, 1, 0},
276 {950000, 1000000, 0, 279, 50175, 50175, 434, 1, 1, 0},
277 {1000000, 1050000, 0, 279, 50058, 50058, 465, 1, 1, 0},
278 {1050000, 1100000, 0, 279, 50019, 50019, 496, 1, 1, 0},
279 {1100000, 1150000, 0, 279, 50006, 50006, 527, 1, 1, 0},
280 {1150000, 1200000, 0, 279, 50002, 50002, 558, 1, 1, 0},
281 {1200000, 1250000, 0, 550, 50000, 50000, 589, 1, 1, 0},
282 {1250000, 1300000, 0, 550, 50000, 50000, 620, 1, 0, 0}, // Fullness expiry
283 {1300000, 1350000, 0, 550, 50000, 50000, 635, 1, 1, 0},
284 {1350000, 1400000, 0, 550, 50000, 50000, 650, 1, 1, 0},
285 {1400000, 1450000, 0, 150, 50000, 50000, 650, 1, 0, 0}, // cwnd not full
286 {1450000, 1500000, 0, 150, 50000, 50000, 650, 1, 0, 0}, // cwnd not full
287 {1500000, 1550000, 0, 550, 50000, 50000, 664, 1, 1, 0}, // cwnd full
288 {1500000, 1600000, 0, 550, 83333, 50000, 584, 0, 1, 0}, // gamma exit
289 {1600000, 1650000, 0, 550, 61111, 50000, 585, 0, 1, 0}, // alpha
290 {1650000, 1700000, 0, 550, 53703, 50000, 586, 0, 1, 0},
291 {1700000, 1750000, 0, 100, 51234, 50000, 586, 0, 0, 0}, // alpha, not full
292 {1750000, 1900000, 0, 100, 117078, 50000, 559, 0, 0, 0}, // delta, not full
293 {1900000, 2000000, 0, 100, 105692, 50000, 558, 0, 0, 0}, // beta, not full
294 {2000000, 2075000, 0, 500, 85230, 50000, 558, 0, 1, 0}, // no change
295 {2075000, 2125000, 1, 500, 61743, 50000, 557, 0, 1, 1}, // beta, blocked
296 {2125000, 2150000, 0, 500, 37247, 37247, 558, 0, 1, 0}, // alpha
297 {2150000, 2350000, 0, 500, 145749, 37247, 451, 0, 1, 0} // delta
299 /* Test exiting slow start via blocked orconn */
300 cwnd_vec_t vect2
[] = {
301 {100000, 200000, 0, 124, 100000, 100000, 155, 1, 0, 0},
302 {200000, 300000, 0, 155, 100000, 100000, 186, 1, 1, 0},
303 {350000, 500000, 0, 186, 133333, 100000, 217, 1, 1, 0},
304 {500000, 550000, 1, 217, 77777, 77777, 403, 0, 1, 1}, // ss exit, blocked
305 {600000, 700000, 0, 248, 92592, 77777, 404, 0, 1, 0}, // alpha
306 {700000, 750000, 1, 404, 64197, 64197, 403, 0, 0, 1}, // blocked beta
307 {750000, 875000, 0, 403, 104732, 64197, 404, 0, 1, 0}
310 cwnd_vec_t vect3
[] = {
311 { 18258527, 19002938, 0, 83, 744411, 744411, 155, 1, 0, 0 },
312 { 18258580, 19254257, 0, 52, 911921, 744411, 186, 1, 1, 0 },
313 { 20003224, 20645298, 0, 164, 732023, 732023, 217, 1, 1, 0 },
314 { 20003367, 21021444, 0, 133, 922725, 732023, 248, 1, 1, 0 },
315 { 20003845, 21265508, 0, 102, 1148683, 732023, 279, 1, 1, 0 },
316 { 20003975, 21429157, 0, 71, 1333015, 732023, 310, 1, 0, 0 },
317 { 20004309, 21707677, 0, 40, 1579917, 732023, 310, 1, 0, 0 }
320 cwnd_vec_t vect4
[] = {
321 { 358297091, 358854163, 0, 83, 557072, 557072, 155, 1, 0, 0 },
322 { 358297649, 359123845, 0, 52, 736488, 557072, 186, 1, 1, 0 },
323 { 359492879, 359995330, 0, 186, 580463, 557072, 217, 1, 1, 0 },
324 { 359493043, 360489243, 0, 217, 857621, 557072, 248, 1, 1, 0 },
325 { 359493232, 360489673, 0, 248, 950167, 557072, 279, 1, 1, 0 },
326 { 359493795, 360489971, 0, 279, 980839, 557072, 310, 1, 0, 0 },
327 { 359493918, 360490248, 0, 310, 991166, 557072, 341, 1, 1, 0 },
328 { 359494029, 360716465, 0, 341, 1145346, 557072, 372, 1, 1, 0 },
329 { 359996888, 360948867, 0, 372, 1016434, 557072, 403, 1, 1, 0 },
330 { 359996979, 360949330, 0, 403, 973712, 557072, 434, 1, 1, 0 },
331 { 360489528, 361113615, 0, 434, 740628, 557072, 465, 1, 1, 0 },
332 { 360489656, 361281604, 0, 465, 774841, 557072, 496, 1, 1, 0 },
333 { 360489837, 361500461, 0, 496, 932029, 557072, 482, 0, 1, 0 },
334 { 360489963, 361500631, 0, 482, 984455, 557072, 482, 0, 1, 0 },
335 { 360490117, 361842481, 0, 482, 1229727, 557072, 481, 0, 1, 0 }
338 congestion_control_t
*cc
= NULL
;
339 channel_t dummy_channel
= {0};
341 MOCK(circuitmux_attach_circuit
, circuitmux_attach_circuit_mock
);
342 testing_enable_reproducible_rng();
345 monotime_enable_test_mocking();
346 monotime_set_mock_time_nsec(0);
348 dummy_channel
.cmux
= circuitmux_alloc();
349 circuit_t
*circ
= TO_CIRCUIT(new_fake_orcirc(&dummy_channel
,
351 circ
->purpose
= CIRCUIT_PURPOSE_OR
;
353 params
.cc_enabled
= 1;
354 params
.sendme_inc_cells
= TLS_RECORD_MAX_CELLS
;
355 cc_alg
= CC_ALG_VEGAS
;
357 cc
= congestion_control_new(¶ms
, CC_PATH_EXIT
);
358 run_vegas_cwnd_test_vec(cc
, circ
, vect1
,
359 sizeof(vect1
)/sizeof(cwnd_vec_t
));
360 congestion_control_free(cc
);
362 cc
= congestion_control_new(¶ms
, CC_PATH_EXIT
);
363 run_vegas_cwnd_test_vec(cc
, circ
, vect2
,
364 sizeof(vect2
)/sizeof(cwnd_vec_t
));
365 congestion_control_free(cc
);
367 cc
= congestion_control_new(¶ms
, CC_PATH_EXIT
);
368 run_vegas_cwnd_test_vec(cc
, circ
, vect3
,
369 sizeof(vect3
)/sizeof(cwnd_vec_t
));
370 congestion_control_free(cc
);
372 cc
= congestion_control_new(¶ms
, CC_PATH_EXIT
);
373 run_vegas_cwnd_test_vec(cc
, circ
, vect4
,
374 sizeof(vect4
)/sizeof(cwnd_vec_t
));
375 congestion_control_free(cc
);
378 circuitmux_free(dummy_channel
.cmux
);
382 #define TEST_CONGESTION_CONTROL(name, flags) \
383 { #name, test_##name, (flags), NULL, NULL }
385 struct testcase_t congestion_control_tests
[] = {
386 TEST_CONGESTION_CONTROL(congestion_control_clock
, TT_FORK
),
387 TEST_CONGESTION_CONTROL(congestion_control_rtt
, TT_FORK
),
388 TEST_CONGESTION_CONTROL(congestion_control_vegas_cwnd
, TT_FORK
),