Tor 0.4.9.0-alpha-dev
circuitmux.c
Go to the documentation of this file.
1/* * Copyright (c) 2012-2021, The Tor Project, Inc. */
2/* See LICENSE for licensing information */
3
4/**
5 * \file circuitmux.c
6 * \brief Circuit mux/cell selection abstraction
7 *
8 * A circuitmux is responsible for <b>MU</b>ltiple<b>X</b>ing all of the
9 * circuits that are writing on a single channel. It keeps track of which of
10 * these circuits has something to write (aka, "active" circuits), and which
11 * one should write next. A circuitmux corresponds 1:1 with a channel.
12 *
13 * There can be different implementations of the circuitmux's rules (which
14 * decide which circuit is next to write).
15 *
16 * A circuitmux exposes three distinct
17 * interfaces to other components:
18 *
19 * To channels, which each have a circuitmux_t, the supported operations
20 * (invoked from relay.c) are:
21 *
22 * circuitmux_get_first_active_circuit():
23 *
24 * Pick one of the circuitmux's active circuits to send cells from.
25 *
26 * circuitmux_notify_xmit_cells():
27 *
28 * Notify the circuitmux that cells have been sent on a circuit.
29 *
30 * To circuits, the exposed operations are:
31 *
32 * circuitmux_attach_circuit():
33 *
34 * Attach a circuit to the circuitmux; this will allocate any policy-
35 * specific data wanted for this circuit and add it to the active
36 * circuits list if it has queued cells.
37 *
38 * circuitmux_detach_circuit():
39 *
40 * Detach a circuit from the circuitmux, freeing associated structures.
41 *
42 * circuitmux_clear_num_cells():
43 *
44 * Clear the circuitmux's cell counter for this circuit.
45 *
46 * circuitmux_set_num_cells():
47 *
48 * Set the circuitmux's cell counter for this circuit. One of
49 * circuitmuc_clear_num_cells() or circuitmux_set_num_cells() MUST be
50 * called when the number of cells queued on a circuit changes.
51 *
52 * See circuitmux.h for the circuitmux_policy_t data structure, which contains
53 * a table of function pointers implementing a circuit selection policy, and
54 * circuitmux_ewma.c for an example of a circuitmux policy. Circuitmux
55 * policies can be manipulated with:
56 *
57 * circuitmux_get_policy():
58 *
59 * Return the current policy for a circuitmux_t, if any.
60 *
61 * circuitmux_clear_policy():
62 *
63 * Remove a policy installed on a circuitmux_t, freeing all associated
64 * data. The circuitmux will revert to the built-in round-robin behavior.
65 *
66 * circuitmux_set_policy():
67 *
68 * Install a policy on a circuitmux_t; the appropriate callbacks will be
69 * made to attach all existing circuits to the new policy.
70 **/
71
72#define CIRCUITMUX_PRIVATE
73
74#include "core/or/or.h"
75#include "core/or/channel.h"
76#include "core/or/circuitlist.h"
77#include "core/or/circuitmux.h"
78#include "core/or/relay.h"
79
80#include "core/or/or_circuit_st.h"
81
83
84/*
85 * Private typedefs for circuitmux.c
86 */
87
88/*
89 * Hash table entry (yeah, calling it chanid_circid_muxinfo_s seems to
90 * break the hash table code).
91 */
93
94/*
95 * Anything the mux wants to store per-circuit in the map; right now just
96 * a count of queued cells.
97 */
98
100
101/*
102 * This struct holds whatever we want to store per attached circuit on a
103 * circuitmux_t; right now, just the count of queued cells and the direction.
104 */
105
107 /* Count of cells on this circuit at last update */
108 unsigned int cell_count;
109 /* Direction of flow */
110 cell_direction_t direction;
111 /* Policy-specific data */
113 /* Mark bit for consistency checker */
114 unsigned int mark:1;
115};
116
117/*
118 * A map from channel ID and circuit ID to a circuit_muxinfo_t for that
119 * circuit.
120 */
121
123 HT_ENTRY(chanid_circid_muxinfo_t) node;
124 uint64_t chan_id;
125 circid_t circ_id;
126 circuit_muxinfo_t muxinfo;
127};
128
129/*
130 * Static function declarations
131 */
132
133static inline int
136static inline unsigned int
139circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ);
140static void
141circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ);
142static void
143circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ);
144
145/* Static global variables */
146
147/** Count the destroy balance to debug destroy queue logic */
148static int64_t global_destroy_ctr = 0;
149
150/* Function definitions */
151
152/**
153 * Helper for chanid_circid_cell_count_map_t hash table: compare the channel
154 * ID and circuit ID for a and b, and return less than, equal to, or greater
155 * than zero appropriately.
156 */
157
158static inline int
161{
162 return a->chan_id == b->chan_id && a->circ_id == b->circ_id;
163}
164
165/**
166 * Helper: return a hash based on circuit ID and channel ID in a.
167 */
168
169static inline unsigned int
171{
172 uint8_t data[8 + 4];
173 set_uint64(data, a->chan_id);
174 set_uint32(data + 8, a->circ_id);
175 return (unsigned) siphash24g(data, sizeof(data));
176}
177
178/* Emit a bunch of hash table stuff */
179HT_PROTOTYPE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
181HT_GENERATE2(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
184
185/*
186 * Circuitmux alloc/free functions
187 */
188
189/**
190 * Allocate a new circuitmux_t
191 */
192
193circuitmux_t *
195{
196 circuitmux_t *rv = NULL;
197
198 rv = tor_malloc_zero(sizeof(*rv));
199 rv->chanid_circid_map = tor_malloc_zero(sizeof(*( rv->chanid_circid_map)));
200 HT_INIT(chanid_circid_muxinfo_map, rv->chanid_circid_map);
201 destroy_cell_queue_init(&rv->destroy_cell_queue);
202
203 return rv;
204}
205
206/**
207 * Detach all circuits from a circuitmux (use before circuitmux_free())
208 *
209 * If <b>detached_out</b> is non-NULL, add every detached circuit_t to
210 * detached_out.
211 */
212
213void
214circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
215{
216 chanid_circid_muxinfo_t **i = NULL, *to_remove;
217 channel_t *chan = NULL;
218 circuit_t *circ = NULL;
219
220 tor_assert(cmux);
221
222 i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
223 while (i) {
224 to_remove = *i;
225
226 if (! to_remove) {
227 log_warn(LD_BUG, "Somehow, an HT iterator gave us a NULL pointer.");
228 break;
229 } else {
230 /* Find a channel and circuit */
231 chan = channel_find_by_global_id(to_remove->chan_id);
232 if (chan) {
233 circ =
235 chan);
236 if (circ) {
237 /* Clear the circuit's mux for this direction */
238 if (to_remove->muxinfo.direction == CELL_DIRECTION_OUT) {
239 /*
240 * Update active_circuits et al.; this does policy notifies, so
241 * comes before freeing policy data
242 */
243
244 if (to_remove->muxinfo.cell_count > 0) {
246 }
247
248 if (detached_out)
249 smartlist_add(detached_out, circ);
250 } else if (circ->magic == OR_CIRCUIT_MAGIC) {
251 /*
252 * Update active_circuits et al.; this does policy notifies, so
253 * comes before freeing policy data
254 */
255
256 if (to_remove->muxinfo.cell_count > 0) {
258 }
259
260 if (detached_out)
261 smartlist_add(detached_out, circ);
262 } else {
263 /* Complain and move on */
264 log_warn(LD_CIRC,
265 "Circuit %u/channel %"PRIu64 " had direction == "
266 "CELL_DIRECTION_IN, but isn't an or_circuit_t",
267 (unsigned)to_remove->circ_id,
268 (to_remove->chan_id));
269 }
270
271 /* Free policy-specific data if we have it */
272 if (to_remove->muxinfo.policy_data) {
273 /*
274 * If we have policy data, assert that we have the means to
275 * free it
276 */
277 tor_assert(cmux->policy);
278 tor_assert(cmux->policy->free_circ_data);
279 /* Call free_circ_data() */
280 cmux->policy->free_circ_data(cmux,
281 cmux->policy_data,
282 circ,
283 to_remove->muxinfo.policy_data);
284 to_remove->muxinfo.policy_data = NULL;
285 }
286 } else {
287 /* Complain and move on */
288 log_warn(LD_CIRC,
289 "Couldn't find circuit %u (for channel %"PRIu64 ")",
290 (unsigned)to_remove->circ_id,
291 (to_remove->chan_id));
292 }
293 } else {
294 /* Complain and move on */
295 log_warn(LD_CIRC,
296 "Couldn't find channel %"PRIu64 " (for circuit id %u)",
297 (to_remove->chan_id),
298 (unsigned)to_remove->circ_id);
299 }
300
301 /* Assert that we don't have un-freed policy data for this circuit */
302 tor_assert(to_remove->muxinfo.policy_data == NULL);
303 }
304
305 i = HT_NEXT_RMV(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
306
307 /* Free it */
308 tor_free(to_remove);
309 }
310
311 cmux->n_circuits = 0;
312 cmux->n_active_circuits = 0;
313 cmux->n_cells = 0;
314}
315
316/** Reclaim all circuit IDs currently marked as unusable on <b>chan</b> because
317 * of pending destroy cells in <b>cmux</b>.
318 *
319 * This function must be called AFTER circuits are unlinked from the (channel,
320 * circuid-id) map with circuit_unlink_all_from_channel(), but before calling
321 * circuitmux_free().
322 */
323void
325{
326 destroy_cell_t *cell;
327 TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) {
328 channel_mark_circid_usable(chan, cell->circid);
329 }
330}
331
332/**
333 * Free a circuitmux_t; the circuits must be detached first with
334 * circuitmux_detach_all_circuits().
335 */
336
337void
338circuitmux_free_(circuitmux_t *cmux)
339{
340 if (!cmux) return;
341
342 tor_assert(cmux->n_circuits == 0);
343 tor_assert(cmux->n_active_circuits == 0);
344
345 /*
346 * Free policy-specific data if we have any; we don't
347 * need to do circuitmux_set_policy(cmux, NULL) to cover
348 * the circuits because they would have been handled in
349 * circuitmux_detach_all_circuits() before this was
350 * called.
351 */
352 if (cmux->policy && cmux->policy->free_cmux_data) {
353 if (cmux->policy_data) {
354 cmux->policy->free_cmux_data(cmux, cmux->policy_data);
355 cmux->policy_data = NULL;
356 }
357 } else tor_assert(cmux->policy_data == NULL);
358
359 if (cmux->chanid_circid_map) {
360 HT_CLEAR(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
361 tor_free(cmux->chanid_circid_map);
362 }
363
364 /*
365 * We're throwing away some destroys; log the counter and
366 * adjust the global counter by the queue size.
367 */
368 if (cmux->destroy_cell_queue.n > 0) {
369 cmux->destroy_ctr -= cmux->destroy_cell_queue.n;
370 global_destroy_ctr -= cmux->destroy_cell_queue.n;
371 log_debug(LD_CIRC,
372 "Freeing cmux at %p with %u queued destroys; the last cmux "
373 "destroy balance was %"PRId64", global is %"PRId64,
374 cmux, cmux->destroy_cell_queue.n,
375 (cmux->destroy_ctr),
377 } else {
378 log_debug(LD_CIRC,
379 "Freeing cmux at %p with no queued destroys, the cmux destroy "
380 "balance was %"PRId64", global is %"PRId64,
381 cmux,
382 (cmux->destroy_ctr),
384 }
385
386 destroy_cell_queue_clear(&cmux->destroy_cell_queue);
387
388 tor_free(cmux);
389}
390
391/*
392 * Circuitmux policy control functions
393 */
394
395/**
396 * Remove any policy installed on cmux; all policy data will be freed and
397 * cmux behavior will revert to the built-in round-robin active_circuits
398 * mechanism.
399 */
400
401void
402circuitmux_clear_policy(circuitmux_t *cmux)
403{
404 tor_assert(cmux);
405
406 /* Internally, this is just setting policy to NULL */
407 circuitmux_set_policy(cmux, NULL);
408}
409
410/**
411 * Return the policy currently installed on a circuitmux_t
412 */
413
415circuitmux_get_policy, (circuitmux_t *cmux))
416{
417 tor_assert(cmux);
418
419 return cmux->policy;
420}
421
422/**
423 * Set policy; allocate for new policy, detach all circuits from old policy
424 * if any, attach them to new policy, and free old policy data.
425 */
426
427void
428circuitmux_set_policy(circuitmux_t *cmux,
429 const circuitmux_policy_t *pol)
430{
431 const circuitmux_policy_t *old_pol = NULL, *new_pol = NULL;
432 circuitmux_policy_data_t *old_pol_data = NULL, *new_pol_data = NULL;
433 chanid_circid_muxinfo_t **i = NULL;
434 channel_t *chan = NULL;
435 uint64_t last_chan_id_searched = 0;
436 circuit_t *circ = NULL;
437
438 tor_assert(cmux);
439
440 /* Set up variables */
441 old_pol = cmux->policy;
442 old_pol_data = cmux->policy_data;
443 new_pol = pol;
444
445 /* Check if this is the trivial case */
446 if (old_pol == new_pol) return;
447
448 /* Allocate data for new policy, if any */
449 if (new_pol && new_pol->alloc_cmux_data) {
450 /*
451 * If alloc_cmux_data is not null, then we expect to get some policy
452 * data. Assert that we also have free_cmux_data so we can free it
453 * when the time comes, and allocate it.
454 */
455 tor_assert(new_pol->free_cmux_data);
456 new_pol_data = new_pol->alloc_cmux_data(cmux);
457 tor_assert(new_pol_data);
458 }
459
460 /* Install new policy and new policy data on cmux */
461 cmux->policy = new_pol;
462 cmux->policy_data = new_pol_data;
463
464 /* Iterate over all circuits, attaching/detaching each one */
465 i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
466 while (i) {
467 /* Assert that this entry isn't NULL */
468 tor_assert(*i);
469
470 /*
471 * Get the channel; since normal case is all circuits on the mux share a
472 * channel, we cache last_chan_id_searched
473 */
474 if (!chan || last_chan_id_searched != (*i)->chan_id) {
475 chan = channel_find_by_global_id((*i)->chan_id);
476 last_chan_id_searched = (*i)->chan_id;
477 }
478 tor_assert(chan);
479
480 /* Get the circuit */
481 circ = circuit_get_by_circid_channel_even_if_marked((*i)->circ_id, chan);
482 tor_assert(circ);
483
484 /* Need to tell old policy it becomes inactive (i.e., it is active) ? */
485 if (old_pol && old_pol->notify_circ_inactive &&
486 (*i)->muxinfo.cell_count > 0) {
487 old_pol->notify_circ_inactive(cmux, old_pol_data, circ,
488 (*i)->muxinfo.policy_data);
489 }
490
491 /* Need to free old policy data? */
492 if ((*i)->muxinfo.policy_data) {
493 /* Assert that we have the means to free it if we have policy data */
494 tor_assert(old_pol);
495 tor_assert(old_pol->free_circ_data);
496 /* Free it */
497 old_pol->free_circ_data(cmux, old_pol_data, circ,
498 (*i)->muxinfo.policy_data);
499 (*i)->muxinfo.policy_data = NULL;
500 }
501
502 /* Need to allocate new policy data? */
503 if (new_pol && new_pol->alloc_circ_data) {
504 /*
505 * If alloc_circ_data is not null, we expect to get some per-circuit
506 * policy data. Assert that we also have free_circ_data so we can
507 * free it when the time comes, and allocate it.
508 */
509 tor_assert(new_pol->free_circ_data);
510 (*i)->muxinfo.policy_data =
511 new_pol->alloc_circ_data(cmux, new_pol_data, circ,
512 (*i)->muxinfo.direction,
513 (*i)->muxinfo.cell_count);
514 }
515
516 /* Need to make active on new policy? */
517 if (new_pol && new_pol->notify_circ_active &&
518 (*i)->muxinfo.cell_count > 0) {
519 new_pol->notify_circ_active(cmux, new_pol_data, circ,
520 (*i)->muxinfo.policy_data);
521 }
522
523 /* Advance to next circuit map entry */
524 i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
525 }
526
527 /* Free data for old policy, if any */
528 if (old_pol_data) {
529 /*
530 * If we had old policy data, we should have an old policy and a free
531 * function for it.
532 */
533 tor_assert(old_pol);
534 tor_assert(old_pol->free_cmux_data);
535 old_pol->free_cmux_data(cmux, old_pol_data);
536 old_pol_data = NULL;
537 }
538}
539
540/*
541 * Circuitmux/circuit attachment status inquiry functions
542 */
543
544/**
545 * Query the direction of an attached circuit
546 */
547
550{
551 chanid_circid_muxinfo_t *hashent = NULL;
552
553 /* Try to find a map entry */
554 hashent = circuitmux_find_map_entry(cmux, circ);
555
556 /*
557 * This function should only be called on attached circuits; assert that
558 * we had a map entry.
559 */
560 tor_assert(hashent);
561
562 /* Return the direction from the map entry */
563 return hashent->muxinfo.direction;
564}
565
566/**
567 * Find an entry in the cmux's map for this circuit or return NULL if there
568 * is none.
569 */
570
572circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ)
573{
574 chanid_circid_muxinfo_t search, *hashent = NULL;
575
576 /* Sanity-check parameters */
577 tor_assert(cmux);
578 tor_assert(cmux->chanid_circid_map);
579 tor_assert(circ);
580
581 /* Check if we have n_chan */
582 if (circ->n_chan) {
583 /* Okay, let's see if it's attached for n_chan/n_circ_id */
584 search.chan_id = circ->n_chan->global_identifier;
585 search.circ_id = circ->n_circ_id;
586
587 /* Query */
588 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
589 &search);
590 }
591
592 /* Found something? */
593 if (hashent) {
594 /*
595 * Assert that the direction makes sense for a hashent we found by
596 * n_chan/n_circ_id before we return it.
597 */
598 tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_OUT);
599 } else {
600 /* Not there, have we got a p_chan/p_circ_id to try? */
601 if (circ->magic == OR_CIRCUIT_MAGIC) {
602 search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
603 /* Check for p_chan */
604 if (TO_OR_CIRCUIT(circ)->p_chan) {
605 search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier;
606 /* Okay, search for that */
607 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
608 &search);
609 /* Find anything? */
610 if (hashent) {
611 /* Assert that the direction makes sense before we return it */
612 tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_IN);
613 }
614 }
615 }
616 }
617
618 /* Okay, hashent is it if it was there */
619 return hashent;
620}
621
622/**
623 * Query whether a circuit is attached to a circuitmux
624 */
625
626int
628{
629 chanid_circid_muxinfo_t *hashent = NULL;
630
631 /* Look if it's in the circuit map */
632 hashent = circuitmux_find_map_entry(cmux, circ);
633
634 return (hashent != NULL);
635}
636
637/**
638 * Query whether a circuit is active on a circuitmux
639 */
640
641int
642circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ)
643{
644 chanid_circid_muxinfo_t *hashent = NULL;
645 int is_active = 0;
646
647 tor_assert(cmux);
648 tor_assert(circ);
649
650 /* Look if it's in the circuit map */
651 hashent = circuitmux_find_map_entry(cmux, circ);
652 if (hashent) {
653 /* Check the number of cells on this circuit */
654 is_active = (hashent->muxinfo.cell_count > 0);
655 }
656 /* else not attached, so not active */
657
658 return is_active;
659}
660
661/**
662 * Query number of available cells for a circuit on a circuitmux
663 */
664
665unsigned int
667{
668 chanid_circid_muxinfo_t *hashent = NULL;
669 unsigned int n_cells = 0;
670
671 tor_assert(cmux);
672 tor_assert(circ);
673
674 /* Look if it's in the circuit map */
675 hashent = circuitmux_find_map_entry(cmux, circ);
676 if (hashent) {
677 /* Just get the cell count for this circuit */
678 n_cells = hashent->muxinfo.cell_count;
679 }
680 /* else not attached, so 0 cells */
681
682 return n_cells;
683}
684
685/**
686 * Query total number of available cells on a circuitmux
687 */
688
689MOCK_IMPL(unsigned int,
690circuitmux_num_cells, (circuitmux_t *cmux))
691{
692 tor_assert(cmux);
693
694 return cmux->n_cells + cmux->destroy_cell_queue.n;
695}
696
697/**
698 * Query total number of circuits active on a circuitmux
699 */
700
701unsigned int
703{
704 tor_assert(cmux);
705
706 return cmux->n_active_circuits;
707}
708
709/**
710 * Query total number of circuits attached to a circuitmux
711 */
712
713unsigned int
714circuitmux_num_circuits(circuitmux_t *cmux)
715{
716 tor_assert(cmux);
717
718 return cmux->n_circuits;
719}
720
721/*
722 * Functions for circuit code to call to update circuit status
723 */
724
725/**
726 * Attach a circuit to a circuitmux, for the specified direction.
727 */
728
729MOCK_IMPL(void,
730circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
732{
733 channel_t *chan = NULL;
734 uint64_t channel_id;
735 circid_t circ_id;
736 chanid_circid_muxinfo_t search, *hashent = NULL;
737 unsigned int cell_count;
738
739 tor_assert(cmux);
740 tor_assert(circ);
741 tor_assert(direction == CELL_DIRECTION_IN ||
742 direction == CELL_DIRECTION_OUT);
743
744 /*
745 * Figure out which channel we're using, and get the circuit's current
746 * cell count and circuit ID; assert that the circuit is not already
747 * attached to another mux.
748 */
749 if (direction == CELL_DIRECTION_OUT) {
750 /* It's n_chan */
751 chan = circ->n_chan;
752 cell_count = circ->n_chan_cells.n;
753 circ_id = circ->n_circ_id;
754 } else {
755 /* We want p_chan */
756 chan = TO_OR_CIRCUIT(circ)->p_chan;
757 cell_count = TO_OR_CIRCUIT(circ)->p_chan_cells.n;
758 circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
759 }
760 /* Assert that we did get a channel */
761 tor_assert(chan);
762 /* Assert that the circuit ID is sensible */
763 tor_assert(circ_id != 0);
764
765 /* Get the channel ID */
766 channel_id = chan->global_identifier;
767
768 /* See if we already have this one */
769 search.chan_id = channel_id;
770 search.circ_id = circ_id;
771 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
772 &search);
773
774 if (hashent) {
775 /*
776 * This circuit was already attached to this cmux; make sure the
777 * directions match and update the cell count and active circuit count.
778 */
779 log_info(LD_CIRC,
780 "Circuit %u on channel %"PRIu64 " was already attached to "
781 "(trying to attach to %p)",
782 (unsigned)circ_id, (channel_id),
783 cmux);
784
785 /*
786 * The mux pointer on this circuit and the direction in result should
787 * match; otherwise assert.
788 */
789 tor_assert(hashent->muxinfo.direction == direction);
790
791 /*
792 * Looks okay; just update the cell count and active circuits if we must
793 */
794 if (hashent->muxinfo.cell_count > 0 && cell_count == 0) {
795 --(cmux->n_active_circuits);
797 } else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) {
798 ++(cmux->n_active_circuits);
800 }
801 cmux->n_cells -= hashent->muxinfo.cell_count;
802 cmux->n_cells += cell_count;
803 hashent->muxinfo.cell_count = cell_count;
804 } else {
805 /*
806 * New circuit; add an entry and update the circuit/active circuit
807 * counts.
808 */
809 log_debug(LD_CIRC,
810 "Attaching circuit %u on channel %"PRIu64 " to cmux %p",
811 (unsigned)circ_id, (channel_id), cmux);
812
813 /* Insert it in the map */
814 hashent = tor_malloc_zero(sizeof(*hashent));
815 hashent->chan_id = channel_id;
816 hashent->circ_id = circ_id;
817 hashent->muxinfo.cell_count = cell_count;
818 hashent->muxinfo.direction = direction;
819 /* Allocate policy specific circuit data if we need it */
820 if (cmux->policy->alloc_circ_data) {
821 /* Assert that we have the means to free policy-specific data */
822 tor_assert(cmux->policy->free_circ_data);
823 /* Allocate it */
824 hashent->muxinfo.policy_data =
825 cmux->policy->alloc_circ_data(cmux,
826 cmux->policy_data,
827 circ,
828 direction,
829 cell_count);
830 /* If we wanted policy data, it's an error not to get any */
831 tor_assert(hashent->muxinfo.policy_data);
832 }
833 HT_INSERT(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
834 hashent);
835
836 /* Update counters */
837 ++(cmux->n_circuits);
838 if (cell_count > 0) {
839 ++(cmux->n_active_circuits);
841 }
842 cmux->n_cells += cell_count;
843 }
844}
845
846/**
847 * Detach a circuit from a circuitmux and update all counters as needed;
848 * no-op if not attached.
849 */
850
851MOCK_IMPL(void,
852circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
853{
854 chanid_circid_muxinfo_t search, *hashent = NULL;
855 /*
856 * Use this to keep track of whether we found it for n_chan or
857 * p_chan for consistency checking.
858 *
859 * The 0 initializer is not a valid cell_direction_t value.
860 * We assert that it has been replaced with a valid value before it is used.
861 */
862 cell_direction_t last_searched_direction = 0;
863
864 tor_assert(cmux);
865 tor_assert(cmux->chanid_circid_map);
866 tor_assert(circ);
867
868 /* See if we have it for n_chan/n_circ_id */
869 if (circ->n_chan) {
870 search.chan_id = circ->n_chan->global_identifier;
871 search.circ_id = circ->n_circ_id;
872 hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
873 &search);
874 last_searched_direction = CELL_DIRECTION_OUT;
875 }
876
877 /* Got one? If not, see if it's an or_circuit_t and try p_chan/p_circ_id */
878 if (!hashent) {
879 if (circ->magic == OR_CIRCUIT_MAGIC) {
880 search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
881 if (TO_OR_CIRCUIT(circ)->p_chan) {
882 search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier;
883 hashent = HT_FIND(chanid_circid_muxinfo_map,
884 cmux->chanid_circid_map,
885 &search);
886 last_searched_direction = CELL_DIRECTION_IN;
887 }
888 }
889 }
890
891 tor_assert(last_searched_direction == CELL_DIRECTION_OUT
892 || last_searched_direction == CELL_DIRECTION_IN);
893
894 /*
895 * If hashent isn't NULL, we have a circuit to detach; don't remove it from
896 * the map until later of circuitmux_make_circuit_inactive() breaks.
897 */
898 if (hashent) {
899 /* Update counters */
900 --(cmux->n_circuits);
901 if (hashent->muxinfo.cell_count > 0) {
902 --(cmux->n_active_circuits);
903 /* This does policy notifies, so comes before freeing policy data */
905 }
906 cmux->n_cells -= hashent->muxinfo.cell_count;
907
908 /* Free policy-specific data if we have it */
909 if (hashent->muxinfo.policy_data) {
910 /* If we have policy data, assert that we have the means to free it */
911 tor_assert(cmux->policy);
912 tor_assert(cmux->policy->free_circ_data);
913 /* Call free_circ_data() */
914 cmux->policy->free_circ_data(cmux,
915 cmux->policy_data,
916 circ,
917 hashent->muxinfo.policy_data);
918 hashent->muxinfo.policy_data = NULL;
919 }
920
921 /* Consistency check: the direction must match the direction searched */
922 tor_assert(last_searched_direction == hashent->muxinfo.direction);
923
924 /* Now remove it from the map */
925 HT_REMOVE(chanid_circid_muxinfo_map, cmux->chanid_circid_map, hashent);
926
927 /* Wipe and free the hash entry */
928 // This isn't sensitive, but we want to be sure to know if we're accessing
929 // this accidentally.
930 memwipe(hashent, 0xef, sizeof(*hashent));
931 tor_free(hashent);
932 }
933}
934
935/**
936 * Make a circuit active; update active list and policy-specific info, but
937 * we don't mess with the counters or hash table here.
938 */
939
940static void
942{
943 tor_assert(cmux);
944 tor_assert(cmux->policy);
945 tor_assert(circ);
946
947 /* Policy-specific notification */
948 if (cmux->policy->notify_circ_active) {
949 /* Okay, we need to check the circuit for policy data now */
951 /* We should have found something */
952 tor_assert(hashent);
953 /* Notify */
954 cmux->policy->notify_circ_active(cmux, cmux->policy_data,
955 circ, hashent->muxinfo.policy_data);
956 }
957}
958
959/**
960 * Make a circuit inactive; update active list and policy-specific info, but
961 * we don't mess with the counters or hash table here.
962 */
963
964static void
966{
967 tor_assert(cmux);
968 tor_assert(cmux->policy);
969 tor_assert(circ);
970
971 /* Policy-specific notification */
972 if (cmux->policy->notify_circ_inactive) {
973 /* Okay, we need to check the circuit for policy data now */
975 /* We should have found something */
976 tor_assert(hashent);
977 /* Notify */
978 cmux->policy->notify_circ_inactive(cmux, cmux->policy_data,
979 circ, hashent->muxinfo.policy_data);
980 }
981}
982
983/**
984 * Clear the cell counter for a circuit on a circuitmux
985 */
986
987void
988circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ)
989{
990 /* This is the same as setting the cell count to zero */
991 circuitmux_set_num_cells(cmux, circ, 0);
992}
993
994/**
995 * Set the cell counter for a circuit on a circuitmux
996 */
997
998void
999circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
1000 unsigned int n_cells)
1001{
1002 chanid_circid_muxinfo_t *hashent = NULL;
1003
1004 tor_assert(cmux);
1005 tor_assert(circ);
1006
1007 /* Search for this circuit's entry */
1008 hashent = circuitmux_find_map_entry(cmux, circ);
1009 /* Assert that we found one */
1010 tor_assert(hashent);
1011
1012 /* Update cmux cell counter */
1013 cmux->n_cells -= hashent->muxinfo.cell_count;
1014 cmux->n_cells += n_cells;
1015
1016 /* Do we need to notify a cmux policy? */
1017 if (cmux->policy->notify_set_n_cells) {
1018 /* Call notify_set_n_cells */
1019 cmux->policy->notify_set_n_cells(cmux,
1020 cmux->policy_data,
1021 circ,
1022 hashent->muxinfo.policy_data,
1023 n_cells);
1024 }
1025
1026 /*
1027 * Update cmux active circuit counter: is the old cell count > 0 and the
1028 * new cell count == 0 ?
1029 */
1030 if (hashent->muxinfo.cell_count > 0 && n_cells == 0) {
1031 --(cmux->n_active_circuits);
1032 hashent->muxinfo.cell_count = n_cells;
1034 /* Is the old cell count == 0 and the new cell count > 0 ? */
1035 } else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) {
1036 ++(cmux->n_active_circuits);
1037 hashent->muxinfo.cell_count = n_cells;
1039 } else {
1040 hashent->muxinfo.cell_count = n_cells;
1041 }
1042}
1043
1044/*
1045 * Functions for channel code to call to get a circuit to transmit from or
1046 * notify that cells have been transmitted.
1047 */
1048
1049/**
1050 * Pick a circuit to send from, using the active circuits list or a
1051 * circuitmux policy if one is available. This is called from channel.c.
1052 *
1053 * If we would rather send a destroy cell, return NULL and set
1054 * *<b>destroy_queue_out</b> to the destroy queue.
1055 *
1056 * If we have nothing to send, set *<b>destroy_queue_out</b> to NULL and
1057 * return NULL.
1058 */
1059
1060circuit_t *
1062 destroy_cell_queue_t **destroy_queue_out)
1063{
1064 circuit_t *circ = NULL;
1065
1066 tor_assert(cmux);
1067 tor_assert(cmux->policy);
1068 /* This callback is mandatory. */
1069 tor_assert(cmux->policy->pick_active_circuit);
1070 tor_assert(destroy_queue_out);
1071
1072 *destroy_queue_out = NULL;
1073
1074 if (cmux->destroy_cell_queue.n &&
1075 (!cmux->last_cell_was_destroy || cmux->n_active_circuits == 0)) {
1076 /* We have destroy cells to send, and either we just sent a relay cell,
1077 * or we have no relay cells to send. */
1078
1079 /* XXXX We should let the cmux policy have some say in this eventually. */
1080 /* XXXX Alternating is not a terribly brilliant approach here. */
1081 *destroy_queue_out = &cmux->destroy_cell_queue;
1082
1083 cmux->last_cell_was_destroy = 1;
1084 } else if (cmux->n_active_circuits > 0) {
1085 /* We also must have a cell available for this to be the case */
1086 tor_assert(cmux->n_cells > 0);
1087 /* Do we have a policy-provided circuit selector? */
1088 circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data);
1089 cmux->last_cell_was_destroy = 0;
1090 } else {
1091 tor_assert(cmux->n_cells == 0);
1092 tor_assert(cmux->destroy_cell_queue.n == 0);
1093 }
1094
1095 return circ;
1096}
1097
1098/**
1099 * Notify the circuitmux that cells have been sent on a circuit; this
1100 * is called from channel.c.
1101 */
1102
1103void
1104circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
1105 unsigned int n_cells)
1106{
1107 chanid_circid_muxinfo_t *hashent = NULL;
1108 int becomes_inactive = 0;
1109
1110 tor_assert(cmux);
1111 tor_assert(circ);
1112
1113 if (n_cells == 0) return;
1114
1115 /*
1116 * To handle this, we have to:
1117 *
1118 * 1.) Adjust the circuit's cell counter in the cmux hash table
1119 * 2.) Move the circuit to the tail of the active_circuits linked list
1120 * for this cmux, or make the circuit inactive if the cell count
1121 * went to zero.
1122 * 3.) Call cmux->policy->notify_xmit_cells(), if any
1123 */
1124
1125 /* Find the hash entry */
1126 hashent = circuitmux_find_map_entry(cmux, circ);
1127 /* Assert that we found one */
1128 tor_assert(hashent);
1129
1130 /* Adjust the cell counter and assert that we had that many cells to send */
1131 tor_assert(n_cells <= hashent->muxinfo.cell_count);
1132 hashent->muxinfo.cell_count -= n_cells;
1133 /* Do we need to make the circuit inactive? */
1134 if (hashent->muxinfo.cell_count == 0) becomes_inactive = 1;
1135 /* Adjust the mux cell counter */
1136 cmux->n_cells -= n_cells;
1137
1138 /*
1139 * We call notify_xmit_cells() before making the circuit inactive if needed,
1140 * so the policy can always count on this coming in on an active circuit.
1141 */
1142 if (cmux->policy->notify_xmit_cells) {
1143 cmux->policy->notify_xmit_cells(cmux, cmux->policy_data, circ,
1144 hashent->muxinfo.policy_data,
1145 n_cells);
1146 }
1147
1148 /*
1149 * Now make the circuit inactive if needed; this will call the policy's
1150 * notify_circ_inactive() if present.
1151 */
1152 if (becomes_inactive) {
1153 --(cmux->n_active_circuits);
1155 }
1156}
1157
1158/**
1159 * Notify the circuitmux that a destroy was sent, so we can update
1160 * the counter.
1161 */
1162
1163void
1165{
1166 tor_assert(cmux);
1167
1168 --(cmux->destroy_ctr);
1170 log_debug(LD_CIRC,
1171 "Cmux at %p sent a destroy, cmux counter is now %"PRId64", "
1172 "global counter is now %"PRId64,
1173 cmux,
1174 (cmux->destroy_ctr),
1176}
1177
1178/*DOCDOC */
1179void
1180circuitmux_append_destroy_cell(channel_t *chan,
1181 circuitmux_t *cmux,
1182 circid_t circ_id,
1183 uint8_t reason)
1184{
1185 destroy_cell_queue_append(&cmux->destroy_cell_queue, circ_id, reason);
1186
1187 /* Destroy entering the queue, update counters */
1188 ++(cmux->destroy_ctr);
1190 log_debug(LD_CIRC,
1191 "Cmux at %p queued a destroy for circ %u, cmux counter is now "
1192 "%"PRId64", global counter is now %"PRId64,
1193 cmux, circ_id,
1194 (cmux->destroy_ctr),
1196
1197 /* XXXX Duplicate code from append_cell_to_circuit_queue */
1198 if (!channel_has_queued_writes(chan)) {
1199 /* There is no data at all waiting to be sent on the outbuf. Add a
1200 * cell, so that we can notice when it gets flushed, flushed_some can
1201 * get called, and we can start putting more data onto the buffer then.
1202 */
1203 log_debug(LD_GENERAL, "Primed a buffer.");
1205 }
1206}
1207
1208/*DOCDOC; for debugging 12184. This runs slowly. */
1209int64_t
1210circuitmux_count_queued_destroy_cells(const channel_t *chan,
1211 const circuitmux_t *cmux)
1212{
1213 int64_t n_destroy_cells = cmux->destroy_ctr;
1214 int64_t destroy_queue_size = cmux->destroy_cell_queue.n;
1215
1216 int64_t manual_total = 0;
1217 int64_t manual_total_in_map = 0;
1218 destroy_cell_t *cell;
1219
1220 TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) {
1221 circid_t id;
1222 ++manual_total;
1223
1224 id = cell->circid;
1226 ++manual_total_in_map;
1227 }
1228
1229 if (n_destroy_cells != destroy_queue_size ||
1230 n_destroy_cells != manual_total ||
1231 n_destroy_cells != manual_total_in_map) {
1232 log_warn(LD_BUG, " Discrepancy in counts for queued destroy cells on "
1233 "circuitmux. n=%"PRId64". queue_size=%"PRId64". "
1234 "manual_total=%"PRId64". manual_total_in_map=%"PRId64".",
1235 (n_destroy_cells),
1236 (destroy_queue_size),
1237 (manual_total),
1238 (manual_total_in_map));
1239 }
1240
1241 return n_destroy_cells;
1242}
1243
1244/**
1245 * Compare cmuxes to see which is more preferred; return < 0 if
1246 * cmux_1 has higher priority (i.e., cmux_1 < cmux_2 in the scheduler's
1247 * sort order), > 0 if cmux_2 has higher priority, or 0 if they are
1248 * equally preferred.
1249 *
1250 * If the cmuxes have different cmux policies or the policy does not
1251 * support the cmp_cmux method, return 0.
1252 */
1253
1254MOCK_IMPL(int,
1255circuitmux_compare_muxes, (circuitmux_t *cmux_1, circuitmux_t *cmux_2))
1256{
1257 const circuitmux_policy_t *policy;
1258
1259 tor_assert(cmux_1);
1260 tor_assert(cmux_2);
1261
1262 if (cmux_1 == cmux_2) {
1263 /* Equivalent because they're the same cmux */
1264 return 0;
1265 }
1266
1267 if (cmux_1->policy && cmux_2->policy) {
1268 if (cmux_1->policy == cmux_2->policy) {
1269 policy = cmux_1->policy;
1270
1271 if (policy->cmp_cmux) {
1272 /* Okay, we can compare! */
1273 return policy->cmp_cmux(cmux_1, cmux_1->policy_data,
1274 cmux_2, cmux_2->policy_data);
1275 } else {
1276 /*
1277 * Equivalent because the policy doesn't know how to compare between
1278 * muxes.
1279 */
1280 return 0;
1281 }
1282 } else {
1283 /* Equivalent because they have different policies */
1284 return 0;
1285 }
1286 } else {
1287 /* Equivalent because one or both are missing a policy */
1288 return 0;
1289 }
1290}
static void set_uint64(void *cp, uint64_t v)
Definition: bytes.h:96
static void set_uint32(void *cp, uint32_t v)
Definition: bytes.h:87
int channel_has_queued_writes(channel_t *chan)
Definition: channel.c:2874
channel_t * channel_find_by_global_id(uint64_t global_identifier)
Definition: channel.c:651
Header file for channel.c.
#define OR_CIRCUIT_MAGIC
Definition: circuit_st.h:33
circuit_t * circuit_get_by_circid_channel_even_if_marked(circid_t circ_id, channel_t *chan)
Definition: circuitlist.c:1560
int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan)
Definition: circuitlist.c:1574
void channel_mark_circid_usable(channel_t *chan, circid_t id)
Definition: circuitlist.c:405
or_circuit_t * TO_OR_CIRCUIT(circuit_t *x)
Definition: circuitlist.c:173
Header file for circuitlist.c.
const circuitmux_policy_t * circuitmux_get_policy(circuitmux_t *cmux)
Definition: circuitmux.c:415
cell_direction_t circuitmux_attached_circuit_direction(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:549
void circuitmux_clear_policy(circuitmux_t *cmux)
Definition: circuitmux.c:402
static unsigned int chanid_circid_entry_hash(chanid_circid_muxinfo_t *a)
Definition: circuitmux.c:170
void circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, channel_t *chan)
Definition: circuitmux.c:324
void circuitmux_notify_xmit_destroy(circuitmux_t *cmux)
Definition: circuitmux.c:1164
unsigned int circuitmux_num_cells_for_circuit(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:666
void circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
Definition: circuitmux.c:214
void circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ, unsigned int n_cells)
Definition: circuitmux.c:1104
static void circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:941
void circuitmux_set_policy(circuitmux_t *cmux, const circuitmux_policy_t *pol)
Definition: circuitmux.c:428
int circuitmux_compare_muxes(circuitmux_t *cmux_1, circuitmux_t *cmux_2)
Definition: circuitmux.c:1255
static void circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:965
unsigned int circuitmux_num_active_circuits(circuitmux_t *cmux)
Definition: circuitmux.c:702
void circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ, cell_direction_t direction)
Definition: circuitmux.c:731
unsigned int circuitmux_num_circuits(circuitmux_t *cmux)
Definition: circuitmux.c:714
void circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:852
static chanid_circid_muxinfo_t * circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:572
static int64_t global_destroy_ctr
Definition: circuitmux.c:148
int circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:642
void circuitmux_free_(circuitmux_t *cmux)
Definition: circuitmux.c:338
void circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:988
circuitmux_t * circuitmux_alloc(void)
Definition: circuitmux.c:194
int circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ)
Definition: circuitmux.c:627
static int chanid_circid_entries_eq(chanid_circid_muxinfo_t *a, chanid_circid_muxinfo_t *b)
Definition: circuitmux.c:159
void circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ, unsigned int n_cells)
Definition: circuitmux.c:999
circuit_t * circuitmux_get_first_active_circuit(circuitmux_t *cmux, destroy_cell_queue_t **destroy_queue_out)
Definition: circuitmux.c:1061
unsigned int circuitmux_num_cells(circuitmux_t *cmux)
Definition: circuitmux.c:690
Header file for circuitmux.c.
void memwipe(void *mem, uint8_t byte, size_t sz)
Definition: crypto_util.c:55
Common functions for cryptographic routines.
HT_PROTOTYPE(hs_circuitmap_ht, circuit_t, hs_circuitmap_node, hs_circuit_hash_token, hs_circuits_have_same_token)
#define LD_BUG
Definition: log.h:86
#define LD_GENERAL
Definition: log.h:62
#define LD_CIRC
Definition: log.h:82
void * tor_reallocarray_(void *ptr, size_t sz1, size_t sz2)
Definition: malloc.c:146
void tor_free_(void *mem)
Definition: malloc.c:227
#define tor_free(p)
Definition: malloc.h:56
Master header file for Tor-specific functionality.
uint32_t circid_t
Definition: or.h:497
cell_direction_t
Definition: or.h:375
@ CELL_DIRECTION_OUT
Definition: or.h:377
@ CELL_DIRECTION_IN
Definition: or.h:376
int channel_flush_from_first_active_circuit(channel_t *chan, int max)
Definition: relay.c:3146
void destroy_cell_queue_init(destroy_cell_queue_t *queue)
Definition: relay.c:2821
void destroy_cell_queue_clear(destroy_cell_queue_t *queue)
Definition: relay.c:2829
void destroy_cell_queue_append(destroy_cell_queue_t *queue, circid_t circid, uint8_t reason)
Definition: relay.c:2855
Header file for relay.c.
void smartlist_add(smartlist_t *sl, void *element)
uint64_t global_identifier
Definition: channel.h:197
cell_queue_t n_chan_cells
Definition: circuit_st.h:82
uint32_t magic
Definition: circuit_st.h:63
channel_t * n_chan
Definition: circuit_st.h:70
circid_t n_circ_id
Definition: circuit_st.h:79
channel_t * p_chan
Definition: or_circuit_st.h:37
circid_t p_circ_id
Definition: or_circuit_st.h:33
cell_queue_t p_chan_cells
Definition: or_circuit_st.h:35
#define MOCK_IMPL(rv, funcname, arglist)
Definition: testsupport.h:133
#define tor_assert(expr)
Definition: util_bug.h:103