|
@@ -85,6 +85,14 @@ static const signed_descriptor_t *get_signed_descriptor_by_fp(
|
|
|
time_t publish_cutoff);
|
|
|
static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei,
|
|
|
const char **msg);
|
|
|
+static void dirserv_cache_measured_bw(measured_bw_line_t *parsed_line,
|
|
|
+ time_t as_of);
|
|
|
+static void dirserv_clear_measured_bw_cache(void);
|
|
|
+static void dirserv_expire_measured_bw_cache(time_t now);
|
|
|
+static int dirserv_get_measured_bw_cache_size(void);
|
|
|
+static int dirserv_query_measured_bw_cache(char *node_id, long *bw_out,
|
|
|
+ time_t *as_of_out);
|
|
|
+static uint32_t dirserv_get_bandwidth_for_router(routerinfo_t *ri);
|
|
|
|
|
|
|
|
|
#define MAX_MEASUREMENT_AGE (3*24*60*60)
|
|
@@ -1824,7 +1832,7 @@ dirserv_thinks_router_is_unreliable(time_t now,
|
|
|
}
|
|
|
}
|
|
|
if (need_capacity) {
|
|
|
- uint32_t bw = router_get_advertised_bandwidth(router);
|
|
|
+ uint32_t bw = dirserv_get_bandwidth_for_router(router);
|
|
|
if (bw < fast_bandwidth)
|
|
|
return 1;
|
|
|
}
|
|
@@ -1883,7 +1891,7 @@ router_counts_toward_thresholds(const node_t *node, time_t now,
|
|
|
{
|
|
|
return node->ri && router_is_active(node->ri, node, now) &&
|
|
|
!digestmap_get(omit_as_sybil, node->ri->cache_info.identity_digest) &&
|
|
|
- (router_get_advertised_bandwidth(node->ri) >=
|
|
|
+ (dirserv_get_bandwidth_for_router(node->ri) >=
|
|
|
ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER);
|
|
|
}
|
|
|
|
|
@@ -1947,7 +1955,7 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
|
|
|
uptimes[n_active] = (uint32_t)real_uptime(ri, now);
|
|
|
mtbfs[n_active] = rep_hist_get_stability(id, now);
|
|
|
tks [n_active] = rep_hist_get_weighted_time_known(id, now);
|
|
|
- bandwidths[n_active] = bw = router_get_advertised_bandwidth(ri);
|
|
|
+ bandwidths[n_active] = bw = dirserv_get_bandwidth_for_router(ri);
|
|
|
total_bandwidth += bw;
|
|
|
if (node->is_exit && !node->is_bad_exit) {
|
|
|
total_exit_bandwidth += bw;
|
|
@@ -2046,6 +2054,165 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
|
|
|
tor_free(wfus);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+typedef struct mbw_cache_entry_s {
|
|
|
+ long mbw;
|
|
|
+ time_t as_of;
|
|
|
+} mbw_cache_entry_t;
|
|
|
+
|
|
|
+
|
|
|
+ * mbw_cache_entry_t *. */
|
|
|
+static digestmap_t *mbw_cache = NULL;
|
|
|
+
|
|
|
+
|
|
|
+ * bandwidths file. */
|
|
|
+static void
|
|
|
+dirserv_cache_measured_bw(measured_bw_line_t *parsed_line, time_t as_of)
|
|
|
+{
|
|
|
+ mbw_cache_entry_t *e = NULL;
|
|
|
+
|
|
|
+ tor_assert(parsed_line);
|
|
|
+
|
|
|
+
|
|
|
+ if (!mbw_cache) mbw_cache = digestmap_new();
|
|
|
+
|
|
|
+
|
|
|
+ e = digestmap_get(mbw_cache, parsed_line->node_id);
|
|
|
+
|
|
|
+ if (e) {
|
|
|
+
|
|
|
+ if (as_of > e->as_of) {
|
|
|
+ e->mbw = parsed_line->bw;
|
|
|
+ e->as_of = as_of;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+
|
|
|
+ e = tor_malloc(sizeof(*e));
|
|
|
+ e->mbw = parsed_line->bw;
|
|
|
+ e->as_of = as_of;
|
|
|
+ digestmap_set(mbw_cache, parsed_line->node_id, e);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static void
|
|
|
+dirserv_clear_measured_bw_cache(void)
|
|
|
+{
|
|
|
+ if (mbw_cache) {
|
|
|
+
|
|
|
+ digestmap_free(mbw_cache, tor_free_);
|
|
|
+ mbw_cache = NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static void
|
|
|
+dirserv_expire_measured_bw_cache(time_t now)
|
|
|
+{
|
|
|
+ digestmap_iter_t *itr = NULL;
|
|
|
+ const char *k = NULL;
|
|
|
+ void *e_v = NULL;
|
|
|
+ mbw_cache_entry_t *e = NULL;
|
|
|
+ int rmv;
|
|
|
+
|
|
|
+ if (mbw_cache) {
|
|
|
+
|
|
|
+ itr = digestmap_iter_init(mbw_cache);
|
|
|
+ while (!digestmap_iter_done(itr)) {
|
|
|
+ rmv = 0;
|
|
|
+ digestmap_iter_get(itr, &k, &e_v);
|
|
|
+ e = (mbw_cache_entry_t *)e_v;
|
|
|
+ if (e) {
|
|
|
+
|
|
|
+ if (now - e->as_of > MAX_MEASUREMENT_AGE) {
|
|
|
+ tor_free(e);
|
|
|
+ rmv = 1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+
|
|
|
+ log_warn(LD_BUG, "Saw NULL entry in measured bandwidth cache");
|
|
|
+ rmv = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (rmv) {
|
|
|
+ itr = digestmap_iter_next_rmv(mbw_cache, itr);
|
|
|
+ } else {
|
|
|
+ itr = digestmap_iter_next(mbw_cache, itr);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (digestmap_size(mbw_cache) == 0) {
|
|
|
+ digestmap_free(mbw_cache, tor_free_);
|
|
|
+ mbw_cache = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int
|
|
|
+dirserv_get_measured_bw_cache_size(void)
|
|
|
+{
|
|
|
+ if (mbw_cache) return digestmap_size(mbw_cache);
|
|
|
+ else return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * we found it. */
|
|
|
+static int
|
|
|
+dirserv_query_measured_bw_cache(char *node_id, long *bw_out,
|
|
|
+ time_t *as_of_out)
|
|
|
+{
|
|
|
+ mbw_cache_entry_t *v = NULL;
|
|
|
+ int rv = 0;
|
|
|
+
|
|
|
+ if (mbw_cache && node_id) {
|
|
|
+ v = digestmap_get(mbw_cache, node_id);
|
|
|
+ if (v) {
|
|
|
+
|
|
|
+ rv = 1;
|
|
|
+ if (bw_out) *bw_out = v->mbw;
|
|
|
+ if (as_of_out) *as_of_out = v->as_of;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return rv;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * preferring measured to advertised values if available. */
|
|
|
+
|
|
|
+static uint32_t
|
|
|
+dirserv_get_bandwidth_for_router(routerinfo_t *ri)
|
|
|
+{
|
|
|
+ uint32_t bw = 0;
|
|
|
+
|
|
|
+ * Yeah, measured bandwidths in measured_bw_line_t are (implicitly
|
|
|
+ * signed) longs and the ones router_get_advertised_bandwidth() returns
|
|
|
+ * are uint32_t.
|
|
|
+ */
|
|
|
+ long mbw = 0;
|
|
|
+
|
|
|
+ if (ri) {
|
|
|
+
|
|
|
+ * * First try to see if we have a measured bandwidth; don't bother with
|
|
|
+ * as_of_out here, on the theory that a stale measured bandwidth is still
|
|
|
+ * better to trust than an advertised one.
|
|
|
+ */
|
|
|
+ if (dirserv_query_measured_bw_cache(ri->cache_info.identity_digest,
|
|
|
+ &mbw, NULL)) {
|
|
|
+
|
|
|
+ bw = (uint32_t)mbw;
|
|
|
+ } else {
|
|
|
+
|
|
|
+ bw = router_get_advertised_bandwidth(ri);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return bw;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
* in a vote document. */
|
|
|
char *
|
|
@@ -2327,8 +2494,8 @@ compare_routerinfo_by_ip_and_bw_(const void **a, const void **b)
|
|
|
else if (!first_is_running && second_is_running)
|
|
|
return 1;
|
|
|
|
|
|
- bw_first = router_get_advertised_bandwidth(first);
|
|
|
- bw_second = router_get_advertised_bandwidth(second);
|
|
|
+ bw_first = dirserv_get_bandwidth_for_router(first);
|
|
|
+ bw_second = dirserv_get_bandwidth_for_router(second);
|
|
|
|
|
|
if (bw_first > bw_second)
|
|
|
return -1;
|
|
@@ -2468,7 +2635,7 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
|
|
|
int listbaddirs, int vote_on_hsdirs)
|
|
|
{
|
|
|
const or_options_t *options = get_options();
|
|
|
- uint32_t routerbw = router_get_advertised_bandwidth(ri);
|
|
|
+ uint32_t routerbw = dirserv_get_bandwidth_for_router(ri);
|
|
|
|
|
|
memset(rs, 0, sizeof(routerstatus_t));
|
|
|
|
|
@@ -2670,8 +2837,9 @@ dirserv_read_measured_bandwidths(const char *from_file,
|
|
|
char line[256];
|
|
|
FILE *fp = tor_fopen_cloexec(from_file, "r");
|
|
|
int applied_lines = 0;
|
|
|
- time_t file_time;
|
|
|
+ time_t file_time, now;
|
|
|
int ok;
|
|
|
+
|
|
|
if (fp == NULL) {
|
|
|
log_warn(LD_CONFIG, "Can't open bandwidth file at configured location: %s",
|
|
|
from_file);
|
|
@@ -2695,7 +2863,8 @@ dirserv_read_measured_bandwidths(const char *from_file,
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
- if ((time(NULL) - file_time) > MAX_MEASUREMENT_AGE) {
|
|
|
+ now = time(NULL);
|
|
|
+ if ((now - file_time) > MAX_MEASUREMENT_AGE) {
|
|
|
log_warn(LD_DIRSERV, "Bandwidth measurement file stale. Age: %u",
|
|
|
(unsigned)(time(NULL) - file_time));
|
|
|
fclose(fp);
|
|
@@ -2709,12 +2878,17 @@ dirserv_read_measured_bandwidths(const char *from_file,
|
|
|
measured_bw_line_t parsed_line;
|
|
|
if (fgets(line, sizeof(line), fp) && strlen(line)) {
|
|
|
if (measured_bw_line_parse(&parsed_line, line) != -1) {
|
|
|
+
|
|
|
+ dirserv_cache_measured_bw(&parsed_line, file_time);
|
|
|
if (measured_bw_line_apply(&parsed_line, routerstatuses) > 0)
|
|
|
applied_lines++;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ dirserv_expire_measured_bw_cache(now);
|
|
|
+
|
|
|
fclose(fp);
|
|
|
log_info(LD_DIRSERV,
|
|
|
"Bandwidth measurement file successfully read. "
|
|
@@ -2778,6 +2952,14 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
|
|
|
if (!contact)
|
|
|
contact = "(none)";
|
|
|
|
|
|
+
|
|
|
+ * Do this so dirserv_compute_performance_thresholds() and
|
|
|
+ * set_routerstatus_from_routerinfo() see up-to-date bandwidth info.
|
|
|
+ */
|
|
|
+ if (options->V3BandwidthsFile) {
|
|
|
+ dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL);
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
* means. */
|
|
|
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, {
|
|
@@ -2841,6 +3023,14 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
|
|
|
if (options->V3BandwidthsFile) {
|
|
|
dirserv_read_measured_bandwidths(options->V3BandwidthsFile,
|
|
|
routerstatuses);
|
|
|
+ } else {
|
|
|
+
|
|
|
+ * No bandwidths file; clear the measured bandwidth cache in case we had
|
|
|
+ * one last time around.
|
|
|
+ */
|
|
|
+ if (dirserv_get_measured_bw_cache_size() > 0) {
|
|
|
+ dirserv_clear_measured_bw_cache();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
v3_out = tor_malloc_zero(sizeof(networkstatus_t));
|