Merge branch 'ticket25268_034_01'

This commit is contained in:
Nick Mathewson 2018-03-19 06:01:02 -04:00
commit a324cd9020
17 changed files with 125 additions and 804 deletions

7
changes/ticket25268 Normal file
View File

@ -0,0 +1,7 @@
o Removed features:
- The old "round-robin" circuit multiplexer (circuitmux)
implementation has been removed, along with a fairly large set of
code that existed to support it. It has not been the default
circuitmux since we introduced the "EWMA" circuitmux in 0.2.4.x,
but it still required an unreasonable amount of memory and CPU.
Closes ticket 25268.

View File

@ -780,17 +780,15 @@ GENERAL OPTIONS
This is useful when running on flash memory or other media that support This is useful when running on flash memory or other media that support
only a limited number of writes. (Default: 0) only a limited number of writes. (Default: 0)
[[CircuitPriorityHalflife]] **CircuitPriorityHalflife** __NUM1__:: [[CircuitPriorityHalflife]] **CircuitPriorityHalflife** __NUM__::
If this value is set, we override the default algorithm for choosing which If this value is set, we override the default algorithm for choosing which
circuit's cell to deliver or relay next. When the value is 0, we circuit's cell to deliver or relay next. It is delivered first to the
round-robin between the active circuits on a connection, delivering one circuit that has the lowest weighted cell count, where cells are weighted
cell from each in turn. When the value is positive, we prefer delivering exponentially according to this value (in seconds). If the value is -1, it
cells from whichever connection has the lowest weighted cell count, where is taken from the consensus if possible else it will fallback to the
cells are weighted exponentially according to the supplied default value of 30. Minimum: 1, Maximum: 2147483647. This can be defined
CircuitPriorityHalflife value (in seconds). If this option is not set at as a float value. This is an advanced option; you generally shouldn't have
all, we use the behavior recommended in the current consensus to mess with it. (Default: -1)
networkstatus. This is an advanced option; you generally shouldn't have
to mess with it. (Default: not set)
[[CountPrivateBandwidth]] **CountPrivateBandwidth** **0**|**1**:: [[CountPrivateBandwidth]] **CountPrivateBandwidth** **0**|**1**::
If this option is set, then Tor's rate-limiting applies not only to If this option is set, then Tor's rate-limiting applies not only to

View File

@ -2108,21 +2108,6 @@ channel_listener_dumpstats(int severity)
} }
} }
/**
* Set the cmux policy on all active channels.
*/
void
channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol)
{
if (!active_channels) return;
SMARTLIST_FOREACH_BEGIN(active_channels, channel_t *, curr) {
if (curr->cmux) {
circuitmux_set_policy(curr->cmux, pol);
}
} SMARTLIST_FOREACH_END(curr);
}
/** /**
* Clean up channels. * Clean up channels.
* *

View File

@ -422,9 +422,6 @@ void channel_free_all(void);
void channel_dumpstats(int severity); void channel_dumpstats(int severity);
void channel_listener_dumpstats(int severity); void channel_listener_dumpstats(int severity);
/* Set the cmux policy on all active channels */
void channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol);
#ifdef TOR_CHANNEL_INTERNAL_ #ifdef TOR_CHANNEL_INTERNAL_
#ifdef CHANNEL_PRIVATE_ #ifdef CHANNEL_PRIVATE_

View File

