aboutsummaryrefslogtreecommitdiffstats
path: root/src/transport
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-07 22:35:10 +0100
committertv <tv@krebsco.de>2026-11-07 22:35:10 +0100
commit0e03a77bcb1d39f1fbda23d8e704ac40302afb93 (patch)
tree79245416e9721cdccb1b6879b8f1cfc43629cc74 /src/transport
parentc016fc783ff29e9069a446e17876046df64760a8 (diff)
dashboard: without LINKS; LINKS removed
The dashboard reads every member's links from the members themselves; LINKS and LINKS_REPLY, swarm::links and their wire tags go (wire version bumped). Nodes the browser can't reach are drawn from what the reachable ones measure. Auth plan M3.
Diffstat (limited to 'src/transport')
-rw-r--r--src/transport/mod.rs97
-rw-r--r--src/transport/paths.rs2
-rw-r--r--src/transport/traffic.rs11
-rw-r--r--src/transport/wire.rs49
4 files changed, 4 insertions, 155 deletions
diff --git a/src/transport/mod.rs b/src/transport/mod.rs
index 8cbf412..f5b2db1 100644
--- a/src/transport/mod.rs
+++ b/src/transport/mod.rs
@@ -238,11 +238,6 @@ pub(crate) enum ParsedMessage {
nonce: u64,
at: crate::clock::UnixMillis,
},
- /// Asks a member how it is linked to its peers, for a map of the swarm
- /// (`swarm::links`).
- Links(LinksRequest),
- /// Answers a LINKS.
- LinksReply(LinksReply),
/// Asks whether the recipient reaches a member (`swarm::working_links`).
Probe(ProbeRequest),
/// Answers a PROBE.
@@ -397,8 +392,6 @@ pub(crate) enum MessageKind {
Me,
Ping,
Pong,
- Links,
- LinksReply,
Probe,
ProbeReply,
Prune,
@@ -421,8 +414,6 @@ impl ParsedMessage {
ParsedMessage::Me(_) => MessageKind::Me,
ParsedMessage::Ping(_) => MessageKind::Ping,
ParsedMessage::Pong { .. } => MessageKind::Pong,
- ParsedMessage::Links(_) => MessageKind::Links,
- ParsedMessage::LinksReply(_) => MessageKind::LinksReply,
ParsedMessage::Probe(_) => MessageKind::Probe,
ParsedMessage::ProbeReply(_) => MessageKind::ProbeReply,
ParsedMessage::Prune(_) => MessageKind::Prune,
@@ -446,8 +437,6 @@ impl ParsedMessage {
Some((status.epoch, status.epoch_seq))
}
ParsedMessage::Blob(blob) => Some((blob.epoch, blob.epoch_seq)),
- ParsedMessage::Links(request) => Some((request.epoch, request.epoch_seq)),
- ParsedMessage::LinksReply(reply) => Some((reply.epoch, reply.epoch_seq)),
ParsedMessage::Probe(request) => Some((request.epoch, request.epoch_seq)),
ParsedMessage::ProbeReply(reply) => Some((reply.epoch, reply.epoch_seq)),
ParsedMessage::Prune(link) | ParsedMessage::Graft(link) => {
@@ -530,92 +519,6 @@ pub(crate) struct ProbeReply {
pub(crate) reached: Option<bool>,
}
-/// LINKS: what a member is asked for a map of the swarm (`swarm::links`).
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub(crate) struct LinksRequest {
- #[serde(with = "crate::transport::wire::codec::epoch")]
- pub(crate) epoch: Epoch,
- /// See `SyncEnvelope::epoch_seq`.
- pub(crate) epoch_seq: u32,
- /// Repeated in the reply: which request it answers.
- pub(crate) nonce: u64,
- /// For this long (seconds), a LINKS_REPLY again whenever the links change (a
- /// subscription; the next LINKS renews it). 0: this reply only, and a subscription
- /// ends (a relayed one runs out instead).
- pub(crate) subscribe_secs: u32,
- /// Members the receiver is to ask on the sender's behalf, which the sender can't
- /// reach, passing their links on (relayed, `swarm::links`); none: the receiver's own.
- pub(crate) of: Vec<String>,
- /// How long relayed links may be held to send several in one LINKS_REPLY, by the
- /// receiver and the hops after it together (milliseconds; `swarm::links`).
- pub(crate) batch_ms: u32,
- /// How many more nodes a relayed request may go through, after the receiver.
- pub(crate) hops: u8,
-}
-
-/// LINKS_REPLY: how the sender is linked to its neighbours, as it measures them.
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub(crate) struct LinksReply {
- #[serde(with = "crate::transport::wire::codec::epoch")]
- pub(crate) epoch: Epoch,
- /// See `SyncEnvelope::epoch_seq`.
- pub(crate) epoch_seq: u32,
- /// The request's.
- pub(crate) nonce: u64,
- /// The sender's own, if asked for; at most `swarm::links::MAX_LINKS`.
- pub(crate) links: Vec<Link>,
- /// Other members' links, passed on (`LinksRequest::of`).
- pub(crate) relayed: Vec<RelayedLinks>,
-}
-
-/// A member's links as a LINKS_REPLY passes them on.
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub(crate) struct RelayedLinks {
- pub(crate) member: String,
- /// How long ago the member reported them (milliseconds).
- pub(crate) age_ms: u32,
- /// The member's epoch, as its LINKS_REPLY said (`LinksReply::epoch`): a dashboard
- /// shows who entered a new one, swarm-wide.
- #[serde(with = "crate::transport::wire::codec::epoch")]
- pub(crate) epoch: Epoch,
- pub(crate) links: Vec<Link>,
-}
-
-/// One of a member's links, in a LINKS_REPLY.
-#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
-pub(crate) struct Link {
- /// The peer's node ID.
- pub(crate) peer: String,
- /// The transport its messages go over now (the scheme of the path in use), if any.
- pub(crate) transport: Option<String>,
- /// Only through a relay (libp2p).
- pub(crate) relayed: bool,
- /// The path in use is down: none to the peer answers (`paths`), whatever its
- /// connection was.
- pub(crate) down: bool,
- /// The round trip on that path, in microseconds, if measured.
- pub(crate) rtt_us: Option<u32>,
- /// Silent for long (`peers.md`, dormancy).
- pub(crate) dormant: bool,
- /// The peer's other transports (`swarm::links::MAX_OTHERS` at most): where else
- /// it proved itself, those paths up.
- pub(crate) others: Vec<OtherPath>,
- /// How far the peer's clock is ahead of the member's (`paths::ClockOffset`), if
- /// measured: with every member's, a map of the swarm shows whose clock is off.
- pub(crate) clock: Option<paths::ClockOffset>,
-}
-
-/// A transport of a link besides the one in use, in a LINKS_REPLY.
-#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
-pub(crate) struct OtherPath {
- /// Its scheme (`mycelium`, `libp2p`, `tor`).
- pub(crate) transport: String,
- /// The round trip of its fastest path, in microseconds, if any is measured.
- pub(crate) rtt_us: Option<u32>,
- /// Only through a relay (libp2p): no direct connection at any of its paths.
- pub(crate) relayed: bool,
-}
-
#[derive(Clone, Serialize, Deserialize)]
pub(crate) struct HelloRequest {
/// The sender's swarm, if it knows it (a new node doesn't yet). A receiver in
diff --git a/src/transport/paths.rs b/src/transport/paths.rs
index aca0684..844a897 100644
--- a/src/transport/paths.rs
+++ b/src/transport/paths.rs
@@ -209,7 +209,7 @@ impl Table {
/// `usable`, with each one's place in the configured order, best first (as
/// `Paths::rank` says). With `sending`, for a message about to go: they count as
/// used (`ACTIVE_FOR`), and the one in use may change for a faster one. Without, a
- /// look at the choice as it stands, changing nothing (`/peers`, figures, LINKS).
+ /// look at the choice as it stands, changing nothing (`/peers`, figures, the dashboard's links).
fn rank(
&mut self,
mut usable: Vec<(String, usize)>,
diff --git a/src/transport/traffic.rs b/src/transport/traffic.rs
index 8220041..13ca9fa 100644
--- a/src/transport/traffic.rs
+++ b/src/transport/traffic.rs
@@ -51,8 +51,6 @@ pub(crate) struct ByKind {
pub(crate) identity: Counter,
/// PING and PONG (`transport::paths`), counted by the paths layer under the address.
pub(crate) paths: Counter,
- /// LINKS and LINKS_REPLY (`swarm::links`).
- pub(crate) links: Counter,
/// PROBE and PROBE_REPLY (`swarm::working_links`).
pub(crate) probe: Counter,
/// PRUNE and GRAFT (`swarm::plumtree`).
@@ -72,7 +70,6 @@ impl ByKind {
MessageKind::Blob,
MessageKind::Who,
MessageKind::Ping,
- MessageKind::Links,
MessageKind::Probe,
MessageKind::Prune,
MessageKind::Neighbour,
@@ -92,7 +89,6 @@ impl ByKind {
MessageKind::Blob => &self.blob,
MessageKind::Who | MessageKind::Me => &self.identity,
MessageKind::Ping | MessageKind::Pong => &self.paths,
- MessageKind::Links | MessageKind::LinksReply => &self.links,
MessageKind::Probe | MessageKind::ProbeReply => &self.probe,
MessageKind::Prune | MessageKind::Graft => &self.plumtree,
MessageKind::Neighbour | MessageKind::NeighbourReply | MessageKind::Disconnect => {
@@ -111,7 +107,6 @@ impl ByKind {
MessageKind::Blob => &mut self.blob,
MessageKind::Who | MessageKind::Me => &mut self.identity,
MessageKind::Ping | MessageKind::Pong => &mut self.paths,
- MessageKind::Links | MessageKind::LinksReply => &mut self.links,
MessageKind::Probe | MessageKind::ProbeReply => &mut self.probe,
MessageKind::Prune | MessageKind::Graft => &mut self.plumtree,
MessageKind::Neighbour | MessageKind::NeighbourReply | MessageKind::Disconnect => {
@@ -199,7 +194,7 @@ pub(crate) struct Logged {
/// What ties `message`, with `peer`, to other messages: a PING and its PONG (the
/// nonce alone: a PING may go to an address and its PONG come back up from the node
-/// there, `paths`), a LINKS and its replies (the nonce), a HELLO and its replies (the run of the
+/// there, `paths`), a HELLO and its replies (the run of the
/// node that sent the HELLO, which the reply echoes), a blob's requests and answers, from
/// any peer (its ID), and a delta offered in a SYNC with the blob it is fetched as. None
/// for the rest (a STATUS and its reply carry nothing of the kind).
@@ -209,8 +204,6 @@ fn related(peer: &str, message: &ParsedMessage) -> Option<String> {
ParsedMessage::Ping(nonce) | ParsedMessage::Pong { nonce, .. } => {
format!("ping {nonce}")
}
- ParsedMessage::Links(request) => format!("links {peer} {}", request.nonce),
- ParsedMessage::LinksReply(reply) => format!("links {peer} {}", reply.nonce),
ParsedMessage::Probe(request) => format!("probe {peer} {}", request.nonce),
ParsedMessage::ProbeReply(reply) => format!("probe {peer} {}", reply.nonce),
ParsedMessage::Hello(hello) => format!("hello {peer} {}", Hex(&hello.run_id)),
@@ -321,8 +314,6 @@ fn names(kind: MessageKind) -> (&'static str, &'static str) {
MessageKind::Me => ("ME", "identity"),
MessageKind::Ping => ("PING", "paths"),
MessageKind::Pong => ("PONG", "paths"),
- MessageKind::Links => ("LINKS", "links"),
- MessageKind::LinksReply => ("LINKS_REPLY", "links"),
MessageKind::Probe => ("PROBE", "probe"),
MessageKind::ProbeReply => ("PROBE_REPLY", "probe"),
MessageKind::Prune => ("PRUNE", "plumtree"),
diff --git a/src/transport/wire.rs b/src/transport/wire.rs
index 0733d9c..8ead9b0 100644
--- a/src/transport/wire.rs
+++ b/src/transport/wire.rs
@@ -14,7 +14,7 @@ use super::{EncodedMessage, MessageKind, ParsedMessage};
/// The wire format's version, the first byte of every payload. Bump it with every change
/// to a message type or a codec (`golden_bytes` fails then).
-pub(crate) const VERSION: u8 = 38;
+pub(crate) const VERSION: u8 = 39;
/// What the second byte of a payload says.
fn tag(kind: MessageKind) -> u8 {
@@ -29,8 +29,6 @@ fn tag(kind: MessageKind) -> u8 {
MessageKind::Me => 7,
MessageKind::Ping => 8,
MessageKind::Pong => 9,
- MessageKind::Links => 10,
- MessageKind::LinksReply => 11,
MessageKind::Probe => 12,
MessageKind::ProbeReply => 13,
MessageKind::Prune => 14,
@@ -90,8 +88,6 @@ pub(crate) fn encode(message: &ParsedMessage) -> Result<Vec<u8>, WireError> {
}
ParsedMessage::Ping(nonce) => rmp_serde::encode::write(&mut payload, nonce)?,
ParsedMessage::Pong { nonce, at } => rmp_serde::encode::write(&mut payload, &(nonce, at))?,
- ParsedMessage::Links(request) => rmp_serde::encode::write(&mut payload, request)?,
- ParsedMessage::LinksReply(reply) => rmp_serde::encode::write(&mut payload, reply)?,
ParsedMessage::Probe(request) => rmp_serde::encode::write(&mut payload, request)?,
ParsedMessage::ProbeReply(reply) => rmp_serde::encode::write(&mut payload, reply)?,
ParsedMessage::Prune(link) | ParsedMessage::Graft(link) => {
@@ -166,10 +162,6 @@ pub(crate) fn decode(payload: &[u8]) -> Result<ParsedMessage, WireError> {
} else if is(MessageKind::Pong) {
let (nonce, at) = rmp_serde::from_slice(body)?;
ParsedMessage::Pong { nonce, at }
- } else if is(MessageKind::Links) {
- ParsedMessage::Links(rmp_serde::from_slice(body)?)
- } else if is(MessageKind::LinksReply) {
- ParsedMessage::LinksReply(rmp_serde::from_slice(body)?)
} else if is(MessageKind::Probe) {
ParsedMessage::Probe(rmp_serde::from_slice(body)?)
} else if is(MessageKind::ProbeReply) {
@@ -504,43 +496,6 @@ pub(crate) fn samples() -> Vec<ParsedMessage> {
nonce: u64::MAX,
at: crate::clock::UnixMillis(5),
},
- ParsedMessage::Links(crate::transport::LinksRequest {
- epoch,
- epoch_seq: 1,
- nonce: 3,
- subscribe_secs: 60,
- of: vec!["q".into()],
- batch_ms: 250,
- hops: 2,
- }),
- ParsedMessage::LinksReply(crate::transport::LinksReply {
- epoch,
- epoch_seq: 1,
- nonce: 3,
- links: vec![crate::transport::Link {
- peer: "p".into(),
- transport: Some("libp2p".into()),
- relayed: true,
- down: false,
- rtt_us: Some(1500),
- dormant: false,
- others: vec![crate::transport::OtherPath {
- transport: "mycelium".into(),
- rtt_us: None,
- relayed: false,
- }],
- clock: Some(crate::transport::paths::ClockOffset {
- offset_ms: -2_500,
- within_ms: 40,
- }),
- }],
- relayed: vec![crate::transport::RelayedLinks {
- member: "q".into(),
- age_ms: 1200,
- epoch,
- links: Vec::new(),
- }],
- }),
ParsedMessage::Probe(crate::transport::ProbeRequest {
epoch,
epoch_seq: 1,
@@ -610,7 +565,7 @@ mod tests {
#[test]
fn every_kind_round_trips() {
let samples = samples();
- assert_eq!(samples.len(), 19, "a kind is missing from `samples`");
+ assert_eq!(samples.len(), 17, "a kind is missing from `samples`");
for message in samples {
let bytes = encode(&message).unwrap();
let decoded = decode(&bytes).unwrap();