aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Dingledine <arma@torproject.org>2013-08-31 23:35:58 -0400
committerRoger Dingledine <arma@torproject.org>2013-09-04 23:21:45 -0400
commit87a18514efc7af2ee70d3f180aede5a8da95457c (patch)
treed2273b8a729f027c37ebfbe852cb5b0de06df5a5
parenta60d21a85deacad98fa04d20fb4e83b57ad191d7 (diff)
downloadtor-87a18514efc7af2ee70d3f180aede5a8da95457c.tar
tor-87a18514efc7af2ee70d3f180aede5a8da95457c.tar.gz
Separate cpuworker queues by handshake type
Now we prioritize ntor create cells over tap create cells. Starts to address ticket 9574.
-rw-r--r--src/or/onion.c53
1 files changed, 37 insertions, 16 deletions
diff --git a/src/or/onion.c b/src/or/onion.c
index d4a65022f..60dfddef2 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -28,6 +28,7 @@
typedef struct onion_queue_t {
TOR_TAILQ_ENTRY(onion_queue_t) next;
or_circuit_t *circ;
+ uint16_t handshake_type;
create_cell_t *onionskin;
time_t when_added;
} onion_queue_t;
@@ -35,11 +36,16 @@ typedef struct onion_queue_t {
/** 5 seconds on the onion queue til we just send back a destroy */
#define ONIONQUEUE_WAIT_CUTOFF 5
-/** Queue of circuits waiting for CPU workers, or NULL if the list is empty.*/
-TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t) ol_list =
- TOR_TAILQ_HEAD_INITIALIZER(ol_list);
+/** Array of queues of circuits waiting for CPU workers. An element is NULL
+ * if that queue is empty.*/
+TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t)
+ ol_list[MAX_ONION_HANDSHAKE_TYPE+1] = {
+ TOR_TAILQ_HEAD_INITIALIZER(ol_list[0]), /* tap */
+ TOR_TAILQ_HEAD_INITIALIZER(ol_list[1]), /* fast */
+ TOR_TAILQ_HEAD_INITIALIZER(ol_list[2]), /* ntor */
+};
-/** Number of entries of each type currently in ol_list. */
+/** Number of entries of each type currently in each element of ol_list[]. */
static int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1];
static void onion_queue_entry_remove(onion_queue_t *victim);
@@ -60,8 +66,7 @@ have_room_for_onionskin(uint16_t type)
int num_cpus;
uint64_t tap_usec, ntor_usec;
/* If we've got fewer than 50 entries, we always have room for one more. */
- if (ol_entries[ONION_HANDSHAKE_TYPE_TAP] +
- ol_entries[ONION_HANDSHAKE_TYPE_NTOR] < 50)
+ if (ol_entries[type] < 50)
return 1;
num_cpus = get_num_cpus(options);
/* Compute how many microseconds we'd expect to need to clear all
@@ -72,10 +77,17 @@ have_room_for_onionskin(uint16_t type)
ntor_usec = estimated_usec_for_onionskins(
ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
+
/* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue
* this. */
- if ((tap_usec + ntor_usec) / 1000 > (uint64_t)options->MaxOnionQueueDelay)
+ if (type == ONION_HANDSHAKE_TYPE_NTOR &&
+ ntor_usec / 1000 > (uint64_t)options->MaxOnionQueueDelay)
return 0;
+
+ if (type == ONION_HANDSHAKE_TYPE_TAP &&
+ (tap_usec + ntor_usec) / 1000 > (uint64_t)options->MaxOnionQueueDelay)
+ return 0;
+
#ifdef CURVE25519_ENABLED
/* If we support the ntor handshake, then don't let TAP handshakes use
* more than 2/3 of the space on the queue. */
@@ -100,6 +112,7 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
tmp = tor_malloc_zero(sizeof(onion_queue_t));
tmp->circ = circ;
+ tmp->handshake_type = onionskin->handshake_type;
tmp->onionskin = onionskin;
tmp->when_added = now;
@@ -108,7 +121,8 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
static ratelim_t last_warned =
RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL);
char *m;
- if ((m = rate_limit_log(&last_warned, approx_time()))) {
+ if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR &&
+ (m = rate_limit_log(&last_warned, approx_time()))) {
log_warn(LD_GENERAL,
"Your computer is too slow to handle this many circuit "
"creation requests! Please consider using the "
@@ -122,11 +136,11 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
++ol_entries[onionskin->handshake_type];
circ->onionqueue_entry = tmp;
- TOR_TAILQ_INSERT_TAIL(&ol_list, tmp, next);
+ TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next);
/* cull elderly requests. */
while (1) {
- onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list);
+ onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]);
if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF)
break;
@@ -140,14 +154,18 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
return 0;
}
-/** Remove the first item from ol_list and return it, or return
- * NULL if the list is empty.
+/** Remove the highest priority item from ol_list[] and return it, or
+ * return NULL if the lists are empty.
*/
or_circuit_t *
onion_next_task(create_cell_t **onionskin_out)
{
or_circuit_t *circ;
- onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list);
+
+ /* skip ol_list[ONION_HANDSHAKE_TYPE_FAST] since we know it'll be empty */
+ onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[ONION_HANDSHAKE_TYPE_NTOR]);
+ if (!head)
+ head = TOR_TAILQ_FIRST(&ol_list[ONION_HANDSHAKE_TYPE_TAP]);
if (!head)
return NULL; /* no onions pending, we're done */
@@ -186,7 +204,7 @@ onion_pending_remove(or_circuit_t *circ)
static void
onion_queue_entry_remove(onion_queue_t *victim)
{
- TOR_TAILQ_REMOVE(&ol_list, victim, next);
+ TOR_TAILQ_REMOVE(&ol_list[victim->handshake_type], victim, next);
if (victim->circ)
victim->circ->onionqueue_entry = NULL;
@@ -204,8 +222,11 @@ void
clear_pending_onions(void)
{
onion_queue_t *victim;
- while ((victim = TOR_TAILQ_FIRST(&ol_list))) {
- onion_queue_entry_remove(victim);
+ int i;
+ for (i=0; i<=MAX_ONION_HANDSHAKE_TYPE; i++) {
+ while ((victim = TOR_TAILQ_FIRST(&ol_list[i]))) {
+ onion_queue_entry_remove(victim);
+ }
}
memset(ol_entries, 0, sizeof(ol_entries));
}