Bladeren bron

Separate cpuworker queues by handshake type

Now we prioritize ntor create cells over tap create cells.

Starts to address ticket 9574.
Roger Dingledine 11 jaren geleden
bovenliggende
commit
87a18514ef
1 gewijzigde bestanden met toevoegingen van 37 en 16 verwijderingen
  1. 37 16
      src/or/onion.c

+ 37 - 16
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));
 }