netlink_packet_route/route/
via.rs

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