1use anyhow::Context;
4use netlink_packet_utils::{
5 nla::{DefaultNla, Nla, NlaBuffer, NlasIterator},
6 parsers::parse_string,
7 DecodeError, Emitable, Parseable, ParseableParametrized,
8};
9
10use super::super::{InfoData, InfoPortData, InfoPortKind, LinkXstats};
11
12const IFLA_INFO_KIND: u16 = 1;
13const IFLA_INFO_DATA: u16 = 2;
14const IFLA_INFO_XSTATS: u16 = 3;
15const IFLA_INFO_PORT_KIND: u16 = 4;
16const IFLA_INFO_PORT_DATA: u16 = 5;
17
18const DUMMY: &str = "dummy";
19const IFB: &str = "ifb";
20const BRIDGE: &str = "bridge";
21const TUN: &str = "tun";
22const NLMON: &str = "nlmon";
23const VLAN: &str = "vlan";
24const VETH: &str = "veth";
25const VXLAN: &str = "vxlan";
26const BOND: &str = "bond";
27const IPVLAN: &str = "ipvlan";
28const IPVTAP: &str = "ipvtap";
29const MACVLAN: &str = "macvlan";
30const MACVTAP: &str = "macvtap";
31const GRETAP: &str = "gretap";
32const IP6GRETAP: &str = "ip6gretap";
33const IPIP: &str = "ipip";
34const SIT: &str = "sit";
35const GRE: &str = "gre";
36const IP6GRE: &str = "ip6gre";
37const VTI: &str = "vti";
38const VRF: &str = "vrf";
39const GTP: &str = "gtp";
40const IPOIB: &str = "ipoib";
41const WIREGUARD: &str = "wireguard";
42const XFRM: &str = "xfrm";
43const MACSEC: &str = "macsec";
44const HSR: &str = "hsr";
45const GENEVE: &str = "geneve";
46
47#[derive(Debug, PartialEq, Eq, Clone)]
48#[non_exhaustive]
49pub enum LinkInfo {
50 Xstats(LinkXstats),
51 Kind(InfoKind),
52 Data(InfoData),
53 PortKind(InfoPortKind),
54 PortData(InfoPortData),
55 Other(DefaultNla),
56}
57
58impl Nla for LinkInfo {
59 fn value_len(&self) -> usize {
60 match self {
61 Self::Xstats(v) => v.buffer_len(),
62 Self::Kind(nla) => nla.value_len(),
63 Self::Data(nla) => nla.value_len(),
64 Self::PortKind(nla) => nla.value_len(),
65 Self::PortData(nla) => nla.value_len(),
66 Self::Other(nla) => nla.value_len(),
67 }
68 }
69
70 fn emit_value(&self, buffer: &mut [u8]) {
71 match self {
72 Self::Xstats(v) => v.emit(buffer),
73 Self::Kind(nla) => nla.emit_value(buffer),
74 Self::Data(nla) => nla.emit_value(buffer),
75 Self::PortKind(nla) => nla.emit_value(buffer),
76 Self::PortData(nla) => nla.emit_value(buffer),
77 Self::Other(nla) => nla.emit_value(buffer),
78 }
79 }
80
81 fn kind(&self) -> u16 {
82 match self {
83 Self::Xstats(_) => IFLA_INFO_XSTATS,
84 Self::PortKind(_) => IFLA_INFO_PORT_KIND,
85 Self::PortData(_) => IFLA_INFO_PORT_DATA,
86 Self::Kind(_) => IFLA_INFO_KIND,
87 Self::Data(_) => IFLA_INFO_DATA,
88 Self::Other(nla) => nla.kind(),
89 }
90 }
91}
92
93pub(crate) struct VecLinkInfo(pub(crate) Vec<LinkInfo>);
94
95impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for VecLinkInfo {
107 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
108 let mut nlas = Vec::new();
109 let mut link_info_kind: Option<InfoKind> = None;
110 let mut link_info_port_kind: Option<InfoPortKind> = None;
111 for nla in NlasIterator::new(buf.into_inner()) {
112 let nla = nla?;
113 match nla.kind() {
114 IFLA_INFO_XSTATS => {
115 if let Some(link_info_kind) = &link_info_kind {
116 nlas.push(LinkInfo::Xstats(
117 LinkXstats::parse_with_param(&nla, link_info_kind)?,
118 ));
119 } else {
120 return Err("IFLA_INFO_XSTATS is not \
121 preceded by an IFLA_INFO_KIND"
122 .into());
123 }
124 }
125 IFLA_INFO_PORT_KIND => {
126 let parsed = InfoPortKind::parse(&nla)?;
127 nlas.push(LinkInfo::PortKind(parsed.clone()));
128 link_info_port_kind = Some(parsed);
129 }
130 IFLA_INFO_PORT_DATA => {
131 if let Some(link_info_port_kind) = link_info_port_kind {
132 nlas.push(LinkInfo::PortData(
133 InfoPortData::parse_with_param(
134 nla.value(),
135 link_info_port_kind,
136 )?,
137 ));
138 } else {
139 return Err("IFLA_INFO_PORT_DATA is not preceded by \
140 an IFLA_INFO_PORT_KIND"
141 .into());
142 }
143 link_info_port_kind = None;
144 }
145 IFLA_INFO_KIND => {
146 let parsed = InfoKind::parse(&nla)?;
147 nlas.push(LinkInfo::Kind(parsed.clone()));
148 link_info_kind = Some(parsed);
149 }
150 IFLA_INFO_DATA => {
151 if let Some(link_info_kind) = &link_info_kind {
152 nlas.push(LinkInfo::Data(InfoData::parse_with_param(
153 nla.value(),
154 link_info_kind,
155 )?));
156 } else {
157 return Err("IFLA_INFO_DATA is not preceded by an \
158 IFLA_INFO_KIND"
159 .into());
160 }
161 }
162 _kind => nlas.push(LinkInfo::Other(
163 DefaultNla::parse(&nla).context(format!(
164 "Unknown NLA type for IFLA_INFO_DATA {:?}",
165 nla
166 ))?,
167 )),
168 }
169 }
170 Ok(Self(nlas))
171 }
172}
173
174#[derive(Debug, PartialEq, Eq, Clone)]
175#[non_exhaustive]
176pub enum InfoKind {
177 Dummy,
178 Ifb,
179 Bridge,
180 Tun,
181 Nlmon,
182 Vlan,
183 Veth,
184 Vxlan,
185 Bond,
186 IpVlan,
187 IpVtap,
188 MacVlan,
189 MacVtap,
190 GreTap,
191 GreTap6,
192 IpTun,
193 SitTun,
194 GreTun,
195 GreTun6,
196 Vti,
197 Vrf,
198 Gtp,
199 Ipoib,
200 Wireguard,
201 Xfrm,
202 MacSec,
203 Hsr,
204 Geneve,
205 Other(String),
206}
207
208impl std::fmt::Display for InfoKind {
209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210 write!(
211 f,
212 "{}",
213 match self {
214 Self::Dummy => DUMMY,
215 Self::Ifb => IFB,
216 Self::Bridge => BRIDGE,
217 Self::Tun => TUN,
218 Self::Nlmon => NLMON,
219 Self::Vlan => VLAN,
220 Self::Veth => VETH,
221 Self::Vxlan => VXLAN,
222 Self::Bond => BOND,
223 Self::IpVlan => IPVLAN,
224 Self::IpVtap => IPVTAP,
225 Self::MacVlan => MACVLAN,
226 Self::MacVtap => MACVTAP,
227 Self::GreTap => GRETAP,
228 Self::GreTap6 => IP6GRETAP,
229 Self::IpTun => IPIP,
230 Self::SitTun => SIT,
231 Self::GreTun => GRE,
232 Self::GreTun6 => IP6GRE,
233 Self::Vti => VTI,
234 Self::Vrf => VRF,
235 Self::Gtp => GTP,
236 Self::Ipoib => IPOIB,
237 Self::Wireguard => WIREGUARD,
238 Self::Xfrm => XFRM,
239 Self::MacSec => MACSEC,
240 Self::Hsr => HSR,
241 Self::Geneve => GENEVE,
242 Self::Other(s) => s.as_str(),
243 }
244 )
245 }
246}
247
248impl Nla for InfoKind {
249 fn value_len(&self) -> usize {
250 let len = match self {
251 Self::Dummy => DUMMY.len(),
252 Self::Ifb => IFB.len(),
253 Self::Bridge => BRIDGE.len(),
254 Self::Tun => TUN.len(),
255 Self::Nlmon => NLMON.len(),
256 Self::Vlan => VLAN.len(),
257 Self::Veth => VETH.len(),
258 Self::Vxlan => VXLAN.len(),
259 Self::Bond => BOND.len(),
260 Self::IpVlan => IPVLAN.len(),
261 Self::IpVtap => IPVTAP.len(),
262 Self::MacVlan => MACVLAN.len(),
263 Self::MacVtap => MACVTAP.len(),
264 Self::GreTap => GRETAP.len(),
265 Self::GreTap6 => IP6GRETAP.len(),
266 Self::IpTun => IPIP.len(),
267 Self::SitTun => SIT.len(),
268 Self::GreTun => GRE.len(),
269 Self::GreTun6 => IP6GRE.len(),
270 Self::Vti => VTI.len(),
271 Self::Vrf => VRF.len(),
272 Self::Gtp => GTP.len(),
273 Self::Ipoib => IPOIB.len(),
274 Self::Wireguard => WIREGUARD.len(),
275 Self::Xfrm => XFRM.len(),
276 Self::MacSec => MACSEC.len(),
277 Self::Hsr => HSR.len(),
278 Self::Geneve => GENEVE.len(),
279 Self::Other(s) => s.len(),
280 };
281 len + 1
282 }
283
284 fn emit_value(&self, buffer: &mut [u8]) {
285 let kind = self.to_string();
286 let s = kind.as_str();
287 buffer[..s.len()].copy_from_slice(s.to_string().as_bytes());
288 buffer[s.len()] = 0;
289 }
290
291 fn kind(&self) -> u16 {
292 IFLA_INFO_KIND
293 }
294}
295
296impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoKind {
297 fn parse(buf: &NlaBuffer<&'a T>) -> Result<InfoKind, DecodeError> {
298 if buf.kind() != IFLA_INFO_KIND {
299 return Err(format!(
300 "failed to parse IFLA_INFO_KIND: NLA type is {}",
301 buf.kind()
302 )
303 .into());
304 }
305 let s = parse_string(buf.value())
306 .context("invalid IFLA_INFO_KIND value")?;
307 Ok(match s.as_str() {
308 DUMMY => Self::Dummy,
309 IFB => Self::Ifb,
310 BRIDGE => Self::Bridge,
311 TUN => Self::Tun,
312 NLMON => Self::Nlmon,
313 VLAN => Self::Vlan,
314 VETH => Self::Veth,
315 VXLAN => Self::Vxlan,
316 BOND => Self::Bond,
317 IPVLAN => Self::IpVlan,
318 IPVTAP => Self::IpVtap,
319 MACVLAN => Self::MacVlan,
320 MACVTAP => Self::MacVtap,
321 GRETAP => Self::GreTap,
322 IP6GRETAP => Self::GreTap6,
323 IPIP => Self::IpTun,
324 SIT => Self::SitTun,
325 GRE => Self::GreTun,
326 IP6GRE => Self::GreTun6,
327 VTI => Self::Vti,
328 VRF => Self::Vrf,
329 GTP => Self::Gtp,
330 IPOIB => Self::Ipoib,
331 WIREGUARD => Self::Wireguard,
332 MACSEC => Self::MacSec,
333 XFRM => Self::Xfrm,
334 HSR => Self::Hsr,
335 GENEVE => Self::Geneve,
336 _ => Self::Other(s),
337 })
338 }
339}