[tor-commits] [tor/master] Cache netflow-related consensus parameters.

nickm at torproject.org nickm at torproject.org
Mon May 8 18:00:18 UTC 2017


commit 687a85950afc25010c80cd14539728b3a7ae5675
Author: Mike Perry <mikeperry-git at torproject.org>
Date:   Thu Sep 22 17:52:25 2016 -0400

    Cache netflow-related consensus parameters.
    
    Checking all of these parameter lists for every single connection every second
    seems like it could be an expensive waste.
    
    Updating globally cached versions when there is a new consensus will still
    allow us to apply consensus parameter updates to all existing connections
    immediately.
---
 src/or/channelpadding.c        | 148 +++++++++++++++++++++++++++--------------
 src/or/channelpadding.h        |   1 +
 src/or/main.c                  |   4 ++
 src/or/networkstatus.c         |   2 +
 src/test/test_channelpadding.c |  11 +++
 src/test/testing_common.c      |   3 +
 6 files changed, 118 insertions(+), 51 deletions(-)

diff --git a/src/or/channelpadding.c b/src/or/channelpadding.c
index 3156051..a84994a 100644
--- a/src/or/channelpadding.c
+++ b/src/or/channelpadding.c
@@ -29,6 +29,87 @@ STATIC int64_t channelpadding_compute_time_until_pad_for_netflow(channel_t *);
 /** The total number of pending channelpadding timers */
 static uint64_t total_timers_pending;
 
+/** These are cached consensus parameters for netflow */
+/** The timeout lower bound that is allowed before sending padding */
+static int consensus_nf_ito_low;
+/** The timeout upper bound that is allowed before sending padding */
+static int consensus_nf_ito_high;
+/** The timeout lower bound that is allowed before sending reduced padding */
+static int consensus_nf_ito_low_reduced;
+/** The timeout upper bound that is allowed before sending reduced padding */
+static int consensus_nf_ito_high_reduced;
+/** The connection timeout between relays */
+static int consensus_nf_conntimeout_relays;
+/** The connection timeout for client connections */
+static int consensus_nf_conntimeout_clients;
+/** Should we pad before circuits are actually used for client data? */
+static int consensus_nf_pad_before_usage;
+/** Should we pad relay-to-relay connections? */
+static int consensus_nf_pad_relays;
+
+/**
+ * This function is called to update cached consensus parameters every time
+ * there is a consensus update. This allows us to move the consensus param
+ * search off of the critical path, so it does not need to be evaluated
+ * for every single connection, every second.
+ */
+void
+channelpadding_new_consensus_params(networkstatus_t *ns)
+{
+#define DFLT_NETFLOW_INACTIVE_KEEPALIVE_LOW 1500
+#define DFLT_NETFLOW_INACTIVE_KEEPALIVE_HIGH 9500
+#define DFLT_NETFLOW_INACTIVE_KEEPALIVE_MIN 0
+#define DFLT_NETFLOW_INACTIVE_KEEPALIVE_MAX 60000
+  consensus_nf_ito_low = networkstatus_get_param(ns, "nf_ito_low",
+      DFLT_NETFLOW_INACTIVE_KEEPALIVE_LOW,
+      DFLT_NETFLOW_INACTIVE_KEEPALIVE_MIN,
+      DFLT_NETFLOW_INACTIVE_KEEPALIVE_MAX);
+  consensus_nf_ito_high = networkstatus_get_param(NULL, "nf_ito_high",
+      DFLT_NETFLOW_INACTIVE_KEEPALIVE_HIGH,
+      consensus_nf_ito_low,
+      DFLT_NETFLOW_INACTIVE_KEEPALIVE_MAX);
+
+#define DFLT_NETFLOW_REDUCED_KEEPALIVE_LOW 9000
+#define DFLT_NETFLOW_REDUCED_KEEPALIVE_HIGH 14000
+#define DFLT_NETFLOW_REDUCED_KEEPALIVE_MIN 0
+#define DFLT_NETFLOW_REDUCED_KEEPALIVE_MAX 60000
+  consensus_nf_ito_low_reduced =
+    networkstatus_get_param(NULL, "nf_ito_low_reduced",
+        DFLT_NETFLOW_REDUCED_KEEPALIVE_LOW,
+        DFLT_NETFLOW_REDUCED_KEEPALIVE_MIN,
+        DFLT_NETFLOW_REDUCED_KEEPALIVE_MAX);
+
+  consensus_nf_ito_high_reduced =
+    networkstatus_get_param(NULL, "nf_ito_high_reduced",
+        DFLT_NETFLOW_REDUCED_KEEPALIVE_HIGH,
+        consensus_nf_ito_low_reduced,
+        DFLT_NETFLOW_REDUCED_KEEPALIVE_MAX);
+
+#define CONNTIMEOUT_RELAYS_DFLT (60*60) // 1 hour
+#define CONNTIMEOUT_RELAYS_MIN 60
+#define CONNTIMEOUT_RELAYS_MAX (7*24*60*60) // 1 week
+  consensus_nf_conntimeout_relays =
+    networkstatus_get_param(NULL, "nf_conntimeout_relays",
+        CONNTIMEOUT_RELAYS_DFLT,
+        CONNTIMEOUT_RELAYS_MIN,
+        CONNTIMEOUT_RELAYS_MAX);
+
+#define CIRCTIMEOUT_CLIENTS_DFLT (30*60) // 30 minutes
+#define CIRCTIMEOUT_CLIENTS_MIN 60
+#define CIRCTIMEOUT_CLIENTS_MAX (24*60*60) // 24 hours
+  consensus_nf_conntimeout_clients =
+    networkstatus_get_param(NULL, "nf_conntimeout_clients",
+        CIRCTIMEOUT_CLIENTS_DFLT,
+        CIRCTIMEOUT_CLIENTS_MIN,
+        CIRCTIMEOUT_CLIENTS_MAX);
+
+  consensus_nf_pad_before_usage =
+    networkstatus_get_param(NULL, "nf_pad_before_usage", 1, 0, 1);
+
+  consensus_nf_pad_relays =
+    networkstatus_get_param(NULL, "nf_pad_relays", 0, 0, 1);
+}
+
 /**
  * Get a random netflow inactive timeout keepalive period in milliseconds,
  * the range for which is determined by consensus parameters, negotiation,
@@ -47,21 +128,11 @@ static uint64_t total_timers_pending;
  * Returns the next timeout period (in milliseconds) after which we should
  * send a padding packet, or 0 if padding is disabled.
  */
