aboutsummaryrefslogtreecommitdiffstats
path: root/src/transport
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-29 04:30:28 +0100
committertv <tv@krebsco.de>2026-10-29 04:30:28 +0100
commita17bc7e17109bc680f841498007adf72be3c735f (patch)
tree70425faeebf387da567d55dc1474330a56a37acc /src/transport
parent3438b80afc64a74bd68b2e3b9a9b52fd38261ec8 (diff)
paths: make probes location-aware
Diffstat (limited to 'src/transport')
-rw-r--r--src/transport/paths.rs46
1 files changed, 43 insertions, 3 deletions
diff --git a/src/transport/paths.rs b/src/transport/paths.rs
index 93ba464..13fc6db 100644
--- a/src/transport/paths.rs
+++ b/src/transport/paths.rs
@@ -113,6 +113,8 @@ struct PathState {
used: Option<Instant>,
/// Smoothed round-trip time of its PINGs.
rtt: Option<Duration>,
+ /// Where the transport went when `rtt` was measured (`Paths::location`).
+ measured_at: Option<String>,
/// The PING out, by nonce, and when it went.
probe: Option<(u64, Instant)>,
last_probe: Option<Instant>,
@@ -301,6 +303,22 @@ impl Table {
}
/// A PONG with `nonce` from `address`: the round trip, if it answers our PING out.
+ /// The transport of `address` now goes to `location` (a libp2p peer over another
+ /// connection: through a relay before, directly now): round trips measured before
+ /// were of another way, and would weigh on the next ones for minutes (`pong`
+ /// smooths), so they are dropped.
+ fn located(&mut self, address: &str, location: &str) {
+ let Some(path) = self.paths.get_mut(address) else {
+ return;
+ };
+ if path.measured_at.as_deref() != Some(location) {
+ if path.measured_at.is_some() {
+ path.rtt = None;
+ }
+ path.measured_at = Some(location.to_owned());
+ }
+ }
+
fn pong(&mut self, address: &str, nonce: u64, now: Instant) -> Option<Duration> {
let path = self.paths.get_mut(address)?;
let (expected, sent) = path.probe?;
@@ -788,9 +806,10 @@ impl Paths {
});
}
ParsedMessage::Pong(nonce) => {
- self.table
- .lock_or_recover()
- .pong(&address, nonce, Instant::now());
+ let location = self.location(&address);
+ let mut table = self.table.lock_or_recover();
+ table.located(&address, &location);
+ table.pong(&address, nonce, Instant::now());
}
_ => {}
}
@@ -1055,6 +1074,27 @@ mod tests {
assert!((rtt - 100.0).abs() < 1e-6, "{rtt}");
}
+ /// Round trips of another way to the peer (through a relay, then directly) don't
+ /// weigh on those of the new one.
+ #[test]
+ fn a_path_that_goes_elsewhere_is_measured_anew() {
+ let mut table = Table::default();
+ let now = Instant::now();
+ table.rank(paths(&["libp2p:x", "mycelium:x"]), now);
+ let ping = |table: &mut Table, nonce: u64, at: Instant, ms: u64| {
+ table.pinged("libp2p:x", nonce, at);
+ table.pong("libp2p:x", nonce, at + Duration::from_millis(ms));
+ };
+ table.located("libp2p:x", "libp2p:/relayed");
+ ping(&mut table, 1, now, 120);
+ table.located("libp2p:x", "libp2p:/relayed");
+ ping(&mut table, 2, now + Duration::from_secs(30), 120);
+ table.located("libp2p:x", "libp2p:/lan");
+ ping(&mut table, 3, now + Duration::from_secs(60), 2);
+ let rtt = table.info("libp2p:x", now).rtt_ms.unwrap();
+ assert!((rtt - 2.0).abs() < 1e-6, "{rtt}");
+ }
+
/// The node's keepalive PING on a path is its probe: paths doesn't ping it too, and
/// the PONG measures it.
#[test]