netlink_packet_route/link/link_info/
info_port.rs

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