netlink_packet_route/link/link_info/
infos.rs

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