netlink_packet_route/link/af_spec/
unspec.rs

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