1 /* * Copyright (c) 2012-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
6 * \brief Circuit mux/cell selection abstraction
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.
13 * There can be different implementations of the circuitmux's rules (which
14 * decide which circuit is next to write).
16 * A circuitmux exposes three distinct
17 * interfaces to other components:
19 * To channels, which each have a circuitmux_t, the supported operations
20 * (invoked from relay.c) are:
22 * circuitmux_get_first_active_circuit():
24 * Pick one of the circuitmux's active circuits to send cells from.
26 * circuitmux_notify_xmit_cells():
28 * Notify the circuitmux that cells have been sent on a circuit.
30 * To circuits, the exposed operations are:
32 * circuitmux_attach_circuit():
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.
38 * circuitmux_detach_circuit():
40 * Detach a circuit from the circuitmux, freeing associated structures.
42 * circuitmux_clear_num_cells():
44 * Clear the circuitmux's cell counter for this circuit.
46 * circuitmux_set_num_cells():
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.
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:
57 * circuitmux_get_policy():
59 * Return the current policy for a circuitmux_t, if any.
61 * circuitmux_clear_policy():
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.
66 * circuitmux_set_policy():
68 * Install a policy on a circuitmux_t; the appropriate callbacks will be
69 * made to attach all existing circuits to the new policy.
72 #define CIRCUITMUX_PRIVATE
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"
80 #include "core/or/or_circuit_st.h"
82 #include "lib/crypt_ops/crypto_util.h"
85 * Private typedefs for circuitmux.c
89 * Hash table entry (yeah, calling it chanid_circid_muxinfo_s seems to
90 * break the hash table code).
92 typedef struct chanid_circid_muxinfo_t chanid_circid_muxinfo_t
;
95 * Anything the mux wants to store per-circuit in the map; right now just
96 * a count of queued cells.
99 typedef struct circuit_muxinfo_t circuit_muxinfo_t
;
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.
106 struct circuit_muxinfo_t
{
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 */
112 circuitmux_policy_circ_data_t
*policy_data
;
113 /* Mark bit for consistency checker */
118 * A map from channel ID and circuit ID to a circuit_muxinfo_t for that
122 struct chanid_circid_muxinfo_t
{
123 HT_ENTRY(chanid_circid_muxinfo_t
) node
;
126 circuit_muxinfo_t muxinfo
;
130 * Static function declarations
134 chanid_circid_entries_eq(chanid_circid_muxinfo_t
*a
,
135 chanid_circid_muxinfo_t
*b
);
136 static inline unsigned int
137 chanid_circid_entry_hash(chanid_circid_muxinfo_t
*a
);
138 static chanid_circid_muxinfo_t
*
139 circuitmux_find_map_entry(circuitmux_t
*cmux
, circuit_t
*circ
);
141 circuitmux_make_circuit_active(circuitmux_t
*cmux
, circuit_t
*circ
);
143 circuitmux_make_circuit_inactive(circuitmux_t
*cmux
, circuit_t
*circ
);
145 /* Static global variables */
147 /** Count the destroy balance to debug destroy queue logic */
148 static int64_t global_destroy_ctr
= 0;
150 /* Function definitions */
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.
159 chanid_circid_entries_eq(chanid_circid_muxinfo_t
*a
,
160 chanid_circid_muxinfo_t
*b
)
162 return a
->chan_id
== b
->chan_id
&& a
->circ_id
== b
->circ_id
;
166 * Helper: return a hash based on circuit ID and channel ID in a.
169 static inline unsigned int
170 chanid_circid_entry_hash(chanid_circid_muxinfo_t
*a
)
173 set_uint64(data
, a
->chan_id
);
174 set_uint32(data
+ 8, a
->circ_id
);
175 return (unsigned) siphash24g(data
, sizeof(data
));
178 /* Emit a bunch of hash table stuff */
179 HT_PROTOTYPE(chanid_circid_muxinfo_map
, chanid_circid_muxinfo_t
, node
,
180 chanid_circid_entry_hash
, chanid_circid_entries_eq
);
181 HT_GENERATE2(chanid_circid_muxinfo_map
, chanid_circid_muxinfo_t
, node
,
182 chanid_circid_entry_hash
, chanid_circid_entries_eq
, 0.6,
183 tor_reallocarray_
, tor_free_
);
186 * Circuitmux alloc/free functions
190 * Allocate a new circuitmux_t
194 circuitmux_alloc(void)
196 circuitmux_t
*rv
= NULL
;
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
);
207 * Detach all circuits from a circuitmux (use before circuitmux_free())
209 * If <b>detached_out</b> is non-NULL, add every detached circuit_t to
214 circuitmux_detach_all_circuits(circuitmux_t
*cmux
, smartlist_t
*detached_out
)
216 chanid_circid_muxinfo_t
**i
= NULL
, *to_remove
;
217 channel_t
*chan
= NULL
;
218 circuit_t
*circ
= NULL
;
222 i
= HT_START(chanid_circid_muxinfo_map
, cmux
->chanid_circid_map
);
227 log_warn(LD_BUG
, "Somehow, an HT iterator gave us a NULL pointer.");
230 /* Find a channel and circuit */
231 chan
= channel_find_by_global_id(to_remove
->chan_id
);
234 circuit_get_by_circid_channel_even_if_marked(to_remove
->circ_id
,
237 /* Clear the circuit's mux for this direction */
238 if (to_remove
->muxinfo
.direction
== CELL_DIRECTION_OUT
) {
240 * Update active_circuits et al.; this does policy notifies, so
241 * comes before freeing policy data
244 if (to_remove
->muxinfo
.cell_count
> 0) {
245 circuitmux_make_circuit_inactive(cmux
, circ
);
249 smartlist_add(detached_out
, circ
);
250 } else if (circ
->magic
== OR_CIRCUIT_MAGIC
) {
252 * Update active_circuits et al.; this does policy notifies, so
253 * comes before freeing policy data
256 if (to_remove
->muxinfo
.cell_count
> 0) {
257 circuitmux_make_circuit_inactive(cmux
, circ
);
261 smartlist_add(detached_out
, circ
);
263 /* Complain and move on */
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
));
271 /* Free policy-specific data if we have it */
272 if (to_remove
->muxinfo
.policy_data
) {
274 * If we have policy data, assert that we have the means to
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
,
283 to_remove
->muxinfo
.policy_data
);
284 to_remove
->muxinfo
.policy_data
= NULL
;
287 /* Complain and move on */
289 "Couldn't find circuit %u (for channel %"PRIu64
")",
290 (unsigned)to_remove
->circ_id
,
291 (to_remove
->chan_id
));
294 /* Complain and move on */
296 "Couldn't find channel %"PRIu64
" (for circuit id %u)",
297 (to_remove
->chan_id
),
298 (unsigned)to_remove
->circ_id
);
301 /* Assert that we don't have un-freed policy data for this circuit */
302 tor_assert(to_remove
->muxinfo
.policy_data
== NULL
);
305 i
= HT_NEXT_RMV(chanid_circid_muxinfo_map
, cmux
->chanid_circid_map
, i
);
311 cmux
->n_circuits
= 0;
312 cmux
->n_active_circuits
= 0;
316 /** Reclaim all circuit IDs currently marked as unusable on <b>chan</b> because
317 * of pending destroy cells in <b>cmux</b>.
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
324 circuitmux_mark_destroyed_circids_usable(circuitmux_t
*cmux
, channel_t
*chan
)
326 destroy_cell_t
*cell
;
327 TOR_SIMPLEQ_FOREACH(cell
, &cmux
->destroy_cell_queue
.head
, next
) {
328 channel_mark_circid_usable(chan
, cell
->circid
);
333 * Free a circuitmux_t; the circuits must be detached first with
334 * circuitmux_detach_all_circuits().
338 circuitmux_free_(circuitmux_t
*cmux
)
342 tor_assert(cmux
->n_circuits
== 0);
343 tor_assert(cmux
->n_active_circuits
== 0);
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
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
;
357 } else tor_assert(cmux
->policy_data
== NULL
);
359 if (cmux
->chanid_circid_map
) {
360 HT_CLEAR(chanid_circid_muxinfo_map
, cmux
->chanid_circid_map
);
361 tor_free(cmux
->chanid_circid_map
);
365 * We're throwing away some destroys; log the counter and
366 * adjust the global counter by the queue size.
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
;
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
,
376 (global_destroy_ctr
));
379 "Freeing cmux at %p with no queued destroys, the cmux destroy "
380 "balance was %"PRId64
", global is %"PRId64
,
383 (global_destroy_ctr
));
386 destroy_cell_queue_clear(&cmux
->destroy_cell_queue
);
392 * Circuitmux policy control functions
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
402 circuitmux_clear_policy(circuitmux_t
*cmux
)
406 /* Internally, this is just setting policy to NULL */
407 circuitmux_set_policy(cmux
, NULL
);
411 * Return the policy currently installed on a circuitmux_t
414 MOCK_IMPL(const circuitmux_policy_t
*,
415 circuitmux_get_policy
, (circuitmux_t
*cmux
))
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.
428 circuitmux_set_policy(circuitmux_t
*cmux
,
429 const circuitmux_policy_t
*pol
)
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
;
440 /* Set up variables */
441 old_pol
= cmux
->policy
;
442 old_pol_data
= cmux
->policy_data
;
445 /* Check if this is the trivial case */
446 if (old_pol
== new_pol
) return;
448 /* Allocate data for new policy, if any */
449 if (new_pol
&& new_pol
->alloc_cmux_data
) {
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.
455 tor_assert(new_pol
->free_cmux_data
);
456 new_pol_data
= new_pol
->alloc_cmux_data(cmux
);
457 tor_assert(new_pol_data
);
460 /* Install new policy and new policy data on cmux */
461 cmux
->policy
= new_pol
;
462 cmux
->policy_data
= new_pol_data
;
464 /* Iterate over all circuits, attaching/detaching each one */
465 i
= HT_START(chanid_circid_muxinfo_map
, cmux
->chanid_circid_map
);
467 /* Assert that this entry isn't NULL */
471 * Get the channel; since normal case is all circuits on the mux share a
472 * channel, we cache last_chan_id_searched
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
;
480 /* Get the circuit */
481 circ
= circuit_get_by_circid_channel_even_if_marked((*i
)->circ_id
, chan
);
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
);
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 */
495 tor_assert(old_pol
->free_circ_data
);
497 old_pol
->free_circ_data(cmux
, old_pol_data
, circ
,
498 (*i
)->muxinfo
.policy_data
);
499 (*i
)->muxinfo
.policy_data
= NULL
;
502 /* Need to allocate new policy data? */
503 if (new_pol
&& new_pol
->alloc_circ_data
) {
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.
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
);
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
);
523 /* Advance to next circuit map entry */
524 i
= HT_NEXT(chanid_circid_muxinfo_map
, cmux
->chanid_circid_map
, i
);
527 /* Free data for old policy, if any */
530 * If we had old policy data, we should have an old policy and a free
534 tor_assert(old_pol
->free_cmux_data
);
535 old_pol
->free_cmux_data(cmux
, old_pol_data
);
541 * Circuitmux/circuit attachment status inquiry functions
545 * Query the direction of an attached circuit
549 circuitmux_attached_circuit_direction(circuitmux_t
*cmux
, circuit_t
*circ
)
551 chanid_circid_muxinfo_t
*hashent
= NULL
;
553 /* Try to find a map entry */
554 hashent
= circuitmux_find_map_entry(cmux
, circ
);
557 * This function should only be called on attached circuits; assert that
558 * we had a map entry.
562 /* Return the direction from the map entry */
563 return hashent
->muxinfo
.direction
;
567 * Find an entry in the cmux's map for this circuit or return NULL if there
571 static chanid_circid_muxinfo_t
*
572 circuitmux_find_map_entry(circuitmux_t
*cmux
, circuit_t
*circ
)
574 chanid_circid_muxinfo_t search
, *hashent
= NULL
;
576 /* Sanity-check parameters */
578 tor_assert(cmux
->chanid_circid_map
);
581 /* Check if we have 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
;
588 hashent
= HT_FIND(chanid_circid_muxinfo_map
, cmux
->chanid_circid_map
,
592 /* Found something? */
595 * Assert that the direction makes sense for a hashent we found by
596 * n_chan/n_circ_id before we return it.
598 tor_assert(hashent
->muxinfo
.direction
== CELL_DIRECTION_OUT
);
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
,
611 /* Assert that the direction makes sense before we return it */
612 tor_assert(hashent
->muxinfo
.direction
== CELL_DIRECTION_IN
);
618 /* Okay, hashent is it if it was there */
623 * Query whether a circuit is attached to a circuitmux
627 circuitmux_is_circuit_attached(circuitmux_t
*cmux
, circuit_t
*circ
)
629 chanid_circid_muxinfo_t
*hashent
= NULL
;
631 /* Look if it's in the circuit map */
632 hashent
= circuitmux_find_map_entry(cmux
, circ
);
634 return (hashent
!= NULL
);
638 * Query whether a circuit is active on a circuitmux
642 circuitmux_is_circuit_active(circuitmux_t
*cmux
, circuit_t
*circ
)
644 chanid_circid_muxinfo_t
*hashent
= NULL
;
650 /* Look if it's in the circuit map */
651 hashent
= circuitmux_find_map_entry(cmux
, circ
);
653 /* Check the number of cells on this circuit */
654 is_active
= (hashent
->muxinfo
.cell_count
> 0);
656 /* else not attached, so not active */
662 * Query number of available cells for a circuit on a circuitmux
666 circuitmux_num_cells_for_circuit(circuitmux_t
*cmux
, circuit_t
*circ
)
668 chanid_circid_muxinfo_t
*hashent
= NULL
;
669 unsigned int n_cells
= 0;
674 /* Look if it's in the circuit map */
675 hashent
= circuitmux_find_map_entry(cmux
, circ
);
677 /* Just get the cell count for this circuit */
678 n_cells
= hashent
->muxinfo
.cell_count
;
680 /* else not attached, so 0 cells */
686 * Query total number of available cells on a circuitmux
689 MOCK_IMPL(unsigned int,
690 circuitmux_num_cells
, (circuitmux_t
*cmux
))
694 return cmux
->n_cells
+ cmux
->destroy_cell_queue
.n
;
698 * Query total number of circuits active on a circuitmux
702 circuitmux_num_active_circuits(circuitmux_t
*cmux
)
706 return cmux
->n_active_circuits
;
710 * Query total number of circuits attached to a circuitmux
714 circuitmux_num_circuits(circuitmux_t
*cmux
)
718 return cmux
->n_circuits
;
722 * Functions for circuit code to call to update circuit status
726 * Attach a circuit to a circuitmux, for the specified direction.
730 circuitmux_attach_circuit
,(circuitmux_t
*cmux
, circuit_t
*circ
,
731 cell_direction_t direction
))
733 channel_t
*chan
= NULL
;
736 chanid_circid_muxinfo_t search
, *hashent
= NULL
;
737 unsigned int cell_count
;
741 tor_assert(direction
== CELL_DIRECTION_IN
||
742 direction
== CELL_DIRECTION_OUT
);
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.
749 if (direction
== CELL_DIRECTION_OUT
) {
752 cell_count
= circ
->n_chan_cells
.n
;
753 circ_id
= circ
->n_circ_id
;
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
;
760 /* Assert that we did get a channel */
762 /* Assert that the circuit ID is sensible */
763 tor_assert(circ_id
!= 0);
765 /* Get the channel ID */
766 channel_id
= chan
->global_identifier
;
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
,
776 * This circuit was already attached to this cmux; make sure the
777 * directions match and update the cell count and active circuit count.
780 "Circuit %u on channel %"PRIu64
" was already attached to "
781 "(trying to attach to %p)",
782 (unsigned)circ_id
, (channel_id
),
786 * The mux pointer on this circuit and the direction in result should
787 * match; otherwise assert.
789 tor_assert(hashent
->muxinfo
.direction
== direction
);
792 * Looks okay; just update the cell count and active circuits if we must
794 if (hashent
->muxinfo
.cell_count
> 0 && cell_count
== 0) {
795 --(cmux
->n_active_circuits
);
796 circuitmux_make_circuit_inactive(cmux
, circ
);
797 } else if (hashent
->muxinfo
.cell_count
== 0 && cell_count
> 0) {
798 ++(cmux
->n_active_circuits
);
799 circuitmux_make_circuit_active(cmux
, circ
);
801 cmux
->n_cells
-= hashent
->muxinfo
.cell_count
;
802 cmux
->n_cells
+= cell_count
;
803 hashent
->muxinfo
.cell_count
= cell_count
;
806 * New circuit; add an entry and update the circuit/active circuit
810 "Attaching circuit %u on channel %"PRIu64
" to cmux %p",
811 (unsigned)circ_id
, (channel_id
), cmux
);
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
);
824 hashent
->muxinfo
.policy_data
=
825 cmux
->policy
->alloc_circ_data(cmux
,
830 /* If we wanted policy data, it's an error not to get any */
831 tor_assert(hashent
->muxinfo
.policy_data
);
833 HT_INSERT(chanid_circid_muxinfo_map
, cmux
->chanid_circid_map
,
836 /* Update counters */
837 ++(cmux
->n_circuits
);
838 if (cell_count
> 0) {
839 ++(cmux
->n_active_circuits
);
840 circuitmux_make_circuit_active(cmux
, circ
);
842 cmux
->n_cells
+= cell_count
;
847 * Detach a circuit from a circuitmux and update all counters as needed;
848 * no-op if not attached.
852 circuitmux_detach_circuit
,(circuitmux_t
*cmux
, circuit_t
*circ
))
854 chanid_circid_muxinfo_t search
, *hashent
= NULL
;
856 * Use this to keep track of whether we found it for n_chan or
857 * p_chan for consistency checking.
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.
862 cell_direction_t last_searched_direction
= 0;
865 tor_assert(cmux
->chanid_circid_map
);
868 /* See if we have it for n_chan/n_circ_id */
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
,
874 last_searched_direction
= CELL_DIRECTION_OUT
;
877 /* Got one? If not, see if it's an or_circuit_t and try p_chan/p_circ_id */
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
,
886 last_searched_direction
= CELL_DIRECTION_IN
;
891 tor_assert(last_searched_direction
== CELL_DIRECTION_OUT
892 || last_searched_direction
== CELL_DIRECTION_IN
);
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.
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 */
904 circuitmux_make_circuit_inactive(cmux
, circ
);
906 cmux
->n_cells
-= hashent
->muxinfo
.cell_count
;
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
,
917 hashent
->muxinfo
.policy_data
);
918 hashent
->muxinfo
.policy_data
= NULL
;
921 /* Consistency check: the direction must match the direction searched */
922 tor_assert(last_searched_direction
== hashent
->muxinfo
.direction
);
924 /* Now remove it from the map */
925 HT_REMOVE(chanid_circid_muxinfo_map
, cmux
->chanid_circid_map
, hashent
);
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
));
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.
941 circuitmux_make_circuit_active(circuitmux_t
*cmux
, circuit_t
*circ
)
944 tor_assert(cmux
->policy
);
947 /* Policy-specific notification */
948 if (cmux
->policy
->notify_circ_active
) {
949 /* Okay, we need to check the circuit for policy data now */
950 chanid_circid_muxinfo_t
*hashent
= circuitmux_find_map_entry(cmux
, circ
);
951 /* We should have found something */
954 cmux
->policy
->notify_circ_active(cmux
, cmux
->policy_data
,
955 circ
, hashent
->muxinfo
.policy_data
);
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.
965 circuitmux_make_circuit_inactive(circuitmux_t
*cmux
, circuit_t
*circ
)
968 tor_assert(cmux
->policy
);
971 /* Policy-specific notification */
972 if (cmux
->policy
->notify_circ_inactive
) {
973 /* Okay, we need to check the circuit for policy data now */
974 chanid_circid_muxinfo_t
*hashent
= circuitmux_find_map_entry(cmux
, circ
);
975 /* We should have found something */
978 cmux
->policy
->notify_circ_inactive(cmux
, cmux
->policy_data
,
979 circ
, hashent
->muxinfo
.policy_data
);
984 * Clear the cell counter for a circuit on a circuitmux
988 circuitmux_clear_num_cells(circuitmux_t
*cmux
, circuit_t
*circ
)
990 /* This is the same as setting the cell count to zero */
991 circuitmux_set_num_cells(cmux
, circ
, 0);
995 * Set the cell counter for a circuit on a circuitmux
999 circuitmux_set_num_cells(circuitmux_t
*cmux
, circuit_t
*circ
,
1000 unsigned int n_cells
)
1002 chanid_circid_muxinfo_t
*hashent
= NULL
;
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
);
1012 /* Update cmux cell counter */
1013 cmux
->n_cells
-= hashent
->muxinfo
.cell_count
;
1014 cmux
->n_cells
+= n_cells
;
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
,
1022 hashent
->muxinfo
.policy_data
,
1027 * Update cmux active circuit counter: is the old cell count > 0 and the
1028 * new cell count == 0 ?
1030 if (hashent
->muxinfo
.cell_count
> 0 && n_cells
== 0) {
1031 --(cmux
->n_active_circuits
);
1032 hashent
->muxinfo
.cell_count
= n_cells
;
1033 circuitmux_make_circuit_inactive(cmux
, circ
);
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
;
1038 circuitmux_make_circuit_active(cmux
, circ
);
1040 hashent
->muxinfo
.cell_count
= n_cells
;
1045 * Functions for channel code to call to get a circuit to transmit from or
1046 * notify that cells have been transmitted.
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.
1053 * If we would rather send a destroy cell, return NULL and set
1054 * *<b>destroy_queue_out</b> to the destroy queue.
1056 * If we have nothing to send, set *<b>destroy_queue_out</b> to NULL and
1061 circuitmux_get_first_active_circuit(circuitmux_t
*cmux
,
1062 destroy_cell_queue_t
**destroy_queue_out
)
1064 circuit_t
*circ
= NULL
;
1067 tor_assert(cmux
->policy
);
1068 /* This callback is mandatory. */
1069 tor_assert(cmux
->policy
->pick_active_circuit
);
1070 tor_assert(destroy_queue_out
);
1072 *destroy_queue_out
= NULL
;
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. */
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
;
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;
1091 tor_assert(cmux
->n_cells
== 0);
1092 tor_assert(cmux
->destroy_cell_queue
.n
== 0);
1099 * Notify the circuitmux that cells have been sent on a circuit; this
1100 * is called from channel.c.
1104 circuitmux_notify_xmit_cells(circuitmux_t
*cmux
, circuit_t
*circ
,
1105 unsigned int n_cells
)
1107 chanid_circid_muxinfo_t
*hashent
= NULL
;
1108 int becomes_inactive
= 0;
1113 if (n_cells
== 0) return;
1116 * To handle this, we have to:
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
1122 * 3.) Call cmux->policy->notify_xmit_cells(), if any
1125 /* Find the hash entry */
1126 hashent
= circuitmux_find_map_entry(cmux
, circ
);
1127 /* Assert that we found one */
1128 tor_assert(hashent
);
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
;
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.
1142 if (cmux
->policy
->notify_xmit_cells
) {
1143 cmux
->policy
->notify_xmit_cells(cmux
, cmux
->policy_data
, circ
,
1144 hashent
->muxinfo
.policy_data
,
1149 * Now make the circuit inactive if needed; this will call the policy's
1150 * notify_circ_inactive() if present.
1152 if (becomes_inactive
) {
1153 --(cmux
->n_active_circuits
);
1154 circuitmux_make_circuit_inactive(cmux
, circ
);
1159 * Notify the circuitmux that a destroy was sent, so we can update
1164 circuitmux_notify_xmit_destroy(circuitmux_t
*cmux
)
1168 --(cmux
->destroy_ctr
);
1169 --(global_destroy_ctr
);
1171 "Cmux at %p sent a destroy, cmux counter is now %"PRId64
", "
1172 "global counter is now %"PRId64
,
1174 (cmux
->destroy_ctr
),
1175 (global_destroy_ctr
));
1180 circuitmux_append_destroy_cell(channel_t
*chan
,
1185 destroy_cell_queue_append(&cmux
->destroy_cell_queue
, circ_id
, reason
);
1187 /* Destroy entering the queue, update counters */
1188 ++(cmux
->destroy_ctr
);
1189 ++global_destroy_ctr
;
1191 "Cmux at %p queued a destroy for circ %u, cmux counter is now "
1192 "%"PRId64
", global counter is now %"PRId64
,
1194 (cmux
->destroy_ctr
),
1195 (global_destroy_ctr
));
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.
1203 log_debug(LD_GENERAL
, "Primed a buffer.");
1204 channel_flush_from_first_active_circuit(chan
, 1);
1208 /*DOCDOC; for debugging 12184. This runs slowly. */
1210 circuitmux_count_queued_destroy_cells(const channel_t
*chan
,
1211 const circuitmux_t
*cmux
)
1213 int64_t n_destroy_cells
= cmux
->destroy_ctr
;
1214 int64_t destroy_queue_size
= cmux
->destroy_cell_queue
.n
;
1216 int64_t manual_total
= 0;
1217 int64_t manual_total_in_map
= 0;
1218 destroy_cell_t
*cell
;
1220 TOR_SIMPLEQ_FOREACH(cell
, &cmux
->destroy_cell_queue
.head
, next
) {
1225 if (circuit_id_in_use_on_channel(id
, (channel_t
*)chan
))
1226 ++manual_total_in_map
;
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
".",
1236 (destroy_queue_size
),
1238 (manual_total_in_map
));
1241 return n_destroy_cells
;
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.
1250 * If the cmuxes have different cmux policies or the policy does not
1251 * support the cmp_cmux method, return 0.
1255 circuitmux_compare_muxes
, (circuitmux_t
*cmux_1
, circuitmux_t
*cmux_2
))
1257 const circuitmux_policy_t
*policy
;
1262 if (cmux_1
== cmux_2
) {
1263 /* Equivalent because they're the same cmux */
1267 if (cmux_1
->policy
&& cmux_2
->policy
) {
1268 if (cmux_1
->policy
== cmux_2
->policy
) {
1269 policy
= cmux_1
->policy
;
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
);
1277 * Equivalent because the policy doesn't know how to compare between
1283 /* Equivalent because they have different policies */
1287 /* Equivalent because one or both are missing a policy */