@ -160,9 +160,8 @@ channel_tls_common_init(channel_tls_t *tlschan)
chan->write_var_cell = channel_tls_write_var_cell_method; chan->write_var_cell = channel_tls_write_var_cell_method;
chan->cmux = circuitmux_alloc(); chan->cmux = circuitmux_alloc();
if (cell_ewma_enabled()) { /* We only have one policy for now so always set it to EWMA. */
circuitmux_set_policy(chan->cmux, &ewma_policy); circuitmux_set_policy(chan->cmux, &ewma_policy);
}
} }
/** /**

View File

@ -403,9 +403,6 @@ circuit_set_p_circid_chan(or_circuit_t *or_circ, circid_t id,
circuit_set_circid_chan_helper(circ, CELL_DIRECTION_IN, id, chan); circuit_set_circid_chan_helper(circ, CELL_DIRECTION_IN, id, chan);
if (chan) { if (chan) {
tor_assert(bool_eq(or_circ->p_chan_cells.n,
or_circ->next_active_on_p_chan));
chan->timestamp_last_had_circuits = approx_time(); chan->timestamp_last_had_circuits = approx_time();
} }
@ -428,8 +425,6 @@ circuit_set_n_circid_chan(circuit_t *circ, circid_t id,
circuit_set_circid_chan_helper(circ, CELL_DIRECTION_OUT, id, chan); circuit_set_circid_chan_helper(circ, CELL_DIRECTION_OUT, id, chan);
if (chan) { if (chan) {
tor_assert(bool_eq(circ->n_chan_cells.n, circ->next_active_on_n_chan));
chan->timestamp_last_had_circuits = approx_time(); chan->timestamp_last_had_circuits = approx_time();
} }

View File

@ -114,13 +114,6 @@ struct circuitmux_s {
*/ */
chanid_circid_muxinfo_map_t *chanid_circid_map; chanid_circid_muxinfo_map_t *chanid_circid_map;
/*
* Double-linked ring of circuits with queued cells waiting for room to
* free up on this connection's outbuf. Every time we pull cells from
* a circuit, we advance this pointer to the next circuit in the ring.
*/
struct circuit_t *active_circuits_head, *active_circuits_tail;
/** List of queued destroy cells */ /** List of queued destroy cells */
destroy_cell_queue_t destroy_cell_queue; destroy_cell_queue_t destroy_cell_queue;
/** Boolean: True iff the last cell to circuitmux_get_first_active_circuit /** Boolean: True iff the last cell to circuitmux_get_first_active_circuit
@ -176,17 +169,6 @@ struct chanid_circid_muxinfo_t {
circuit_muxinfo_t muxinfo; circuit_muxinfo_t muxinfo;
}; };
/*
* Internal-use #defines
*/
#ifdef CMUX_PARANOIA
#define circuitmux_assert_okay_paranoid(cmux) \
circuitmux_assert_okay(cmux)
#else
#define circuitmux_assert_okay_paranoid(cmux)
#endif /* defined(CMUX_PARANOIA) */
/* /*
* Static function declarations * Static function declarations
*/ */
@ -199,21 +181,9 @@ chanid_circid_entry_hash(chanid_circid_muxinfo_t *a);
static chanid_circid_muxinfo_t * static chanid_circid_muxinfo_t *
circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ); circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ);
static void static void
circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ, circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ);
cell_direction_t direction);
static void static void
circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ, circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ);
cell_direction_t direction);
static inline void
circuitmux_move_active_circ_to_tail(circuitmux_t *cmux, circuit_t *circ,
cell_direction_t direction);
static inline circuit_t **
circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ);
static inline circuit_t **
circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ);
static void circuitmux_assert_okay_pass_one(circuitmux_t *cmux);
static void circuitmux_assert_okay_pass_two(circuitmux_t *cmux);
static void circuitmux_assert_okay_pass_three(circuitmux_t *cmux);
/* Static global variables */ /* Static global variables */
@ -222,119 +192,6 @@ static int64_t global_destroy_ctr = 0;
/* Function definitions */ /* Function definitions */
/**
* Linked list helpers
*/
/**
* Move an active circuit to the tail of the cmux's active circuits list;
* used by circuitmux_notify_xmit_cells().
*/
static inline void
circuitmux_move_active_circ_to_tail(circuitmux_t *cmux, circuit_t *circ,
cell_direction_t direction)
{
circuit_t **next_p = NULL, **prev_p = NULL;
circuit_t **next_prev = NULL, **prev_next = NULL;
circuit_t **tail_next = NULL;
or_circuit_t *or_circ = NULL;
tor_assert(cmux);
tor_assert(circ);
circuitmux_assert_okay_paranoid(cmux);
/* Figure out our next_p and prev_p for this cmux/direction */
if (direction) {
if (direction == CELL_DIRECTION_OUT) {
tor_assert(circ->n_mux == cmux);
next_p = &(circ->next_active_on_n_chan);
prev_p = &(circ->prev_active_on_n_chan);
} else {
or_circ = TO_OR_CIRCUIT(circ);
tor_assert(or_circ->p_mux == cmux);
next_p = &(or_circ->next_active_on_p_chan);
prev_p = &(or_circ->prev_active_on_p_chan);
}
} else {
if (circ->n_mux == cmux) {
next_p = &(circ->next_active_on_n_chan);
prev_p = &(circ->prev_active_on_n_chan);
} else {
or_circ = TO_OR_CIRCUIT(circ);
tor_assert(or_circ->p_mux == cmux);
next_p = &(or_circ->next_active_on_p_chan);
prev_p = &(or_circ->prev_active_on_p_chan);
}
}
tor_assert(next_p);
tor_assert(prev_p);
/* Check if this really is an active circuit */
if ((*next_p == NULL && *prev_p == NULL) &&
!(circ == cmux->active_circuits_head ||
circ == cmux->active_circuits_tail)) {
/* Not active, no-op */
return;
}
/* Check if this is already the tail */
if (circ == cmux->active_circuits_tail) return;
/* Okay, we have to move it; figure out next_prev and prev_next */
if (*next_p) next_prev = circuitmux_prev_active_circ_p(cmux, *next_p);
if (*prev_p) prev_next = circuitmux_next_active_circ_p(cmux, *prev_p);
/* Adjust the previous node's next pointer, if any */
if (prev_next) *prev_next = *next_p;
/* Otherwise, we were the head */
else cmux->active_circuits_head = *next_p;
/* Adjust the next node's previous pointer, if any */
if (next_prev) *next_prev = *prev_p;
/* We're out of the list; now re-attach at the tail */
/* Adjust our next and prev pointers */
*next_p = NULL;
*prev_p = cmux->active_circuits_tail;
/* Set the next pointer of the tail, or the head if none */
if (cmux->active_circuits_tail) {
tail_next = circuitmux_next_active_circ_p(cmux,
cmux->active_circuits_tail);
*tail_next = circ;
} else {
cmux->active_circuits_head = circ;
}
/* Set the tail to this circuit */
cmux->active_circuits_tail = circ;
circuitmux_assert_okay_paranoid(cmux);
}
static inline circuit_t **
circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ)
{
tor_assert(cmux);
tor_assert(circ);
if (circ->n_mux == cmux) return &(circ->next_active_on_n_chan);
else {
tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
return &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
}
}
static inline circuit_t **
circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ)
{
tor_assert(cmux);
tor_assert(circ);
if (circ->n_mux == cmux) return &(circ->prev_active_on_n_chan);
else {
tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
return &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
}
}
/** /**
* Helper for chanid_circid_cell_count_map_t hash table: compare the channel * Helper for chanid_circid_cell_count_map_t hash table: compare the channel
* ID and circuit ID for a and b, and return less than, equal to, or greater * ID and circuit ID for a and b, and return less than, equal to, or greater
@ -406,11 +263,6 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
circuit_t *circ = NULL; circuit_t *circ = NULL;
tor_assert(cmux); tor_assert(cmux);
/*
* Don't circuitmux_assert_okay_paranoid() here; this gets called when
* channels are being freed and have already been unregistered, so
* the channel ID lookups it does will fail.
*/
i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map); i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
while (i) { while (i) {
@ -435,7 +287,7 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
*/ */
if (to_remove->muxinfo.cell_count > 0) { if (to_remove->muxinfo.cell_count > 0) {
circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_OUT); circuitmux_make_circuit_inactive(cmux, circ);
} }
/* Clear n_mux */ /* Clear n_mux */
@ -450,7 +302,7 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
*/ */
if (to_remove->muxinfo.cell_count > 0) { if (to_remove->muxinfo.cell_count > 0) {
circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_IN); circuitmux_make_circuit_inactive(cmux, circ);
} }
/* /*
@ -606,9 +458,7 @@ circuitmux_clear_policy(circuitmux_t *cmux)
tor_assert(cmux); tor_assert(cmux);
/* Internally, this is just setting policy to NULL */ /* Internally, this is just setting policy to NULL */
if (cmux->policy) { circuitmux_set_policy(cmux, NULL);
circuitmux_set_policy(cmux, NULL);
}
} }
/** /**
@ -944,7 +794,6 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
tor_assert(circ); tor_assert(circ);
tor_assert(direction == CELL_DIRECTION_IN || tor_assert(direction == CELL_DIRECTION_IN ||
direction == CELL_DIRECTION_OUT); direction == CELL_DIRECTION_OUT);
circuitmux_assert_okay_paranoid(cmux);
/* /*
* Figure out which channel we're using, and get the circuit's current * Figure out which channel we're using, and get the circuit's current
@ -1002,10 +851,10 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
*/ */
if (hashent->muxinfo.cell_count > 0 && cell_count == 0) { if (hashent->muxinfo.cell_count > 0 && cell_count == 0) {
--(cmux->n_active_circuits); --(cmux->n_active_circuits);
circuitmux_make_circuit_inactive(cmux, circ, direction); circuitmux_make_circuit_inactive(cmux, circ);
} else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) { } else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) {
++(cmux->n_active_circuits); ++(cmux->n_active_circuits);
circuitmux_make_circuit_active(cmux, circ, direction); circuitmux_make_circuit_active(cmux, circ);
} }
cmux->n_cells -= hashent->muxinfo.cell_count; cmux->n_cells -= hashent->muxinfo.cell_count;
cmux->n_cells += cell_count; cmux->n_cells += cell_count;
@ -1033,7 +882,7 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
hashent->muxinfo.cell_count = cell_count; hashent->muxinfo.cell_count = cell_count;
hashent->muxinfo.direction = direction; hashent->muxinfo.direction = direction;
/* Allocate policy specific circuit data if we need it */ /* Allocate policy specific circuit data if we need it */
if (cmux->policy && cmux->policy->alloc_circ_data) { if (cmux->policy->alloc_circ_data) {
/* Assert that we have the means to free policy-specific data */ /* Assert that we have the means to free policy-specific data */
tor_assert(cmux->policy->free_circ_data); tor_assert(cmux->policy->free_circ_data);
/* Allocate it */ /* Allocate it */
@ -1053,25 +902,14 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
if (direction == CELL_DIRECTION_OUT) circ->n_mux = cmux; if (direction == CELL_DIRECTION_OUT) circ->n_mux = cmux;
else TO_OR_CIRCUIT(circ)->p_mux = cmux; else TO_OR_CIRCUIT(circ)->p_mux = cmux;
/* Make sure the next/prev pointers are NULL */
if (direction == CELL_DIRECTION_OUT) {
circ->next_active_on_n_chan = NULL;
circ->prev_active_on_n_chan = NULL;
} else {
TO_OR_CIRCUIT(circ)->next_active_on_p_chan = NULL;
TO_OR_CIRCUIT(circ)->prev_active_on_p_chan = NULL;
}
/* Update counters */ /* Update counters */
++(cmux->n_circuits); ++(cmux->n_circuits);
if (cell_count > 0) { if (cell_count > 0) {
++(cmux->n_active_circuits); ++(cmux->n_active_circuits);
circuitmux_make_circuit_active(cmux, circ, direction); circuitmux_make_circuit_active(cmux, circ);
} }
cmux->n_cells += cell_count; cmux->n_cells += cell_count;
} }
circuitmux_assert_okay_paranoid(cmux);
} }
/** /**
@ -1095,7 +933,6 @@ circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
tor_assert(cmux); tor_assert(cmux);
tor_assert(cmux->chanid_circid_map); tor_assert(cmux->chanid_circid_map);
tor_assert(circ); tor_assert(circ);
circuitmux_assert_okay_paranoid(cmux);
/* See if we have it for n_chan/n_circ_id */ /* See if we have it for n_chan/n_circ_id */
if (circ->n_chan) { if (circ->n_chan) {
@ -1133,7 +970,7 @@ circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
if (hashent->muxinfo.cell_count > 0) { if (hashent->muxinfo.cell_count > 0) {
--(cmux->n_active_circuits); --(cmux->n_active_circuits);
/* This does policy notifies, so comes before freeing policy data */ /* This does policy notifies, so comes before freeing policy data */
circuitmux_make_circuit_inactive(cmux, circ, last_searched_direction); circuitmux_make_circuit_inactive(cmux, circ);
} }
cmux->n_cells -= hashent->muxinfo.cell_count; cmux->n_cells -= hashent->muxinfo.cell_count;
@ -1162,8 +999,6 @@ circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
/* Free the hash entry */ /* Free the hash entry */
tor_free(hashent); tor_free(hashent);
} }
circuitmux_assert_okay_paranoid(cmux);
} }
/** /**
@ -1172,94 +1007,22 @@ circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
*/ */
static void static void
circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ, circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ)
cell_direction_t direction)
{ {
circuit_t **next_active = NULL, **prev_active = NULL, **next_prev = NULL;
circuitmux_t *circuit_cmux = NULL;
chanid_circid_muxinfo_t *hashent = NULL;
channel_t *chan = NULL;
circid_t circ_id;
int already_active;
tor_assert(cmux); tor_assert(cmux);
tor_assert(cmux->policy);
tor_assert(circ); tor_assert(circ);
tor_assert(direction == CELL_DIRECTION_OUT ||
direction == CELL_DIRECTION_IN);
/*
* Don't circuitmux_assert_okay_paranoid(cmux) here because the cell count
* already got changed and we have to update the list for it to be consistent
* again.
*/
/* Get the right set of active list links for this direction */
if (direction == CELL_DIRECTION_OUT) {
next_active = &(circ->next_active_on_n_chan);
prev_active = &(circ->prev_active_on_n_chan);
circuit_cmux = circ->n_mux;
chan = circ->n_chan;
circ_id = circ->n_circ_id;
} else {
next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux;
chan = TO_OR_CIRCUIT(circ)->p_chan;
circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
}
/* Assert that it is attached to this mux and a channel */
tor_assert(cmux == circuit_cmux);
tor_assert(chan != NULL);
/*
* Check if the circuit really was inactive; if it's active, at least one
* of the next_active and prev_active pointers will not be NULL, or this
* circuit will be either the head or tail of the list for this cmux.
*/
already_active = (*prev_active != NULL || *next_active != NULL ||
cmux->active_circuits_head == circ ||
cmux->active_circuits_tail == circ);
/* If we're already active, log a warning and finish */
if (already_active) {
log_warn(LD_CIRC,
"Circuit %u on channel " U64_FORMAT " was already active",
(unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier));
return;
}
/*
* This is going at the head of the list; if the old head is not NULL,
* then its prev pointer should point to this.
*/
*next_active = cmux->active_circuits_head; /* Next is old head */
*prev_active = NULL; /* Prev is NULL (this will be the head) */
if (cmux->active_circuits_head) {
/* The list had an old head; update its prev pointer */
next_prev =
circuitmux_prev_active_circ_p(cmux, cmux->active_circuits_head);
tor_assert(next_prev);
*next_prev = circ;
} else {
/* The list was empty; this becomes the tail as well */
cmux->active_circuits_tail = circ;
}
/* This becomes the new head of the list */
cmux->active_circuits_head = circ;
/* Policy-specific notification */ /* Policy-specific notification */
if (cmux->policy && if (cmux->policy->notify_circ_active) {
cmux->policy->notify_circ_active) {
/* Okay, we need to check the circuit for policy data now */ /* Okay, we need to check the circuit for policy data now */
hashent = circuitmux_find_map_entry(cmux, circ); chanid_circid_muxinfo_t *hashent = circuitmux_find_map_entry(cmux, circ);
/* We should have found something */ /* We should have found something */
tor_assert(hashent); tor_assert(hashent);
/* Notify */ /* Notify */
cmux->policy->notify_circ_active(cmux, cmux->policy_data, cmux->policy->notify_circ_active(cmux, cmux->policy_data,
circ, hashent->muxinfo.policy_data); circ, hashent->muxinfo.policy_data);
} }
circuitmux_assert_okay_paranoid(cmux);
} }
/** /**
@ -1268,112 +1031,22 @@ circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
*/ */
static void static void
circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ, circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ)
cell_direction_t direction)
{ {
circuit_t **next_active = NULL, **prev_active = NULL;
circuit_t **next_prev = NULL, **prev_next = NULL;
circuitmux_t *circuit_cmux = NULL;
chanid_circid_muxinfo_t *hashent = NULL;
channel_t *chan = NULL;
circid_t circ_id;
int already_inactive;
tor_assert(cmux); tor_assert(cmux);
tor_assert(cmux->policy);
tor_assert(circ); tor_assert(circ);
tor_assert(direction == CELL_DIRECTION_OUT ||
direction == CELL_DIRECTION_IN);
/*
* Don't circuitmux_assert_okay_paranoid(cmux) here because the cell count
* already got changed and we have to update the list for it to be consistent
* again.
*/
/* Get the right set of active list links for this direction */
if (direction == CELL_DIRECTION_OUT) {
next_active = &(circ->next_active_on_n_chan);
prev_active = &(circ->prev_active_on_n_chan);
circuit_cmux = circ->n_mux;
chan = circ->n_chan;
circ_id = circ->n_circ_id;
} else {
next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux;
chan = TO_OR_CIRCUIT(circ)->p_chan;
circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
}
/* Assert that it is attached to this mux and a channel */
tor_assert(cmux == circuit_cmux);
tor_assert(chan != NULL);
/*
* Check if the circuit really was active; if it's inactive, the
* next_active and prev_active pointers will be NULL and this circuit
* will not be the head or tail of the list for this cmux.
*/
already_inactive = (*prev_active == NULL && *next_active == NULL &&
cmux->active_circuits_head != circ &&
cmux->active_circuits_tail != circ);
/* If we're already inactive, log a warning and finish */
if (already_inactive) {
log_warn(LD_CIRC,
"Circuit %d on channel " U64_FORMAT " was already inactive",
(unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier));
return;
}
/* Remove from the list; first get next_prev and prev_next */
if (*next_active) {
/*
* If there's a next circuit, its previous circuit becomes this
* circuit's previous circuit.
*/
next_prev = circuitmux_prev_active_circ_p(cmux, *next_active);
} else {
/* Else, the tail becomes this circuit's previous circuit */
next_prev = &(cmux->active_circuits_tail);
}
/* Got next_prev, now prev_next */
if (*prev_active) {
/*
* If there's a previous circuit, its next circuit becomes this circuit's
* next circuit.
*/
prev_next = circuitmux_next_active_circ_p(cmux, *prev_active);
} else {
/* Else, the head becomes this circuit's next circuit */
prev_next = &(cmux->active_circuits_head);
}
/* Assert that we got sensible values for the next/prev pointers */
tor_assert(next_prev != NULL);
tor_assert(prev_next != NULL);
/* Update the next/prev pointers - this removes circ from the list */
*next_prev = *prev_active;
*prev_next = *next_active;
/* Now null out prev_active/next_active */
*prev_active = NULL;
*next_active = NULL;
/* Policy-specific notification */ /* Policy-specific notification */
if (cmux->policy && if (cmux->policy->notify_circ_inactive) {
cmux->policy->notify_circ_inactive) {
/* Okay, we need to check the circuit for policy data now */ /* Okay, we need to check the circuit for policy data now */
hashent = circuitmux_find_map_entry(cmux, circ); chanid_circid_muxinfo_t *hashent = circuitmux_find_map_entry(cmux, circ);
/* We should have found something */ /* We should have found something */
tor_assert(hashent); tor_assert(hashent);
/* Notify */ /* Notify */
cmux->policy->notify_circ_inactive(cmux, cmux->policy_data, cmux->policy->notify_circ_inactive(cmux, cmux->policy_data,
circ, hashent->muxinfo.policy_data); circ, hashent->muxinfo.policy_data);
} }
circuitmux_assert_okay_paranoid(cmux);
} }
/** /**
@ -1400,8 +1073,6 @@ circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
tor_assert(cmux); tor_assert(cmux);
tor_assert(circ); tor_assert(circ);
circuitmux_assert_okay_paranoid(cmux);
/* Search for this circuit's entry */ /* Search for this circuit's entry */
hashent = circuitmux_find_map_entry(cmux, circ); hashent = circuitmux_find_map_entry(cmux, circ);
/* Assert that we found one */ /* Assert that we found one */
@ -1412,7 +1083,7 @@ circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
cmux->n_cells += n_cells; cmux->n_cells += n_cells;
/* Do we need to notify a cmux policy? */ /* Do we need to notify a cmux policy? */
if (cmux->policy && cmux->policy->notify_set_n_cells) { if (cmux->policy->notify_set_n_cells) {
/* Call notify_set_n_cells */ /* Call notify_set_n_cells */
cmux->policy->notify_set_n_cells(cmux, cmux->policy->notify_set_n_cells(cmux,
cmux->policy_data, cmux->policy_data,
@ -1428,21 +1099,15 @@ circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
if (hashent->muxinfo.cell_count > 0 && n_cells == 0) { if (hashent->muxinfo.cell_count > 0 && n_cells == 0) {
--(cmux->n_active_circuits); --(cmux->n_active_circuits);
hashent->muxinfo.cell_count = n_cells; hashent->muxinfo.cell_count = n_cells;
circuitmux_make_circuit_inactive(cmux, circ, hashent->muxinfo.direction); circuitmux_make_circuit_inactive(cmux, circ);
/* Is the old cell count == 0 and the new cell count > 0 ? */ /* Is the old cell count == 0 and the new cell count > 0 ? */
} else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) { } else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) {
++(cmux->n_active_circuits); ++(cmux->n_active_circuits);
hashent->muxinfo.cell_count = n_cells; hashent->muxinfo.cell_count = n_cells;
circuitmux_make_circuit_active(cmux, circ, hashent->muxinfo.direction); circuitmux_make_circuit_active(cmux, circ);
} else { } else {
/*
* Update the entry cell count like this so we can put a
* circuitmux_assert_okay_paranoid inside make_circuit_(in)active() too.
*/
hashent->muxinfo.cell_count = n_cells; hashent->muxinfo.cell_count = n_cells;
} }
circuitmux_assert_okay_paranoid(cmux);
} }
/* /*
@ -1468,6 +1133,9 @@ circuitmux_get_first_active_circuit(circuitmux_t *cmux,
circuit_t *circ = NULL; circuit_t *circ = NULL;
tor_assert(cmux); tor_assert(cmux);
tor_assert(cmux->policy);
/* This callback is mandatory. */
tor_assert(cmux->policy->pick_active_circuit);
tor_assert(destroy_queue_out); tor_assert(destroy_queue_out);
*destroy_queue_out = NULL; *destroy_queue_out = NULL;
@ -1486,14 +1154,7 @@ circuitmux_get_first_active_circuit(circuitmux_t *cmux,
/* We also must have a cell available for this to be the case */ /* We also must have a cell available for this to be the case */
tor_assert(cmux->n_cells > 0); tor_assert(cmux->n_cells > 0);
/* Do we have a policy-provided circuit selector? */ /* Do we have a policy-provided circuit selector? */
if (cmux->policy && cmux->policy->pick_active_circuit) { circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data);
circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data);
}
/* Fall back on the head of the active circuits list */
if (!circ) {
tor_assert(cmux->active_circuits_head);
circ = cmux->active_circuits_head;
}
cmux->last_cell_was_destroy = 0; cmux->last_cell_was_destroy = 0;
} else { } else {
tor_assert(cmux->n_cells == 0); tor_assert(cmux->n_cells == 0);
@ -1517,7 +1178,6 @@ circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
tor_assert(cmux); tor_assert(cmux);
tor_assert(circ); tor_assert(circ);
circuitmux_assert_okay_paranoid(cmux);
if (n_cells == 0) return; if (n_cells == 0) return;
@ -1544,17 +1204,11 @@ circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
/* Adjust the mux cell counter */ /* Adjust the mux cell counter */
cmux->n_cells -= n_cells; cmux->n_cells -= n_cells;
/* If we aren't making it inactive later, move it to the tail of the list */
if (!becomes_inactive) {
circuitmux_move_active_circ_to_tail(cmux, circ,
hashent->muxinfo.direction);
}
/* /*
* We call notify_xmit_cells() before making the circuit inactive if needed, * We call notify_xmit_cells() before making the circuit inactive if needed,
* so the policy can always count on this coming in on an active circuit. * so the policy can always count on this coming in on an active circuit.
*/ */
if (cmux->policy && cmux->policy->notify_xmit_cells) { if (cmux->policy->notify_xmit_cells) {
cmux->policy->notify_xmit_cells(cmux, cmux->policy_data, circ, cmux->policy->notify_xmit_cells(cmux, cmux->policy_data, circ,
hashent->muxinfo.policy_data, hashent->muxinfo.policy_data,
n_cells); n_cells);
@ -1566,10 +1220,8 @@ circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
*/ */
if (becomes_inactive) { if (becomes_inactive) {
--(cmux->n_active_circuits); --(cmux->n_active_circuits);
circuitmux_make_circuit_inactive(cmux, circ, hashent->muxinfo.direction); circuitmux_make_circuit_inactive(cmux, circ);
} }
circuitmux_assert_okay_paranoid(cmux);
} }
/** /**
@ -1592,282 +1244,6 @@ circuitmux_notify_xmit_destroy(circuitmux_t *cmux)
I64_PRINTF_ARG(global_destroy_ctr)); I64_PRINTF_ARG(global_destroy_ctr));
} }
/*
* Circuitmux consistency checking assertions
*/
/**
* Check that circuitmux data structures are consistent and fail with an
* assert if not.
*/
void
circuitmux_assert_okay(circuitmux_t *cmux)
{
tor_assert(cmux);
/*
* Pass 1: iterate the hash table; for each entry:
* a) Check that the circuit has this cmux for n_mux or p_mux
* b) If the cell_count is > 0, set the mark bit; otherwise clear it
* c) Also check activeness (cell_count > 0 should be active)
* d) Count the number of circuits, active circuits and queued cells
* and at the end check that they match the counters in the cmux.
*
* Pass 2: iterate the active circuits list; for each entry,
* make sure the circuit is attached to this mux and appears
* in the hash table. Make sure the mark bit is 1, and clear
* it in the hash table entry. Consistency-check the linked
* list pointers.
*
* Pass 3: iterate the hash table again; assert if any active circuits
* (mark bit set to 1) are discovered that weren't cleared in pass 2
* (don't appear in the linked list).
*/
circuitmux_assert_okay_pass_one(cmux);
circuitmux_assert_okay_pass_two(cmux);
circuitmux_assert_okay_pass_three(cmux);
}
/**
* Do the first pass of circuitmux_assert_okay(); see the comment in that
* function.
*/
static void
circuitmux_assert_okay_pass_one(circuitmux_t *cmux)
{
chanid_circid_muxinfo_t **i = NULL;
uint64_t chan_id;
channel_t *chan;
circid_t circ_id;
circuit_t *circ;
or_circuit_t *or_circ;
circuit_t **next_p, **prev_p;
unsigned int n_circuits, n_active_circuits, n_cells;
tor_assert(cmux);
tor_assert(cmux->chanid_circid_map);
/* Reset the counters */
n_circuits = n_active_circuits = n_cells = 0;
/* Start iterating the hash table */
i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
while (i) {
/* Assert that the hash table entry isn't null */
tor_assert(*i);
/* Get the channel and circuit id */
chan_id = (*i)->chan_id;
circ_id = (*i)->circ_id;
/* Find the channel and circuit, assert that they exist */
chan = channel_find_by_global_id(chan_id);
tor_assert(chan);
circ = circuit_get_by_circid_channel_even_if_marked(circ_id, chan);
tor_assert(circ);
/* Assert that we know which direction this is going */
tor_assert((*i)->muxinfo.direction == CELL_DIRECTION_OUT ||
(*i)->muxinfo.direction == CELL_DIRECTION_IN);
if ((*i)->muxinfo.direction == CELL_DIRECTION_OUT) {
/* We should be n_mux on this circuit */
tor_assert(cmux == circ->n_mux);
tor_assert(chan == circ->n_chan);
/* Get next and prev for next test */
next_p = &(circ->next_active_on_n_chan);
prev_p = &(circ->prev_active_on_n_chan);
} else {
/* This should be an or_circuit_t and we should be p_mux */
or_circ = TO_OR_CIRCUIT(circ);
tor_assert(cmux == or_circ->p_mux);
tor_assert(chan == or_circ->p_chan);
/* Get next and prev for next test */
next_p = &(or_circ->next_active_on_p_chan);
prev_p = &(or_circ->prev_active_on_p_chan);
}
/*
* Should this circuit be active? I.e., does the mux know about > 0
* cells on it?
*/
const int circ_is_active = ((*i)->muxinfo.cell_count > 0);
/* It should be in the linked list iff it's active */
if (circ_is_active) {
/* Either we have a next link or we are the tail */
tor_assert(*next_p || (circ == cmux->active_circuits_tail));
/* Either we have a prev link or we are the head */
tor_assert(*prev_p || (circ == cmux->active_circuits_head));
/* Increment the active circuits counter */
++n_active_circuits;
} else {
/* Shouldn't be in list, so no next or prev link */
tor_assert(!(*next_p));
tor_assert(!(*prev_p));
/* And can't be head or tail */
tor_assert(circ != cmux->active_circuits_head);
tor_assert(circ != cmux->active_circuits_tail);
}
/* Increment the circuits counter */
++n_circuits;
/* Adjust the cell counter */
n_cells += (*i)->muxinfo.cell_count;
/* Set the mark bit to circ_is_active */
(*i)->muxinfo.mark = circ_is_active;
/* Advance to the next entry */
i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
}
/* Now check the counters */
tor_assert(n_cells == cmux->n_cells);
tor_assert(n_circuits == cmux->n_circuits);
tor_assert(n_active_circuits == cmux->n_active_circuits);
}
/**
* Do the second pass of circuitmux_assert_okay(); see the comment in that
* function.
*/
static void
circuitmux_assert_okay_pass_two(circuitmux_t *cmux)
{
circuit_t *curr_circ, *prev_circ = NULL, *next_circ;
or_circuit_t *curr_or_circ;
uint64_t curr_chan_id;
circid_t curr_circ_id;
circuit_t **next_p, **prev_p;
channel_t *chan;
unsigned int n_active_circuits = 0;
chanid_circid_muxinfo_t search, *hashent = NULL;
tor_assert(cmux);
tor_assert(cmux->chanid_circid_map);
/*
* Walk the linked list of active circuits in cmux; keep track of the
* previous circuit seen for consistency checking purposes. Count them
* to make sure the number in the linked list matches
* cmux->n_active_circuits.
*/
curr_circ = cmux->active_circuits_head;
while (curr_circ) {
/* Reset some things */
chan = NULL;
curr_or_circ = NULL;
next_circ = NULL;
next_p = prev_p = NULL;
cell_direction_t direction;
/* Figure out if this is n_mux or p_mux */
if (cmux == curr_circ->n_mux) {
/* Get next_p and prev_p */
next_p = &(curr_circ->next_active_on_n_chan);
prev_p = &(curr_circ->prev_active_on_n_chan);
/* Get the channel */
chan = curr_circ->n_chan;
/* Get the circuit id */
curr_circ_id = curr_circ->n_circ_id;
/* Remember the direction */
direction = CELL_DIRECTION_OUT;
} else {
/* We must be p_mux and this must be an or_circuit_t */
curr_or_circ = TO_OR_CIRCUIT(curr_circ);
tor_assert(cmux == curr_or_circ->p_mux);
/* Get next_p and prev_p */
next_p = &(curr_or_circ->next_active_on_p_chan);
prev_p = &(curr_or_circ->prev_active_on_p_chan);
/* Get the channel */
chan = curr_or_circ->p_chan;
/* Get the circuit id */
curr_circ_id = curr_or_circ->p_circ_id;
/* Remember the direction */
direction = CELL_DIRECTION_IN;
}
/* Assert that we got a channel and get the channel ID */
tor_assert(chan);
curr_chan_id = chan->global_identifier;
/* Assert that prev_p points to last circuit we saw */
tor_assert(*prev_p == prev_circ);
/* If that's NULL, assert that we are the head */
if (!(*prev_p)) tor_assert(curr_circ == cmux->active_circuits_head);
/* Get the next circuit */
next_circ = *next_p;
/* If it's NULL, assert that we are the tail */
if (!(*next_p)) tor_assert(curr_circ == cmux->active_circuits_tail);
/* Now find the hash table entry for this circuit */
search.chan_id = curr_chan_id;
search.circ_id = curr_circ_id;
hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
&search);
/* Assert that we have one */
tor_assert(hashent);
/* Assert that the direction matches */
tor_assert(direction == hashent->muxinfo.direction);
/* Assert that the hash entry got marked in pass one */
tor_assert(hashent->muxinfo.mark);
/* Clear the mark */
hashent->muxinfo.mark = 0;
/* Increment the counter */
++n_active_circuits;
/* Advance to the next active circuit and update prev_circ */
prev_circ = curr_circ;
curr_circ = next_circ;
}
/* Assert that the counter matches the cmux */
tor_assert(n_active_circuits == cmux->n_active_circuits);
}
/**
* Do the third pass of circuitmux_assert_okay(); see the comment in that
* function.
*/
static void
circuitmux_assert_okay_pass_three(circuitmux_t *cmux)
{
chanid_circid_muxinfo_t **i = NULL;
tor_assert(cmux);
tor_assert(cmux->chanid_circid_map);
/* Start iterating the hash table */
i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
/* Advance through each entry */
while (i) {
/* Assert that it isn't null */
tor_assert(*i);
/*
* Assert that this entry is not marked - i.e., that either we didn't
* think it should be active in pass one or we saw it in the active
* circuits linked list.
*/
tor_assert(!((*i)->muxinfo.mark));
/* Advance to the next entry */
i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
}
}
/*DOCDOC */ /*DOCDOC */
void void
circuitmux_append_destroy_cell(channel_t *chan, circuitmux_append_destroy_cell(channel_t *chan,

View File

@ -223,8 +223,6 @@ ewma_cmp_cmux(circuitmux_t *cmux_1, circuitmux_policy_data_t *pol_data_1,
* has value ewma_scale_factor ** N.) * has value ewma_scale_factor ** N.)
*/ */
static double ewma_scale_factor = 0.1; static double ewma_scale_factor = 0.1;
/* DOCDOC ewma_enabled */
static int ewma_enabled = 0;
/*** EWMA circuitmux_policy_t method table ***/ /*** EWMA circuitmux_policy_t method table ***/
@ -243,6 +241,13 @@ circuitmux_policy_t ewma_policy = {
/*** EWMA method implementations using the below EWMA helper functions ***/ /*** EWMA method implementations using the below EWMA helper functions ***/
/** Compute and return the current cell_ewma tick. */
static inline unsigned int
cell_ewma_get_tick(void)
{
return ((unsigned)approx_time() / EWMA_TICK_LEN);
}
/** /**
* Allocate an ewma_policy_data_t and upcast it to a circuitmux_policy_data_t; * Allocate an ewma_policy_data_t and upcast it to a circuitmux_policy_data_t;
* this is called when setting the policy on a circuitmux_t to ewma_policy. * this is called when setting the policy on a circuitmux_t to ewma_policy.
@ -612,59 +617,79 @@ cell_ewma_tick_from_timeval(const struct timeval *now,
return res; return res;
} }
/** Tell the caller whether ewma_enabled is set */ /* Default value for the CircuitPriorityHalflifeMsec consensus parameter in
int * msec. */
cell_ewma_enabled(void) #define CMUX_PRIORITY_HALFLIFE_MSEC_DEFAULT 30000
{ /* Minimum and maximum value for the CircuitPriorityHalflifeMsec consensus
return ewma_enabled; * parameter. */
} #define CMUX_PRIORITY_HALFLIFE_MSEC_MIN 1
#define CMUX_PRIORITY_HALFLIFE_MSEC_MAX INT32_MAX
/** Compute and return the current cell_ewma tick. */ /* Return the value of the circuit priority halflife from the options if
unsigned int * available or else from the consensus (in that order). If none can be found,
cell_ewma_get_tick(void) * a default value is returned.
*
* The source_msg points to a string describing from where the value was
* picked so it can be used for logging. */
static double
get_circuit_priority_halflife(const or_options_t *options,
const networkstatus_t *consensus,
const char **source_msg)
{ {
return ((unsigned)approx_time() / EWMA_TICK_LEN); int32_t halflife_ms;
double halflife;
/* Compute the default value now. We might need it. */
double halflife_default =
((double) CMUX_PRIORITY_HALFLIFE_MSEC_DEFAULT) / 1000.0;
/* Try to get it from configuration file first. */
if (options && options->CircuitPriorityHalflife < EPSILON) {
halflife = options->CircuitPriorityHalflife;
*source_msg = "CircuitPriorityHalflife in configuration";
goto end;
}
/* Try to get the msec value from the consensus. */
halflife_ms = networkstatus_get_param(consensus,
"CircuitPriorityHalflifeMsec",
CMUX_PRIORITY_HALFLIFE_MSEC_DEFAULT,
CMUX_PRIORITY_HALFLIFE_MSEC_MIN,
CMUX_PRIORITY_HALFLIFE_MSEC_MAX);
halflife = ((double) halflife_ms) / 1000.0;
*source_msg = "CircuitPriorityHalflifeMsec in consensus";
end:
/* We should never go below the EPSILON else we would consider it disabled
* and we can't have that. */
if (halflife < EPSILON) {
log_warn(LD_CONFIG, "CircuitPriorityHalflife is too small (%f). "
"Adjusting to the smallest value allowed: %f.",
halflife, halflife_default);
halflife = halflife_default;
}
return halflife;
} }
/** Adjust the global cell scale factor based on <b>options</b> */ /** Adjust the global cell scale factor based on <b>options</b> */
void void
cell_ewma_set_scale_factor(const or_options_t *options, cmux_ewma_set_options(const or_options_t *options,
const networkstatus_t *consensus) const networkstatus_t *consensus)
{ {
int32_t halflife_ms;
double halflife; double halflife;
const char *source; const char *source;
if (options && options->CircuitPriorityHalflife >= -EPSILON) {
halflife = options->CircuitPriorityHalflife;
source = "CircuitPriorityHalflife in configuration";
} else if (consensus && (halflife_ms = networkstatus_get_param(
consensus, "CircuitPriorityHalflifeMsec",
-1, -1, INT32_MAX)) >= 0) {
halflife = ((double)halflife_ms)/1000.0;
source = "CircuitPriorityHalflifeMsec in consensus";
} else {
halflife = EWMA_DEFAULT_HALFLIFE;
source = "Default value";
}
if (halflife <= EPSILON) { /* Both options and consensus can be NULL. This assures us to either get a
/* The cell EWMA algorithm is disabled. */ * valid configured value or the default one. */
ewma_scale_factor = 0.1; halflife = get_circuit_priority_halflife(options, consensus, &source);
ewma_enabled = 0;
log_info(LD_OR, /* convert halflife into halflife-per-tick. */
"Disabled cell_ewma algorithm because of value in %s", halflife /= EWMA_TICK_LEN;
source); /* compute per-tick scale factor. */
} else { ewma_scale_factor = exp( LOG_ONEHALF / halflife );
/* convert halflife into halflife-per-tick. */ log_info(LD_OR,
halflife /= EWMA_TICK_LEN; "Enabled cell_ewma algorithm because of value in %s; "
/* compute per-tick scale factor. */ "scale factor is %f per %d seconds",
ewma_scale_factor = exp( LOG_ONEHALF / halflife ); source, ewma_scale_factor, EWMA_TICK_LEN);
ewma_enabled = 1;
log_info(LD_OR,
"Enabled cell_ewma algorithm because of value in %s; "
"scale factor is %f per %d seconds",
source, ewma_scale_factor, EWMA_TICK_LEN);
}
} }
/** Return the multiplier necessary to convert the value of a cell sent in /** Return the multiplier necessary to convert the value of a cell sent in

View File

@ -12,13 +12,12 @@
#include "or.h" #include "or.h"
#include "circuitmux.h" #include "circuitmux.h"
/* The public EWMA policy callbacks object. */
extern circuitmux_policy_t ewma_policy; extern circuitmux_policy_t ewma_policy;
/* Externally visible EWMA functions */ /* Externally visible EWMA functions */
int cell_ewma_enabled(void); void cmux_ewma_set_options(const or_options_t *options,
unsigned int cell_ewma_get_tick(void); const networkstatus_t *consensus);
void cell_ewma_set_scale_factor(const or_options_t *options,
const networkstatus_t *consensus);
#endif /* !defined(TOR_CIRCUITMUX_EWMA_H) */ #endif /* !defined(TOR_CIRCUITMUX_EWMA_H) */

View File

@ -264,7 +264,7 @@ static config_var_t option_vars_[] = {
OBSOLETE("CircuitIdleTimeout"), OBSOLETE("CircuitIdleTimeout"),
V(CircuitsAvailableTimeout, INTERVAL, "0"), V(CircuitsAvailableTimeout, INTERVAL, "0"),
V(CircuitStreamTimeout, INTERVAL, "0"), V(CircuitStreamTimeout, INTERVAL, "0"),
V(CircuitPriorityHalflife, DOUBLE, "-100.0"), /*negative:'Use default'*/ V(CircuitPriorityHalflife, DOUBLE, "-1.0"), /*negative:'Use default'*/
V(ClientDNSRejectInternalAddresses, BOOL,"1"), V(ClientDNSRejectInternalAddresses, BOOL,"1"),
V(ClientOnly, BOOL, "0"), V(ClientOnly, BOOL, "0"),
V(ClientPreferIPv6ORPort, AUTOBOOL, "auto"), V(ClientPreferIPv6ORPort, AUTOBOOL, "auto"),
@ -1791,7 +1791,6 @@ options_act(const or_options_t *old_options)
char *msg=NULL; char *msg=NULL;
const int transition_affects_workers = const int transition_affects_workers =
old_options && options_transition_affects_workers(old_options, options); old_options && options_transition_affects_workers(old_options, options);
int old_ewma_enabled;
const int transition_affects_guards = const int transition_affects_guards =
old_options && options_transition_affects_guards(old_options, options); old_options && options_transition_affects_guards(old_options, options);
@ -2065,16 +2064,8 @@ options_act(const or_options_t *old_options)
if (accounting_is_enabled(options)) if (accounting_is_enabled(options))
configure_accounting(time(NULL)); configure_accounting(time(NULL));
old_ewma_enabled = cell_ewma_enabled();
/* Change the cell EWMA settings */ /* Change the cell EWMA settings */
cell_ewma_set_scale_factor(options, networkstatus_get_latest_consensus()); cmux_ewma_set_options(options, networkstatus_get_latest_consensus());
/* If we just enabled ewma, set the cmux policy on all active channels */
if (cell_ewma_enabled() && !old_ewma_enabled) {
channel_set_cmux_policy_everywhere(&ewma_policy);
} else if (!cell_ewma_enabled() && old_ewma_enabled) {
/* Turn it off everywhere */
channel_set_cmux_policy_everywhere(NULL);
}
/* Update the BridgePassword's hashed version as needed. We store this as a /* Update the BridgePassword's hashed version as needed. We store this as a
* digest so that we can do side-channel-proof comparisons on it. * digest so that we can do side-channel-proof comparisons on it.

View File

@ -1768,7 +1768,6 @@ networkstatus_set_current_consensus(const char *consensus,
consensus_waiting_for_certs_t *waiting = NULL; consensus_waiting_for_certs_t *waiting = NULL;
time_t current_valid_after = 0; time_t current_valid_after = 0;
int free_consensus = 1; /* Free 'c' at the end of the function */ int free_consensus = 1; /* Free 'c' at the end of the function */
int old_ewma_enabled;
int checked_protocols_already = 0; int checked_protocols_already = 0;
if (flav < 0) { if (flav < 0) {
@ -2001,17 +2000,8 @@ networkstatus_set_current_consensus(const char *consensus,
/* XXXXNM Microdescs: needs a non-ns variant. ???? NM*/ /* XXXXNM Microdescs: needs a non-ns variant. ???? NM*/
update_consensus_networkstatus_fetch_time(now); update_consensus_networkstatus_fetch_time(now);
/* Update ewma and adjust policy if needed; first cache the old value */
old_ewma_enabled = cell_ewma_enabled();
/* Change the cell EWMA settings */ /* Change the cell EWMA settings */
cell_ewma_set_scale_factor(options, c); cmux_ewma_set_options(options, c);
/* If we just enabled ewma, set the cmux policy on all active channels */
if (cell_ewma_enabled() && !old_ewma_enabled) {
channel_set_cmux_policy_everywhere(&ewma_policy);
} else if (!cell_ewma_enabled() && old_ewma_enabled) {
/* Turn it off everywhere */
channel_set_cmux_policy_everywhere(NULL);
}
/* XXXX this call might be unnecessary here: can changing the /* XXXX this call might be unnecessary here: can changing the
* current consensus really alter our view of any OR's rate limits? */ * current consensus really alter our view of any OR's rate limits? */

View File

@ -3162,15 +3162,6 @@ typedef struct circuit_t {
/** Index in smartlist of all circuits (global_circuitlist). */ /** Index in smartlist of all circuits (global_circuitlist). */
int global_circuitlist_idx; int global_circuitlist_idx;
/** Next circuit in the doubly-linked ring of circuits waiting to add
* cells to n_conn. NULL if we have no cells pending, or if we're not
* linked to an OR connection. */
struct circuit_t *next_active_on_n_chan;
/** Previous circuit in the doubly-linked ring of circuits waiting to add
* cells to n_conn. NULL if we have no cells pending, or if we're not
* linked to an OR connection. */
struct circuit_t *prev_active_on_n_chan;
/** Various statistics about cells being added to or removed from this /** Various statistics about cells being added to or removed from this
* circuit's queues; used only if CELL_STATS events are enabled and * circuit's queues; used only if CELL_STATS events are enabled and
* cleared after being sent to control port. */ * cleared after being sent to control port. */
@ -3450,14 +3441,6 @@ struct onion_queue_t;
typedef struct or_circuit_t { typedef struct or_circuit_t {
circuit_t base_; circuit_t base_;
/** Next circuit in the doubly-linked ring of circuits waiting to add
* cells to p_chan. NULL if we have no cells pending, or if we're not
* linked to an OR connection. */
struct circuit_t *next_active_on_p_chan;
/** Previous circuit in the doubly-linked ring of circuits waiting to add
* cells to p_chan. NULL if we have no cells pending, or if we're not
* linked to an OR connection. */
struct circuit_t *prev_active_on_p_chan;
/** Pointer to an entry on the onion queue, if this circuit is waiting for a /** Pointer to an entry on the onion queue, if this circuit is waiting for a
* chance to give an onionskin to a cpuworker. Used only in onion.c */ * chance to give an onionskin to a cpuworker. Used only in onion.c */
struct onion_queue_t *onionqueue_entry; struct onion_queue_t *onionqueue_entry;

View File

@ -2399,13 +2399,6 @@ circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint)
} }
} }
#ifdef ACTIVE_CIRCUITS_PARANOIA
#define assert_cmux_ok_paranoid(chan) \
assert_circuit_mux_okay(chan)
#else
#define assert_cmux_ok_paranoid(chan)
#endif /* defined(ACTIVE_CIRCUITS_PARANOIA) */
/** The total number of cells we have allocated. */ /** The total number of cells we have allocated. */
static size_t total_cells_allocated = 0; static size_t total_cells_allocated = 0;
@ -2693,16 +2686,12 @@ update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction,
} }
tor_assert(circuitmux_attached_circuit_direction(cmux, circ) == direction); tor_assert(circuitmux_attached_circuit_direction(cmux, circ) == direction);
assert_cmux_ok_paranoid(chan);
/* Update the number of cells we have for the circuit mux */ /* Update the number of cells we have for the circuit mux */
if (direction == CELL_DIRECTION_OUT) { if (direction == CELL_DIRECTION_OUT) {
circuitmux_set_num_cells(cmux, circ, circ->n_chan_cells.n); circuitmux_set_num_cells(cmux, circ, circ->n_chan_cells.n);
} else { } else {
circuitmux_set_num_cells(cmux, circ, or_circ->p_chan_cells.n); circuitmux_set_num_cells(cmux, circ, or_circ->p_chan_cells.n);
} }
assert_cmux_ok_paranoid(chan);
} }
/** Remove all circuits from the cmux on <b>chan</b>. /** Remove all circuits from the cmux on <b>chan</b>.
@ -2847,7 +2836,6 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
} }
/* If it returns NULL, no cells left to send */ /* If it returns NULL, no cells left to send */
if (!circ) break; if (!circ) break;
assert_cmux_ok_paranoid(chan);
if (circ->n_chan == chan) { if (circ->n_chan == chan) {
queue = &circ->n_chan_cells; queue = &circ->n_chan_cells;
@ -2951,8 +2939,6 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
} }
/* Okay, we're done sending now */ /* Okay, we're done sending now */
assert_cmux_ok_paranoid(chan);
return n_flushed; return n_flushed;
} }
@ -3103,17 +3089,6 @@ circuit_clear_cell_queue(circuit_t *circ, channel_t *chan)
update_circuit_on_cmux(circ, direction); update_circuit_on_cmux(circ, direction);
} }
/** Fail with an assert if the circuit mux on chan is corrupt
*/
void
assert_circuit_mux_okay(channel_t *chan)
{
tor_assert(chan);
tor_assert(chan->cmux);
circuitmux_assert_okay(chan->cmux);
}
/** Return 1 if we shouldn't restart reading on this circuit, even if /** Return 1 if we shouldn't restart reading on this circuit, even if
* we get a SENDME. Else return 0. * we get a SENDME. Else return 0.
*/ */

