From 780ca741f3738877ad577f84fcebf6874427b2bc Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 9 Nov 2022 15:10:19 -0500 Subject: [PATCH] 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 --- src/feature/nodelist/networkstatus.c | 2 + src/feature/relay/onion_queue.c | 115 ++++++++++++++++----------- src/feature/relay/onion_queue.h | 2 + 3 files changed, 71 insertions(+), 48 deletions(-) diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c index fa1e38dac0..af3bde83a5 100644 --- a/src/feature/nodelist/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -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 diff --git a/src/feature/relay/onion_queue.c b/src/feature/relay/onion_queue.c index 5897ee8a48..6d1a6de15c 100644 --- a/src/feature/relay/onion_queue.c +++ b/src/feature/relay/onion_queue.c @@ -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); +} diff --git a/src/feature/relay/onion_queue.h b/src/feature/relay/onion_queue.h index 5ac1b1b280..0c2b97c2b0 100644 --- a/src/feature/relay/onion_queue.h +++ b/src/feature/relay/onion_queue.h @@ -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);