diff --git a/crates/integration-tests/src/lib.rs b/crates/integration-tests/src/lib.rs index 902aeab..35fa456 100644 --- a/crates/integration-tests/src/lib.rs +++ b/crates/integration-tests/src/lib.rs @@ -56,6 +56,7 @@ pub fn peer_config(name: &str, endpoint: impl Into, remote_asn: u32) - groups: Vec::new(), reflector_client: false, passive: false, + expected_routes: None, } } diff --git a/crates/server/proto/config.proto b/crates/server/proto/config.proto index 2efe0d1..e74ea34 100644 --- a/crates/server/proto/config.proto +++ b/crates/server/proto/config.proto @@ -384,6 +384,15 @@ message Peer { // new peer whose side is not ready yet, or one that is to open the // connections itself. bool passive = 16; + + // About how many routes the peer sends when all is well: a full table, + // a few hundred from an exchange peer, one from a customer. Nothing is + // decided by it. The status page compares the routes the peer has in + // the table with it, and shows an established session with fewer than + // half as needing attention: a peer that is up but has sent next to + // nothing looks, without this, exactly like one that is fine. Zero, the + // default, compares nothing. + uint32 expected_routes = 17; } // What is announced to a peer. diff --git a/crates/server/src/config.rs b/crates/server/src/config.rs index 3c27d7c..8fa6c9f 100644 --- a/crates/server/src/config.rs +++ b/crates/server/src/config.rs @@ -113,6 +113,9 @@ pub struct PeerConfig { pub reflector_client: bool, /// Do not dial the peer: wait for it to connect. pub passive: bool, + /// About how many routes the peer sends when all is well, for the + /// status page to compare with; nothing here acts on it. + pub expected_routes: Option, } impl Config { @@ -555,6 +558,7 @@ fn parse_peer(peer: Peer, defaults: &PeerDefaults) -> Result 0), }) } @@ -1494,6 +1498,24 @@ mod tests { )); } + /// What a peer is expected to send is kept for the status page; zero, + /// the default, is nothing to compare with. + #[test] + fn expected_routes_are_kept_when_given() { + let config = parse(&format!( + "{BASE}peers {{ name: \"a\" endpoint {{ address: \"192.0.2.2\" }} remote_asn: 1 + expected_routes: 900000 }} + peers {{ name: \"b\" endpoint {{ address: \"192.0.2.3\" }} remote_asn: 2 }}" + )) + .unwrap(); + let expected: Vec> = config + .peers + .iter() + .map(|peer| peer.expected_routes) + .collect(); + assert_eq!(expected, [Some(900_000), None]); + } + /// A peer is dialled unless it is passive. #[test] fn a_peer_can_be_left_to_connect() { diff --git a/crates/server/src/server.rs b/crates/server/src/server.rs index fe9ffb2..2ad8656 100644 --- a/crates/server/src/server.rs +++ b/crates/server/src/server.rs @@ -127,6 +127,7 @@ impl BgpServer { remote_asn: p.remote_asn, role: p.role, passive: p.passive, + expected_routes: p.expected_routes, }) .collect(); // The client starts now: with luck the data is there before the diff --git a/crates/server/src/session.rs b/crates/server/src/session.rs index b184055..f199307 100644 --- a/crates/server/src/session.rs +++ b/crates/server/src/session.rs @@ -75,6 +75,8 @@ pub struct ConfiguredPeer { pub role: Option, /// Whether it is left to the peer to connect. pub passive: bool, + /// About how many routes it sends when all is well, if that was said. + pub expected_routes: Option, } /// Counts kept by a session as it goes, for whoever wants to look. diff --git a/crates/web/src/api.rs b/crates/web/src/api.rs index bef659a..c556b33 100644 --- a/crates/web/src/api.rs +++ b/crates/web/src/api.rs @@ -92,6 +92,9 @@ pub struct PeerView { /// How many of the peer's routes are held out of the table as invalid /// by the RPKI's data, to be taken if that changes. pub held_routes: Option, + /// About how many routes the peer sends when all is well, from the + /// configuration (`expected_routes`), for `routes` to be compared with. + pub expected_routes: Option, /// What the peer is to us, if configured: `provider`, `customer`, /// `peer`, `route server` or `route server client`. pub role: Option<&'static str>, @@ -157,6 +160,7 @@ impl From<&SessionHandle> for PeerView { routes: Some(s.counters.routes()), rejected_routes: Some(s.counters.rejected()), held_routes: Some(s.counters.held()), + expected_routes: None, role: s.role.map(PeerRole::as_str), role_confirmed: s.role.map(|_| s.role_confirmed), last_error: None, @@ -195,6 +199,7 @@ impl PeerView { routes: None, rejected_routes: None, held_routes: None, + expected_routes: peer.expected_routes, role: peer.role.map(PeerRole::as_str), role_confirmed: None, last_error, @@ -225,6 +230,7 @@ pub fn peer_views(registry: &SessionRegistry, restarts: &Restarts) -> Vec + Status for ferrix_bgp