netlink_packet_route/link/link_info/
info_port.rs

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