Passive peers: configured, and left to connect
A session could only be configured for a peer we would then dial, every few seconds to two minutes, for as long as it was not up. A new peer whose side was not ready yet filled the log with failed attempts, and a peer that opens its sessions itself was dialled for nothing. A peer with `passive: true` is not dialled. A connection from its address is taken as for any configured peer, and the session comes up with all that is configured for it: role, import policy, export limits, hold-downs. Until then the status page and /api/peers show it as `Passive`, waiting for the peer to connect; after a session, with how that session ended, which nothing else would say since nobody dials it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
910dd258fb
commit
c9751883c4
22 files changed
+178
-8
No files matched your search
@@ -43,6 +43,7 @@ async fn server_offering(
|
||||
graceful_restart: Default::default(),
|
||||
groups: Vec::new(),
|
||||
export_limits: None,
|
||||
passive: false,
|
||||
reflector_client: false,
|
||||
name: "route-server-client".into(),
|
||||
endpoint: SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 1).into(),
|
||||
|
||||
@@ -33,6 +33,7 @@ fn peer_at(endpoint: SocketAddr) -> PeerConfig {
|
||||
require_role: false,
|
||||
export: Default::default(),
|
||||
export_limits: None,
|
||||
passive: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ async fn server_with(
|
||||
graceful_restart: Default::default(),
|
||||
groups: Vec::new(),
|
||||
export_limits: None,
|
||||
passive: false,
|
||||
reflector_client: false,
|
||||
name: "r1".into(),
|
||||
endpoint: endpoint.into(),
|
||||
|
||||
@@ -39,6 +39,7 @@ async fn server_dialing(listener: &TcpListener) -> Result<TestServer> {
|
||||
graceful_restart: Default::default(),
|
||||
groups: Vec::new(),
|
||||
export_limits: None,
|
||||
passive: false,
|
||||
reflector_client: false,
|
||||
name: "r1".into(),
|
||||
endpoint: endpoint.into(),
|
||||
|
||||
@@ -170,6 +170,7 @@ async fn test_refused_routes_can_be_seen_and_counted() -> Result<()> {
|
||||
graceful_restart: Default::default(),
|
||||
groups: Vec::new(),
|
||||
export_limits: None,
|
||||
passive: false,
|
||||
reflector_client: false,
|
||||
name: "refused-demo".into(),
|
||||
endpoint: endpoint.into(),
|
||||
|
||||
@@ -23,13 +23,25 @@ const TIMEOUT: Duration = Duration::from_secs(5);
|
||||
|
||||
/// Starts a server configured to dial `listener`'s address as peer "r1".
|
||||
async fn server_dialing(listener: &TcpListener, remote_asn: u32) -> Result<TestServer> {
|
||||
server_with_peer(listener, remote_asn, false).await
|
||||
}
|
||||
|
||||
/// Starts a server with peer "r1" at `listener`'s address, which it dials
|
||||
/// unless the peer is `passive`.
|
||||
async fn server_with_peer(
|
||||
listener: &TcpListener,
|
||||
remote_asn: u32,
|
||||
passive: bool,
|
||||
) -> Result<TestServer> {
|
||||
let endpoint: SocketAddr = listener.local_addr()?;
|
||||
TestServer::start_with(LOCAL_ASN, |c| {
|
||||
c.connect_retry = Duration::from_millis(200);
|
||||
c.accept_unconfigured_peers = !passive;
|
||||
c.peers = vec![PeerConfig {
|
||||
graceful_restart: Default::default(),
|
||||
groups: Vec::new(),
|
||||
export_limits: None,
|
||||
passive,
|
||||
reflector_client: false,
|
||||
name: "r1".into(),
|
||||
endpoint: endpoint.into(),
|
||||
@@ -192,6 +204,7 @@ async fn test_inbound_from_configured_address_uses_config() -> Result<()> {
|
||||
graceful_restart: Default::default(),
|
||||
groups: Vec::new(),
|
||||
export_limits: None,
|
||||
passive: false,
|
||||
reflector_client: false,
|
||||
name: "r1".into(),
|
||||
endpoint: SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 1).into(),
|
||||
@@ -248,6 +261,7 @@ async fn test_local_address_is_used_as_the_source() -> Result<()> {
|
||||
graceful_restart: Default::default(),
|
||||
groups: Vec::new(),
|
||||
export_limits: None,
|
||||
passive: false,
|
||||
reflector_client: false,
|
||||
name: "r1".into(),
|
||||
endpoint: endpoint.into(),
|
||||
@@ -273,6 +287,7 @@ async fn test_local_address_is_used_as_the_source() -> Result<()> {
|
||||
graceful_restart: Default::default(),
|
||||
groups: Vec::new(),
|
||||
export_limits: None,
|
||||
passive: false,
|
||||
reflector_client: false,
|
||||
name: "r1".into(),
|
||||
endpoint: endpoint.into(),
|
||||
@@ -350,3 +365,57 @@ async fn test_a_peer_that_refuses_the_session_is_dialled_ever_more_slowly() -> R
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A passive peer is not dialled: its session comes up when it connects,
|
||||
/// and until then, and after, it is shown as waiting, with how its last
|
||||
/// session ended.
|
||||
#[tokio::test]
|
||||
async fn test_a_passive_peer_is_not_dialled_and_comes_up_when_it_connects() -> Result<()> {
|
||||
let listener = TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).await?;
|
||||
let server = server_with_peer(&listener, PEER_ASN, true).await?;
|
||||
let state = || server.registry.configured_peers()[0].1.clone();
|
||||
|
||||
// Many retry intervals pass, and nothing connects.
|
||||
assert!(
|
||||
tokio::time::timeout(Duration::from_secs(1), listener.accept())
|
||||
.await
|
||||
.is_err(),
|
||||
"a passive peer was dialled"
|
||||
);
|
||||
assert_eq!(state(), DialState::Passive { last_error: None });
|
||||
|
||||
let mut peer = TestPeer::connect(server.addr).await?;
|
||||
peer.handshake(PEER_ASN, Ipv4Addr::new(10, 0, 0, 2), 90)
|
||||
.await?;
|
||||
let listed = tokio::time::timeout(TIMEOUT, async {
|
||||
loop {
|
||||
if let Some(session) = server.registry.list().first().cloned() {
|
||||
return session;
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(5)).await;
|
||||
}
|
||||
})
|
||||
.await?;
|
||||
assert_eq!(listed.name.as_deref(), Some("r1"));
|
||||
|
||||
drop(peer);
|
||||
tokio::time::timeout(TIMEOUT, async {
|
||||
while !matches!(
|
||||
state(),
|
||||
DialState::Passive {
|
||||
last_error: Some(_)
|
||||
}
|
||||
) {
|
||||
tokio::time::sleep(Duration::from_millis(5)).await;
|
||||
}
|
||||
})
|
||||
.await?;
|
||||
assert!(server.registry.list().is_empty());
|
||||
assert!(
|
||||
tokio::time::timeout(Duration::from_millis(600), listener.accept())
|
||||
.await
|
||||
.is_err(),
|
||||
"a passive peer was dialled after its session ended"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -54,6 +54,7 @@ async fn server_with(originated: &[&str], limits: ExportLimits) -> Result<Setup>
|
||||
graceful_restart: Default::default(),
|
||||
groups: Vec::new(),
|
||||
export_limits: Some(Arc::new(limits)),
|
||||
passive: false,
|
||||
reflector_client: false,
|
||||
name: "r1".into(),
|
||||
endpoint: endpoint.into(),
|
||||
|
||||
@@ -45,6 +45,7 @@ async fn server_with(import: ImportPolicy) -> Result<(TestServer, TcpListener)>
|
||||
graceful_restart: Default::default(),
|
||||
groups: Vec::new(),
|
||||
export_limits: None,
|
||||
passive: false,
|
||||
reflector_client: false,
|
||||
name: "r1".into(),
|
||||
endpoint: endpoint.into(),
|
||||
|
||||
@@ -186,6 +186,7 @@ async fn test_no_family_in_common_refuses_the_session() -> Result<()> {
|
||||
graceful_restart: Default::default(),
|
||||
groups: Vec::new(),
|
||||
export_limits: None,
|
||||
passive: false,
|
||||
reflector_client: false,
|
||||
name: "v6-only".into(),
|
||||
endpoint: SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 1).into(),
|
||||
|
||||
@@ -51,6 +51,7 @@ async fn server_with(role: Option<PeerRole>, require_role: bool) -> Result<Setup
|
||||
graceful_restart: Default::default(),
|
||||
groups: Vec::new(),
|
||||
export_limits: None,
|
||||
passive: false,
|
||||
reflector_client: false,
|
||||
name: "r1".into(),
|
||||
endpoint: endpoint.into(),
|
||||
|
||||
@@ -70,6 +70,7 @@ async fn server_with(
|
||||
graceful_restart: Default::default(),
|
||||
groups: Vec::new(),
|
||||
export_limits: None,
|
||||
passive: false,
|
||||
reflector_client: false,
|
||||
name: "r1".into(),
|
||||
endpoint: endpoint.into(),
|
||||
|
||||
Reference in new issue
Block a user