#![deny(unsafe_code)]
#![deny(clippy::all)]
#![warn(clippy::pedantic)]
pub mod attribute;
pub mod capability;
pub mod constants;
pub mod error;
pub mod evpn;
pub mod flowspec;
pub mod header;
pub mod keepalive;
pub mod message;
pub mod nlri;
pub mod notification;
pub mod notification_msg;
pub mod open;
pub mod pmsi;
pub mod route_refresh;
pub mod update;
pub mod validate;
pub use capability::{
AddPathFamily, AddPathMode, Afi, Capability, ExtendedNextHopFamily, GracefulRestartFamily,
LlgrFamily, Safi,
};
pub use constants::{EXTENDED_MAX_MESSAGE_LEN, MAX_MESSAGE_LEN};
pub use error::{DecodeError, EncodeError};
pub use header::{BgpHeader, MessageType, peek_message_length};
pub use message::{Message, decode_message, encode_message, encode_message_with_limit};
pub use notification::NotificationCode;
pub use notification_msg::NotificationMessage;
pub use open::OpenMessage;
pub use route_refresh::{RouteRefreshMessage, RouteRefreshSubtype};
pub use update::{Ipv4UnicastMode, UpdateMessage};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum RpkiValidation {
Valid,
Invalid,
#[default]
NotFound,
}
impl std::fmt::Display for RpkiValidation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Valid => write!(f, "valid"),
Self::Invalid => write!(f, "invalid"),
Self::NotFound => write!(f, "not_found"),
}
}
}
impl std::str::FromStr for RpkiValidation {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"valid" => Ok(Self::Valid),
"invalid" => Ok(Self::Invalid),
"not_found" => Ok(Self::NotFound),
other => Err(format!(
"unknown RPKI validation state {other:?}, expected \"valid\", \"invalid\", or \"not_found\""
)),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum AspaValidation {
Valid,
Invalid,
#[default]
Unknown,
}
impl std::fmt::Display for AspaValidation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Valid => write!(f, "valid"),
Self::Invalid => write!(f, "invalid"),
Self::Unknown => write!(f, "unknown"),
}
}
}
impl std::str::FromStr for AspaValidation {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"valid" => Ok(Self::Valid),
"invalid" => Ok(Self::Invalid),
"unknown" => Ok(Self::Unknown),
other => Err(format!(
"unknown ASPA validation state {other:?}, expected \"valid\", \"invalid\", or \"unknown\""
)),
}
}
}
pub use attribute::{
AsPath, AsPathSegment, ExtendedCommunity, LargeCommunity, MpReachNlri, MpUnreachNlri, Origin,
PathAttribute, RawAttribute, is_private_asn,
};
pub use nlri::{Ipv4NlriEntry, Ipv4Prefix, Ipv6Prefix, NlriEntry, Prefix};
pub use pmsi::{PmsiTunnel, PmsiTunnelIdentifier, PmsiTunnelType};
pub use update::ParsedUpdate;
pub use validate::{UpdateError, is_valid_ipv6_nexthop};
pub use flowspec::{
BitmaskMatch, FlowSpecAction, FlowSpecComponent, FlowSpecPrefix, FlowSpecRule,
Ipv6PrefixOffset, NumericMatch,
};
pub use evpn::{
EthernetSegmentIdentifier, EthernetTagId, EvpnEadPerEs, EvpnEadPerEvi, EvpnEs, EvpnImet,
EvpnIpPrefixRoute, EvpnIpPrefixValue, EvpnMacIp, EvpnRoute, EvpnRouteKey, MacAddress,
MplsLabel, RouteDistinguisher, RouteDistinguisherParseError, decode_evpn_nlri,
encode_evpn_nlri,
};
pub const COMMUNITY_GRACEFUL_SHUTDOWN: u32 = 0xFFFF_0000;
pub const COMMUNITY_LLGR_STALE: u32 = 0xFFFF_0006;
pub const COMMUNITY_NO_LLGR: u32 = 0xFFFF_0007;
#[cfg(test)]
mod well_known_community_tests {
use super::*;
#[test]
fn well_known_community_values_match_specs() {
assert_eq!(COMMUNITY_GRACEFUL_SHUTDOWN, 0xFFFF_0000, "RFC 8326 §3");
assert_eq!(COMMUNITY_LLGR_STALE, 0xFFFF_0006, "RFC 9494 §4.6");
assert_eq!(COMMUNITY_NO_LLGR, 0xFFFF_0007, "RFC 9494 §4.7");
}
}