Browse Source

Separate cpuworker queues by handshake type

Now we prioritize ntor create cells over tap create cells.

Starts to address ticket 9574.
Roger Dingledine 11 years ago
parent
commit
87a18514ef
1 changed files with 37 additions and 16 deletions
  1. 37 16
      src/or/onion.c

+ 37 - 16
src/or/onion.c

@@ -28,6 +28,7 @@
 typedef struct onion_queue_t {
 typedef struct onion_queue_t {
   TOR_TAILQ_ENTRY(onion_queue_t) next;
   TOR_TAILQ_ENTRY(onion_queue_t) next;
   or_circuit_t *circ;
   or_circuit_t *circ;
+  uint16_t handshake_type;
   create_cell_t *onionskin;
   create_cell_t *onionskin;
   time_t when_added;
   time_t when_added;
 } onion_queue_t;
 } 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 */
 /** 5 seconds on the onion queue til we just send back a destroy */
 #define ONIONQUEUE_WAIT_CUTOFF 5
 #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 int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1];
 
 
 static void onion_queue_entry_remove(onion_queue_t *victim);
 static void onion_queue_entry_remove(onion_queue_t *victim);
@@ -60,8 +66,7 @@ have_room_for_onionskin(uint16_t type)
   int num_cpus;
   int num_cpus;
   uint64_t tap_usec, ntor_usec;
   uint64_t tap_usec, ntor_usec;
   /* If we've got fewer than 50 entries, we always have room for one more. */
   /* 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;
     return 1;
   num_cpus = get_num_cpus(options);
   num_cpus = get_num_cpus(options);
   /* Compute how many microseconds we'd expect to need to clear all
   /* 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(
   ntor_usec = estimated_usec_for_onionskins(
                                     ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
                                     ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
                                     ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
                                     ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
+
   /* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue
   /* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue
    * this. */
    * 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;
     return 0;
+
+  if (type == ONION_HANDSHAKE_TYPE_TAP &&
+      (tap_usec + ntor_usec) / 1000 > (uint64_t)options->MaxOnionQueueDelay)
+    return 0;
+
 #ifdef CURVE25519_ENABLED
 #ifdef CURVE25519_ENABLED
   /* If we support the ntor handshake, then don't let TAP handshakes use
   /* If we support the ntor handshake, then don't let TAP handshakes use
    * more than 2/3 of the space on the queue. */
    * 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 = tor_malloc_zero(sizeof(onion_queue_t));
   tmp->circ = circ;
   tmp->circ = circ;
+  tmp->handshake_type = onionskin->handshake_type;
   tmp->onionskin = onionskin;
   tmp->onionskin = onionskin;
   tmp->when_added = now;
   tmp->when_added = now;
 
 
@@ -108,7 +121,8 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
     static ratelim_t last_warned =
     static ratelim_t last_warned =
       RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL);
       RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL);
     char *m;
     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,
       log_warn(LD_GENERAL,
                "Your computer is too slow to handle this many circuit "
                "Your computer is too slow to handle this many circuit "
                "creation requests! Please consider using the "
                "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];
   ++ol_entries[onionskin->handshake_type];
   circ->onionqueue_entry = tmp;
   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. */
   /* cull elderly requests. */
   while (1) {
   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)
     if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF)
       break;
       break;
 
 
@@ -140,14 +154,18 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
   return 0;
   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 *
 or_circuit_t *
 onion_next_task(create_cell_t **onionskin_out)
 onion_next_task(create_cell_t **onionskin_out)
 {
 {
   or_circuit_t *circ;
   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)
   if (!head)
     return NULL; /* no onions pending, we're done */
     return NULL; /* no onions pending, we're done */
@@ -186,7 +204,7 @@ onion_pending_remove(or_circuit_t *circ)
 static void
 static void
 onion_queue_entry_remove(onion_queue_t *victim)
 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)
   if (victim->circ)
     victim->circ->onionqueue_entry = NULL;
     victim->circ->onionqueue_entry = NULL;
@@ -204,8 +222,11 @@ void
 clear_pending_onions(void)
 clear_pending_onions(void)
 {
 {
   onion_queue_t *victim;
   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));
   memset(ol_entries, 0, sizeof(ol_entries));
 }
 }