From b5904c8f8c16d7be8eba9b01de85a7e345dc6cfd Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Wed, 10 Jun 2020 12:54:16 +0200 Subject: [PATCH] Add BGP vs ROAs stats to prometheus. (#245) --- src/commons/api/ca.rs | 53 ++++++++++++++++++++- src/commons/bgp/report.rs | 19 +++++++- src/daemon/http/server.rs | 97 ++++++++++++++++++++++++++++++++++++++- src/daemon/krillserver.rs | 9 +++- 4 files changed, 172 insertions(+), 6 deletions(-) diff --git a/src/commons/api/ca.rs b/src/commons/api/ca.rs index 67298212..5541c6e1 100644 --- a/src/commons/api/ca.rs +++ b/src/commons/api/ca.rs @@ -1891,13 +1891,15 @@ impl CertAuthIssues { pub struct CertAuthStats { roa_count: usize, child_count: usize, + bgp_stats: BgpStats, } impl CertAuthStats { - pub fn new(roa_count: usize, child_count: usize) -> Self { + pub fn new(roa_count: usize, child_count: usize, bgp_stats: BgpStats) -> Self { CertAuthStats { roa_count, child_count, + bgp_stats, } } @@ -1908,6 +1910,55 @@ impl CertAuthStats { pub fn child_count(&self) -> usize { self.child_count } + + pub fn bgp_stats(&self) -> &BgpStats { + &self.bgp_stats + } +} + +//------------ BgpStats ------------------------------------------------------ + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct BgpStats { + pub announcements_valid: usize, + pub announcements_invalid_asn: usize, + pub announcements_invalid_length: usize, + pub announcements_not_found: usize, + pub roas_stale: usize, +} + +impl Default for BgpStats { + fn default() -> Self { + BgpStats { + announcements_valid: 0, + announcements_invalid_asn: 0, + announcements_invalid_length: 0, + announcements_not_found: 0, + roas_stale: 0, + } + } +} + +impl BgpStats { + pub fn increment_valid(&mut self) { + self.announcements_valid += 1; + } + + pub fn increment_invalid_asn(&mut self) { + self.announcements_invalid_asn += 1; + } + + pub fn increment_invalid_length(&mut self) { + self.announcements_invalid_length += 1; + } + + pub fn increment_not_found(&mut self) { + self.announcements_not_found += 1; + } + + pub fn increment_stale(&mut self) { + self.roas_stale += 1; + } } //------------ ResSetErr ----------------------------------------------------- diff --git a/src/commons/bgp/report.rs b/src/commons/bgp/report.rs index 30af0fcc..ea6d9ec6 100644 --- a/src/commons/bgp/report.rs +++ b/src/commons/bgp/report.rs @@ -2,7 +2,7 @@ use std::cmp::Ordering; use std::collections::HashMap; use std::fmt; -use crate::commons::api::RoaDefinition; +use crate::commons::api::{BgpStats, RoaDefinition}; use crate::commons::bgp::Announcement; //------------ BgpAnalysisReport ------------------------------------------- @@ -32,6 +32,23 @@ impl BgpAnalysisReport { } } +impl From for BgpStats { + fn from(r: BgpAnalysisReport) -> BgpStats { + let mut stats = BgpStats::default(); + for e in r.0.iter() { + match e.state { + BgpAnalysisState::AnnouncementValid => stats.increment_valid(), + BgpAnalysisState::AnnouncementInvalidAsn => stats.increment_invalid_asn(), + BgpAnalysisState::AnnouncementInvalidLength => stats.increment_invalid_length(), + BgpAnalysisState::AnnouncementNotFound => stats.increment_not_found(), + BgpAnalysisState::RoaStale => stats.increment_stale(), + _ => {} // nothing to see, move along + } + } + stats + } +} + impl fmt::Display for BgpAnalysisReport { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let entries = self.entries(); diff --git a/src/daemon/http/server.rs b/src/daemon/http/server.rs index 009aad9f..84e526be 100644 --- a/src/daemon/http/server.rs +++ b/src/daemon/http/server.rs @@ -19,8 +19,8 @@ use hyper::service::{make_service_fn, service_fn}; use hyper::Method; use crate::commons::api::{ - ChildHandle, CommandHistoryCriteria, Handle, ParentCaContact, ParentCaReq, ParentHandle, - PublisherList, RepositoryUpdate, + BgpStats, ChildHandle, CommandHistoryCriteria, Handle, ParentCaContact, ParentCaReq, + ParentHandle, PublisherList, RepositoryUpdate, }; use crate::commons::error::Error; use crate::commons::remote::rfc8183; @@ -29,6 +29,7 @@ use crate::daemon::http::statics::statics; use crate::daemon::http::{tls, tls_keys, HttpResponse, Request, RequestPath, RoutingResult}; use crate::daemon::krillserver::KrillServer; use crate::upgrades::{post_start_upgrade, pre_start_upgrade}; +use std::collections::HashMap; //------------ State ----------------------------------------------------- @@ -175,6 +176,28 @@ pub async fn metrics(req: Request) -> RoutingResult { let server = req.state(); let server = server.read().await; + struct AllBgpStats { + announcements_valid: HashMap, + announcements_invalid_asn: HashMap, + announcements_invalid_length: HashMap, + announcements_not_found: HashMap, + roas_stale: HashMap, + } + + impl AllBgpStats { + fn add_ca(&mut self, ca: &Handle, stats: &BgpStats) { + self.announcements_valid + .insert(ca.clone(), stats.announcements_valid); + self.announcements_invalid_asn + .insert(ca.clone(), stats.announcements_invalid_asn); + self.announcements_invalid_length + .insert(ca.clone(), stats.announcements_invalid_length); + self.announcements_not_found + .insert(ca.clone(), stats.announcements_not_found); + self.roas_stale.insert(ca.clone(), stats.roas_stale); + } + } + let mut res = String::new(); let info = server.server_info(); @@ -277,6 +300,76 @@ pub async fn metrics(req: Request) -> RoutingResult { )); } + // Aggregate ROA vs BGP stats per status + let mut all_bgp_stats = AllBgpStats { + announcements_valid: HashMap::new(), + announcements_invalid_asn: HashMap::new(), + announcements_invalid_length: HashMap::new(), + announcements_not_found: HashMap::new(), + roas_stale: HashMap::new(), + }; + for (ca, status) in cas_status.iter() { + all_bgp_stats.add_ca(ca, status.bgp_stats()); + } + + res.push_str("\n"); + res.push_str("# HELP krill_cas_bgp_announcements_valid number of valid announcements\n"); + res.push_str("# TYPE krill_cas_bgp_announcements_valid gauge\n"); + for (ca, nr) in all_bgp_stats.announcements_valid.iter() { + res.push_str(&format!( + "krill_cas_bgp_announcements_valid{{ca=\"{}\"}} {}\n", + ca, nr + )); + } + + res.push_str("\n"); + res.push_str( + "# HELP krill_cas_bgp_announcements_invalid_asn number of announcements from an invalid asn\n", + ); + res.push_str("# TYPE krill_cas_bgp_announcements_invalid_asn gauge\n"); + for (ca, nr) in all_bgp_stats.announcements_invalid_asn.iter() { + res.push_str(&format!( + "krill_cas_bgp_announcements_invalid_asn{{ca=\"{}\"}} {}\n", + ca, nr + )); + } + + res.push_str("\n"); + res.push_str( + "# HELP krill_cas_bgp_announcements_invalid_length number of announcements which are too specific for asn\n", + ); + res.push_str("# TYPE krill_cas_bgp_announcements_invalid_length gauge\n"); + for (ca, nr) in all_bgp_stats.announcements_invalid_length.iter() { + res.push_str(&format!( + "krill_cas_bgp_announcements_invalid_length{{ca=\"{}\"}} {}\n", + ca, nr + )); + } + + res.push_str("\n"); + res.push_str( + "# HELP krill_cas_bgp_announcements_not_found number of announcements which are not covered by ROAs by this CA\n", + ); + res.push_str("# TYPE krill_cas_bgp_announcements_not_found gauge\n"); + for (ca, nr) in all_bgp_stats.announcements_not_found.iter() { + res.push_str(&format!( + "krill_cas_bgp_announcements_not_found{{ca=\"{}\"}} {}\n", + ca, nr + )); + } + + res.push_str("\n"); + res.push_str( + "# HELP krill_cas_bgp_roas_stale number of ROAs for this CA for which no announcements are seen\n", + ); + res.push_str("# TYPE krill_cas_bgp_roas_stale gauge\n"); + for (ca, nr) in all_bgp_stats.roas_stale.iter() { + res.push_str(&format!( + "krill_cas_bgp_roas_stale{{ca=\"{}\"}} {}\n", + ca, nr + )); + } + Ok(HttpResponse::text(res.into_bytes())) } else { Err(req) diff --git a/src/daemon/krillserver.rs b/src/daemon/krillserver.rs index 7c8936db..7f5249e7 100644 --- a/src/daemon/krillserver.rs +++ b/src/daemon/krillserver.rs @@ -438,12 +438,17 @@ impl KrillServer { for ca in self.caserver.ca_list().cas() { // can't fail really, but to be sure if let Ok(ca) = self.caserver.get_ca(ca.handle()) { - let roa_count = ca.roa_definitions().len(); + let roas = ca.roa_definitions(); + let roa_count = roas.len(); let child_count = ca.children().count(); + let bgp_report = self + .bgp_analyser + .analyse(roas.as_slice(), &ca.all_resources()); + res.insert( ca.handle().clone(), - CertAuthStats::new(roa_count, child_count), + CertAuthStats::new(roa_count, child_count, bgp_report.into()), ); } }