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