use core::{
convert::Infallible as Never,
fmt::{Debug, Display, Formatter},
hash::Hash,
};
use net_types::{
ip::{GenericOverIp, Ip, IpAddress, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Subnet, SubnetEither},
SpecifiedAddr,
};
use crate::socket::address::SocketIpAddr;
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct RawMetric(pub u32);
impl Display for RawMetric {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
let RawMetric(metric) = self;
write!(f, "{}", metric)
}
}
impl From<RawMetric> for u32 {
fn from(RawMetric(metric): RawMetric) -> u32 {
metric
}
}
impl From<RawMetric> for u64 {
fn from(RawMetric(metric): RawMetric) -> u64 {
u64::from(metric)
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum AddableMetric {
MetricTracksInterface,
ExplicitMetric(RawMetric),
}
impl From<Metric> for AddableMetric {
fn from(metric: Metric) -> AddableMetric {
match metric {
Metric::MetricTracksInterface(_) => AddableMetric::MetricTracksInterface,
Metric::ExplicitMetric(metric) => AddableMetric::ExplicitMetric(metric),
}
}
}
#[derive(Debug, Copy, Clone, Eq, GenericOverIp, PartialEq, Hash)]
#[generic_over_ip(A, IpAddress)]
pub struct AddableEntry<A: IpAddress, D> {
pub subnet: Subnet<A>,
pub device: D,
pub gateway: Option<SpecifiedAddr<A>>,
pub metric: AddableMetric,
}
impl<D, A: IpAddress> AddableEntry<A, D> {
pub fn with_gateway(
subnet: Subnet<A>,
device: D,
gateway: SpecifiedAddr<A>,
metric: AddableMetric,
) -> Self {
Self { subnet, device, gateway: Some(gateway), metric }
}
pub fn without_gateway(subnet: Subnet<A>, device: D, metric: AddableMetric) -> Self {
Self { subnet, device, gateway: None, metric }
}
pub fn resolve_metric(self, device_metric: RawMetric) -> Entry<A, D> {
let Self { subnet, device, gateway, metric } = self;
let metric = match metric {
AddableMetric::MetricTracksInterface => Metric::MetricTracksInterface(device_metric),
AddableMetric::ExplicitMetric(metric) => Metric::ExplicitMetric(metric),
};
Entry { subnet, device, gateway, metric }
}
pub fn map_device_id<D2>(self, f: impl FnOnce(D) -> D2) -> AddableEntry<A, D2> {
let Self { subnet, device, gateway, metric } = self;
AddableEntry { subnet, device: f(device), gateway, metric }
}
pub fn try_map_device_id<D2, E>(
self,
f: impl FnOnce(D) -> Result<D2, E>,
) -> Result<AddableEntry<A, D2>, E> {
let Self { subnet, device, gateway, metric } = self;
Ok(AddableEntry { subnet, device: f(device)?, gateway, metric })
}
pub fn with_generation(self, generation: Generation) -> AddableEntryAndGeneration<A, D> {
AddableEntryAndGeneration { entry: self, generation }
}
}
#[allow(missing_docs)]
#[derive(Debug, Copy, Clone, Eq, GenericOverIp, PartialEq, Hash)]
#[generic_over_ip()]
pub enum AddableEntryEither<D> {
V4(AddableEntry<Ipv4Addr, D>),
V6(AddableEntry<Ipv6Addr, D>),
}
impl<D> AddableEntryEither<D> {
pub fn without_gateway(subnet: SubnetEither, device: D, metric: AddableMetric) -> Self {
match subnet {
SubnetEither::V4(subnet) => {
AddableEntry::without_gateway(subnet, device, metric).into()
}
SubnetEither::V6(subnet) => {
AddableEntry::without_gateway(subnet, device, metric).into()
}
}
}
}
impl<A: IpAddress, D> From<AddableEntry<A, D>> for AddableEntryEither<D> {
fn from(entry: AddableEntry<A, D>) -> AddableEntryEither<D> {
A::Version::map_ip(entry, AddableEntryEither::V4, AddableEntryEither::V6)
}
}
#[derive(Debug, Copy, Clone, GenericOverIp)]
#[generic_over_ip(A, IpAddress)]
pub struct AddableEntryAndGeneration<A: IpAddress, D> {
pub entry: AddableEntry<A, D>,
pub generation: Generation,
}
#[derive(GenericOverIp)]
#[generic_over_ip(A, IpAddress)]
pub struct EntryUpgrader<'a, A: IpAddress, DeviceId, WeakDeviceId>(
#[allow(dead_code)]
pub &'a mut dyn FnMut(
AddableEntryAndGeneration<A, WeakDeviceId>,
) -> Option<EntryAndGeneration<A, DeviceId>>,
);
impl<A: IpAddress, D> From<Entry<A, D>> for AddableEntry<A, D> {
fn from(Entry { subnet, device, gateway, metric }: Entry<A, D>) -> Self {
Self { subnet: subnet, device: device, gateway: gateway, metric: metric.into() }
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum Metric {
MetricTracksInterface(RawMetric),
ExplicitMetric(RawMetric),
}
impl Metric {
pub fn value(&self) -> RawMetric {
match self {
Self::MetricTracksInterface(value) => *value,
Self::ExplicitMetric(value) => *value,
}
}
}
#[derive(Debug, Copy, Clone, Eq, GenericOverIp, PartialEq, Hash)]
#[generic_over_ip(A, IpAddress)]
pub struct Entry<A: IpAddress, D> {
pub subnet: Subnet<A>,
pub device: D,
pub gateway: Option<SpecifiedAddr<A>>,
pub metric: Metric,
}
#[derive(Debug, Copy, Clone, GenericOverIp, PartialEq, Eq)]
#[generic_over_ip(A, IpAddress)]
pub struct EntryAndGeneration<A: IpAddress, D> {
pub entry: Entry<A, D>,
pub generation: Generation,
}
impl<A: IpAddress, D: Debug> Display for EntryAndGeneration<A, D> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
let EntryAndGeneration { entry, generation: Generation(generation) } = self;
write!(f, "{} (generation = {})", entry, generation)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Generation(u64);
impl Generation {
pub fn initial() -> Self {
Self(0)
}
pub fn next(&self) -> Generation {
let Self(n) = self;
Generation(n + 1)
}
}
impl<A: IpAddress, D> Entry<A, D> {
pub fn map_device_id<D2>(self, f: impl FnOnce(D) -> D2) -> Entry<A, D2> {
let Self { subnet, device, gateway, metric } = self;
Entry { subnet, device: f(device), gateway, metric }
}
pub fn with_generation(self, generation: Generation) -> EntryAndGeneration<A, D> {
EntryAndGeneration { entry: self, generation }
}
}
impl<A: IpAddress, D: Debug> Display for Entry<A, D> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
let Entry { subnet, device, gateway, metric } = self;
match gateway {
Some(gateway) => {
write!(f, "{:?} (via {}) -> {} metric {}", device, gateway, subnet, metric.value())
}
None => write!(f, "{:?} -> {} metric {}", device, subnet, metric.value()),
}
}
}
#[allow(missing_docs)]
#[derive(Debug, Copy, Clone, Eq, GenericOverIp, PartialEq)]
#[generic_over_ip()]
pub enum EntryEither<D> {
V4(Entry<Ipv4Addr, D>),
V6(Entry<Ipv6Addr, D>),
}
impl<A: IpAddress, D> From<Entry<A, D>> for EntryEither<D> {
fn from(entry: Entry<A, D>) -> EntryEither<D> {
#[derive(GenericOverIp)]
#[generic_over_ip(I, Ip)]
struct EntryHolder<I: Ip, D>(Entry<I::Addr, D>);
A::Version::map_ip(entry, EntryEither::V4, EntryEither::V6)
}
}
#[derive(PartialEq, PartialOrd, Eq, Ord)]
pub(crate) enum OrderedLocality {
OnLink,
OffLink,
}
#[derive(PartialEq, PartialOrd, Eq, Ord)]
pub(crate) struct OrderedEntry<'a, A: IpAddress, D> {
prefix_len: core::cmp::Reverse<u8>,
metric: u32,
locality: OrderedLocality,
generation: Generation,
subnet_addr: A,
device: &'a D,
gateway: Option<SpecifiedAddr<A>>,
}
impl<'a, A: IpAddress, D> From<&'a EntryAndGeneration<A, D>> for OrderedEntry<'a, A, D> {
fn from(entry: &'a EntryAndGeneration<A, D>) -> OrderedEntry<'a, A, D> {
let EntryAndGeneration { entry: Entry { subnet, device, gateway, metric }, generation } =
entry;
OrderedEntry {
prefix_len: core::cmp::Reverse(subnet.prefix()),
metric: metric.value().into(),
locality: gateway.map_or(OrderedLocality::OnLink, |_gateway| OrderedLocality::OffLink),
generation: *generation,
subnet_addr: subnet.network(),
device: &device,
gateway: *gateway,
}
}
}
pub trait IpTypesIpExt: packet_formats::ip::IpExt {
type BroadcastMarker: Debug + Copy + Clone + PartialEq + Eq;
}
impl IpTypesIpExt for Ipv4 {
type BroadcastMarker = ();
}
impl IpTypesIpExt for Ipv6 {
type BroadcastMarker = Never;
}
#[derive(GenericOverIp)]
#[generic_over_ip(I, Ip)]
pub struct WrapBroadcastMarker<I: IpTypesIpExt>(pub I::BroadcastMarker);
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum NextHop<A: IpAddress>
where
A::Version: IpTypesIpExt,
{
RemoteAsNeighbor,
Gateway(SpecifiedAddr<A>),
Broadcast(<A::Version as IpTypesIpExt>::BroadcastMarker),
}
impl<A: IpAddress, NewIp: IpTypesIpExt> GenericOverIp<NewIp> for NextHop<A>
where
A::Version: IpTypesIpExt,
{
type Type = NextHop<NewIp::Addr>;
}
impl<A> NextHop<A>
where
A: IpAddress,
A::Version: IpTypesIpExt,
{
pub(crate) fn into_next_hop_and_broadcast_marker(
self,
remote_ip: SpecifiedAddr<A>,
) -> (SpecifiedAddr<A>, Option<<A::Version as IpTypesIpExt>::BroadcastMarker>) {
match self {
NextHop::RemoteAsNeighbor => (remote_ip, None),
NextHop::Gateway(gateway) => (gateway, None),
NextHop::Broadcast(marker) => (remote_ip, Some(marker)),
}
}
}
pub type RoutableIpAddr<A> = SocketIpAddr<A>;
#[derive(Debug, Copy, Clone, PartialEq, Eq, GenericOverIp)]
#[generic_over_ip(I, Ip)]
pub struct ResolvedRoute<I: IpTypesIpExt, D> {
pub src_addr: RoutableIpAddr<I::Addr>,
pub device: D,
pub local_delivery_device: Option<D>,
pub next_hop: NextHop<I::Addr>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) struct Destination<A: IpAddress, D>
where
A::Version: IpTypesIpExt,
{
pub(crate) next_hop: NextHop<A>,
pub(crate) device: D,
}