relay: Cache onion queue parameters on consensus change

This is part of the fast path so we need to cache consensus parameters
instead of querying it everytime we need to learn a value.

Part of #40704

Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
David Goulet 2022-11-09 15:10:19 -05:00
parent e3f6908984
commit 780ca741f3
3 changed files with 71 additions and 48 deletions

View File

@ -84,6 +84,7 @@
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/torcert.h"
#include "feature/relay/dns.h"
#include "feature/relay/onion_queue.h"
#include "feature/relay/routermode.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
@ -1670,6 +1671,7 @@ notify_before_networkstatus_changes(const networkstatus_t *old_c,
hs_dos_consensus_has_changed(new_c);
rep_hist_consensus_has_changed(new_c);
cpuworker_consensus_has_changed(new_c);
onion_consensus_has_changed(new_c);
}
/* Called after a new consensus has been put in the global state. It is safe

View File

@ -38,6 +38,22 @@
#include "core/or/or_circuit_st.h"
#include "core/or/channel.h"
/** Onion queue default, max and min. */
/* In seconds. */
#define ONION_QUEUE_WAIT_CUTOFF_DEFAULT 5
#define ONION_QUEUE_WAIT_CUTOFF_MIN 0
#define ONION_QUEUE_WAIT_CUTOFF_MAX INT32_MAX
/* In msec. */
#define ONION_QUEUE_MAX_DELAY_DEFAULT 1750
#define ONION_QUEUE_MAX_DELAY_MIN 1
#define ONION_QUEUE_MAX_DELAY_MAX INT32_MAX
#define NUM_NTORS_PER_TAP_DEFAULT 10
#define NUM_NTORS_PER_TAP_MIN 1
#define NUM_NTORS_PER_TAP_MAX 100000
/** Type for a linked list of circuits that are waiting for a free CPU worker
* to process a waiting onion handshake. */
typedef struct onion_queue_t {
@ -65,40 +81,36 @@ static onion_queue_head_t ol_list[MAX_QUEUE_IDX+1] =
/** Number of entries of each type currently in each element of ol_list[]. */
static int ol_entries[MAX_QUEUE_IDX+1];
static int num_ntors_per_tap(void);
static void onion_queue_entry_remove(onion_queue_t *victim);
/** Return the onion queue wait cutoff value from the consensus parameter. */
static time_t
get_onionqueue_wait_cutoff(void)
/** Consensus parameters. */
static int32_t ns_num_ntors_per_tap = NUM_NTORS_PER_TAP_DEFAULT;
static time_t ns_onion_queue_wait_cutoff = ONION_QUEUE_WAIT_CUTOFF_DEFAULT;
static uint32_t ns_onion_queue_max_delay = ONION_QUEUE_MAX_DELAY_DEFAULT;
/** Return the number of ntors per tap from the cached parameter. */
static inline int32_t
get_num_ntors_per_tap(void)
{
/* In seconds. */
#define ONION_QUEUE_WAIT_CUTOFF_DEFAULT 5
#define ONION_QUEUE_WAIT_CUTOFF_MIN 0
#define ONION_QUEUE_WAIT_CUTOFF_MAX INT32_MAX
return networkstatus_get_param(NULL, "onion_queue_wait_cutoff",
ONION_QUEUE_WAIT_CUTOFF_DEFAULT,
ONION_QUEUE_WAIT_CUTOFF_MIN,
ONION_QUEUE_WAIT_CUTOFF_MAX);
return ns_num_ntors_per_tap;
}
/** Return the onion queue wait cutoff value from the cached parameter. */
static inline time_t
get_onion_queue_wait_cutoff(void)
{
return ns_onion_queue_wait_cutoff;
}
/** Return the max onion queue delay value either from the torrc options (if
* the user explicitly set it) else from the consensus parameter. */
static uint64_t
get_max_onion_queue_delay(const or_options_t *options)
* the user explicitly set it) else from the cached parameter. */
static inline uint32_t
get_onion_queue_max_delay(const or_options_t *options)
{
#define MAX_ONION_QUEUE_DELAY_DEFAULT 1750 /* msec */
#define MAX_ONION_QUEUE_DELAY_MIN 1 /* msec */
#define MAX_ONION_QUEUE_DELAY_MAX INT32_MAX /* msec */
if (options && options->MaxOnionQueueDelay > 0) {
return options->MaxOnionQueueDelay;
}
return networkstatus_get_param(NULL, "MaxOnionQueueDelay",
MAX_ONION_QUEUE_DELAY_DEFAULT,
MAX_ONION_QUEUE_DELAY_MIN,
MAX_ONION_QUEUE_DELAY_MAX);
return ns_onion_queue_max_delay;
}
/**
@ -141,7 +153,7 @@ have_room_for_onionskin(uint16_t type)
if (ol_entries[type] < 50)
return 1;
num_cpus = get_num_cpus(options);
max_onion_queue_delay = get_max_onion_queue_delay(options);
max_onion_queue_delay = get_onion_queue_max_delay(options);
/* Compute how many microseconds we'd expect to need to clear all
* onionskins in various combinations of the queues. */
@ -160,14 +172,14 @@ have_room_for_onionskin(uint16_t type)
* process while draining the ntor queue? */
tap_during_ntor_usec = estimated_usec_for_onionskins(
MIN(ol_entries[ONION_HANDSHAKE_TYPE_TAP],
ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / num_ntors_per_tap()),
ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / get_num_ntors_per_tap()),
ONION_HANDSHAKE_TYPE_TAP) / num_cpus;
/* How long would it take to process the ntor cells that we expect to
* process while draining the tap queue? */
ntor_during_tap_usec = estimated_usec_for_onionskins(
MIN(ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
ol_entries[ONION_HANDSHAKE_TYPE_TAP] * num_ntors_per_tap()),
ol_entries[ONION_HANDSHAKE_TYPE_TAP] * get_num_ntors_per_tap()),
ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
/* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue
@ -253,7 +265,7 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
/* cull elderly requests. */
while (1) {
onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[queue_idx]);
if (now - head->when_added < get_onionqueue_wait_cutoff())
if (now - head->when_added < get_onion_queue_wait_cutoff())
break;
circ = head->circ;
@ -268,24 +280,6 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
return 0;
}
/** Return a fairness parameter, to prefer processing NTOR style
* handshakes but still slowly drain the TAP queue so we don't starve
* it entirely. */
static int
num_ntors_per_tap(void)
{
#define DEFAULT_NUM_NTORS_PER_TAP 10
#define MIN_NUM_NTORS_PER_TAP 1
#define MAX_NUM_NTORS_PER_TAP 100000
int result = networkstatus_get_param(NULL, "NumNTorsPerTAP",
DEFAULT_NUM_NTORS_PER_TAP,
MIN_NUM_NTORS_PER_TAP,
MAX_NUM_NTORS_PER_TAP);
tor_assert(result > 0);
return result;
}
/** Choose which onion queue we'll pull from next. If one is empty choose
* the other; if they both have elements, load balance across them but
* favoring NTOR. */
@ -309,7 +303,7 @@ decide_next_handshake_type(void)
* once tap is rare. We should reevaluate whether we like this decision
* once tap gets more rare. */
if (ol_entries[ONION_HANDSHAKE_TYPE_NTOR] &&
recently_chosen_ntors <= num_ntors_per_tap())
recently_chosen_ntors <= get_num_ntors_per_tap())
++recently_chosen_ntors;
return ONION_HANDSHAKE_TYPE_NTOR; /* no taps? try ntor */
@ -317,7 +311,7 @@ decide_next_handshake_type(void)
/* They both have something queued. Pick ntor if we haven't done that
* too much lately. */
if (++recently_chosen_ntors <= num_ntors_per_tap()) {
if (++recently_chosen_ntors <= get_num_ntors_per_tap()) {
return ONION_HANDSHAKE_TYPE_NTOR;
}
@ -427,3 +421,28 @@ clear_pending_onions(void)
}
memset(ol_entries, 0, sizeof(ol_entries));
}
/** Consensus has changed, update the cached parameters. */
void
onion_consensus_has_changed(const networkstatus_t *ns)
{
tor_assert(ns);
ns_onion_queue_max_delay =
networkstatus_get_param(ns, "MaxOnionQueueDelay",
ONION_QUEUE_MAX_DELAY_DEFAULT,
ONION_QUEUE_MAX_DELAY_MIN,
ONION_QUEUE_MAX_DELAY_MAX);
ns_onion_queue_wait_cutoff =
networkstatus_get_param(ns, "onion_queue_wait_cutoff",
ONION_QUEUE_WAIT_CUTOFF_DEFAULT,
ONION_QUEUE_WAIT_CUTOFF_MIN,
ONION_QUEUE_WAIT_CUTOFF_MAX);
ns_num_ntors_per_tap =
networkstatus_get_param(ns, "NumNTorsPerTAP",
NUM_NTORS_PER_TAP_DEFAULT,
NUM_NTORS_PER_TAP_MIN,
NUM_NTORS_PER_TAP_MAX);
}

View File

@ -14,6 +14,8 @@
struct create_cell_t;
void onion_consensus_has_changed(const networkstatus_t *ns);
int onion_pending_add(or_circuit_t *circ, struct create_cell_t *onionskin);
or_circuit_t *onion_next_task(struct create_cell_t **onionskin_out);
int onion_num_pending(uint16_t handshake_type);