netlink_packet_route/link/link_info/
infos.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_core::{
4    parse_string, DecodeError, DefaultNla, Emitable, ErrorContext, Nla,
5    NlaBuffer, NlasIterator, Parseable, ParseableParametrized,
6};
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 IP6TNL: &str = "ip6tnl";
33const SIT: &str = "sit";
34const GRE: &str = "gre";
35const IP6GRE: &str = "ip6gre";
36const VTI: &str = "vti";
37const VRF: &str = "vrf";
38const GTP: &str = "gtp";
39const IPOIB: &str = "ipoib";
40const WIREGUARD: &str = "wireguard";
41const XFRM: &str = "xfrm";
42const MACSEC: &str = "macsec";
43const HSR: &str = "hsr";
44const GENEVE: &str = "geneve";
45const NETKIT: &str = "netkit";
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 preceded by an \
121                                    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 {nla:?}"
165                    ))?,
166                )),
167            }
168        }
169        Ok(Self(nlas))
170    }
171}
172
173#[derive(Debug, PartialEq, Eq, Clone)]
174#[non_exhaustive]
175pub enum InfoKind {
176    Dummy,
177    Ifb,
178    Bridge,
179    Tun,
180    Nlmon,
181    Vlan,
182    Veth,
183    Vxlan,
184    Bond,
185    IpVlan,
186    IpVtap,
187    MacVlan,
188    MacVtap,
189    GreTap,
190    GreTap6,
191    IpIp,
192    Ip6Tnl,
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    Netkit,
206    Other(String),
207}
208
209impl std::fmt::Display for InfoKind {
210    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211        write!(
212            f,
213            "{}",
214            match self {
215                Self::Dummy => DUMMY,
216                Self::Ifb => IFB,
217                Self::Bridge => BRIDGE,
218                Self::Tun => TUN,
219                Self::Nlmon => NLMON,
220                Self::Vlan => VLAN,
221                Self::Veth => VETH,
222                Self::Vxlan => VXLAN,
223                Self::Bond => BOND,
224                Self::IpVlan => IPVLAN,
225                Self::IpVtap => IPVTAP,
226                Self::MacVlan => MACVLAN,
227                Self::MacVtap => MACVTAP,
228                Self::GreTap => GRETAP,
229                Self::GreTap6 => IP6GRETAP,
230                Self::IpIp => IPIP,
231                Self::Ip6Tnl => IP6TNL,
232                Self::SitTun => SIT,
233                Self::GreTun => GRE,
234                Self::GreTun6 => IP6GRE,
235                Self::Vti => VTI,
236                Self::Vrf => VRF,
237                Self::Gtp => GTP,
238                Self::Ipoib => IPOIB,
239                Self::Wireguard => WIREGUARD,
240                Self::Xfrm => XFRM,
241                Self::MacSec => MACSEC,
242                Self::Hsr => HSR,
243                Self::Geneve => GENEVE,
244                Self::Netkit => NETKIT,
245                Self::Other(s) => s.as_str(),
246            }
247        )
248    }
249}
250
251impl Nla for InfoKind {
252    fn value_len(&self) -> usize {
253        let len = match self {
254            Self::Dummy => DUMMY.len(),
255            Self::Ifb => IFB.len(),
256            Self::Bridge => BRIDGE.len(),
257            Self::Tun => TUN.len(),
258            Self::Nlmon => NLMON.len(),
259            Self::Vlan => VLAN.len(),
260            Self::Veth => VETH.len(),
261            Self::Vxlan => VXLAN.len(),
262            Self::Bond => BOND.len(),
263            Self::IpVlan => IPVLAN.len(),
264            Self::IpVtap => IPVTAP.len(),
265            Self::MacVlan => MACVLAN.len(),
266            Self::MacVtap => MACVTAP.len(),
267            Self::GreTap => GRETAP.len(),
268            Self::GreTap6 => IP6GRETAP.len(),
269            Self::IpIp => IPIP.len(),
270            Self::Ip6Tnl => IP6TNL.len(),
271            Self::SitTun => SIT.len(),
272            Self::GreTun => GRE.len(),
273            Self::GreTun6 => IP6GRE.len(),
274            Self::Vti => VTI.len(),
275            Self::Vrf => VRF.len(),
276            Self::Gtp => GTP.len(),
277            Self::Ipoib => IPOIB.len(),
278            Self::Wireguard => WIREGUARD.len(),
279            Self::Xfrm => XFRM.len(),
280            Self::MacSec => MACSEC.len(),
281            Self::Hsr => HSR.len(),
282            Self::Geneve => GENEVE.len(),
283            Self::Netkit => NETKIT.len(),
284            Self::Other(s) => s.len(),
285        };
286        len + 1
287    }
288
289    fn emit_value(&self, buffer: &mut [u8]) {
290        let kind = self.to_string();
291        let s = kind.as_str();
292        buffer[..s.len()].copy_from_slice(s.to_string().as_bytes());
293        buffer[s.len()] = 0;
294    }
295
296    fn kind(&self) -> u16 {
297        IFLA_INFO_KIND
298    }
299}
300
301impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoKind {
302    fn parse(buf: &NlaBuffer<&'a T>) -> Result<InfoKind, DecodeError> {
303        if buf.kind() != IFLA_INFO_KIND {
304            return Err(format!(
305                "failed to parse IFLA_INFO_KIND: NLA type is {}",
306                buf.kind()
307            )
308            .into());
309        }
310        let s = parse_string(buf.value())
311            .context("invalid IFLA_INFO_KIND value")?;
312        Ok(match s.as_str() {
313            DUMMY => Self::Dummy,
314            IFB => Self::Ifb,
315            BRIDGE => Self::Bridge,
316            TUN => Self::Tun,
317            NLMON => Self::Nlmon,
318            VLAN => Self::Vlan,
319            VETH => Self::Veth,
320            VXLAN => Self::Vxlan,
321            BOND => Self::Bond,
322            IPVLAN => Self::IpVlan,
323            IPVTAP => Self::IpVtap,
324            MACVLAN => Self::MacVlan,
325            MACVTAP => Self::MacVtap,
326            GRETAP => Self::GreTap,
327            IP6GRETAP => Self::GreTap6,
328            IPIP => Self::IpIp,
329            IP6TNL => Self::Ip6Tnl,
330            SIT => Self::SitTun,
331            GRE => Self::GreTun,
332            IP6GRE => Self::GreTun6,
333            VTI => Self::Vti,
334            VRF => Self::Vrf,
335            GTP => Self::Gtp,
336            IPOIB => Self::Ipoib,
337            WIREGUARD => Self::Wireguard,
338            MACSEC => Self::MacSec,
339            XFRM => Self::Xfrm,
340            HSR => Self::Hsr,
341            GENEVE => Self::Geneve,
342            NETKIT => Self::Netkit,
343            _ => Self::Other(s),
344        })
345    }
346}