View File

@ -76,7 +76,6 @@ void destroy_cell_queue_append(destroy_cell_queue_t *queue,
void channel_unlink_all_circuits(channel_t *chan, smartlist_t *detached_out); void channel_unlink_all_circuits(channel_t *chan, smartlist_t *detached_out);
MOCK_DECL(int, channel_flush_from_first_active_circuit, MOCK_DECL(int, channel_flush_from_first_active_circuit,
(channel_t *chan, int max)); (channel_t *chan, int max));
void assert_circuit_mux_okay(channel_t *chan);
void update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction, void update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction,
const char *file, int lineno); const char *file, int lineno);
#define update_circuit_on_cmux(circ, direction) \ #define update_circuit_on_cmux(circ, direction) \

View File

@ -281,6 +281,7 @@ new_fake_channel(void)
chan->state = CHANNEL_STATE_OPEN; chan->state = CHANNEL_STATE_OPEN;
chan->cmux = circuitmux_alloc(); chan->cmux = circuitmux_alloc();
circuitmux_set_policy(chan->cmux, &ewma_policy);
return chan; return chan;
} }
@ -575,15 +576,13 @@ test_channel_outbound_cell(void *arg)
channel_register(chan); channel_register(chan);
tt_int_op(chan->registered, OP_EQ, 1); tt_int_op(chan->registered, OP_EQ, 1);
/* Set EWMA policy so we can pick it when flushing. */ /* Set EWMA policy so we can pick it when flushing. */
channel_set_cmux_policy_everywhere(&ewma_policy); circuitmux_set_policy(chan->cmux, &ewma_policy);
tt_ptr_op(circuitmux_get_policy(chan->cmux), OP_EQ, &ewma_policy); tt_ptr_op(circuitmux_get_policy(chan->cmux), OP_EQ, &ewma_policy);
/* Register circuit to the channel circid map which will attach the circuit /* Register circuit to the channel circid map which will attach the circuit
* to the channel's cmux as well. */ * to the channel's cmux as well. */
circuit_set_n_circid_chan(TO_CIRCUIT(circ), 42, chan); circuit_set_n_circid_chan(TO_CIRCUIT(circ), 42, chan);
tt_int_op(channel_num_circuits(chan), OP_EQ, 1); tt_int_op(channel_num_circuits(chan), OP_EQ, 1);
tt_assert(!TO_CIRCUIT(circ)->next_active_on_n_chan);
tt_assert(!TO_CIRCUIT(circ)->prev_active_on_n_chan);
/* Test the cmux state. */ /* Test the cmux state. */
tt_ptr_op(TO_CIRCUIT(circ)->n_mux, OP_EQ, chan->cmux); tt_ptr_op(TO_CIRCUIT(circ)->n_mux, OP_EQ, chan->cmux);
tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)), tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)),

