commit 813a0f8c40d57390412ce9dc52ef503d80e1f474 Author: Nick Mathewson nickm@torproject.org Date: Fri Jan 18 13:24:14 2013 -0500
Compute whether we're ready to build circuits based on fraction of paths
Previously we did this based on the fraction of descriptors we had. But really, we should be going based on what fraction of paths we're able to build based on weighted bandwidth, since otherwise a directory guard or two could make us behave quite oddly.
Implementation for feature 5956 --- changes/feature5956 | 6 ++ src/or/nodelist.c | 127 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 86 insertions(+), 47 deletions(-)
diff --git a/changes/feature5956 b/changes/feature5956 new file mode 100644 index 0000000..dbc6a1e --- /dev/null +++ b/changes/feature5956 @@ -0,0 +1,6 @@ + o Major features: + - When deciding whether we have enough descriptors to build circuits, + instead of looking at raw circuit counts, look at which fraction of + (bandwidth-weighted) paths we're able to build. This approach keeps + clients from building circuits if their paths are likely to stand out + statistically. Fixes issue 5956. diff --git a/src/or/nodelist.c b/src/or/nodelist.c index add9c03..77e4ae0 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -1213,7 +1213,7 @@ static int have_min_dir_info = 0; static int need_to_update_have_min_dir_info = 1; /** String describing what we're missing before we have enough directory * info. */ -static char dir_info_status[128] = ""; +static char dir_info_status[256] = "";
/** Return true iff we have enough networkstatus and router information to * start building circuits. Right now, this means "more than half the @@ -1299,6 +1299,66 @@ count_usable_descriptors(int *num_present, int *num_usable, md ? "microdesc" : "desc", exit_only ? " exits" : "s"); }
+/** Return an extimate of which fraction of usable paths through the Tor + * network we have available for use. */ +static double +compute_frac_paths_available(const networkstatus_t *consensus, + const or_options_t *options, time_t now, + int *num_present_out, int *num_usable_out, + char **status_out) +{ + smartlist_t *guards = smartlist_new(); + smartlist_t *mid = smartlist_new(); + smartlist_t *exits = smartlist_new(); + smartlist_t *myexits= smartlist_new(); + double f_guard, f_mid, f_exit, f_myexit; + int np, nu; /* Ignored */ + + count_usable_descriptors(num_present_out, num_usable_out, + mid, consensus, options, now, NULL, 0); + if (options->EntryNodes) { + count_usable_descriptors(&np, &nu, guards, consensus, options, now, + options->EntryNodes, 0); + } else { + SMARTLIST_FOREACH(mid, const node_t *, node, { + if (node->is_possible_guard) + smartlist_add(guards, (node_t*)node); + }); + } + + count_usable_descriptors(&np, &nu, exits, consensus, options, now, + NULL, 1); + count_usable_descriptors(&np, &nu, myexits, consensus, options, now, + options->ExitNodes, 1); + + f_guard = frac_nodes_with_descriptors(guards, WEIGHT_FOR_GUARD); + f_mid = frac_nodes_with_descriptors(mid, WEIGHT_FOR_MID); + f_exit = frac_nodes_with_descriptors(exits, WEIGHT_FOR_EXIT); + f_myexit= frac_nodes_with_descriptors(myexits,WEIGHT_FOR_EXIT); + + smartlist_free(guards); + smartlist_free(mid); + smartlist_free(exits); + smartlist_free(myexits); + + /* This is a tricky point here: we don't want to make it easy for a + * directory to trickle exits to us until it learns which exits we have + * configured, so require that we have a threshold both of total exits + * and usable exits. */ + if (f_myexit < f_exit) + f_exit = f_myexit; + + tor_asprintf(status_out, + "%02d%% of guards bw, " + "%02d%% of midpoint bw, and " + "%02d%% of exit bw", + (int)(f_guard*100), + (int)(f_mid*100), + (int)(f_exit*100)); + + return f_guard * f_mid * f_exit; +} + /** We just fetched a new set of descriptors. Compute how far through * the "loading descriptors" bootstrapping phase we are, so we can inform * the controller of our progress. */ @@ -1333,8 +1393,6 @@ count_loading_descriptors_progress(void) static void update_router_have_minimum_dir_info(void) { - int num_present = 0, num_usable=0; - int num_exit_present = 0, num_exit_usable = 0; time_t now = time(NULL); int res; const or_options_t *options = get_options(); @@ -1363,57 +1421,32 @@ update_router_have_minimum_dir_info(void)
using_md = consensus->flavor == FLAV_MICRODESC;
- count_usable_descriptors(&num_present, &num_usable, NULL, - consensus, options, now, - NULL, 0); - count_usable_descriptors(&num_exit_present, &num_exit_usable, NULL, - consensus, options, now, options->ExitNodes, 1); - -/* What fraction of desired server descriptors do we need before we will - * build circuits? */ -#define FRAC_USABLE_NEEDED .75 -/* What fraction of desired _exit_ server descriptors do we need before we - * will build circuits? */ -#define FRAC_EXIT_USABLE_NEEDED .5 - - if (num_present < num_usable * FRAC_USABLE_NEEDED) { - tor_snprintf(dir_info_status, sizeof(dir_info_status), - "We have only %d/%d usable %sdescriptors.", - num_present, num_usable, using_md ? "micro" : ""); - res = 0; - control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0); - goto done; - } else if (num_present < 2) { - tor_snprintf(dir_info_status, sizeof(dir_info_status), - "Only %d %sdescriptor%s here and believed reachable!", - num_present, using_md ? "micro" : "", num_present ? "" : "s"); - res = 0; - goto done; - } else if (num_exit_present < num_exit_usable * FRAC_EXIT_USABLE_NEEDED) { - tor_snprintf(dir_info_status, sizeof(dir_info_status), - "We have only %d/%d usable exit node descriptors.", - num_exit_present, num_exit_usable); - res = 0; - control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0); - goto done; - } + { + char *status = NULL; + int num_present=0, num_usable=0; + double paths = compute_frac_paths_available(consensus, options, now, + &num_present, &num_usable, + &status);
- /* Check for entry nodes. */ - if (options->EntryNodes) { - count_usable_descriptors(&num_present, &num_usable, NULL, - consensus, options, - now, options->EntryNodes, 0); +/* What fraction of desired paths do we need before we will build circuits? */ +#define FRAC_USABLE_NEEDED .6
- if (!num_usable || !num_present) { + if (paths < FRAC_USABLE_NEEDED) { tor_snprintf(dir_info_status, sizeof(dir_info_status), - "We have only %d/%d usable entry node %sdescriptors.", - num_present, num_usable, using_md?"micro":""); + "We need more %sdescriptors: we have %d/%d, and " + "can only build %02d%% of likely paths. (We have %s.)", + using_md?"micro":"", num_present, num_usable, + (int)(paths*100), status); + /* log_notice(LD_NET, "%s", dir_info_status); */ + tor_free(status); res = 0; + control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0); goto done; } - }
- res = 1; + tor_free(status); + res = 1; + }
done: if (res && !have_min_dir_info) {
tor-commits@lists.torproject.org