GuardMgr: Function to tell how permissive a filter is.

When we're filtering guards, we have to check whether the filter is
"restrictive": if it forbids most of the guards (by bandwidth), we
keep its guards separated from the main set.  If it is
super-restrictive, we also warn.

This functionality is specified in guard-spec.txt.
This commit is contained in:
Nick Mathewson 2022-06-08 09:05:38 -04:00
parent 19fa946fc7
commit a720f4f667
1 changed files with 50 additions and 0 deletions

View File

@ -79,6 +79,26 @@ impl GuardFilter {
pub(crate) fn is_unfiltered(&self) -> bool {
self.filters.is_empty()
}
/// Return a fraction between 0.0 and 1.0 describing what fraction of the
/// guard bandwidth this filter permits.
#[allow(dead_code)]
pub(crate) fn frac_bw_permitted(&self, netdir: &tor_netdir::NetDir) -> f64 {
use tor_netdir::{RelayWeight, WeightRole};
let mut guard_bw: RelayWeight = 0.into();
let mut permitted_bw: RelayWeight = 0.into();
for relay in netdir.relays() {
if relay.is_flagged_guard() {
let w = netdir.relay_weight(&relay, WeightRole::Guard);
guard_bw += w;
if self.permits(&relay) {
permitted_bw += w;
}
}
}
permitted_bw.checked_div(guard_bw).unwrap_or(1.0)
}
}
impl SingleFilter {
@ -112,3 +132,33 @@ impl SingleFilter {
Ok(first_hop)
}
}
#[cfg(test)]
mod test {
#![allow(clippy::unwrap_used)]
use super::*;
use float_eq::assert_float_eq;
use tor_netdir::testnet;
#[test]
fn permissiveness() {
let nd = testnet::construct_netdir().unwrap_if_sufficient().unwrap();
const TOL: f64 = 0.01;
let non_filter = GuardFilter::default();
assert_float_eq!(non_filter.frac_bw_permitted(&nd), 1.0, abs <= TOL);
let forbid_all = {
let mut f = GuardFilter::default();
f.push_reachable_addresses(vec!["*:1".parse().unwrap()]);
f
};
assert_float_eq!(forbid_all.frac_bw_permitted(&nd), 0.0, abs <= TOL);
let net_1_only = {
let mut f = GuardFilter::default();
f.push_reachable_addresses(vec!["1.0.0.0/8:*".parse().unwrap()]);
f
};
assert_float_eq!(net_1_only.frac_bw_permitted(&nd), 54.0 / 330.0, abs <= TOL);
}
}