Verify AS paths with ASPAs, over RTR version 2

Origin validation says who may originate a prefix and nothing about the
rest of the path: it does not catch a route leak, nor a hijack that keeps
the right origin at the end of a made-up path. ASPAs, in which a network
lists its providers, do.

bgp-rpki:
- aspa: the ASPAs and the upstream and downstream verification procedures
  of draft-ietf-sidrops-aspa-verification-24, tested against the draft's
  wording as written.
- rtr: protocol version 2 (draft-ietf-sidrops-8210bis-23) with the ASPA
  PDU and the new error codes.
- client: asks for version 2 and falls back to whatever older version the
  cache speaks; keeps ASPAs with the VRPs, applied whole or not at all;
  publishes which customers' ASPAs changed; tells the cache why it is
  being left (Error Report); does not ask one version's serial of another.

Server:
- A peer has a role (provider, customer, peer, route server, route server
  client), which decides how its paths are verified. Without one they are
  not.
- A route whose path is invalid is refused ("ASPA invalid") and held, like
  one with an invalid origin; accept_aspa_invalid exempts a peer.
- When ASPAs change, routes in the table whose path has a changed customer
  on it are verified again, and held routes are released when they pass
  both checks.
- The revalidator finds a route's peer by index instead of searching a
  list for every route.

The status page and API show each peer's role, each route's path validity,
the number of ASPAs and the RTR version in use; bgp_rpki_aspas is on
/metricz.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Rayhaan JaufeerallyandClaude Fable 5.1 committed 2026-10-02 14:12:59 +02:00
1 parent bdaf226a16
commit 8086aa994f
35 files changed
+2484 -359

No files matched your search

+4
View File
@@ -35,6 +35,7 @@ async fn server_dialing(listener: &TcpListener, remote_asn: u32) -> Result<TestS
families: FamilySet::supported(),
add_path: None,
import: ImportPolicy::permissive(),
role: None,
}];
})
.await
@@ -190,6 +191,7 @@ async fn test_inbound_from_configured_address_uses_config() -> Result<()> {
families: FamilySet::supported(),
add_path: None,
import: ImportPolicy::permissive(),
role: None,
}];
})
.await?;
@@ -239,6 +241,7 @@ async fn test_local_address_is_used_as_the_source() -> Result<()> {
families: FamilySet::supported(),
add_path: None,
import: ImportPolicy::permissive(),
role: None,
}];
})
.await?;
@@ -257,6 +260,7 @@ async fn test_local_address_is_used_as_the_source() -> Result<()> {
families: FamilySet::supported(),
add_path: None,
import: ImportPolicy::permissive(),
role: None,
}];
})
.await?;