netlink_packet_route/route/
via.rs

1// SPDX-License-Identifier: MIT
2
3use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
4
5use netlink_packet_core::{DecodeError, Emitable, Parseable};
6
7use crate::{
8    ip::{parse_ipv4_addr, parse_ipv6_addr, IPV4_ADDR_LEN, IPV6_ADDR_LEN},
9    AddressFamily,
10};
11
12#[derive(Debug, PartialEq, Eq, Clone)]
13#[non_exhaustive]
14// Kernel representative is `struct rtvia`
15// In Linux kernel 6.18, MPLS route also use `AF_PACKET`
16// and MPLS route. Even the MPLS is using AF_PACKET, so we cannot simply
17// treat `RouteVia` as `IpAddr`.
18pub enum RouteVia {
19    Inet(Ipv4Addr),
20    Inet6(Ipv6Addr),
21    #[cfg(any(target_os = "linux", target_os = "fuchsia"))]
22    Packet(Vec<u8>),
23    Other((AddressFamily, Vec<u8>)),
24}
25
26const RTVIA_LEN: usize = 2;
27
28buffer!(RouteViaBuffer(RTVIA_LEN) {
29    address_family: (u16, 0..2),
30    address: (slice, RTVIA_LEN..),
31});
32
33impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<RouteViaBuffer<&'a T>>
34    for RouteVia
35{
36    fn parse(buf: &RouteViaBuffer<&'a T>) -> Result<Self, DecodeError> {
37        let address_family: AddressFamily = (buf.address_family() as u8).into();
38        Ok(match address_family {
39            AddressFamily::Inet => Self::Inet(parse_ipv4_addr(buf.address())?),
40            AddressFamily::Inet6 => {
41                Self::Inet6(parse_ipv6_addr(buf.address())?)
42            }
43            #[cfg(any(target_os = "linux", target_os = "fuchsia"))]
44            AddressFamily::Packet => Self::Packet(buf.address().to_vec()),
45            _ => Self::Other((address_family, buf.address().to_vec())),
46        })
47    }
48}
49
50impl Emitable for RouteVia {
51    fn buffer_len(&self) -> usize {
52        match self {
53            Self::Inet(_) => IPV4_ADDR_LEN + 2,
54            Self::Inet6(_) => IPV6_ADDR_LEN + 2,
55            #[cfg(any(target_os = "linux", target_os = "fuchsia"))]
56            Self::Packet(a) => a.len() + 2,
57            Self::Other((_, a)) => a.len() + 2,
58        }
59    }
60
61    fn emit(&self, buffer: &mut [u8]) {
62        let mut buffer = RouteViaBuffer::new(buffer);
63        let (address_family, addr) = match self {
64            Self::Inet(ip) => (AddressFamily::Inet, ip.octets().to_vec()),
65            Self::Inet6(ip) => (AddressFamily::Inet6, ip.octets().to_vec()),
66            #[cfg(any(target_os = "linux", target_os = "fuchsia"))]
67            Self::Packet(a) => (AddressFamily::Packet, a.to_vec()),
68            Self::Other((f, a)) => (*f, a.to_vec()),
69        };
70        buffer.set_address_family(u8::from(address_family).into());
71        buffer.address_mut().copy_from_slice(addr.as_slice());
72    }
73}
74
75impl From<Ipv4Addr> for RouteVia {
76    fn from(v: Ipv4Addr) -> Self {
77        Self::Inet(v)
78    }
79}
80
81impl From<Ipv6Addr> for RouteVia {
82    fn from(v: Ipv6Addr) -> Self {
83        Self::Inet6(v)
84    }
85}
86
87impl From<IpAddr> for RouteVia {
88    fn from(ip: IpAddr) -> Self {
89        match ip {
90            IpAddr::V4(ipv4) => Self::Inet(ipv4),
91            IpAddr::V6(ipv6) => Self::Inet6(ipv6),
92        }
93    }
94}