Loading src/or/circuitbuild.c +147 −53 Original line number Diff line number Diff line Loading @@ -79,6 +79,92 @@ static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); static void entry_guards_changed(void); static int32_t circuit_build_times_max_timeouts(void) { int32_t num = networkstatus_get_param(NULL, "cbtmaxtimeouts", CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT); return num; } static int32_t circuit_build_times_min_circs_to_observe(void) { int32_t num = networkstatus_get_param(NULL, "cbtmincircs", CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE); return num; } double circuit_build_times_quantile_cutoff(void) { int32_t num = networkstatus_get_param(NULL, "cbtquantile", CBT_DEFAULT_QUANTILE_CUTOFF); return num/100.0; } static int32_t circuit_build_times_test_frequency(void) { int32_t num = networkstatus_get_param(NULL, "cbttestfreq", CBT_DEFAULT_TEST_FREQUENCY); return num; } static int32_t circuit_build_times_min_timeout(void) { int32_t num = networkstatus_get_param(NULL, "cbtmintimeout", CBT_DEFAULT_TIMEOUT_MIN_VALUE); return num; } int32_t circuit_build_times_initial_timeout(void) { int32_t num = networkstatus_get_param(NULL, "cbtinitialtimeout", CBT_DEFAULT_TIMEOUT_INITIAL_VALUE); return num; } static int32_t circuit_build_times_recent_circuit_count(void) { int32_t num = networkstatus_get_param(NULL, "cbtrecentcount", CBT_DEFAULT_RECENT_CIRCUITS); return num; } void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, networkstatus_t *ns) { int32_t num = networkstatus_get_param(ns, "cbtrecentcount", CBT_DEFAULT_RECENT_CIRCUITS); if (num != cbt->liveness.num_recent_circs) { int8_t *recent_circs; log_notice(LD_CIRC, "Changing recent timeout size from %d to %d", cbt->liveness.num_recent_circs, num); tor_assert(num > 0); tor_assert(cbt->liveness.timeouts_after_firsthop); recent_circs = tor_malloc_zero(sizeof(int8_t)*num); memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop, sizeof(int8_t)*MIN(num, cbt->liveness.num_recent_circs)); // Adjust the index if it needs it. if (num < cbt->liveness.num_recent_circs) { cbt->liveness.after_firsthop_idx = MIN(num-1, cbt->liveness.after_firsthop_idx); } tor_free(cbt->liveness.timeouts_after_firsthop); cbt->liveness.timeouts_after_firsthop = recent_circs; cbt->liveness.num_recent_circs = num; } } /** Make a note that we're running unit tests (rather than running Tor * itself), so we avoid clobbering our state file. */ void Loading @@ -96,13 +182,13 @@ circuit_build_times_get_initial_timeout(void) double timeout; if (!unit_tests && get_options()->CircuitBuildTimeout) { timeout = get_options()->CircuitBuildTimeout*1000; if (timeout < BUILD_TIMEOUT_MIN_VALUE) { if (timeout < circuit_build_times_min_timeout()) { log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds", BUILD_TIMEOUT_MIN_VALUE/1000); timeout = BUILD_TIMEOUT_MIN_VALUE; circuit_build_times_min_timeout()/1000); timeout = circuit_build_times_min_timeout(); } } else { timeout = BUILD_TIMEOUT_INITIAL_VALUE; timeout = circuit_build_times_initial_timeout(); } return timeout; } Loading Loading @@ -133,6 +219,9 @@ void circuit_build_times_init(circuit_build_times_t *cbt) { memset(cbt, 0, sizeof(*cbt)); cbt->liveness.num_recent_circs = circuit_build_times_recent_circuit_count(); cbt->liveness.timeouts_after_firsthop = tor_malloc_zero(sizeof(int8_t)* cbt->liveness.num_recent_circs); cbt->timeout_ms = circuit_build_times_get_initial_timeout(); control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET); } Loading Loading @@ -162,10 +251,11 @@ circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n) } cbt->build_times_idx -= n; cbt->build_times_idx %= NCIRCUITS_TO_OBSERVE; cbt->build_times_idx %= CBT_NCIRCUITS_TO_OBSERVE; for (i = 0; i < n; i++) { cbt->circuit_build_times[(i+cbt->build_times_idx)%NCIRCUITS_TO_OBSERVE]=0; cbt->circuit_build_times[(i+cbt->build_times_idx) %CBT_NCIRCUITS_TO_OBSERVE]=0; } if (cbt->total_build_times > n) { Loading @@ -189,7 +279,7 @@ circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n) int circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time) { tor_assert(time <= BUILD_TIME_MAX); tor_assert(time <= CBT_BUILD_TIME_MAX); if (time <= 0) { log_warn(LD_CIRC, "Circuit build time is %u!", time); return -1; Loading @@ -199,11 +289,11 @@ circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time) log_info(LD_CIRC, "Adding circuit build time %u", time); cbt->circuit_build_times[cbt->build_times_idx] = time; cbt->build_times_idx = (cbt->build_times_idx + 1) % NCIRCUITS_TO_OBSERVE; if (cbt->total_build_times < NCIRCUITS_TO_OBSERVE) cbt->build_times_idx = (cbt->build_times_idx + 1) % CBT_NCIRCUITS_TO_OBSERVE; if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE) cbt->total_build_times++; if ((cbt->total_build_times % BUILD_TIMES_SAVE_STATE_EVERY) == 0) { if ((cbt->total_build_times % CBT_SAVE_STATE_EVERY) == 0) { /* Save state every n circuit builds */ if (!unit_tests && !get_options()->AvoidDiskWrites) or_state_mark_dirty(get_or_state(), 0); Loading @@ -220,7 +310,7 @@ circuit_build_times_max(circuit_build_times_t *cbt) { int i = 0; build_time_t max_build_time = 0; for (i = 0; i < NCIRCUITS_TO_OBSERVE; i++) { for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (cbt->circuit_build_times[i] > max_build_time) max_build_time = cbt->circuit_build_times[i]; } Loading @@ -233,14 +323,14 @@ build_time_t circuit_build_times_min(circuit_build_times_t *cbt) { int i = 0; build_time_t min_build_time = BUILD_TIME_MAX; for (i = 0; i < NCIRCUITS_TO_OBSERVE; i++) { build_time_t min_build_time = CBT_BUILD_TIME_MAX; for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (cbt->circuit_build_times[i] && /* 0 <-> uninitialized */ cbt->circuit_build_times[i] < min_build_time) min_build_time = cbt->circuit_build_times[i]; } if (min_build_time == BUILD_TIME_MAX) { log_warn(LD_CIRC, "No build times less than BUILD_TIME_MAX!"); if (min_build_time == CBT_BUILD_TIME_MAX) { log_warn(LD_CIRC, "No build times less than CBT_BUILD_TIME_MAX!"); } return min_build_time; } Loading @@ -250,7 +340,7 @@ circuit_build_times_min(circuit_build_times_t *cbt) * Calculate and return a histogram for the set of build times. * * Returns an allocated array of histrogram bins representing * the frequency of index*BUILDTIME_BIN_WIDTH millisecond * the frequency of index*CBT_BIN_WIDTH millisecond * build times. Also outputs the number of bins in nbins. * * The return value must be freed by the caller. Loading @@ -263,14 +353,14 @@ circuit_build_times_create_histogram(circuit_build_times_t *cbt, build_time_t max_build_time = circuit_build_times_max(cbt); int i, c; *nbins = 1 + (max_build_time / BUILDTIME_BIN_WIDTH); *nbins = 1 + (max_build_time / CBT_BIN_WIDTH); histogram = tor_malloc_zero(*nbins * sizeof(build_time_t)); // calculate histogram for (i = 0; i < NCIRCUITS_TO_OBSERVE; i++) { for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (cbt->circuit_build_times[i] == 0) continue; /* 0 <-> uninitialized */ c = (cbt->circuit_build_times[i] / BUILDTIME_BIN_WIDTH); c = (cbt->circuit_build_times[i] / CBT_BIN_WIDTH); histogram[c]++; } Loading @@ -278,7 +368,7 @@ circuit_build_times_create_histogram(circuit_build_times_t *cbt, } /** * Return the most frequent build time (rounded to BUILDTIME_BIN_WIDTH ms). * Return the most frequent build time (rounded to CBT_BIN_WIDTH ms). * * Ties go in favor of the slower time. */ Loading @@ -296,7 +386,7 @@ circuit_build_times_mode(circuit_build_times_t *cbt) tor_free(histogram); return max_bin*BUILDTIME_BIN_WIDTH+BUILDTIME_BIN_WIDTH/2; return max_bin*CBT_BIN_WIDTH+CBT_BIN_WIDTH/2; } /** Loading Loading @@ -327,7 +417,7 @@ circuit_build_times_update_state(circuit_build_times_t *cbt, line->key = tor_strdup("CircuitBuildTimeBin"); line->value = tor_malloc(25); tor_snprintf(line->value, 25, "%d %d", i*BUILDTIME_BIN_WIDTH+BUILDTIME_BIN_WIDTH/2, histogram[i]); i*CBT_BIN_WIDTH+CBT_BIN_WIDTH/2, histogram[i]); next = &(line->next); } Loading @@ -350,9 +440,9 @@ circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt, int num_times) { int n = num_times; if (num_times > NCIRCUITS_TO_OBSERVE) { if (num_times > CBT_NCIRCUITS_TO_OBSERVE) { log_notice(LD_CIRC, "Decreasing circuit_build_times size from %d to %d", num_times, NCIRCUITS_TO_OBSERVE); num_times, CBT_NCIRCUITS_TO_OBSERVE); } /* This code can only be run on a compact array */ Loading @@ -363,9 +453,9 @@ circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt, raw_times[n] = tmp; } /* Since the times are now shuffled, take a random NCIRCUITS_TO_OBSERVE * subset (ie the first NCIRCUITS_TO_OBSERVE values) */ for (n = 0; n < MIN(num_times, NCIRCUITS_TO_OBSERVE); n++) { /* Since the times are now shuffled, take a random CBT_NCIRCUITS_TO_OBSERVE * subset (ie the first CBT_NCIRCUITS_TO_OBSERVE values) */ for (n = 0; n < MIN(num_times, CBT_NCIRCUITS_TO_OBSERVE); n++) { circuit_build_times_add_time(cbt, raw_times[n]); } } Loading Loading @@ -407,7 +497,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt, build_time_t ms; int ok; ms = (build_time_t)tor_parse_ulong(ms_str, 0, 0, BUILD_TIME_MAX, &ok, NULL); CBT_BUILD_TIME_MAX, &ok, NULL); if (!ok) { *msg = tor_strdup("Unable to parse circuit build times: " "Unparsable bin number"); Loading Loading @@ -453,7 +543,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt, circuit_build_times_shuffle_and_store_array(cbt, loaded_times, loaded_cnt); /* Verify that we didn't overwrite any indexes */ for (i=0; i < NCIRCUITS_TO_OBSERVE; i++) { for (i=0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (!cbt->circuit_build_times[i]) break; tot_values++; Loading @@ -462,7 +552,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt, "Loaded %d/%d values from %d lines in circuit time histogram", tot_values, cbt->total_build_times, N); tor_assert(cbt->total_build_times == tot_values); tor_assert(cbt->total_build_times <= NCIRCUITS_TO_OBSERVE); tor_assert(cbt->total_build_times <= CBT_NCIRCUITS_TO_OBSERVE); circuit_build_times_set_timeout(cbt); tor_free(loaded_times); return *msg ? -1 : 0; Loading @@ -489,7 +579,7 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt) * and less frechet-like. */ cbt->Xm = circuit_build_times_mode(cbt); for (i=0; i< NCIRCUITS_TO_OBSERVE; i++) { for (i=0; i< CBT_NCIRCUITS_TO_OBSERVE; i++) { if (!x[i]) { continue; } Loading Loading @@ -598,18 +688,18 @@ circuit_build_times_add_timeout_worker(circuit_build_times_t *cbt, // Keep getting values for the largest timeout bucket over and over // again... Probably because alpha is very very large in that case.. build_time_t gentime = circuit_build_times_generate_sample(cbt, quantile_cutoff, MAX_SYNTHETIC_QUANTILE); quantile_cutoff, CBT_MAX_SYNTHETIC_QUANTILE); if (gentime < (build_time_t)tor_lround(cbt->timeout_ms)) { log_warn(LD_CIRC, "Generated a synthetic timeout LESS than the current timeout: " "%ums vs %lfms using Xm: %d a: %lf, q: %lf", gentime, cbt->timeout_ms, cbt->Xm, cbt->alpha, quantile_cutoff); } else if (gentime > BUILD_TIME_MAX) { } else if (gentime > CBT_BUILD_TIME_MAX) { log_info(LD_CIRC, "Generated a synthetic timeout larger than the max: %u", gentime); gentime = BUILD_TIME_MAX; gentime = CBT_BUILD_TIME_MAX; } else { log_info(LD_CIRC, "Generated synthetic circuit build time %u for timeout", gentime); Loading Loading @@ -653,7 +743,7 @@ circuit_build_times_count_pretimeouts(circuit_build_times_t *cbt) ((double)cbt->pre_timeouts)/ (cbt->pre_timeouts+cbt->total_build_times); /* Make sure it doesn't exceed the synthetic max */ timeout_quantile *= MAX_SYNTHETIC_QUANTILE; timeout_quantile *= CBT_MAX_SYNTHETIC_QUANTILE; cbt->Xm = circuit_build_times_mode(cbt); tor_assert(cbt->Xm > 0); /* Use current timeout to get an estimate on alpha */ Loading @@ -673,7 +763,7 @@ int circuit_build_times_needs_circuits(circuit_build_times_t *cbt) { /* Return true if < MIN_CIRCUITS_TO_OBSERVE */ if (cbt->total_build_times < MIN_CIRCUITS_TO_OBSERVE) if (cbt->total_build_times < circuit_build_times_min_circs_to_observe()) return 1; return 0; } Loading @@ -686,7 +776,7 @@ int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt) { return circuit_build_times_needs_circuits(cbt) && approx_time()-cbt->last_circ_at > BUILD_TIMES_TEST_FREQUENCY; approx_time()-cbt->last_circ_at > circuit_build_times_test_frequency(); } /** Loading @@ -712,7 +802,7 @@ circuit_build_times_network_circ_success(circuit_build_times_t *cbt) { cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] = 0; cbt->liveness.after_firsthop_idx++; cbt->liveness.after_firsthop_idx %= RECENT_CIRCUITS; cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; } /** Loading Loading @@ -743,7 +833,7 @@ circuit_build_times_network_timeout(circuit_build_times_t *cbt, /* Count a one-hop timeout */ cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx]=1; cbt->liveness.after_firsthop_idx++; cbt->liveness.after_firsthop_idx %= RECENT_CIRCUITS; cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; } } Loading @@ -758,7 +848,7 @@ int circuit_build_times_network_check_live(circuit_build_times_t *cbt) { time_t now = approx_time(); if (cbt->liveness.nonlive_timeouts >= NETWORK_NONLIVE_DISCARD_COUNT) { if (cbt->liveness.nonlive_timeouts >= CBT_NETWORK_NONLIVE_DISCARD_COUNT) { if (!cbt->liveness.nonlive_discarded) { cbt->liveness.nonlive_discarded = 1; log_notice(LD_CIRC, "Network is no longer live (too many recent " Loading @@ -766,11 +856,13 @@ circuit_build_times_network_check_live(circuit_build_times_t *cbt) (long int)(now - cbt->liveness.network_last_live)); /* Only discard NETWORK_NONLIVE_TIMEOUT_COUNT-1 because we stopped * counting after that */ circuit_build_times_rewind_history(cbt, NETWORK_NONLIVE_TIMEOUT_COUNT-1); circuit_build_times_rewind_history(cbt, CBT_NETWORK_NONLIVE_TIMEOUT_COUNT-1); control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_DISCARD); } return 0; } else if (cbt->liveness.nonlive_timeouts >= NETWORK_NONLIVE_TIMEOUT_COUNT) { } else if (cbt->liveness.nonlive_timeouts >= CBT_NETWORK_NONLIVE_TIMEOUT_COUNT) { if (cbt->timeout_ms < circuit_build_times_get_initial_timeout()) { log_notice(LD_CIRC, "Network is flaky. No activity for %ld seconds. " Loading Loading @@ -812,19 +904,20 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt) /* how many of our recent circuits made it to the first hop but then * timed out? */ for (i = 0; i < RECENT_CIRCUITS; i++) { for (i = 0; i < cbt->liveness.num_recent_circs; i++) { timeout_count += cbt->liveness.timeouts_after_firsthop[i]; } /* If 80% of our recent circuits are timing out after the first hop, * we need to re-estimate a new initial alpha and timeout. */ if (timeout_count < MAX_RECENT_TIMEOUT_COUNT) { if (timeout_count < circuit_build_times_max_timeouts()) { return 0; } circuit_build_times_reset(cbt); memset(cbt->liveness.timeouts_after_firsthop, 0, sizeof(cbt->liveness.timeouts_after_firsthop)); sizeof(*cbt->liveness.timeouts_after_firsthop)* cbt->liveness.num_recent_circs); cbt->liveness.after_firsthop_idx = 0; /* Check to see if this has happened before. If so, double the timeout Loading Loading @@ -875,13 +968,14 @@ circuit_build_times_add_timeout(circuit_build_times_t *cbt, cbt->pre_timeouts++; log_info(LD_CIRC, "Not enough circuits yet to calculate a new build timeout." " Need %d more.", MIN_CIRCUITS_TO_OBSERVE-cbt->total_build_times); " Need %d more.", circuit_build_times_min_circs_to_observe() - cbt->total_build_times); return 0; } circuit_build_times_count_pretimeouts(cbt); circuit_build_times_add_timeout_worker(cbt, BUILDTIMEOUT_QUANTILE_CUTOFF); circuit_build_times_add_timeout_worker(cbt, circuit_build_times_quantile_cutoff()); return 1; } Loading @@ -893,7 +987,7 @@ circuit_build_times_add_timeout(circuit_build_times_t *cbt, void circuit_build_times_set_timeout(circuit_build_times_t *cbt) { if (cbt->total_build_times < MIN_CIRCUITS_TO_OBSERVE) { if (cbt->total_build_times < circuit_build_times_min_circs_to_observe()) { return; } Loading @@ -901,14 +995,14 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt) circuit_build_times_update_alpha(cbt); cbt->timeout_ms = circuit_build_times_calculate_timeout(cbt, BUILDTIMEOUT_QUANTILE_CUTOFF); circuit_build_times_quantile_cutoff()); cbt->have_computed_timeout = 1; if (cbt->timeout_ms < BUILD_TIMEOUT_MIN_VALUE) { if (cbt->timeout_ms < circuit_build_times_min_timeout()) { log_warn(LD_CIRC, "Set buildtimeout to low value %lfms. Setting to %dms", cbt->timeout_ms, BUILD_TIMEOUT_MIN_VALUE); cbt->timeout_ms = BUILD_TIMEOUT_MIN_VALUE; cbt->timeout_ms, circuit_build_times_min_timeout()); cbt->timeout_ms = circuit_build_times_min_timeout(); } control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_COMPUTED); Loading src/or/control.c +3 −3 Original line number Diff line number Diff line Loading @@ -3480,7 +3480,7 @@ control_event_buildtimeout_set(const circuit_build_times_t *cbt, buildtimeout_set_event_t type) { const char *type_string = NULL; double qnt = BUILDTIMEOUT_QUANTILE_CUTOFF; double qnt = circuit_build_times_quantile_cutoff(); if (!control_event_is_interesting(EVENT_BUILDTIMEOUT_SET)) return 0; Loading src/or/networkstatus.c +1 −0 Original line number Diff line number Diff line Loading @@ -1680,6 +1680,7 @@ networkstatus_set_current_consensus(const char *consensus, dirvote_recalculate_timing(get_options(), now); routerstatus_list_update_named_server_map(); cell_ewma_set_scale_factor(get_options(), current_consensus); circuit_build_times_new_consensus_params(&circ_times, current_consensus); } if (!from_cache) { Loading src/or/or.h +46 −38 Original line number Diff line number Diff line Loading @@ -3002,49 +3002,27 @@ void entry_guards_free_all(void); /* Circuit Build Timeout "public" functions and structures. */ /** Total size of the circuit timeout history to accumulate. * 1000 is approx 2.5 days worth of continual-use circuits. */ #define CBT_NCIRCUITS_TO_OBSERVE 1000 /** Maximum quantile to use to generate synthetic timeouts. * We want to stay a bit short of 1.0, because longtail is * loooooooooooooooooooooooooooooooooooooooooooooooooooong. */ #define MAX_SYNTHETIC_QUANTILE 0.985 /** Minimum circuits before estimating a timeout */ #define MIN_CIRCUITS_TO_OBSERVE 20 /** Total size of the circuit timeout history to accumulate. * 5000 is approx 1.5 weeks worth of continual-use circuits. */ #define NCIRCUITS_TO_OBSERVE 5000 #define CBT_MAX_SYNTHETIC_QUANTILE 0.985 /** Width of the histogram bins in milliseconds */ #define BUILDTIME_BIN_WIDTH ((build_time_t)50) /** Cutoff point on the CDF for our timeout estimation. * TODO: This should be moved to the consensus */ #define BUILDTIMEOUT_QUANTILE_CUTOFF 0.8 #define CBT_BIN_WIDTH ((build_time_t)50) /** A build_time_t is milliseconds */ typedef uint32_t build_time_t; #define BUILD_TIME_MAX ((build_time_t)(INT32_MAX)) /** Lowest allowable value for CircuitBuildTimeout in milliseconds */ #define BUILD_TIMEOUT_MIN_VALUE (3*1000) /** Initial circuit build timeout in milliseconds */ #define BUILD_TIMEOUT_INITIAL_VALUE (60*1000) /** How often in seconds should we build a test circuit */ #define BUILD_TIMES_TEST_FREQUENCY 60 #define CBT_BUILD_TIME_MAX ((build_time_t)(INT32_MAX)) /** Save state every 10 circuits */ #define BUILD_TIMES_SAVE_STATE_EVERY 1 #define CBT_SAVE_STATE_EVERY 10 /* Circuit Build Timeout network liveness constants */ /** * How many circuits count as recent when considering if the * connection has gone gimpy or changed. */ #define RECENT_CIRCUITS 20 /** * Have we received a cell in the last N circ attempts? * Loading @@ -3053,7 +3031,7 @@ typedef uint32_t build_time_t; * at which point we switch back to computing the timeout from * our saved history. */ #define NETWORK_NONLIVE_TIMEOUT_COUNT (RECENT_CIRCUITS*3/20) #define CBT_NETWORK_NONLIVE_TIMEOUT_COUNT (3) /** * This tells us when to toss out the last streak of N timeouts. Loading @@ -3061,7 +3039,15 @@ typedef uint32_t build_time_t; * If instead we start getting cells, we switch back to computing the timeout * from our saved history. */ #define NETWORK_NONLIVE_DISCARD_COUNT (NETWORK_NONLIVE_TIMEOUT_COUNT*2) #define CBT_NETWORK_NONLIVE_DISCARD_COUNT (CBT_NETWORK_NONLIVE_TIMEOUT_COUNT*2) /* Circuit build times consensus parameters */ /** * How many circuits count as recent when considering if the * connection has gone gimpy or changed. */ #define CBT_DEFAULT_RECENT_CIRCUITS 20 /** * Maximum count of timeouts that finish the first hop in the past Loading @@ -3070,10 +3056,28 @@ typedef uint32_t build_time_t; * This tells us to abandon timeout history and set * the timeout back to BUILD_TIMEOUT_INITIAL_VALUE. */ #define MAX_RECENT_TIMEOUT_COUNT (RECENT_CIRCUITS*4/5) #define CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT (CBT_DEFAULT_RECENT_CIRCUITS*9/10) /** Minimum circuits before estimating a timeout */ #define CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE 100 /** Cutoff percentile on the CDF for our timeout estimation. */ #define CBT_DEFAULT_QUANTILE_CUTOFF 80 double circuit_build_times_quantile_cutoff(void); /** How often in seconds should we build a test circuit */ #define CBT_DEFAULT_TEST_FREQUENCY 60 /** Lowest allowable value for CircuitBuildTimeout in milliseconds */ #define CBT_DEFAULT_TIMEOUT_MIN_VALUE (2*1000) /** Initial circuit build timeout in milliseconds */ #define CBT_DEFAULT_TIMEOUT_INITIAL_VALUE (60*1000) int32_t circuit_build_times_initial_timeout(void); #if MAX_RECENT_TIMEOUT_COUNT < 1 || NETWORK_NONLIVE_DISCARD_COUNT < 1 || \ NETWORK_NONLIVE_TIMEOUT_COUNT < 1 #if CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT < 1 || \ CBT_NETWORK_NONLIVE_DISCARD_COUNT < 1 || \ CBT_NETWORK_NONLIVE_TIMEOUT_COUNT < 1 #error "RECENT_CIRCUITS is set too low." #endif Loading @@ -3087,7 +3091,9 @@ typedef struct { int nonlive_discarded; /** Circular array of circuits that have made it to the first hop. Slot is * 1 if circuit timed out, 0 if circuit succeeded */ int8_t timeouts_after_firsthop[RECENT_CIRCUITS]; int8_t *timeouts_after_firsthop; /** Number of elements allocated for the above array */ int num_recent_circs; /** Index into circular array. */ int after_firsthop_idx; /** The network is not live. Timeout gathering is suspended */ Loading @@ -3097,10 +3103,10 @@ typedef struct { /** Structure for circuit build times history */ typedef struct { /** The circular array of recorded build times in milliseconds */ build_time_t circuit_build_times[NCIRCUITS_TO_OBSERVE]; build_time_t circuit_build_times[CBT_NCIRCUITS_TO_OBSERVE]; /** Current index in the circuit_build_times circular array */ int build_times_idx; /** Total number of build times accumulated. Maxes at NCIRCUITS_TO_OBSERVE */ /** Total number of build times accumulated. Max CBT_NCIRCUITS_TO_OBSERVE */ int total_build_times; /** Information about the state of our local network connection */ network_liveness_t liveness; Loading Loading @@ -3132,6 +3138,8 @@ int circuit_build_times_add_time(circuit_build_times_t *cbt, int circuit_build_times_needs_circuits(circuit_build_times_t *cbt); int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt); void circuit_build_times_init(circuit_build_times_t *cbt); void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, networkstatus_t *ns); #ifdef CIRCUIT_PRIVATE double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, Loading src/test/test.c +18 −17 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
src/or/circuitbuild.c +147 −53 Original line number Diff line number Diff line Loading @@ -79,6 +79,92 @@ static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); static void entry_guards_changed(void); static int32_t circuit_build_times_max_timeouts(void) { int32_t num = networkstatus_get_param(NULL, "cbtmaxtimeouts", CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT); return num; } static int32_t circuit_build_times_min_circs_to_observe(void) { int32_t num = networkstatus_get_param(NULL, "cbtmincircs", CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE); return num; } double circuit_build_times_quantile_cutoff(void) { int32_t num = networkstatus_get_param(NULL, "cbtquantile", CBT_DEFAULT_QUANTILE_CUTOFF); return num/100.0; } static int32_t circuit_build_times_test_frequency(void) { int32_t num = networkstatus_get_param(NULL, "cbttestfreq", CBT_DEFAULT_TEST_FREQUENCY); return num; } static int32_t circuit_build_times_min_timeout(void) { int32_t num = networkstatus_get_param(NULL, "cbtmintimeout", CBT_DEFAULT_TIMEOUT_MIN_VALUE); return num; } int32_t circuit_build_times_initial_timeout(void) { int32_t num = networkstatus_get_param(NULL, "cbtinitialtimeout", CBT_DEFAULT_TIMEOUT_INITIAL_VALUE); return num; } static int32_t circuit_build_times_recent_circuit_count(void) { int32_t num = networkstatus_get_param(NULL, "cbtrecentcount", CBT_DEFAULT_RECENT_CIRCUITS); return num; } void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, networkstatus_t *ns) { int32_t num = networkstatus_get_param(ns, "cbtrecentcount", CBT_DEFAULT_RECENT_CIRCUITS); if (num != cbt->liveness.num_recent_circs) { int8_t *recent_circs; log_notice(LD_CIRC, "Changing recent timeout size from %d to %d", cbt->liveness.num_recent_circs, num); tor_assert(num > 0); tor_assert(cbt->liveness.timeouts_after_firsthop); recent_circs = tor_malloc_zero(sizeof(int8_t)*num); memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop, sizeof(int8_t)*MIN(num, cbt->liveness.num_recent_circs)); // Adjust the index if it needs it. if (num < cbt->liveness.num_recent_circs) { cbt->liveness.after_firsthop_idx = MIN(num-1, cbt->liveness.after_firsthop_idx); } tor_free(cbt->liveness.timeouts_after_firsthop); cbt->liveness.timeouts_after_firsthop = recent_circs; cbt->liveness.num_recent_circs = num; } } /** Make a note that we're running unit tests (rather than running Tor * itself), so we avoid clobbering our state file. */ void Loading @@ -96,13 +182,13 @@ circuit_build_times_get_initial_timeout(void) double timeout; if (!unit_tests && get_options()->CircuitBuildTimeout) { timeout = get_options()->CircuitBuildTimeout*1000; if (timeout < BUILD_TIMEOUT_MIN_VALUE) { if (timeout < circuit_build_times_min_timeout()) { log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds", BUILD_TIMEOUT_MIN_VALUE/1000); timeout = BUILD_TIMEOUT_MIN_VALUE; circuit_build_times_min_timeout()/1000); timeout = circuit_build_times_min_timeout(); } } else { timeout = BUILD_TIMEOUT_INITIAL_VALUE; timeout = circuit_build_times_initial_timeout(); } return timeout; } Loading Loading @@ -133,6 +219,9 @@ void circuit_build_times_init(circuit_build_times_t *cbt) { memset(cbt, 0, sizeof(*cbt)); cbt->liveness.num_recent_circs = circuit_build_times_recent_circuit_count(); cbt->liveness.timeouts_after_firsthop = tor_malloc_zero(sizeof(int8_t)* cbt->liveness.num_recent_circs); cbt->timeout_ms = circuit_build_times_get_initial_timeout(); control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET); } Loading Loading @@ -162,10 +251,11 @@ circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n) } cbt->build_times_idx -= n; cbt->build_times_idx %= NCIRCUITS_TO_OBSERVE; cbt->build_times_idx %= CBT_NCIRCUITS_TO_OBSERVE; for (i = 0; i < n; i++) { cbt->circuit_build_times[(i+cbt->build_times_idx)%NCIRCUITS_TO_OBSERVE]=0; cbt->circuit_build_times[(i+cbt->build_times_idx) %CBT_NCIRCUITS_TO_OBSERVE]=0; } if (cbt->total_build_times > n) { Loading @@ -189,7 +279,7 @@ circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n) int circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time) { tor_assert(time <= BUILD_TIME_MAX); tor_assert(time <= CBT_BUILD_TIME_MAX); if (time <= 0) { log_warn(LD_CIRC, "Circuit build time is %u!", time); return -1; Loading @@ -199,11 +289,11 @@ circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time) log_info(LD_CIRC, "Adding circuit build time %u", time); cbt->circuit_build_times[cbt->build_times_idx] = time; cbt->build_times_idx = (cbt->build_times_idx + 1) % NCIRCUITS_TO_OBSERVE; if (cbt->total_build_times < NCIRCUITS_TO_OBSERVE) cbt->build_times_idx = (cbt->build_times_idx + 1) % CBT_NCIRCUITS_TO_OBSERVE; if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE) cbt->total_build_times++; if ((cbt->total_build_times % BUILD_TIMES_SAVE_STATE_EVERY) == 0) { if ((cbt->total_build_times % CBT_SAVE_STATE_EVERY) == 0) { /* Save state every n circuit builds */ if (!unit_tests && !get_options()->AvoidDiskWrites) or_state_mark_dirty(get_or_state(), 0); Loading @@ -220,7 +310,7 @@ circuit_build_times_max(circuit_build_times_t *cbt) { int i = 0; build_time_t max_build_time = 0; for (i = 0; i < NCIRCUITS_TO_OBSERVE; i++) { for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (cbt->circuit_build_times[i] > max_build_time) max_build_time = cbt->circuit_build_times[i]; } Loading @@ -233,14 +323,14 @@ build_time_t circuit_build_times_min(circuit_build_times_t *cbt) { int i = 0; build_time_t min_build_time = BUILD_TIME_MAX; for (i = 0; i < NCIRCUITS_TO_OBSERVE; i++) { build_time_t min_build_time = CBT_BUILD_TIME_MAX; for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (cbt->circuit_build_times[i] && /* 0 <-> uninitialized */ cbt->circuit_build_times[i] < min_build_time) min_build_time = cbt->circuit_build_times[i]; } if (min_build_time == BUILD_TIME_MAX) { log_warn(LD_CIRC, "No build times less than BUILD_TIME_MAX!"); if (min_build_time == CBT_BUILD_TIME_MAX) { log_warn(LD_CIRC, "No build times less than CBT_BUILD_TIME_MAX!"); } return min_build_time; } Loading @@ -250,7 +340,7 @@ circuit_build_times_min(circuit_build_times_t *cbt) * Calculate and return a histogram for the set of build times. * * Returns an allocated array of histrogram bins representing * the frequency of index*BUILDTIME_BIN_WIDTH millisecond * the frequency of index*CBT_BIN_WIDTH millisecond * build times. Also outputs the number of bins in nbins. * * The return value must be freed by the caller. Loading @@ -263,14 +353,14 @@ circuit_build_times_create_histogram(circuit_build_times_t *cbt, build_time_t max_build_time = circuit_build_times_max(cbt); int i, c; *nbins = 1 + (max_build_time / BUILDTIME_BIN_WIDTH); *nbins = 1 + (max_build_time / CBT_BIN_WIDTH); histogram = tor_malloc_zero(*nbins * sizeof(build_time_t)); // calculate histogram for (i = 0; i < NCIRCUITS_TO_OBSERVE; i++) { for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (cbt->circuit_build_times[i] == 0) continue; /* 0 <-> uninitialized */ c = (cbt->circuit_build_times[i] / BUILDTIME_BIN_WIDTH); c = (cbt->circuit_build_times[i] / CBT_BIN_WIDTH); histogram[c]++; } Loading @@ -278,7 +368,7 @@ circuit_build_times_create_histogram(circuit_build_times_t *cbt, } /** * Return the most frequent build time (rounded to BUILDTIME_BIN_WIDTH ms). * Return the most frequent build time (rounded to CBT_BIN_WIDTH ms). * * Ties go in favor of the slower time. */ Loading @@ -296,7 +386,7 @@ circuit_build_times_mode(circuit_build_times_t *cbt) tor_free(histogram); return max_bin*BUILDTIME_BIN_WIDTH+BUILDTIME_BIN_WIDTH/2; return max_bin*CBT_BIN_WIDTH+CBT_BIN_WIDTH/2; } /** Loading Loading @@ -327,7 +417,7 @@ circuit_build_times_update_state(circuit_build_times_t *cbt, line->key = tor_strdup("CircuitBuildTimeBin"); line->value = tor_malloc(25); tor_snprintf(line->value, 25, "%d %d", i*BUILDTIME_BIN_WIDTH+BUILDTIME_BIN_WIDTH/2, histogram[i]); i*CBT_BIN_WIDTH+CBT_BIN_WIDTH/2, histogram[i]); next = &(line->next); } Loading @@ -350,9 +440,9 @@ circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt, int num_times) { int n = num_times; if (num_times > NCIRCUITS_TO_OBSERVE) { if (num_times > CBT_NCIRCUITS_TO_OBSERVE) { log_notice(LD_CIRC, "Decreasing circuit_build_times size from %d to %d", num_times, NCIRCUITS_TO_OBSERVE); num_times, CBT_NCIRCUITS_TO_OBSERVE); } /* This code can only be run on a compact array */ Loading @@ -363,9 +453,9 @@ circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt, raw_times[n] = tmp; } /* Since the times are now shuffled, take a random NCIRCUITS_TO_OBSERVE * subset (ie the first NCIRCUITS_TO_OBSERVE values) */ for (n = 0; n < MIN(num_times, NCIRCUITS_TO_OBSERVE); n++) { /* Since the times are now shuffled, take a random CBT_NCIRCUITS_TO_OBSERVE * subset (ie the first CBT_NCIRCUITS_TO_OBSERVE values) */ for (n = 0; n < MIN(num_times, CBT_NCIRCUITS_TO_OBSERVE); n++) { circuit_build_times_add_time(cbt, raw_times[n]); } } Loading Loading @@ -407,7 +497,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt, build_time_t ms; int ok; ms = (build_time_t)tor_parse_ulong(ms_str, 0, 0, BUILD_TIME_MAX, &ok, NULL); CBT_BUILD_TIME_MAX, &ok, NULL); if (!ok) { *msg = tor_strdup("Unable to parse circuit build times: " "Unparsable bin number"); Loading Loading @@ -453,7 +543,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt, circuit_build_times_shuffle_and_store_array(cbt, loaded_times, loaded_cnt); /* Verify that we didn't overwrite any indexes */ for (i=0; i < NCIRCUITS_TO_OBSERVE; i++) { for (i=0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (!cbt->circuit_build_times[i]) break; tot_values++; Loading @@ -462,7 +552,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt, "Loaded %d/%d values from %d lines in circuit time histogram", tot_values, cbt->total_build_times, N); tor_assert(cbt->total_build_times == tot_values); tor_assert(cbt->total_build_times <= NCIRCUITS_TO_OBSERVE); tor_assert(cbt->total_build_times <= CBT_NCIRCUITS_TO_OBSERVE); circuit_build_times_set_timeout(cbt); tor_free(loaded_times); return *msg ? -1 : 0; Loading @@ -489,7 +579,7 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt) * and less frechet-like. */ cbt->Xm = circuit_build_times_mode(cbt); for (i=0; i< NCIRCUITS_TO_OBSERVE; i++) { for (i=0; i< CBT_NCIRCUITS_TO_OBSERVE; i++) { if (!x[i]) { continue; } Loading Loading @@ -598,18 +688,18 @@ circuit_build_times_add_timeout_worker(circuit_build_times_t *cbt, // Keep getting values for the largest timeout bucket over and over // again... Probably because alpha is very very large in that case.. build_time_t gentime = circuit_build_times_generate_sample(cbt, quantile_cutoff, MAX_SYNTHETIC_QUANTILE); quantile_cutoff, CBT_MAX_SYNTHETIC_QUANTILE); if (gentime < (build_time_t)tor_lround(cbt->timeout_ms)) { log_warn(LD_CIRC, "Generated a synthetic timeout LESS than the current timeout: " "%ums vs %lfms using Xm: %d a: %lf, q: %lf", gentime, cbt->timeout_ms, cbt->Xm, cbt->alpha, quantile_cutoff); } else if (gentime > BUILD_TIME_MAX) { } else if (gentime > CBT_BUILD_TIME_MAX) { log_info(LD_CIRC, "Generated a synthetic timeout larger than the max: %u", gentime); gentime = BUILD_TIME_MAX; gentime = CBT_BUILD_TIME_MAX; } else { log_info(LD_CIRC, "Generated synthetic circuit build time %u for timeout", gentime); Loading Loading @@ -653,7 +743,7 @@ circuit_build_times_count_pretimeouts(circuit_build_times_t *cbt) ((double)cbt->pre_timeouts)/ (cbt->pre_timeouts+cbt->total_build_times); /* Make sure it doesn't exceed the synthetic max */ timeout_quantile *= MAX_SYNTHETIC_QUANTILE; timeout_quantile *= CBT_MAX_SYNTHETIC_QUANTILE; cbt->Xm = circuit_build_times_mode(cbt); tor_assert(cbt->Xm > 0); /* Use current timeout to get an estimate on alpha */ Loading @@ -673,7 +763,7 @@ int circuit_build_times_needs_circuits(circuit_build_times_t *cbt) { /* Return true if < MIN_CIRCUITS_TO_OBSERVE */ if (cbt->total_build_times < MIN_CIRCUITS_TO_OBSERVE) if (cbt->total_build_times < circuit_build_times_min_circs_to_observe()) return 1; return 0; } Loading @@ -686,7 +776,7 @@ int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt) { return circuit_build_times_needs_circuits(cbt) && approx_time()-cbt->last_circ_at > BUILD_TIMES_TEST_FREQUENCY; approx_time()-cbt->last_circ_at > circuit_build_times_test_frequency(); } /** Loading @@ -712,7 +802,7 @@ circuit_build_times_network_circ_success(circuit_build_times_t *cbt) { cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] = 0; cbt->liveness.after_firsthop_idx++; cbt->liveness.after_firsthop_idx %= RECENT_CIRCUITS; cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; } /** Loading Loading @@ -743,7 +833,7 @@ circuit_build_times_network_timeout(circuit_build_times_t *cbt, /* Count a one-hop timeout */ cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx]=1; cbt->liveness.after_firsthop_idx++; cbt->liveness.after_firsthop_idx %= RECENT_CIRCUITS; cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; } } Loading @@ -758,7 +848,7 @@ int circuit_build_times_network_check_live(circuit_build_times_t *cbt) { time_t now = approx_time(); if (cbt->liveness.nonlive_timeouts >= NETWORK_NONLIVE_DISCARD_COUNT) { if (cbt->liveness.nonlive_timeouts >= CBT_NETWORK_NONLIVE_DISCARD_COUNT) { if (!cbt->liveness.nonlive_discarded) { cbt->liveness.nonlive_discarded = 1; log_notice(LD_CIRC, "Network is no longer live (too many recent " Loading @@ -766,11 +856,13 @@ circuit_build_times_network_check_live(circuit_build_times_t *cbt) (long int)(now - cbt->liveness.network_last_live)); /* Only discard NETWORK_NONLIVE_TIMEOUT_COUNT-1 because we stopped * counting after that */ circuit_build_times_rewind_history(cbt, NETWORK_NONLIVE_TIMEOUT_COUNT-1); circuit_build_times_rewind_history(cbt, CBT_NETWORK_NONLIVE_TIMEOUT_COUNT-1); control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_DISCARD); } return 0; } else if (cbt->liveness.nonlive_timeouts >= NETWORK_NONLIVE_TIMEOUT_COUNT) { } else if (cbt->liveness.nonlive_timeouts >= CBT_NETWORK_NONLIVE_TIMEOUT_COUNT) { if (cbt->timeout_ms < circuit_build_times_get_initial_timeout()) { log_notice(LD_CIRC, "Network is flaky. No activity for %ld seconds. " Loading Loading @@ -812,19 +904,20 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt) /* how many of our recent circuits made it to the first hop but then * timed out? */ for (i = 0; i < RECENT_CIRCUITS; i++) { for (i = 0; i < cbt->liveness.num_recent_circs; i++) { timeout_count += cbt->liveness.timeouts_after_firsthop[i]; } /* If 80% of our recent circuits are timing out after the first hop, * we need to re-estimate a new initial alpha and timeout. */ if (timeout_count < MAX_RECENT_TIMEOUT_COUNT) { if (timeout_count < circuit_build_times_max_timeouts()) { return 0; } circuit_build_times_reset(cbt); memset(cbt->liveness.timeouts_after_firsthop, 0, sizeof(cbt->liveness.timeouts_after_firsthop)); sizeof(*cbt->liveness.timeouts_after_firsthop)* cbt->liveness.num_recent_circs); cbt->liveness.after_firsthop_idx = 0; /* Check to see if this has happened before. If so, double the timeout Loading Loading @@ -875,13 +968,14 @@ circuit_build_times_add_timeout(circuit_build_times_t *cbt, cbt->pre_timeouts++; log_info(LD_CIRC, "Not enough circuits yet to calculate a new build timeout." " Need %d more.", MIN_CIRCUITS_TO_OBSERVE-cbt->total_build_times); " Need %d more.", circuit_build_times_min_circs_to_observe() - cbt->total_build_times); return 0; } circuit_build_times_count_pretimeouts(cbt); circuit_build_times_add_timeout_worker(cbt, BUILDTIMEOUT_QUANTILE_CUTOFF); circuit_build_times_add_timeout_worker(cbt, circuit_build_times_quantile_cutoff()); return 1; } Loading @@ -893,7 +987,7 @@ circuit_build_times_add_timeout(circuit_build_times_t *cbt, void circuit_build_times_set_timeout(circuit_build_times_t *cbt) { if (cbt->total_build_times < MIN_CIRCUITS_TO_OBSERVE) { if (cbt->total_build_times < circuit_build_times_min_circs_to_observe()) { return; } Loading @@ -901,14 +995,14 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt) circuit_build_times_update_alpha(cbt); cbt->timeout_ms = circuit_build_times_calculate_timeout(cbt, BUILDTIMEOUT_QUANTILE_CUTOFF); circuit_build_times_quantile_cutoff()); cbt->have_computed_timeout = 1; if (cbt->timeout_ms < BUILD_TIMEOUT_MIN_VALUE) { if (cbt->timeout_ms < circuit_build_times_min_timeout()) { log_warn(LD_CIRC, "Set buildtimeout to low value %lfms. Setting to %dms", cbt->timeout_ms, BUILD_TIMEOUT_MIN_VALUE); cbt->timeout_ms = BUILD_TIMEOUT_MIN_VALUE; cbt->timeout_ms, circuit_build_times_min_timeout()); cbt->timeout_ms = circuit_build_times_min_timeout(); } control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_COMPUTED); Loading
src/or/control.c +3 −3 Original line number Diff line number Diff line Loading @@ -3480,7 +3480,7 @@ control_event_buildtimeout_set(const circuit_build_times_t *cbt, buildtimeout_set_event_t type) { const char *type_string = NULL; double qnt = BUILDTIMEOUT_QUANTILE_CUTOFF; double qnt = circuit_build_times_quantile_cutoff(); if (!control_event_is_interesting(EVENT_BUILDTIMEOUT_SET)) return 0; Loading
src/or/networkstatus.c +1 −0 Original line number Diff line number Diff line Loading @@ -1680,6 +1680,7 @@ networkstatus_set_current_consensus(const char *consensus, dirvote_recalculate_timing(get_options(), now); routerstatus_list_update_named_server_map(); cell_ewma_set_scale_factor(get_options(), current_consensus); circuit_build_times_new_consensus_params(&circ_times, current_consensus); } if (!from_cache) { Loading
src/or/or.h +46 −38 Original line number Diff line number Diff line Loading @@ -3002,49 +3002,27 @@ void entry_guards_free_all(void); /* Circuit Build Timeout "public" functions and structures. */ /** Total size of the circuit timeout history to accumulate. * 1000 is approx 2.5 days worth of continual-use circuits. */ #define CBT_NCIRCUITS_TO_OBSERVE 1000 /** Maximum quantile to use to generate synthetic timeouts. * We want to stay a bit short of 1.0, because longtail is * loooooooooooooooooooooooooooooooooooooooooooooooooooong. */ #define MAX_SYNTHETIC_QUANTILE 0.985 /** Minimum circuits before estimating a timeout */ #define MIN_CIRCUITS_TO_OBSERVE 20 /** Total size of the circuit timeout history to accumulate. * 5000 is approx 1.5 weeks worth of continual-use circuits. */ #define NCIRCUITS_TO_OBSERVE 5000 #define CBT_MAX_SYNTHETIC_QUANTILE 0.985 /** Width of the histogram bins in milliseconds */ #define BUILDTIME_BIN_WIDTH ((build_time_t)50) /** Cutoff point on the CDF for our timeout estimation. * TODO: This should be moved to the consensus */ #define BUILDTIMEOUT_QUANTILE_CUTOFF 0.8 #define CBT_BIN_WIDTH ((build_time_t)50) /** A build_time_t is milliseconds */ typedef uint32_t build_time_t; #define BUILD_TIME_MAX ((build_time_t)(INT32_MAX)) /** Lowest allowable value for CircuitBuildTimeout in milliseconds */ #define BUILD_TIMEOUT_MIN_VALUE (3*1000) /** Initial circuit build timeout in milliseconds */ #define BUILD_TIMEOUT_INITIAL_VALUE (60*1000) /** How often in seconds should we build a test circuit */ #define BUILD_TIMES_TEST_FREQUENCY 60 #define CBT_BUILD_TIME_MAX ((build_time_t)(INT32_MAX)) /** Save state every 10 circuits */ #define BUILD_TIMES_SAVE_STATE_EVERY 1 #define CBT_SAVE_STATE_EVERY 10 /* Circuit Build Timeout network liveness constants */ /** * How many circuits count as recent when considering if the * connection has gone gimpy or changed. */ #define RECENT_CIRCUITS 20 /** * Have we received a cell in the last N circ attempts? * Loading @@ -3053,7 +3031,7 @@ typedef uint32_t build_time_t; * at which point we switch back to computing the timeout from * our saved history. */ #define NETWORK_NONLIVE_TIMEOUT_COUNT (RECENT_CIRCUITS*3/20) #define CBT_NETWORK_NONLIVE_TIMEOUT_COUNT (3) /** * This tells us when to toss out the last streak of N timeouts. Loading @@ -3061,7 +3039,15 @@ typedef uint32_t build_time_t; * If instead we start getting cells, we switch back to computing the timeout * from our saved history. */ #define NETWORK_NONLIVE_DISCARD_COUNT (NETWORK_NONLIVE_TIMEOUT_COUNT*2) #define CBT_NETWORK_NONLIVE_DISCARD_COUNT (CBT_NETWORK_NONLIVE_TIMEOUT_COUNT*2) /* Circuit build times consensus parameters */ /** * How many circuits count as recent when considering if the * connection has gone gimpy or changed. */ #define CBT_DEFAULT_RECENT_CIRCUITS 20 /** * Maximum count of timeouts that finish the first hop in the past Loading @@ -3070,10 +3056,28 @@ typedef uint32_t build_time_t; * This tells us to abandon timeout history and set * the timeout back to BUILD_TIMEOUT_INITIAL_VALUE. */ #define MAX_RECENT_TIMEOUT_COUNT (RECENT_CIRCUITS*4/5) #define CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT (CBT_DEFAULT_RECENT_CIRCUITS*9/10) /** Minimum circuits before estimating a timeout */ #define CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE 100 /** Cutoff percentile on the CDF for our timeout estimation. */ #define CBT_DEFAULT_QUANTILE_CUTOFF 80 double circuit_build_times_quantile_cutoff(void); /** How often in seconds should we build a test circuit */ #define CBT_DEFAULT_TEST_FREQUENCY 60 /** Lowest allowable value for CircuitBuildTimeout in milliseconds */ #define CBT_DEFAULT_TIMEOUT_MIN_VALUE (2*1000) /** Initial circuit build timeout in milliseconds */ #define CBT_DEFAULT_TIMEOUT_INITIAL_VALUE (60*1000) int32_t circuit_build_times_initial_timeout(void); #if MAX_RECENT_TIMEOUT_COUNT < 1 || NETWORK_NONLIVE_DISCARD_COUNT < 1 || \ NETWORK_NONLIVE_TIMEOUT_COUNT < 1 #if CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT < 1 || \ CBT_NETWORK_NONLIVE_DISCARD_COUNT < 1 || \ CBT_NETWORK_NONLIVE_TIMEOUT_COUNT < 1 #error "RECENT_CIRCUITS is set too low." #endif Loading @@ -3087,7 +3091,9 @@ typedef struct { int nonlive_discarded; /** Circular array of circuits that have made it to the first hop. Slot is * 1 if circuit timed out, 0 if circuit succeeded */ int8_t timeouts_after_firsthop[RECENT_CIRCUITS]; int8_t *timeouts_after_firsthop; /** Number of elements allocated for the above array */ int num_recent_circs; /** Index into circular array. */ int after_firsthop_idx; /** The network is not live. Timeout gathering is suspended */ Loading @@ -3097,10 +3103,10 @@ typedef struct { /** Structure for circuit build times history */ typedef struct { /** The circular array of recorded build times in milliseconds */ build_time_t circuit_build_times[NCIRCUITS_TO_OBSERVE]; build_time_t circuit_build_times[CBT_NCIRCUITS_TO_OBSERVE]; /** Current index in the circuit_build_times circular array */ int build_times_idx; /** Total number of build times accumulated. Maxes at NCIRCUITS_TO_OBSERVE */ /** Total number of build times accumulated. Max CBT_NCIRCUITS_TO_OBSERVE */ int total_build_times; /** Information about the state of our local network connection */ network_liveness_t liveness; Loading Loading @@ -3132,6 +3138,8 @@ int circuit_build_times_add_time(circuit_build_times_t *cbt, int circuit_build_times_needs_circuits(circuit_build_times_t *cbt); int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt); void circuit_build_times_init(circuit_build_times_t *cbt); void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, networkstatus_t *ns); #ifdef CIRCUIT_PRIVATE double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, Loading