[tor-commits] [sbws/maint-1.1] Bug 33009: Require minimum bandwidth for second hop
juga at torproject.org
juga at torproject.org
Tue Apr 14 13:53:20 UTC 2020
commit 20df35c49c67b86b6fb0538e2d14a33e1bc4f011
Author: Georg Koppen <gk at torproject.org>
Date: Wed Apr 1 09:35:28 2020 +0000
Bug 33009: Require minimum bandwidth for second hop
---
sbws/core/scanner.py | 6 ++++++
sbws/lib/relaylist.py | 35 +++++++++++++++++++++++++++++++++++
tests/unit/lib/test_relaylist.py | 11 +++++++++++
3 files changed, 52 insertions(+)
diff --git a/sbws/core/scanner.py b/sbws/core/scanner.py
index 30abd0a..3210c80 100644
--- a/sbws/core/scanner.py
+++ b/sbws/core/scanner.py
@@ -211,10 +211,16 @@ def _pick_ideal_second_hop(relay, dest, rl, cont, is_exit):
else rl.non_exits
if not len(candidates):
return None
+ min_relay_bw = rl.exit_min_bw() if is_exit else rl.non_exit_min_bw()
log.debug('Picking a 2nd hop to measure %s from %d choices. is_exit=%s',
relay.nickname, len(candidates), is_exit)
for min_bw_factor in [2, 1.75, 1.5, 1.25, 1]:
min_bw = relay.consensus_bandwidth * min_bw_factor
+ # We might have a really slow/new relay. Try to measure it properly by
+ # using only relays with or above our calculated min_relay_bw (see:
+ # _calculate_min_bw_second_hop() in relaylist.py).
+ if min_bw < min_relay_bw:
+ min_bw = min_relay_bw
new_candidates = stem_utils.only_relays_with_bandwidth(
cont, candidates, min_bw=min_bw)
if len(new_candidates) > 0:
diff --git a/sbws/lib/relaylist.py b/sbws/lib/relaylist.py
index 4297784..1852199 100644
--- a/sbws/lib/relaylist.py
+++ b/sbws/lib/relaylist.py
@@ -278,6 +278,9 @@ class RelayList:
[], MAX_RECENT_PRIORITY_RELAY_COUNT, state,
"recent_measurement_attempt"
)
+ # Start with 0 for the min bw for our second hops
+ self._exit_min_bw = 0
+ self._non_exit_min_bw = 0
self._refresh()
def _need_refresh(self):
@@ -431,6 +434,10 @@ class RelayList:
int(self._measurements_period / 24 / 60 / 60),
self.recent_consensus_count)
+ # Calculate minimum bandwidth value for 2nd hop after we refreshed
+ # our available relays.
+ self._calculate_min_bw_second_hop()
+
@property
def recent_consensus_count(self):
"""Number of times a new consensus was obtained."""
@@ -455,3 +462,31 @@ class RelayList:
@property
def recent_measurement_attempt_count(self):
return len(self._recent_measurement_attempt)
+
+ def _calculate_min_bw_second_hop(self):
+ """
+ Calculates the minimum bandwidth for both exit and non-exit relays
+ chosen as a second hop by picking the lowest bandwidth value available
+ from the top 75% of the respective category.
+ """
+ # Sort our sets of candidates according to bw, lowest amount first.
+ # It's okay to keep things simple for the calculation and go over all
+ # exits, including badexits.
+ exit_candidates = sorted(self.exits,
+ key=lambda r: r.consensus_bandwidth)
+ non_exit_candidates = sorted(self.non_exits,
+ key=lambda r: r.consensus_bandwidth)
+ # We know the bandwidth is sorted from least to most. Dividing the
+ # length of the available relays by 4 gives us the position of the
+ # relay with the lowest bandwidth from the top 75%. We do this both
+ # for our exit and non-exit candidates.
+ pos = int(len(exit_candidates)/4)
+ self._exit_min_bw = exit_candidates[pos].consensus_bandwidth
+ pos = int(len(non_exit_candidates)/4)
+ self._non_exit_min_bw = non_exit_candidates[pos].consensus_bandwidth
+
+ def exit_min_bw(self):
+ return self._exit_min_bw
+
+ def non_exit_min_bw(self):
+ return self._non_exit_min_bw
diff --git a/tests/unit/lib/test_relaylist.py b/tests/unit/lib/test_relaylist.py
index 88f9db5..31673ba 100644
--- a/tests/unit/lib/test_relaylist.py
+++ b/tests/unit/lib/test_relaylist.py
@@ -18,6 +18,8 @@ def test_init_relays(
Test `init_relays` when creating the RelayList the first time and when a
new consensus is received.
Test that the number of consesus timesamps and relays is correct.
+ Additionally, make sure the calculated min bw for the second hop for
+ exit/non-exit relays is correct, too.
"""
state = State(conf['paths']['state_fpath'])
# There is no need to mock datetime to update the consensus, since the
@@ -31,6 +33,9 @@ def test_init_relays(
# The actual number of relays in the consensus
assert len(relay_list._relays) == 6433
fps = {r.fingerprint for r in relay_list._relays}
+ # The calculated min bw for the second hop
+ assert 2100000 == relay_list._exit_min_bw
+ assert 220000 == relay_list._non_exit_min_bw
# One hour later there is a new consensus
relay_list._controller = controller_1h_later
@@ -44,6 +49,9 @@ def test_init_relays(
fps_1h_later = {r.fingerprint for r in relay_list._relays}
added_fps = fps_1h_later.difference(fps)
assert 6505 == 6433 + len(added_fps)
+ # The calculated min bw for the second hop
+ assert 2120000 == relay_list._exit_min_bw
+ assert 200000 == relay_list._non_exit_min_bw
# Five days later plus 1 second.
# The first consensus timestamp will get removed.
@@ -62,6 +70,9 @@ def test_init_relays(
# The number of relays will be the number of relays in the cosensus plus
# the added ones minus the removed ones.
assert 6925 == 6505 + len(added_fps) - len(removed_fps)
+ # The calculated min bw for the second hop
+ assert 2790000 == relay_list._exit_min_bw
+ assert 110000 == relay_list._non_exit_min_bw
def test_increment_recent_measurement_attempt(args, conf, controller):
More information about the tor-commits
mailing list