netlink_packet_route/link/af_spec/
unspec.rs

1// SPDX-License-Identifier: MIT
2
3use anyhow::Context;
4use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer, NlasIterator};
5use netlink_packet_utils::traits::{Emitable, Parseable};
6use netlink_packet_utils::DecodeError;
7
8use crate::link::af_spec::{VecAfSpecInet, VecAfSpecInet6};
9use crate::link::{AfSpecInet, AfSpecInet6};
10use crate::AddressFamily;
11
12// For `AF_UNSPEC`, the `IFLA_AF_SPEC` is two layer array:
13//
14// [{nla_len=408, nla_type=IFLA_AF_SPEC},
15//     [
16//         [{nla_len=140, nla_type=AF_INET}, [
17//             {nla_len=136, nla_type=IFLA_INET_CONF}, [
18//                 [IPV4_DEVCONF_FORWARDING-1] = 0,
19//                 <omitted>
20//                 [IPV4_DEVCONF_ARP_EVICT_NOCARRIER-1] = 1]]],
21//         [{nla_len=264, nla_type=AF_INET6}, [
22//             [{nla_len=8, nla_type=IFLA_INET6_FLAGS}, IF_READY],
23//             [{nla_len=20, nla_type=IFLA_INET6_CACHEINFO},
24//                 {
25//                     max_reasm_len=65535,
26//                     tstamp=3794,
27//                     reachable_time=37584,
28//                     retrans_time=1000}],
29//             [{nla_len=232, nla_type=IFLA_INET6_CONF},
30//                 [[DEVCONF_FORWARDING] = 0,
31//                 <omitted>
32//                 [DEVCONF_NDISC_EVICT_NOCARRIER] = 1]]]]]]
33
34#[derive(Clone, Eq, PartialEq, Debug)]
35#[non_exhaustive]
36pub enum AfSpecUnspec {
37    Inet(Vec<AfSpecInet>),
38    Inet6(Vec<AfSpecInet6>),
39    Other(DefaultNla),
40}
41
42pub(crate) struct VecAfSpecUnspec(pub(crate) Vec<AfSpecUnspec>);
43
44impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for VecAfSpecUnspec {
45    type Error = DecodeError;
46    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
47        let mut nlas = vec![];
48        let err = "Invalid NLA for IFLA_AF_SPEC(AF_UNSPEC)";
49        for nla in NlasIterator::new(buf.into_inner()) {
50            let nla = nla.context(err)?;
51            nlas.push(match nla.kind() {
52                k if k == u8::from(AddressFamily::Inet) as u16 => AfSpecUnspec::Inet(
53                    VecAfSpecInet::parse(&NlaBuffer::new_checked(&nla.value()).context(err)?)
54                        .context(err)?
55                        .0,
56                ),
57                k if k == u8::from(AddressFamily::Inet6) as u16 => AfSpecUnspec::Inet6(
58                    VecAfSpecInet6::parse(&NlaBuffer::new_checked(&nla.value()).context(err)?)
59                        .context(err)?
60                        .0,
61                ),
62                kind => {
63                    AfSpecUnspec::Other(DefaultNla::parse(&nla).context(format!(
64                        "Unknown AF_XXX type {kind} for IFLA_AF_SPEC(AF_UNSPEC)"
65                    ))?)
66                }
67            })
68        }
69        Ok(Self(nlas))
70    }
71}
72
73impl Nla for AfSpecUnspec {
74    fn value_len(&self) -> usize {
75        match *self {
76            Self::Inet(ref nlas) => nlas.as_slice().buffer_len(),
77            Self::Inet6(ref nlas) => nlas.as_slice().buffer_len(),
78            Self::Other(ref nla) => nla.value_len(),
79        }
80    }
81
82    fn emit_value(&self, buffer: &mut [u8]) {
83        match *self {
84            Self::Inet(ref nlas) => nlas.as_slice().emit(buffer),
85            Self::Inet6(ref nlas) => nlas.as_slice().emit(buffer),
86            Self::Other(ref nla) => nla.emit_value(buffer),
87        }
88    }
89
90    fn kind(&self) -> u16 {
91        match *self {
92            Self::Inet(_) => u8::from(AddressFamily::Inet) as u16,
93            Self::Inet6(_) => u8::from(AddressFamily::Inet6) as u16,
94            Self::Other(ref nla) => nla.kind(),
95        }
96    }
97}