View File

@ -9,6 +9,7 @@
#include "channel.h" #include "channel.h"
#include "circuitbuild.h" #include "circuitbuild.h"
#include "circuitlist.h" #include "circuitlist.h"
#include "circuitmux_ewma.h"
#include "hs_circuitmap.h" #include "hs_circuitmap.h"
#include "test.h" #include "test.h"
#include "log_test_helpers.h" #include "log_test_helpers.h"

View File

@ -7,6 +7,7 @@
#include "or.h" #include "or.h"
#include "channel.h" #include "channel.h"
#include "circuitmux.h" #include "circuitmux.h"
#include "circuitmux_ewma.h"
#include "relay.h" #include "relay.h"
#include "scheduler.h" #include "scheduler.h"
#include "test.h" #include "test.h"
@ -45,6 +46,7 @@ test_cmux_destroy_cell_queue(void *arg)
cmux = circuitmux_alloc(); cmux = circuitmux_alloc();
tt_assert(cmux); tt_assert(cmux);
ch = new_fake_channel(); ch = new_fake_channel();
circuitmux_set_policy(cmux, &ewma_policy);
ch->has_queued_writes = has_queued_writes; ch->has_queued_writes = has_queued_writes;
ch->wide_circ_ids = 1; ch->wide_circ_ids = 1;