netlink_packet_route/link/link_info/
info_port.rs1use 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}