netlink_packet_route/link/link_info/
info_port.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_core::{
4    parse_string, DecodeError, Emitable, ErrorContext, Nla, NlaBuffer,
5    NlasIterator, Parseable,
6};
7
8use super::{
9    super::{InfoBondPort, InfoBridgePort},
10    InfoVrf,
11};
12
13const BOND: &str = "bond";
14const BRIDGE: &str = "bridge";
15const VRF: &str = "vrf";
16
17const IFLA_INFO_PORT_KIND: u16 = 4;
18const IFLA_INFO_PORT_DATA: u16 = 5;
19
20#[derive(Debug, PartialEq, Eq, Clone)]
21#[non_exhaustive]
22pub enum InfoPortKind {
23    Bond,
24    Bridge,
25    Vrf,
26    Other(String),
27}
28
29impl std::fmt::Display for InfoPortKind {
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        write!(
32            f,
33            "{}",
34            match self {
35                Self::Bond => BOND,
36                Self::Bridge => BRIDGE,
37                Self::Vrf => VRF,
38                Self::Other(s) => s.as_str(),
39            }
40        )
41    }
42}
43
44impl Nla for InfoPortKind {
45    fn value_len(&self) -> usize {
46        let len = match self {
47            Self::Bond => BOND.len(),
48            Self::Bridge => BRIDGE.len(),
49            Self::Vrf => VRF.len(),
50            Self::Other(s) => s.len(),
51        };
52        len + 1
53    }
54
55    fn emit_value(&self, buffer: &mut [u8]) {
56        let s = match self {
57            Self::Bond => BOND,
58            Self::Bridge => BRIDGE,
59            Self::Vrf => VRF,
60            Self::Other(s) => s.as_str(),
61        };
62        buffer[..s.len()].copy_from_slice(s.as_bytes());
63        buffer[s.len()] = 0;
64    }
65
66    fn kind(&self) -> u16 {
67        IFLA_INFO_PORT_KIND
68    }
69}
70
71impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoPortKind {
72    fn parse(buf: &NlaBuffer<&'a T>) -> Result<InfoPortKind, DecodeError> {
73        if buf.kind() != IFLA_INFO_PORT_KIND {
74            return Err(format!(
75                "failed to parse IFLA_INFO_PORT_KIND: NLA type is {}",
76                buf.kind()
77            )
78            .into());
79        }
80        let s = parse_string(buf.value())
81            .context("invalid IFLA_INFO_PORT_KIND value")?;
82        Ok(match s.as_str() {
83            BOND => Self::Bond,
84            BRIDGE => Self::Bridge,
85            VRF => Self::Vrf,
86            _ => Self::Other(s),
87        })
88    }
89}
90
91pub type InfoVrfPort = InfoVrf;
92
93#[derive(Debug, PartialEq, Eq, Clone)]
94#[non_exhaustive]
95pub enum InfoPortData {
96    BondPort(Vec<InfoBondPort>),
97    BridgePort(Vec<InfoBridgePort>),
98    VrfPort(Vec<InfoVrfPort>),
99    Other(Vec<u8>),
100}
101
102impl Nla for InfoPortData {
103    fn value_len(&self) -> usize {
104        match self {
105            Self::BondPort(nlas) => nlas.as_slice().buffer_len(),
106            Self::BridgePort(nlas) => nlas.as_slice().buffer_len(),
107            Self::VrfPort(nlas) => nlas.as_slice().buffer_len(),
108            Self::Other(bytes) => bytes.len(),
109        }
110    }
111
112    fn emit_value(&self, buffer: &mut [u8]) {
113        match self {
114            Self::BondPort(nlas) => nlas.as_slice().emit(buffer),
115            Self::BridgePort(nlas) => nlas.as_slice().emit(buffer),
116            Self::VrfPort(nlas) => nlas.as_slice().emit(buffer),
117            Self::Other(bytes) => buffer.copy_from_slice(bytes),
118        }
119    }
120
121    fn kind(&self) -> u16 {
122        IFLA_INFO_PORT_DATA
123    }
124}
125
126impl InfoPortData {
127    pub(crate) fn parse_with_param(
128        payload: &[u8],
129        kind: InfoPortKind,
130    ) -> Result<InfoPortData, DecodeError> {
131        let port_data = match kind {
132            InfoPortKind::Bond => NlasIterator::new(payload)
133                .map(|nla| nla.and_then(|nla| InfoBondPort::parse(&nla)))
134                .collect::<Result<Vec<_>, _>>()
135                .map(InfoPortData::BondPort),
136            InfoPortKind::Bridge => NlasIterator::new(payload)
137                .map(|nla| nla.and_then(|nla| InfoBridgePort::parse(&nla)))
138                .collect::<Result<Vec<_>, _>>()
139                .map(InfoPortData::BridgePort),
140            InfoPortKind::Vrf => NlasIterator::new(payload)
141                .map(|nla| nla.and_then(|nla| InfoVrfPort::parse(&nla)))
142                .collect::<Result<Vec<_>, _>>()
143                .map(InfoPortData::VrfPort),
144            InfoPortKind::Other(_) => Ok(InfoPortData::Other(payload.to_vec())),
145        };
146
147        port_data.context(format!(
148            "failed to parse IFLA_INFO_PORT_DATA (IFLA_INFO_PORT_KIND is \
149             '{kind}')"
150        ))
151    }
152}