netlink_packet_route/link/link_info/
infos.rs

1// SPDX-License-Identifier: MIT
2
3use anyhow::Context;
4use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer, NlasIterator};
5use netlink_packet_utils::parsers::parse_string;
6use netlink_packet_utils::{DecodeError, Emitable, Parseable, ParseableParametrized};
7
8use super::super::{InfoData, InfoPortData, InfoPortKind, LinkXstats};
9
10const IFLA_INFO_KIND: u16 = 1;
11const IFLA_INFO_DATA: u16 = 2;
12const IFLA_INFO_XSTATS: u16 = 3;
13const IFLA_INFO_PORT_KIND: u16 = 4;
14const IFLA_INFO_PORT_DATA: u16 = 5;
15
16const DUMMY: &str = "dummy";
17const IFB: &str = "ifb";
18const BRIDGE: &str = "bridge";
19const TUN: &str = "tun";
20const NLMON: &str = "nlmon";
21const VLAN: &str = "vlan";
22const VETH: &str = "veth";
23const VXLAN: &str = "vxlan";
24const BOND: &str = "bond";
25const IPVLAN: &str = "ipvlan";
26const IPVTAP: &str = "ipvtap";
27const MACVLAN: &str = "macvlan";
28const MACVTAP: &str = "macvtap";
29const GRETAP: &str = "gretap";
30const IP6GRETAP: &str = "ip6gretap";
31const IPIP: &str = "ipip";
32const SIT: &str = "sit";
33const GRE: &str = "gre";
34const IP6GRE: &str = "ip6gre";
35const VTI: &str = "vti";
36const VRF: &str = "vrf";
37const GTP: &str = "gtp";
38const IPOIB: &str = "ipoib";
39const WIREGUARD: &str = "wireguard";
40const XFRM: &str = "xfrm";
41const MACSEC: &str = "macsec";
42const HSR: &str = "hsr";
43
44#[derive(Debug, PartialEq, Eq, Clone)]
45#[non_exhaustive]
46pub enum LinkInfo {
47    Xstats(LinkXstats),
48    Kind(InfoKind),
49    Data(InfoData),
50    PortKind(InfoPortKind),
51    PortData(InfoPortData),
52    Other(DefaultNla),
53}
54
55impl Nla for LinkInfo {
56    fn value_len(&self) -> usize {
57        match self {
58            Self::Xstats(v) => v.buffer_len(),
59            Self::Kind(nla) => nla.value_len(),
60            Self::Data(nla) => nla.value_len(),
61            Self::PortKind(nla) => nla.value_len(),
62            Self::PortData(nla) => nla.value_len(),
63            Self::Other(nla) => nla.value_len(),
64        }
65    }
66
67    fn emit_value(&self, buffer: &mut [u8]) {
68        match self {
69            Self::Xstats(v) => v.emit(buffer),
70            Self::Kind(nla) => nla.emit_value(buffer),
71            Self::Data(nla) => nla.emit_value(buffer),
72            Self::PortKind(nla) => nla.emit_value(buffer),
73            Self::PortData(nla) => nla.emit_value(buffer),
74            Self::Other(nla) => nla.emit_value(buffer),
75        }
76    }
77
78    fn kind(&self) -> u16 {
79        match self {
80            Self::Xstats(_) => IFLA_INFO_XSTATS,
81            Self::PortKind(_) => IFLA_INFO_PORT_KIND,
82            Self::PortData(_) => IFLA_INFO_PORT_DATA,
83            Self::Kind(_) => IFLA_INFO_KIND,
84            Self::Data(_) => IFLA_INFO_DATA,
85            Self::Other(nla) => nla.kind(),
86        }
87    }
88}
89
90pub(crate) struct VecLinkInfo(pub(crate) Vec<LinkInfo>);
91
92// We cannot `impl Parseable<_> for Info` because some attributes
93// depend on each other. To parse IFLA_INFO_DATA we first need to
94// parse the preceding IFLA_INFO_KIND for example.
95//
96// Moreover, with cannot `impl Parseable for Vec<LinkInfo>` due to the
97// orphan rule: `Parseable` and `Vec<_>` are both defined outside of
98// this crate. Thus, we create this internal VecLinkInfo struct that wraps
99// `Vec<LinkInfo>` and allows us to circumvent the orphan rule.
100//
101// The downside is that this impl will not be exposed.
102
103impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for VecLinkInfo {
104    type Error = DecodeError;
105    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
106        let mut nlas = Vec::new();
107        let mut link_info_kind: Option<InfoKind> = None;
108        let mut link_info_port_kind: Option<InfoPortKind> = None;
109        for nla in NlasIterator::new(buf.into_inner()) {
110            let nla = nla?;
111            match nla.kind() {
112                IFLA_INFO_XSTATS => {
113                    if let Some(link_info_kind) = &link_info_kind {
114                        nlas.push(LinkInfo::Xstats(LinkXstats::parse_with_param(
115                            &nla,
116                            link_info_kind,
117                        )?));
118                    } else {
119                        return Err("IFLA_INFO_XSTATS is not \
120                            preceded by an IFLA_INFO_KIND"
121                            .into());
122                    }
123                }
124                IFLA_INFO_PORT_KIND => {
125                    let parsed = InfoPortKind::parse(&nla)?;
126                    nlas.push(LinkInfo::PortKind(parsed.clone()));
127                    link_info_port_kind = Some(parsed);
128                }
129                IFLA_INFO_PORT_DATA => {
130                    if let Some(link_info_port_kind) = link_info_port_kind {
131                        nlas.push(LinkInfo::PortData(InfoPortData::parse_with_param(
132                            nla.value(),
133                            link_info_port_kind,
134                        )?));
135                    } else {
136                        return Err("IFLA_INFO_PORT_DATA is not preceded by \
137                            an IFLA_INFO_PORT_KIND"
138                            .into());
139                    }
140                    link_info_port_kind = None;
141                }
142                IFLA_INFO_KIND => {
143                    let parsed = InfoKind::parse(&nla)?;
144                    nlas.push(LinkInfo::Kind(parsed.clone()));
145                    link_info_kind = Some(parsed);
146                }
147                IFLA_INFO_DATA => {
148                    if let Some(link_info_kind) = &link_info_kind {
149                        nlas.push(LinkInfo::Data(InfoData::parse_with_param(
150                            nla.value(),
151                            link_info_kind,
152                        )?));
153                    } else {
154                        return Err("IFLA_INFO_DATA is not preceded by an \
155                            IFLA_INFO_KIND"
156                            .into());
157                    }
158                }
159                _kind => nlas.push(LinkInfo::Other(
160                    DefaultNla::parse(&nla)
161                        .context(format!("Unknown NLA type for IFLA_INFO_DATA {:?}", nla))?,
162                )),
163            }
164        }
165        Ok(Self(nlas))
166    }
167}
168
169#[derive(Debug, PartialEq, Eq, Clone)]
170#[non_exhaustive]
171pub enum InfoKind {
172    Dummy,
173    Ifb,
174    Bridge,
175    Tun,
176    Nlmon,
177    Vlan,
178    Veth,
179    Vxlan,
180    Bond,
181    IpVlan,
182    IpVtap,
183    MacVlan,
184    MacVtap,
185    GreTap,
186    GreTap6,
187    IpTun,
188    SitTun,
189    GreTun,
190    GreTun6,
191    Vti,
192    Vrf,
193    Gtp,
194    Ipoib,
195    Wireguard,
196    Xfrm,
197    MacSec,
198    Hsr,
199    Other(String),
200}
201
202impl std::fmt::Display for InfoKind {
203    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204        write!(
205            f,
206            "{}",
207            match self {
208                Self::Dummy => DUMMY,
209                Self::Ifb => IFB,
210                Self::Bridge => BRIDGE,
211                Self::Tun => TUN,
212                Self::Nlmon => NLMON,
213                Self::Vlan => VLAN,
214                Self::Veth => VETH,
215                Self::Vxlan => VXLAN,
216                Self::Bond => BOND,
217                Self::IpVlan => IPVLAN,
218                Self::IpVtap => IPVTAP,
219                Self::MacVlan => MACVLAN,
220                Self::MacVtap => MACVTAP,
221                Self::GreTap => GRETAP,
222                Self::GreTap6 => IP6GRETAP,
223                Self::IpTun => IPIP,
224                Self::SitTun => SIT,
225                Self::GreTun => GRE,
226                Self::GreTun6 => IP6GRE,
227                Self::Vti => VTI,
228                Self::Vrf => VRF,
229                Self::Gtp => GTP,
230                Self::Ipoib => IPOIB,
231                Self::Wireguard => WIREGUARD,
232                Self::Xfrm => XFRM,
233                Self::MacSec => MACSEC,
234                Self::Hsr => HSR,
235                Self::Other(s) => s.as_str(),
236            }
237        )
238    }
239}
240
241impl Nla for InfoKind {
242    fn value_len(&self) -> usize {
243        let len = match self {
244            Self::Dummy => DUMMY.len(),
245            Self::Ifb => IFB.len(),
246            Self::Bridge => BRIDGE.len(),
247            Self::Tun => TUN.len(),
248            Self::Nlmon => NLMON.len(),
249            Self::Vlan => VLAN.len(),
250            Self::Veth => VETH.len(),
251            Self::Vxlan => VXLAN.len(),
252            Self::Bond => BOND.len(),
253            Self::IpVlan => IPVLAN.len(),
254            Self::IpVtap => IPVTAP.len(),
255            Self::MacVlan => MACVLAN.len(),
256            Self::MacVtap => MACVTAP.len(),
257            Self::GreTap => GRETAP.len(),
258            Self::GreTap6 => IP6GRETAP.len(),
259            Self::IpTun => IPIP.len(),
260            Self::SitTun => SIT.len(),
261            Self::GreTun => GRE.len(),
262            Self::GreTun6 => IP6GRE.len(),
263            Self::Vti => VTI.len(),
264            Self::Vrf => VRF.len(),
265            Self::Gtp => GTP.len(),
266            Self::Ipoib => IPOIB.len(),
267            Self::Wireguard => WIREGUARD.len(),
268            Self::Xfrm => XFRM.len(),
269            Self::MacSec => MACSEC.len(),
270            Self::Hsr => HSR.len(),
271            Self::Other(s) => s.len(),
272        };
273        len + 1
274    }
275
276    fn emit_value(&self, buffer: &mut [u8]) {
277        let kind = self.to_string();
278        let s = kind.as_str();
279        buffer[..s.len()].copy_from_slice(s.to_string().as_bytes());
280        buffer[s.len()] = 0;
281    }
282
283    fn kind(&self) -> u16 {
284        IFLA_INFO_KIND
285    }
286}
287
288impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoKind {
289    type Error = DecodeError;
290    fn parse(buf: &NlaBuffer<&'a T>) -> Result<InfoKind, DecodeError> {
291        if buf.kind() != IFLA_INFO_KIND {
292            return Err(
293                format!("failed to parse IFLA_INFO_KIND: NLA type is {}", buf.kind()).into()
294            );
295        }
296        let s = parse_string(buf.value()).context("invalid IFLA_INFO_KIND value")?;
297        Ok(match s.as_str() {
298            DUMMY => Self::Dummy,
299            IFB => Self::Ifb,
300            BRIDGE => Self::Bridge,
301            TUN => Self::Tun,
302            NLMON => Self::Nlmon,
303            VLAN => Self::Vlan,
304            VETH => Self::Veth,
305            VXLAN => Self::Vxlan,
306            BOND => Self::Bond,
307            IPVLAN => Self::IpVlan,
308            IPVTAP => Self::IpVtap,
309            MACVLAN => Self::MacVlan,
310            MACVTAP => Self::MacVtap,
311            GRETAP => Self::GreTap,
312            IP6GRETAP => Self::GreTap6,
313            IPIP => Self::IpTun,
314            SIT => Self::SitTun,
315            GRE => Self::GreTun,
316            IP6GRE => Self::GreTun6,
317            VTI => Self::Vti,
318            VRF => Self::Vrf,
319            GTP => Self::Gtp,
320            IPOIB => Self::Ipoib,
321            WIREGUARD => Self::Wireguard,
322            MACSEC => Self::MacSec,
323            XFRM => Self::Xfrm,
324            HSR => Self::Hsr,
325            _ => Self::Other(s),
326        })
327    }
328}