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