Hello all, I am in the process of adding RPKI/ROA (RFC 6810/RFC 6811) support to OpenBGPd. I have an almost working PoC but I'd like to hear your opinion and discuss implementation details with misc@ before going further.
First of all, here is what RPKI-enabled bgpd.conf looks like : ----8<-------------- AS 65530 router-id 10.0.0.102 fib-update yes Transitv4="10.0.0.1" validator "2001:db8::102" { port 8282 poll-interval 300 } neighbor $Transitv4 { descr "ROA Lab" remote-as 65531 announce none } #match from any rpki-invalid set localpref 80 deny from any rpki-invalid match from any rpki-valid set localpref 120 match from any rpki-not-found set localpref 99 ----8<-------------- Then what "bgpctl show rib" looks like : (with "match from any rpki-invalid set localpref 80") ----8<-------------- # bgpctl sho rib flags: * = Valid, > = Selected, I = via IBGP, A = Announced, S = Stale, v = RPKI valid, i = RPKI invalid, u = RPKI unknown origin: i = IGP, e = EGP, ? = Incomplete flags destination gateway lpref med aspath origin u*> 10.0.0.0/20 10.0.0.1 99 0 65530 i u*> 10.0.0.0/24 10.0.0.1 99 0 65530 i i*> 93.187.228.0/24 10.0.0.1 80 0 65530 i v*> 185.22.128.0/22 10.0.0.1 120 0 65530 i ----8<-------------- (with "deny from any rpki-invalid") ----8<-------------- # bgpctl sho rib flags: * = Valid, > = Selected, I = via IBGP, A = Announced, S = Stale, v = RPKI valid, i = RPKI invalid, u = RPKI unknown origin: i = IGP, e = EGP, ? = Incomplete flags destination gateway lpref med aspath origin u*> 10.0.0.0/20 10.0.0.1 99 0 65530 i u*> 10.0.0.0/24 10.0.0.1 99 0 65530 i v*> 185.22.128.0/22 10.0.0.1 120 0 65530 i ----8<-------------- So, we have a new keyword ("validator") that is used to define a validation server. Inside that, we have 3 parameters : - port (defaults to 323 - between 1-65535) : tcp port of the validator - poll-interval (defaults to 3600 - between 60-3600) : number of seconds before polling the validator for changes. That's for the visible part :) Now, let's look under the hood. OpenBGPd has now a rpki-client, which connects to a validator, get validated objects from the validator and put them in a list of validated ROA (VRP). It then compares every prefix with the content of the VRP and filters accordingly. The validator connection is handled by session.c, it is close to neighbor connection process. It has 4 states : - init : the beginning - connecting : validator was contacted and is processing the 3-way handshake - syncing : the rpki-client is receiving ROAs. - synced : the rpki-client is now waiting for updates from the validator (or until poll-interval expires). While syncing the rpki-client sends each objects to rde.c. rde.c stores the objects in a RB-list (one for IPv4 prefixes, one for IPv6 prefixes) and removes if it is a withdrawal. when the rpki-client receives a "End of Data" PDU, it sends a command to rde.c to start validation of known peer prefixes (from rib[0]). The VRP size is ~12k, the RIB size is ~530k so that's a lot to check. If you have any implementation advice, I'm all hear :) The major difficulty is to no put too much load on the router when comparing between VRP and RIB and how to update FIB when VRP changes. Regards, Denis