netlink_packet_route/link/link_info/
info_port.rs
1use 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}