|
@@ -2030,9 +2030,10 @@ compute_weighted_bandwidths(const smartlist_t *sl,
|
|
|
if (Wg < 0 || Wm < 0 || We < 0 || Wd < 0 || Wgb < 0 || Wmb < 0 || Wdb < 0
|
|
|
|| Web < 0) {
|
|
|
log_debug(LD_CIRC,
|
|
|
- "Got negative bandwidth weights. Defaulting to old selection"
|
|
|
+ "Got negative bandwidth weights. Defaulting to naive selection"
|
|
|
" algorithm.");
|
|
|
- return -1; // Use old algorithm.
|
|
|
+ Wg = Wm = We = Wd = weight_scale;
|
|
|
+ Wgb = Wmb = Web = Wdb = weight_scale;
|
|
|
}
|
|
|
|
|
|
Wg /= weight_scale;
|
|
@@ -2048,6 +2049,7 @@ compute_weighted_bandwidths(const smartlist_t *sl,
|
|
|
bandwidths = tor_calloc(smartlist_len(sl), sizeof(u64_dbl_t));
|
|
|
|
|
|
// Cycle through smartlist and total the bandwidth.
|
|
|
+ static int warned_missing_bw = 0;
|
|
|
SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
|
|
|
int is_exit = 0, is_guard = 0, is_dir = 0, this_bw = 0;
|
|
|
double weight = 1;
|
|
@@ -2056,15 +2058,18 @@ compute_weighted_bandwidths(const smartlist_t *sl,
|
|
|
is_dir = node_is_dir(node);
|
|
|
if (node->rs) {
|
|
|
if (!node->rs->has_bandwidth) {
|
|
|
- tor_free(bandwidths);
|
|
|
/* This should never happen, unless all the authorites downgrade
|
|
|
* to 0.2.0 or rogue routerstatuses get inserted into our consensus. */
|
|
|
- log_warn(LD_BUG,
|
|
|
- "Consensus is not listing bandwidths. Defaulting back to "
|
|
|
- "old router selection algorithm.");
|
|
|
- return -1;
|
|
|
+ if (! warned_missing_bw) {
|
|
|
+ log_warn(LD_BUG,
|
|
|
+ "Consensus is missing some bandwidths. Using a naive "
|
|
|
+ "router selection algorithm");
|
|
|
+ warned_missing_bw = 1;
|
|
|
+ }
|
|
|
+ this_bw = 30000; /* Chosen arbitrarily */
|
|
|
+ } else {
|
|
|
+ this_bw = kb_to_bytes(node->rs->bandwidth_kb);
|
|
|
}
|
|
|
- this_bw = kb_to_bytes(node->rs->bandwidth_kb);
|
|
|
} else if (node->ri) {
|
|
|
/* bridge or other descriptor not in our consensus */
|
|
|
this_bw = bridge_get_advertised_bandwidth_bounded(node->ri);
|
|
@@ -2141,226 +2146,13 @@ frac_nodes_with_descriptors(const smartlist_t *sl,
|
|
|
return present / total;
|
|
|
}
|
|
|
|
|
|
-/** Helper function:
|
|
|
- * choose a random node_t element of smartlist <b>sl</b>, weighted by
|
|
|
- * the advertised bandwidth of each element.
|
|
|
- *
|
|
|
- * If <b>rule</b>==WEIGHT_FOR_EXIT. we're picking an exit node: consider all
|
|
|
- * nodes' bandwidth equally regardless of their Exit status, since there may
|
|
|
- * be some in the list because they exit to obscure ports. If
|
|
|
- * <b>rule</b>==NO_WEIGHTING, we're picking a non-exit node: weight
|
|
|
- * exit-node's bandwidth less depending on the smallness of the fraction of
|
|
|
- * Exit-to-total bandwidth. If <b>rule</b>==WEIGHT_FOR_GUARD, we're picking a
|
|
|
- * guard node: consider all guard's bandwidth equally. Otherwise, weight
|
|
|
- * guards proportionally less.
|
|
|
- */
|
|
|
-static const node_t *
|
|
|
-smartlist_choose_node_by_bandwidth(const smartlist_t *sl,
|
|
|
- bandwidth_weight_rule_t rule)
|
|
|
-{
|
|
|
- unsigned int i;
|
|
|
- u64_dbl_t *bandwidths;
|
|
|
- int is_exit;
|
|
|
- int is_guard;
|
|
|
- int is_fast;
|
|
|
- double total_nonexit_bw = 0, total_exit_bw = 0;
|
|
|
- double total_nonguard_bw = 0, total_guard_bw = 0;
|
|
|
- double exit_weight;
|
|
|
- double guard_weight;
|
|
|
- int n_unknown = 0;
|
|
|
- bitarray_t *fast_bits;
|
|
|
- bitarray_t *exit_bits;
|
|
|
- bitarray_t *guard_bits;
|
|
|
-
|
|
|
- // This function does not support WEIGHT_FOR_DIR
|
|
|
- // or WEIGHT_FOR_MID
|
|
|
- if (rule == WEIGHT_FOR_DIR || rule == WEIGHT_FOR_MID) {
|
|
|
- rule = NO_WEIGHTING;
|
|
|
- }
|
|
|
-
|
|
|
- /* Can't choose exit and guard at same time */
|
|
|
- tor_assert(rule == NO_WEIGHTING ||
|
|
|
- rule == WEIGHT_FOR_EXIT ||
|
|
|
- rule == WEIGHT_FOR_GUARD);
|
|
|
-
|
|
|
- if (smartlist_len(sl) == 0) {
|
|
|
- log_info(LD_CIRC,
|
|
|
- "Empty routerlist passed in to old node selection for rule %s",
|
|
|
- bandwidth_weight_rule_to_string(rule));
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- /* First count the total bandwidth weight, and make a list
|
|
|
- * of each value. We use UINT64_MAX to indicate "unknown". */
|
|
|
- bandwidths = tor_calloc(smartlist_len(sl), sizeof(u64_dbl_t));
|
|
|
- fast_bits = bitarray_init_zero(smartlist_len(sl));
|
|
|
- exit_bits = bitarray_init_zero(smartlist_len(sl));
|
|
|
- guard_bits = bitarray_init_zero(smartlist_len(sl));
|
|
|
-
|
|
|
- /* Iterate over all the routerinfo_t or routerstatus_t, and */
|
|
|
- SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
|
|
|
- /* first, learn what bandwidth we think i has */
|
|
|
- int is_known = 1;
|
|
|
- uint32_t this_bw = 0;
|
|
|
- i = node_sl_idx;
|
|
|
-
|
|
|
- is_exit = node_is_good_exit(node);
|
|
|
- is_guard = node->is_possible_guard;
|
|
|
- if (node->rs) {
|
|
|
- if (node->rs->has_bandwidth) {
|
|
|
- this_bw = kb_to_bytes(node->rs->bandwidth_kb);
|
|
|
- } else { /* guess */
|
|
|
- is_known = 0;
|
|
|
- }
|
|
|
- } else if (node->ri) {
|
|
|
- /* Must be a bridge if we're willing to use it */
|
|
|
- this_bw = bridge_get_advertised_bandwidth_bounded(node->ri);
|
|
|
- }
|
|
|
-
|
|
|
- if (is_exit)
|
|
|
- bitarray_set(exit_bits, i);
|
|
|
- if (is_guard)
|
|
|
- bitarray_set(guard_bits, i);
|
|
|
- if (node->is_fast)
|
|
|
- bitarray_set(fast_bits, i);
|
|
|
-
|
|
|
- if (is_known) {
|
|
|
- bandwidths[i].dbl = this_bw;
|
|
|
- if (is_guard)
|
|
|
- total_guard_bw += this_bw;
|
|
|
- else
|
|
|
- total_nonguard_bw += this_bw;
|
|
|
- if (is_exit)
|
|
|
- total_exit_bw += this_bw;
|
|
|
- else
|
|
|
- total_nonexit_bw += this_bw;
|
|
|
- } else {
|
|
|
- ++n_unknown;
|
|
|
- bandwidths[i].dbl = -1.0;
|
|
|
- }
|
|
|
- } SMARTLIST_FOREACH_END(node);
|
|
|
-
|
|
|
-#define EPSILON .1
|
|
|
-
|
|
|
- /* Now, fill in the unknown values. */
|
|
|
- if (n_unknown) {
|
|
|
- int32_t avg_fast, avg_slow;
|
|
|
- if (total_exit_bw+total_nonexit_bw < EPSILON) {
|
|
|
- /* if there's some bandwidth, there's at least one known router,
|
|
|
- * so no worries about div by 0 here */
|
|
|
- int n_known = smartlist_len(sl)-n_unknown;
|
|
|
- avg_fast = avg_slow = (int32_t)
|
|
|
- ((total_exit_bw+total_nonexit_bw)/((uint64_t) n_known));
|
|
|
- } else {
|
|
|
- avg_fast = 40000;
|
|
|
- avg_slow = 20000;
|
|
|
- }
|
|
|
- for (i=0; i<(unsigned)smartlist_len(sl); ++i) {
|
|
|
- if (bandwidths[i].dbl >= 0.0)
|
|
|
- continue;
|
|
|
- is_fast = bitarray_is_set(fast_bits, i);
|
|
|
- is_exit = bitarray_is_set(exit_bits, i);
|
|
|
- is_guard = bitarray_is_set(guard_bits, i);
|
|
|
- bandwidths[i].dbl = is_fast ? avg_fast : avg_slow;
|
|
|
- if (is_exit)
|
|
|
- total_exit_bw += bandwidths[i].dbl;
|
|
|
- else
|
|
|
- total_nonexit_bw += bandwidths[i].dbl;
|
|
|
- if (is_guard)
|
|
|
- total_guard_bw += bandwidths[i].dbl;
|
|
|
- else
|
|
|
- total_nonguard_bw += bandwidths[i].dbl;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* If there's no bandwidth at all, pick at random. */
|
|
|
- if (total_exit_bw+total_nonexit_bw < EPSILON) {
|
|
|
- tor_free(bandwidths);
|
|
|
- tor_free(fast_bits);
|
|
|
- tor_free(exit_bits);
|
|
|
- tor_free(guard_bits);
|
|
|
- return smartlist_choose(sl);
|
|
|
- }
|
|
|
-
|
|
|
- /* Figure out how to weight exits and guards */
|
|
|
- {
|
|
|
- double all_bw = U64_TO_DBL(total_exit_bw+total_nonexit_bw);
|
|
|
- double exit_bw = U64_TO_DBL(total_exit_bw);
|
|
|
- double guard_bw = U64_TO_DBL(total_guard_bw);
|
|
|
- /*
|
|
|
- * For detailed derivation of this formula, see
|
|
|
- * http://archives.seul.org/or/dev/Jul-2007/msg00056.html
|
|
|
- */
|
|
|
- if (rule == WEIGHT_FOR_EXIT || total_exit_bw<EPSILON)
|
|
|
- exit_weight = 1.0;
|
|
|
- else
|
|
|
- exit_weight = 1.0 - all_bw/(3.0*exit_bw);
|
|
|
-
|
|
|
- if (rule == WEIGHT_FOR_GUARD || total_guard_bw<EPSILON)
|
|
|
- guard_weight = 1.0;
|
|
|
- else
|
|
|
- guard_weight = 1.0 - all_bw/(3.0*guard_bw);
|
|
|
-
|
|
|
- if (exit_weight <= 0.0)
|
|
|
- exit_weight = 0.0;
|
|
|
-
|
|
|
- if (guard_weight <= 0.0)
|
|
|
- guard_weight = 0.0;
|
|
|
-
|
|
|
- for (i=0; i < (unsigned)smartlist_len(sl); i++) {
|
|
|
- tor_assert(bandwidths[i].dbl >= 0.0);
|
|
|
-
|
|
|
- is_exit = bitarray_is_set(exit_bits, i);
|
|
|
- is_guard = bitarray_is_set(guard_bits, i);
|
|
|
- if (is_exit && is_guard)
|
|
|
- bandwidths[i].dbl *= exit_weight * guard_weight;
|
|
|
- else if (is_guard)
|
|
|
- bandwidths[i].dbl *= guard_weight;
|
|
|
- else if (is_exit)
|
|
|
- bandwidths[i].dbl *= exit_weight;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-#if 0
|
|
|
- log_debug(LD_CIRC, "Total weighted bw = "U64_FORMAT
|
|
|
- ", exit bw = "U64_FORMAT
|
|
|
- ", nonexit bw = "U64_FORMAT", exit weight = %f "
|
|
|
- "(for exit == %d)"
|
|
|
- ", guard bw = "U64_FORMAT
|
|
|
- ", nonguard bw = "U64_FORMAT", guard weight = %f "
|
|
|
- "(for guard == %d)",
|
|
|
- U64_PRINTF_ARG(total_bw),
|
|
|
- U64_PRINTF_ARG(total_exit_bw), U64_PRINTF_ARG(total_nonexit_bw),
|
|
|
- exit_weight, (int)(rule == WEIGHT_FOR_EXIT),
|
|
|
- U64_PRINTF_ARG(total_guard_bw), U64_PRINTF_ARG(total_nonguard_bw),
|
|
|
- guard_weight, (int)(rule == WEIGHT_FOR_GUARD));
|
|
|
-#endif
|
|
|
-
|
|
|
- scale_array_elements_to_u64(bandwidths, smartlist_len(sl), NULL);
|
|
|
-
|
|
|
- {
|
|
|
- int idx = choose_array_element_by_weight(bandwidths,
|
|
|
- smartlist_len(sl));
|
|
|
- tor_free(bandwidths);
|
|
|
- tor_free(fast_bits);
|
|
|
- tor_free(exit_bits);
|
|
|
- tor_free(guard_bits);
|
|
|
- return idx < 0 ? NULL : smartlist_get(sl, idx);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
/** Choose a random element of status list <b>sl</b>, weighted by
|
|
|
* the advertised bandwidth of each node */
|
|
|
const node_t *
|
|
|
node_sl_choose_by_bandwidth(const smartlist_t *sl,
|
|
|
bandwidth_weight_rule_t rule)
|
|
|
{ /*XXXX MOVE */
|
|
|
- const node_t *ret;
|
|
|
- if ((ret = smartlist_choose_node_by_bandwidth_weights(sl, rule))) {
|
|
|
- return ret;
|
|
|
- } else {
|
|
|
- return smartlist_choose_node_by_bandwidth(sl, rule);
|
|
|
- }
|
|
|
+ return smartlist_choose_node_by_bandwidth_weights(sl, rule);
|
|
|
}
|
|
|
|
|
|
/** Return a random running node from the nodelist. Never
|