1 /* Copyright (c) 2013-2020, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #define CHANNEL_OBJECT_PRIVATE
5 #define CIRCUITMUX_PRIVATE
6 #define CIRCUITMUX_EWMA_PRIVATE
9 #include "core/or/or.h"
10 #include "core/or/channel.h"
11 #include "core/or/circuitmux.h"
12 #include "core/or/circuitmux_ewma.h"
13 #include "core/or/destroy_cell_queue_st.h"
14 #include "core/or/relay.h"
15 #include "core/or/scheduler.h"
17 #include "test/fakechans.h"
18 #include "test/fakecircs.h"
19 #include "test/test.h"
24 mock_has_queued_writes_true(channel_t
*c
)
30 /** Test destroy cell queue with no interference from other queues. */
32 test_cmux_destroy_cell_queue(void *arg
)
34 circuitmux_t
*cmux
= NULL
;
36 circuit_t
*circ
= NULL
;
37 destroy_cell_queue_t
*cq
= NULL
;
38 packed_cell_t
*pc
= NULL
;
39 destroy_cell_t
*dc
= NULL
;
41 MOCK(scheduler_release_channel
, scheduler_release_channel_mock
);
45 ch
= new_fake_channel();
46 ch
->has_queued_writes
= mock_has_queued_writes_true
;
47 ch
->wide_circ_ids
= 1;
50 circ
= circuitmux_get_first_active_circuit(cmux
, &cq
);
51 tt_ptr_op(circ
, OP_EQ
, NULL
);
52 tt_ptr_op(cq
, OP_EQ
, NULL
);
54 circuitmux_append_destroy_cell(ch
, cmux
, 100, 10);
55 circuitmux_append_destroy_cell(ch
, cmux
, 190, 6);
56 circuitmux_append_destroy_cell(ch
, cmux
, 30, 1);
58 tt_int_op(circuitmux_num_cells(cmux
), OP_EQ
, 3);
60 circ
= circuitmux_get_first_active_circuit(cmux
, &cq
);
61 tt_ptr_op(circ
, OP_EQ
, NULL
);
64 tt_int_op(cq
->n
, OP_EQ
, 3);
66 dc
= destroy_cell_queue_pop(cq
);
68 tt_uint_op(dc
->circid
, OP_EQ
, 100);
70 tt_int_op(circuitmux_num_cells(cmux
), OP_EQ
, 2);
73 free_fake_channel(ch
);
77 UNMOCK(scheduler_release_channel
);
81 test_cmux_compute_ticks(void *arg
)
83 const int64_t NS_PER_S
= 1000 * 1000 * 1000;
84 const int64_t START_NS
= UINT64_C(1217709000)*NS_PER_S
;
89 circuitmux_ewma_free_all();
90 monotime_enable_test_mocking();
92 monotime_coarse_set_mock_time_nsec(START_NS
);
93 cell_ewma_initialize_ticks();
94 const unsigned tick_zero
= cell_ewma_get_current_tick_and_fraction(&rem
);
95 tt_double_op(rem
, OP_GT
, -1e-9);
96 tt_double_op(rem
, OP_LT
, 1e-9);
98 /* 1.5 second later and we should still be in the same tick. */
99 now
= START_NS
+ NS_PER_S
+ NS_PER_S
/2;
100 monotime_coarse_set_mock_time_nsec(now
);
101 tick
= cell_ewma_get_current_tick_and_fraction(&rem
);
102 tt_uint_op(tick
, OP_EQ
, tick_zero
);
103 #ifdef USING_32BIT_MSEC_HACK
104 const double tolerance
= .0005;
106 const double tolerance
= .00000001;
108 tt_double_op(fabs(rem
- .15), OP_LT
, tolerance
);
110 /* 25 second later and we should be in another tick. */
111 now
= START_NS
+ NS_PER_S
* 25;
112 monotime_coarse_set_mock_time_nsec(now
);
113 tick
= cell_ewma_get_current_tick_and_fraction(&rem
);
114 tt_uint_op(tick
, OP_EQ
, tick_zero
+ 2);
115 tt_double_op(fabs(rem
- .5), OP_LT
, tolerance
);
122 test_cmux_allocate(void *arg
)
124 circuitmux_t
*cmux
= NULL
;
128 cmux
= circuitmux_alloc();
130 tt_assert(cmux
->chanid_circid_map
);
131 tt_int_op(HT_SIZE(cmux
->chanid_circid_map
), OP_EQ
, 0);
132 tt_uint_op(cmux
->n_circuits
, OP_EQ
, 0);
133 tt_uint_op(cmux
->n_active_circuits
, OP_EQ
, 0);
134 tt_uint_op(cmux
->n_cells
, OP_EQ
, 0);
135 tt_uint_op(cmux
->last_cell_was_destroy
, OP_EQ
, 0);
136 tt_i64_op(cmux
->destroy_ctr
, OP_EQ
, 0);
137 tt_ptr_op(cmux
->policy
, OP_EQ
, NULL
);
138 tt_ptr_op(cmux
->policy_data
, OP_EQ
, NULL
);
140 tt_assert(TOR_SIMPLEQ_EMPTY(&cmux
->destroy_cell_queue
.head
));
143 circuitmux_free(cmux
);
147 test_cmux_attach_circuit(void *arg
)
149 circuit_t
*circ
= NULL
;
150 or_circuit_t
*orcirc
= NULL
;
151 channel_t
*pchan
= NULL
, *nchan
= NULL
;
152 cell_direction_t cdir
;
153 unsigned int n_cells
;
157 pchan
= new_fake_channel();
159 nchan
= new_fake_channel();
162 orcirc
= new_fake_orcirc(nchan
, pchan
);
164 circ
= TO_CIRCUIT(orcirc
);
166 /* While assigning a new circuit IDs, the circuitmux_attach_circuit() is
167 * called for a new channel on the circuit. This means, we should now have
168 * the created circuit attached on both the pchan and nchan cmux. */
169 tt_uint_op(circuitmux_num_circuits(pchan
->cmux
), OP_EQ
, 1);
170 tt_uint_op(circuitmux_num_circuits(nchan
->cmux
), OP_EQ
, 1);
172 /* There should be _no_ active circuit due to no queued cells. */
173 tt_uint_op(circuitmux_num_active_circuits(pchan
->cmux
), OP_EQ
, 0);
174 tt_uint_op(circuitmux_num_active_circuits(nchan
->cmux
), OP_EQ
, 0);
176 /* Circuit should not be active on the cmux. */
177 tt_int_op(circuitmux_is_circuit_active(pchan
->cmux
, circ
), OP_EQ
, 0);
178 tt_int_op(circuitmux_is_circuit_active(nchan
->cmux
, circ
), OP_EQ
, 0);
180 /* Not active so no cells. */
181 n_cells
= circuitmux_num_cells_for_circuit(pchan
->cmux
, circ
);
182 tt_uint_op(n_cells
, OP_EQ
, 0);
183 n_cells
= circuitmux_num_cells(pchan
->cmux
);
184 tt_uint_op(n_cells
, OP_EQ
, 0);
185 n_cells
= circuitmux_num_cells_for_circuit(nchan
->cmux
, circ
);
186 tt_uint_op(n_cells
, OP_EQ
, 0);
187 n_cells
= circuitmux_num_cells(nchan
->cmux
);
188 tt_uint_op(n_cells
, OP_EQ
, 0);
190 /* So it should be attached :) */
191 tt_int_op(circuitmux_is_circuit_attached(pchan
->cmux
, circ
), OP_EQ
, 1);
192 tt_int_op(circuitmux_is_circuit_attached(nchan
->cmux
, circ
), OP_EQ
, 1);
194 /* Query the chanid<->circid map in the cmux subsystem with what we just
195 * created and validate the cell direction. */
196 cdir
= circuitmux_attached_circuit_direction(pchan
->cmux
, circ
);
197 tt_int_op(cdir
, OP_EQ
, CELL_DIRECTION_IN
);
198 cdir
= circuitmux_attached_circuit_direction(nchan
->cmux
, circ
);
199 tt_int_op(cdir
, OP_EQ
, CELL_DIRECTION_OUT
);
202 * We'll activate->deactivate->activate to test all code paths of
203 * circuitmux_set_num_cells().
206 /* Activate circuit. */
207 circuitmux_set_num_cells(pchan
->cmux
, circ
, 4);
208 tt_int_op(circuitmux_is_circuit_active(pchan
->cmux
, circ
), OP_EQ
, 1);
211 circuitmux_clear_num_cells(pchan
->cmux
, circ
);
212 tt_int_op(circuitmux_is_circuit_active(pchan
->cmux
, circ
), OP_EQ
, 0);
213 tt_uint_op(circuitmux_num_cells_for_circuit(pchan
->cmux
, circ
), OP_EQ
, 0);
216 circuitmux_set_num_cells(pchan
->cmux
, circ
, 4);
217 tt_int_op(circuitmux_is_circuit_active(pchan
->cmux
, circ
), OP_EQ
, 1);
219 /* Once re-attached, it should become inactive because the circuit has no
220 * cells while the chanid<->circid object has some. The attach code will
221 * reset the count on the cmux for that circuit:
223 * if (chanid_circid_muxinfo_t->muxinfo.cell_count > 0 && cell_count == 0) {
225 circuitmux_attach_circuit(pchan
->cmux
, circ
, CELL_DIRECTION_IN
);
226 n_cells
= circuitmux_num_cells_for_circuit(pchan
->cmux
, circ
);
227 tt_uint_op(n_cells
, OP_EQ
, 0);
228 tt_int_op(circuitmux_is_circuit_active(pchan
->cmux
, circ
), OP_EQ
, 0);
229 tt_uint_op(circuitmux_num_active_circuits(pchan
->cmux
), OP_EQ
, 0);
231 /* Lets queue a cell on the circuit now so it becomes active when
234 * else if (chanid_circid_muxinfo_t->muxinfo.cell_count == 0 &&
237 orcirc
->p_chan_cells
.n
= 1;
238 circuitmux_attach_circuit(pchan
->cmux
, circ
, CELL_DIRECTION_IN
);
239 tt_int_op(circuitmux_is_circuit_active(pchan
->cmux
, circ
), OP_EQ
, 1);
242 free_fake_orcirc(orcirc
);
243 free_fake_channel(pchan
);
244 free_fake_channel(nchan
);
248 test_cmux_detach_circuit(void *arg
)
250 circuit_t
*circ
= NULL
;
251 or_circuit_t
*orcirc
= NULL
;
252 channel_t
*pchan
= NULL
, *nchan
= NULL
;
256 pchan
= new_fake_channel();
258 nchan
= new_fake_channel();
261 orcirc
= new_fake_orcirc(nchan
, pchan
);
263 circ
= TO_CIRCUIT(orcirc
);
265 /* While assigning a new circuit IDs, the circuitmux_attach_circuit() is
266 * called for a new channel on the circuit. This means, we should now have
267 * the created circuit attached on both the pchan and nchan cmux. */
268 tt_uint_op(circuitmux_num_circuits(pchan
->cmux
), OP_EQ
, 1);
269 tt_uint_op(circuitmux_num_circuits(nchan
->cmux
), OP_EQ
, 1);
270 tt_int_op(circuitmux_is_circuit_attached(pchan
->cmux
, circ
), OP_EQ
, 1);
271 tt_int_op(circuitmux_is_circuit_attached(nchan
->cmux
, circ
), OP_EQ
, 1);
273 /* Now, detach the circuit from pchan and then nchan. */
274 circuitmux_detach_circuit(pchan
->cmux
, circ
);
275 tt_uint_op(circuitmux_num_circuits(pchan
->cmux
), OP_EQ
, 0);
276 tt_int_op(circuitmux_is_circuit_attached(pchan
->cmux
, circ
), OP_EQ
, 0);
277 circuitmux_detach_circuit(nchan
->cmux
, circ
);
278 tt_uint_op(circuitmux_num_circuits(nchan
->cmux
), OP_EQ
, 0);
279 tt_int_op(circuitmux_is_circuit_attached(nchan
->cmux
, circ
), OP_EQ
, 0);
282 free_fake_orcirc(orcirc
);
283 free_fake_channel(pchan
);
284 free_fake_channel(nchan
);
288 test_cmux_detach_all_circuits(void *arg
)
290 circuit_t
*circ
= NULL
;
291 or_circuit_t
*orcirc
= NULL
;
292 channel_t
*pchan
= NULL
, *nchan
= NULL
;
293 smartlist_t
*detached_out
= smartlist_new();
297 /* Channels need to be registered in order for the detach all circuit
298 * function to find them. */
299 pchan
= new_fake_channel();
301 channel_register(pchan
);
302 nchan
= new_fake_channel();
304 channel_register(nchan
);
306 orcirc
= new_fake_orcirc(nchan
, pchan
);
308 circ
= TO_CIRCUIT(orcirc
);
310 /* Just make sure it is attached. */
311 tt_uint_op(circuitmux_num_circuits(pchan
->cmux
), OP_EQ
, 1);
312 tt_uint_op(circuitmux_num_circuits(nchan
->cmux
), OP_EQ
, 1);
313 tt_int_op(circuitmux_is_circuit_attached(pchan
->cmux
, circ
), OP_EQ
, 1);
314 tt_int_op(circuitmux_is_circuit_attached(nchan
->cmux
, circ
), OP_EQ
, 1);
316 /* Queue some cells so we can test if the circuit becomes inactive on the
317 * cmux after the mass detach. */
318 circuitmux_set_num_cells(pchan
->cmux
, circ
, 4);
319 circuitmux_set_num_cells(nchan
->cmux
, circ
, 4);
321 /* Detach all on pchan and then nchan. */
322 circuitmux_detach_all_circuits(pchan
->cmux
, detached_out
);
323 tt_uint_op(circuitmux_num_circuits(pchan
->cmux
), OP_EQ
, 0);
324 tt_int_op(circuitmux_is_circuit_attached(pchan
->cmux
, circ
), OP_EQ
, 0);
325 tt_int_op(circuitmux_is_circuit_active(pchan
->cmux
, circ
), OP_EQ
, 0);
326 tt_int_op(smartlist_len(detached_out
), OP_EQ
, 1);
327 circuitmux_detach_all_circuits(nchan
->cmux
, NULL
);
328 tt_uint_op(circuitmux_num_circuits(nchan
->cmux
), OP_EQ
, 0);
329 tt_int_op(circuitmux_is_circuit_attached(nchan
->cmux
, circ
), OP_EQ
, 0);
330 tt_int_op(circuitmux_is_circuit_active(nchan
->cmux
, circ
), OP_EQ
, 0);
333 smartlist_free(detached_out
);
334 free_fake_orcirc(orcirc
);
335 free_fake_channel(pchan
);
336 free_fake_channel(nchan
);
340 test_cmux_policy(void *arg
)
342 circuit_t
*circ
= NULL
;
343 or_circuit_t
*orcirc
= NULL
;
344 channel_t
*pchan
= NULL
, *nchan
= NULL
;
348 pchan
= new_fake_channel();
350 channel_register(pchan
);
351 nchan
= new_fake_channel();
353 channel_register(nchan
);
355 orcirc
= new_fake_orcirc(nchan
, pchan
);
357 circ
= TO_CIRCUIT(orcirc
);
359 /* Confirm we have the EWMA policy by default for new channels. */
360 tt_ptr_op(circuitmux_get_policy(pchan
->cmux
), OP_EQ
, &ewma_policy
);
361 tt_ptr_op(circuitmux_get_policy(nchan
->cmux
), OP_EQ
, &ewma_policy
);
363 /* Putting cell on the cmux means will make the notify policy code path to
365 circuitmux_set_num_cells(pchan
->cmux
, circ
, 4);
368 circuitmux_clear_policy(pchan
->cmux
);
370 /* Set back the EWMA policy. */
371 circuitmux_set_policy(pchan
->cmux
, &ewma_policy
);
374 free_fake_orcirc(orcirc
);
375 free_fake_channel(pchan
);
376 free_fake_channel(nchan
);
380 test_cmux_xmit_cell(void *arg
)
382 circuit_t
*circ
= NULL
;
383 or_circuit_t
*orcirc
= NULL
;
384 channel_t
*pchan
= NULL
, *nchan
= NULL
;
388 pchan
= new_fake_channel();
390 nchan
= new_fake_channel();
393 orcirc
= new_fake_orcirc(nchan
, pchan
);
395 circ
= TO_CIRCUIT(orcirc
);
397 /* Queue 4 cells on the circuit. */
398 circuitmux_set_num_cells(pchan
->cmux
, circ
, 4);
399 tt_uint_op(circuitmux_num_cells_for_circuit(pchan
->cmux
, circ
), OP_EQ
, 4);
400 tt_uint_op(circuitmux_num_cells(pchan
->cmux
), OP_EQ
, 4);
401 tt_int_op(circuitmux_is_circuit_active(pchan
->cmux
, circ
), OP_EQ
, 1);
402 tt_uint_op(circuitmux_num_active_circuits(pchan
->cmux
), OP_EQ
, 1);
404 /* Emit the first cell. Circuit should still be active. */
405 circuitmux_notify_xmit_cells(pchan
->cmux
, circ
, 1);
406 tt_uint_op(circuitmux_num_cells(pchan
->cmux
), OP_EQ
, 3);
407 tt_uint_op(circuitmux_num_cells_for_circuit(pchan
->cmux
, circ
), OP_EQ
, 3);
408 tt_int_op(circuitmux_is_circuit_active(pchan
->cmux
, circ
), OP_EQ
, 1);
409 tt_uint_op(circuitmux_num_active_circuits(pchan
->cmux
), OP_EQ
, 1);
411 /* Emit the last 3 cells. Circuit should become inactive. */
412 circuitmux_notify_xmit_cells(pchan
->cmux
, circ
, 3);
413 tt_uint_op(circuitmux_num_cells(pchan
->cmux
), OP_EQ
, 0);
414 tt_uint_op(circuitmux_num_cells_for_circuit(pchan
->cmux
, circ
), OP_EQ
, 0);
415 tt_int_op(circuitmux_is_circuit_active(pchan
->cmux
, circ
), OP_EQ
, 0);
416 tt_uint_op(circuitmux_num_active_circuits(pchan
->cmux
), OP_EQ
, 0);
418 /* Queue a DESTROY cell. */
419 pchan
->has_queued_writes
= mock_has_queued_writes_true
;
420 circuitmux_append_destroy_cell(pchan
, pchan
->cmux
, orcirc
->p_circ_id
, 0);
421 tt_i64_op(pchan
->cmux
->destroy_ctr
, OP_EQ
, 1);
422 tt_int_op(pchan
->cmux
->destroy_cell_queue
.n
, OP_EQ
, 1);
423 tt_i64_op(circuitmux_count_queued_destroy_cells(pchan
, pchan
->cmux
),
426 /* Emit the DESTROY cell. */
427 circuitmux_notify_xmit_destroy(pchan
->cmux
);
428 tt_i64_op(pchan
->cmux
->destroy_ctr
, OP_EQ
, 0);
431 free_fake_orcirc(orcirc
);
432 free_fake_channel(pchan
);
433 free_fake_channel(nchan
);
437 cmux_setup_test(const struct testcase_t
*tc
)
443 cell_ewma_initialize_ticks();
448 cmux_cleanup_test(const struct testcase_t
*tc
, void *ptr
)
453 circuitmux_ewma_free_all();
458 static struct testcase_setup_t cmux_test_setup
= {
459 .setup_fn
= cmux_setup_test
,
460 .cleanup_fn
= cmux_cleanup_test
,
463 #define TEST_CMUX(name) \
464 { #name, test_cmux_##name, TT_FORK, &cmux_test_setup, NULL }
466 struct testcase_t circuitmux_tests
[] = {
467 /* Test circuitmux_t object */
469 TEST_CMUX(attach_circuit
),
470 TEST_CMUX(detach_circuit
),
471 TEST_CMUX(detach_all_circuits
),
473 TEST_CMUX(xmit_cell
),
476 TEST_CMUX(compute_ticks
),
477 TEST_CMUX(destroy_cell_queue
),