-#define DFLT_NETFLOW_INACTIVE_KEEPALIVE_LOW 1500
-#define DFLT_NETFLOW_INACTIVE_KEEPALIVE_HIGH 9500
-#define DFLT_NETFLOW_INACTIVE_KEEPALIVE_MIN 0
-#define DFLT_NETFLOW_INACTIVE_KEEPALIVE_MAX 60000
 STATIC int
 channelpadding_get_netflow_inactive_timeout_ms(const channel_t *chan)
 {
-  int low_timeout = networkstatus_get_param(NULL, "nf_ito_low",
-      DFLT_NETFLOW_INACTIVE_KEEPALIVE_LOW,
-      DFLT_NETFLOW_INACTIVE_KEEPALIVE_MIN,
-      DFLT_NETFLOW_INACTIVE_KEEPALIVE_MAX);
-  int high_timeout = networkstatus_get_param(NULL, "nf_ito_high",
-      DFLT_NETFLOW_INACTIVE_KEEPALIVE_HIGH,
-      low_timeout,
-      DFLT_NETFLOW_INACTIVE_KEEPALIVE_MAX);
+  int low_timeout = consensus_nf_ito_low;
+  int high_timeout = consensus_nf_ito_high;
   int X1, X2;
 
   if (low_timeout == 0 && low_timeout == high_timeout)
@@ -162,12 +233,8 @@ channelpadding_update_padding_for_channel(channel_t *chan,
 
   /* Min must not be lower than the current consensus parameter
      nf_ito_low. */
-  chan->padding_timeout_low_ms = MAX(networkstatus_get_param(NULL,
-              "nf_ito_low",
-              DFLT_NETFLOW_INACTIVE_KEEPALIVE_LOW,
-              DFLT_NETFLOW_INACTIVE_KEEPALIVE_MIN,
-              DFLT_NETFLOW_INACTIVE_KEEPALIVE_MAX),
-          pad_vars->ito_low_ms);
+  chan->padding_timeout_low_ms = MAX(consensus_nf_ito_low,
+                                     pad_vars->ito_low_ms);
 
   /* Max must not be lower than ito_low_ms */
   chan->padding_timeout_high_ms = MAX(chan->padding_timeout_low_ms,
@@ -399,6 +466,12 @@ channelpadding_compute_time_until_pad_for_netflow(channel_t *chan)
   uint64_t long_now = monotime_coarse_absolute_msec();
 
   if (!chan->next_padding_time_ms) {
+    /* If the below line or crypto_rand_int() shows up on a profile,
+     * we can avoid getting a timeout until we're at least nt_ito_lo
+     * from a timeout window. That will prevent us from setting timers
+     * on connections that were active up to 1.5 seconds ago.
+     * Idle connections should only call this once every 5.5s on average
+     * though, so that might be a micro-optimization for little gain. */
     int64_t padding_timeout =
         channelpadding_get_netflow_inactive_timeout_ms(chan);
 
@@ -475,14 +548,7 @@ channelpadding_get_channel_idle_timeout(const channel_t *chan,
         + crypto_rand_int(CONNTIMEOUT_CLIENTS_BASE/2);
   } else { // Canonical relay-to-relay channels
     // 45..75min or consensus +/- 25%
-#define CONNTIMEOUT_RELAYS_DFLT (60*60) // 1 hour
-#define CONNTIMEOUT_RELAYS_MIN 60
-#define CONNTIMEOUT_RELAYS_MAX (7*24*60*60) // 1 week
-    timeout = networkstatus_get_param(NULL, "nf_conntimeout_relays",
-        CONNTIMEOUT_RELAYS_DFLT,
-        CONNTIMEOUT_RELAYS_MIN,
-        CONNTIMEOUT_RELAYS_MAX);
-
+    timeout = consensus_nf_conntimeout_relays;
     timeout = 3*timeout/4 + crypto_rand_int(timeout/2);
   }
 
@@ -522,13 +588,7 @@ channelpadding_get_circuits_available_timeout(void)
   int timeout = options->CircuitsAvailableTimeout;
 
   if (!timeout) {
-#define CIRCTIMEOUT_CLIENTS_DFLT (30*60) // 30 minutes
-#define CIRCTIMEOUT_CLIENTS_MIN 60
-#define CIRCTIMEOUT_CLIENTS_MAX (24*60*60) // 24 hours
-    timeout = networkstatus_get_param(NULL, "nf_conntimeout_clients",
-        CIRCTIMEOUT_CLIENTS_DFLT,
-        CIRCTIMEOUT_CLIENTS_MIN,
-        CIRCTIMEOUT_CLIENTS_MAX);
+    timeout = consensus_nf_conntimeout_clients;
 
     /* If ReducedConnectionPadding is set, we want to halve the duration of
      * the channel idle timeout, since reducing the additional time that
@@ -579,21 +639,8 @@ channelpadding_reduce_padding_on_channel(channel_t *chan)
     channelpadding_send_disable_command(chan);
   }
 
-#define DFLT_NETFLOW_REDUCED_KEEPALIVE_LOW 9000
-#define DFLT_NETFLOW_REDUCED_KEEPALIVE_HIGH 14000
-#define DFLT_NETFLOW_REDUCED_KEEPALIVE_MIN 0
-#define DFLT_NETFLOW_REDUCED_KEEPALIVE_MAX 60000
-  chan->padding_timeout_low_ms =
-    networkstatus_get_param(NULL, "nf_ito_low_reduced",
-        DFLT_NETFLOW_REDUCED_KEEPALIVE_LOW,
-        DFLT_NETFLOW_REDUCED_KEEPALIVE_MIN,
-        DFLT_NETFLOW_REDUCED_KEEPALIVE_MAX);
-
-  chan->padding_timeout_high_ms =
-    networkstatus_get_param(NULL, "nf_ito_high_reduced",
-        DFLT_NETFLOW_REDUCED_KEEPALIVE_HIGH,
-        chan->padding_timeout_low_ms,
-        DFLT_NETFLOW_REDUCED_KEEPALIVE_MAX);
+  chan->padding_timeout_low_ms = consensus_nf_ito_low_reduced;
+  chan->padding_timeout_high_ms = consensus_nf_ito_high_reduced;
 
   log_fn(LOG_INFO,LD_OR,
          "Reduced padding on channel "U64_FORMAT": lo=%d, hi=%d",
@@ -621,7 +668,7 @@ channelpadding_decide_to_pad_channel(channel_t *chan)
     return CHANNELPADDING_WONTPAD;
 
   if (chan->channel_usage == CHANNEL_USED_FOR_FULL_CIRCS) {
-    if (!networkstatus_get_param(NULL, "nf_pad_before_usage", 1, 0, 1))
+    if (!consensus_nf_pad_before_usage)
       return CHANNELPADDING_WONTPAD;
   } else if (chan->channel_usage != CHANNEL_USED_FOR_USER_TRAFFIC) {
     return CHANNELPADDING_WONTPAD;
@@ -649,8 +696,7 @@ channelpadding_decide_to_pad_channel(channel_t *chan)
     /* If nf_pad_relays=1 is set in the consensus, we pad
      * on *all* idle connections, relay-relay or relay-client.
      * Otherwise pad only for client+bridge cons */
-    if (is_client_channel ||
-        networkstatus_get_param(NULL, "nf_pad_relays", 0, 0, 1)) {
+    if (is_client_channel || consensus_nf_pad_relays) {
       int64_t pad_time_ms =
           channelpadding_compute_time_until_pad_for_netflow(chan);
 
diff --git a/src/or/channelpadding.h b/src/or/channelpadding.h
index 07af7a6..e08f7a2 100644
--- a/src/or/channelpadding.h
+++ b/src/or/channelpadding.h
@@ -33,6 +33,7 @@ int channelpadding_send_enable_command(channel_t *chan, uint16_t low_timeout,
 
 int channelpadding_get_circuits_available_timeout(void);
 unsigned int channelpadding_get_channel_idle_timeout(const channel_t *, int);
+void channelpadding_new_consensus_params(networkstatus_t *ns);
 
 #endif
 
diff --git a/src/or/main.c b/src/or/main.c
index 5bc132a..b729e0b 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -3033,6 +3033,10 @@ tor_init(int argc, char *argv[])
   /* The options are now initialised */
   const or_options_t *options = get_options();
 
+  /* Initialize channelpadding parameters to defaults until we get
+   * a consensus */
+  channelpadding_new_consensus_params(NULL);
+
   /* Initialize predicted ports list after loading options */
   predicted_ports_init();
 
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 76b968a..4107542 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -63,6 +63,7 @@
 #include "shared_random.h"
 #include "transports.h"
 #include "torcert.h"
+#include "channelpadding.h"
 
 /** Map from lowercase nickname to identity digest of named server, if any. */
 static strmap_t *named_server_map = NULL;
@@ -1966,6 +1967,7 @@ networkstatus_set_current_consensus(const char *consensus,
 
     circuit_build_times_new_consensus_params(
                                get_circuit_build_times_mutable(), c);
+    channelpadding_new_consensus_params(c);
   }
 
   /* Reset the failure count only if this consensus is actually valid. */
diff --git a/src/test/test_channelpadding.c b/src/test/test_channelpadding.c
index de88bb2..9b04f55 100644
--- a/src/test/test_channelpadding.c
+++ b/src/test/test_channelpadding.c
@@ -174,6 +174,7 @@ setup_mock_network(void)
         = tor_malloc_zero(sizeof(networkstatus_t));
   current_md_consensus->net_params = smartlist_new();
   current_md_consensus->routerstatus_list = smartlist_new();
+  channelpadding_new_consensus_params(current_md_consensus);
 
   relay1_relay2 = (channel_t*)new_fake_channeltls(2);
   relay1_relay2->write_cell = mock_channel_write_cell_relay1;
@@ -259,6 +260,7 @@ test_channelpadding_timers(void *arg)
 
   monotime_init();
   timers_initialize();
+  channelpadding_new_consensus_params(NULL);
 
   for (int i = 0; i < CHANNELS_TO_TEST; i++) {
     chans[i] = (channel_t*)new_fake_channeltls(0);
@@ -374,6 +376,7 @@ test_channelpadding_consensus(void *arg)
         = tor_malloc_zero(sizeof(networkstatus_t));
   current_md_consensus->net_params = smartlist_new();
   current_md_consensus->routerstatus_list = smartlist_new();
+  channelpadding_new_consensus_params(current_md_consensus);
 
   get_options_mutable()->ORPort_set = 1;
 
@@ -398,6 +401,7 @@ test_channelpadding_consensus(void *arg)
   smartlist_add(current_md_consensus->net_params,
                 (void*)"nf_ito_high=0");
   get_options_mutable()->ConnectionPadding = 1;
+  channelpadding_new_consensus_params(current_md_consensus);
 
   decision = channelpadding_decide_to_pad_channel(chan);
   tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD);
@@ -427,6 +431,7 @@ test_channelpadding_consensus(void *arg)
                 (void*)"nf_ito_low=100");
   smartlist_add(current_md_consensus->net_params,
                 (void*)"nf_ito_high=200");
+  channelpadding_new_consensus_params(current_md_consensus);
 
   tried_to_write_cell = 0;
   decision = channelpadding_decide_to_pad_channel(chan);
@@ -449,6 +454,7 @@ test_channelpadding_consensus(void *arg)
                 (void*)"nf_ito_low=1500");
   smartlist_add(current_md_consensus->net_params,
                 (void*)"nf_ito_high=4500");
+  channelpadding_new_consensus_params(current_md_consensus);
 
   channelpadding_send_enable_command(chan, 100, 200);
   tried_to_write_cell = 0;
@@ -474,6 +480,7 @@ test_channelpadding_consensus(void *arg)
 
   smartlist_add(current_md_consensus->net_params,
                 (void*)"nf_pad_relays=1");
+  channelpadding_new_consensus_params(current_md_consensus);
 
   decision = channelpadding_decide_to_pad_channel(chan);
   tt_int_op(decision, OP_EQ, CHANNELPADDING_PADLATER);
@@ -487,6 +494,7 @@ test_channelpadding_consensus(void *arg)
   /* Test 5: If we disable padding before channel usage, does that work? */
   smartlist_add(current_md_consensus->net_params,
                 (void*)"nf_pad_before_usage=0");
+  channelpadding_new_consensus_params(current_md_consensus);
   tried_to_write_cell = 0;
   decision = channelpadding_decide_to_pad_channel(chan);
   tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD);
@@ -508,6 +516,7 @@ test_channelpadding_consensus(void *arg)
   options->ORPort_set = 1;
   smartlist_add(current_md_consensus->net_params,
                 (void*)"nf_conntimeout_relays=600");
+  channelpadding_new_consensus_params(current_md_consensus);
   val = channelpadding_get_channel_idle_timeout(chan, 1);
   tt_int_op(val, OP_GE, 450);
   tt_int_op(val, OP_LE, 750);
@@ -519,6 +528,7 @@ test_channelpadding_consensus(void *arg)
   options->ReducedConnectionPadding = 1;
   smartlist_add(current_md_consensus->net_params,
                 (void*)"nf_conntimeout_clients=600");
+  channelpadding_new_consensus_params(current_md_consensus);
   val = channelpadding_get_circuits_available_timeout();
   tt_int_op(val, OP_GE, 600/2);
   tt_int_op(val, OP_LE, 600*2/2);
@@ -714,6 +724,7 @@ test_channelpadding_decide_to_pad_channel(void *arg)
 
   monotime_init();
   timers_initialize();
+  channelpadding_new_consensus_params(NULL);
 
   chan = (channel_t*)new_fake_channeltls(0);
   channel_timestamp_active(chan);
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index 43cf0aa..07fd9e0 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -21,6 +21,7 @@ const char tor_git_revision[] = "";
 #include "rephist.h"
 #include "backtrace.h"
 #include "test.h"
+#include "channelpadding.h"
 
 #include <stdio.h>
 #ifdef HAVE_FCNTL_H
@@ -309,6 +310,8 @@ main(int c, const char **v)
 
   init_pregenerated_keys();
 
+  channelpadding_new_consensus_params(NULL);
+
   predicted_ports_init();
 
   atexit(remove_directory);





More information about the tor-commits mailing list