use std::{fmt, hash};
use std::cmp::Ordering;
use std::time::Duration;
use crate::crypto::keys::KeyIdentifier;
use crate::resources::addr::MaxLenPrefix;
use crate::resources::asn::Asn;
use super::pdu::{ProviderAsns, RouterKeyInfo};
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct RouteOrigin {
pub prefix: MaxLenPrefix,
pub asn: Asn,
}
impl RouteOrigin {
pub fn new(prefix: MaxLenPrefix, asn: Asn) -> Self {
RouteOrigin { prefix, asn }
}
pub fn is_v4(self) -> bool {
self.prefix.prefix().is_v4()
}
}
impl PartialEq for RouteOrigin {
fn eq(&self, other: &Self) -> bool {
self.prefix.prefix() == other.prefix.prefix()
&& self.prefix.resolved_max_len() == other.prefix.resolved_max_len()
&& self.asn == other.asn
}
}
impl Eq for RouteOrigin { }
impl PartialOrd for RouteOrigin {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for RouteOrigin {
fn cmp(&self, other: &Self) -> Ordering {
match self.prefix.prefix().cmp(&other.prefix.prefix()) {
Ordering::Equal => { }
other => return other
}
match self.prefix.resolved_max_len().cmp(
&other.prefix.resolved_max_len()
) {
Ordering::Equal => { }
other => return other
}
self.asn.cmp(&other.asn)
}
}
impl hash::Hash for RouteOrigin {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.prefix.prefix().hash(state);
self.prefix.resolved_max_len().hash(state);
self.asn.hash(state);
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct RouterKey {
pub key_identifier: KeyIdentifier,
pub asn: Asn,
pub key_info: RouterKeyInfo,
}
impl RouterKey {
pub fn new(
key_identifier: KeyIdentifier, asn: Asn, key_info: RouterKeyInfo
) -> Self {
RouterKey { key_identifier, asn, key_info }
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Aspa {
pub customer: Asn,
pub providers: ProviderAsns,
}
impl Aspa {
pub fn new(
customer: Asn, providers: ProviderAsns,
) -> Self {
Self { customer, providers }
}
pub fn key(&self) -> Asn {
self.customer
}
pub fn withdraw(&self) -> Self {
Self::new(self.customer, ProviderAsns::empty())
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum PayloadType {
Origin,
RouterKey,
Aspa
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum Payload {
Origin(RouteOrigin),
RouterKey(RouterKey),
Aspa(Aspa),
}
impl Payload {
pub fn origin(prefix: MaxLenPrefix, asn: Asn) -> Self {
Payload::Origin(RouteOrigin::new(prefix, asn))
}
pub fn router_key(
key_identifier: KeyIdentifier, asn: Asn, key_info: RouterKeyInfo
) -> Self {
Payload::RouterKey(RouterKey::new(key_identifier, asn, key_info))
}
pub fn aspa(
customer: Asn, providers: ProviderAsns,
) -> Self {
Payload::Aspa(Aspa::new(customer, providers))
}
pub fn as_ref(&self) -> PayloadRef<'_> {
match self {
Payload::Origin(origin) => PayloadRef::Origin(*origin),
Payload::RouterKey(key) => PayloadRef::RouterKey(key),
Payload::Aspa(aspa) => PayloadRef::Aspa(aspa),
}
}
pub fn payload_type(&self) -> PayloadType {
match self {
Payload::Origin(_) => PayloadType::Origin,
Payload::RouterKey(_) => PayloadType::RouterKey,
Payload::Aspa(_) => PayloadType::Aspa,
}
}
pub fn to_origin(&self) -> Option<RouteOrigin> {
match *self {
Payload::Origin(origin) => Some(origin),
_ => None
}
}
pub fn as_router_key(&self) -> Option<&RouterKey> {
match *self {
Payload::RouterKey(ref key) => Some(key),
_ => None
}
}
pub fn as_aspa(&self) -> Option<&Aspa> {
match *self {
Payload::Aspa(ref aspa) => Some(aspa),
_ => None
}
}
}
impl From<RouteOrigin> for Payload {
fn from(src: RouteOrigin) -> Self {
Payload::Origin(src)
}
}
impl From<RouterKey> for Payload {
fn from(src: RouterKey) -> Self {
Payload::RouterKey(src)
}
}
impl From<Aspa> for Payload {
fn from(src: Aspa) -> Self {
Payload::Aspa(src)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum PayloadRef<'a> {
Origin(RouteOrigin),
RouterKey(&'a RouterKey),
Aspa(&'a Aspa),
}
impl From<RouteOrigin> for PayloadRef<'_> {
fn from(src: RouteOrigin) -> Self {
PayloadRef::Origin(src)
}
}
impl<'a> From<&'a RouteOrigin> for PayloadRef<'a> {
fn from(src: &'a RouteOrigin) -> Self {
PayloadRef::Origin(*src)
}
}
impl<'a> From<&'a RouterKey> for PayloadRef<'a> {
fn from(src: &'a RouterKey) -> Self {
PayloadRef::RouterKey(src)
}
}
impl<'a> From<&'a Aspa> for PayloadRef<'a> {
fn from(src: &'a Aspa) -> Self {
PayloadRef::Aspa(src)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum Action {
Announce,
Withdraw,
}
impl Action {
pub fn is_announce(self) -> bool {
matches!(self, Action::Announce)
}
pub fn is_withdraw(self) -> bool {
matches!(self, Action::Withdraw)
}
pub fn from_flags(flags: u8) -> Self {
if flags & 1 == 1 {
Action::Announce
}
else {
Action::Withdraw
}
}
pub fn into_flags(self) -> u8 {
match self {
Action::Announce => 1,
Action::Withdraw => 0
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Afi(u8);
impl Afi {
pub fn ipv4() -> Self {
Self(0)
}
pub fn ipv6() -> Self {
Self(1)
}
pub fn is_ipv4(self) -> bool {
self.0 & 0x01 == 0
}
pub fn is_ipv6(self) -> bool {
self.0 & 0x01 == 1
}
pub fn into_u8(self) -> u8 {
self.0
}
pub fn from_u8(src: u8) -> Self {
Self(src)
}
}
impl fmt::Display for Afi {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.is_ipv4() {
f.write_str("ipv4")
}
else {
f.write_str("ipv6")
}
}
}
#[cfg(feature = "arbitrary")]
impl<'a> arbitrary::Arbitrary<'a> for Afi {
fn arbitrary(
u: &mut arbitrary::Unstructured<'a>
) -> arbitrary::Result<Self> {
bool::arbitrary(u).map(|val| {
if val {
Self::ipv4()
}
else {
Self::ipv6()
}
})
}
}
#[derive(Clone, Copy, Debug)]
pub struct Timing {
pub refresh: u32,
pub retry: u32,
pub expire: u32
}
impl Timing {
pub fn refresh_duration(self) -> Duration {
Duration::from_secs(u64::from(self.refresh))
}
}
impl Default for Timing {
fn default() -> Self {
Timing {
refresh: 3600,
retry: 600,
expire: 7200
}
}
}