1use std::os::unix::io::RawFd;
4
5use anyhow::Context;
6use byteorder::{ByteOrder, NativeEndian};
7use netlink_packet_utils::{
8 nla::{DefaultNla, Nla, NlaBuffer, NlasIterator, NLA_F_NESTED},
9 parsers::{parse_i32, parse_string, parse_u32, parse_u8},
10 traits::{Emitable, Parseable, ParseableParametrized},
11 DecodeError,
12};
13
14#[cfg(any(target_os = "linux", target_os = "fuchsia",))]
15use super::af_spec::VecAfSpecBridge;
16#[cfg(any(target_os = "linux", target_os = "fuchsia",))]
17use super::proto_info::VecLinkProtoInfoBridge;
18use super::{
19 af_spec::VecAfSpecUnspec,
20 buffer_tool::expand_buffer_if_small,
21 ext_mask::VecLinkExtentMask,
22 link_info::VecLinkInfo,
23 proto_info::VecLinkProtoInfoInet6,
24 sriov::{VecLinkVfInfo, VecLinkVfPort},
25 stats::LINK_STATS_LEN,
26 stats64::LINK_STATS64_LEN,
27 xdp::VecLinkXdp,
28 AfSpecBridge, AfSpecUnspec, LinkEvent, LinkExtentMask, LinkInfo,
29 LinkPhysId, LinkProtoInfoBridge, LinkProtoInfoInet6,
30 LinkProtocolDownReason, LinkVfInfo, LinkVfPort, LinkWirelessEvent, LinkXdp,
31 Map, MapBuffer, Prop, State, Stats, Stats64, Stats64Buffer, StatsBuffer,
32};
33use crate::AddressFamily;
34
35const IFLA_ADDRESS: u16 = 1;
36const IFLA_BROADCAST: u16 = 2;
37const IFLA_IFNAME: u16 = 3;
38const IFLA_MTU: u16 = 4;
39const IFLA_LINK: u16 = 5;
40const IFLA_QDISC: u16 = 6;
41const IFLA_STATS: u16 = 7;
42const IFLA_MASTER: u16 = 10;
47const IFLA_WIRELESS: u16 = 11;
48const IFLA_PROTINFO: u16 = 12;
49const IFLA_TXQLEN: u16 = 13;
50const IFLA_MAP: u16 = 14;
51const IFLA_OPERSTATE: u16 = 16;
54const IFLA_LINKMODE: u16 = 17;
55const IFLA_LINKINFO: u16 = 18;
56const IFLA_NET_NS_PID: u16 = 19;
57const IFLA_IFALIAS: u16 = 20;
58const IFLA_NUM_VF: u16 = 21;
59const IFLA_VFINFO_LIST: u16 = 22;
60const IFLA_STATS64: u16 = 23;
61const IFLA_VF_PORTS: u16 = 24;
62const IFLA_PORT_SELF: u16 = 25;
63const IFLA_AF_SPEC: u16 = 26;
64const IFLA_GROUP: u16 = 27;
65const IFLA_NET_NS_FD: u16 = 28;
66const IFLA_EXT_MASK: u16 = 29;
67const IFLA_PROMISCUITY: u16 = 30;
68const IFLA_NUM_TX_QUEUES: u16 = 31;
69const IFLA_NUM_RX_QUEUES: u16 = 32;
70const IFLA_CARRIER: u16 = 33;
71const IFLA_PHYS_PORT_ID: u16 = 34;
72const IFLA_CARRIER_CHANGES: u16 = 35;
73const IFLA_PHYS_SWITCH_ID: u16 = 36;
74const IFLA_LINK_NETNSID: u16 = 37;
75const IFLA_PHYS_PORT_NAME: u16 = 38;
76const IFLA_PROTO_DOWN: u16 = 39;
77const IFLA_GSO_MAX_SEGS: u16 = 40;
78const IFLA_GSO_MAX_SIZE: u16 = 41;
79const IFLA_XDP: u16 = 43;
81const IFLA_EVENT: u16 = 44;
82const IFLA_NEW_NETNSID: u16 = 45;
83const IFLA_IF_NETNSID: u16 = 46;
84const IFLA_CARRIER_UP_COUNT: u16 = 47;
85const IFLA_CARRIER_DOWN_COUNT: u16 = 48;
86const IFLA_NEW_IFINDEX: u16 = 49;
87const IFLA_MIN_MTU: u16 = 50;
88const IFLA_MAX_MTU: u16 = 51;
89const IFLA_PROP_LIST: u16 = 52;
90const IFLA_PERM_ADDRESS: u16 = 54;
91const IFLA_PROTO_DOWN_REASON: u16 = 55;
92
93#[derive(Debug, PartialEq, Eq, Clone)]
104#[non_exhaustive]
105pub enum LinkAttribute {
106 VfInfoList(Vec<LinkVfInfo>),
107 VfPorts(Vec<LinkVfPort>),
108 PortSelf(LinkVfPort),
109 PhysPortId(LinkPhysId),
110 PhysSwitchId(LinkPhysId),
111 Xdp(Vec<LinkXdp>),
112 Event(LinkEvent),
113 NewNetnsId(i32),
114 IfNetnsId(i32),
115 CarrierUpCount(u32),
116 CarrierDownCount(u32),
117 NewIfIndex(i32),
118 LinkInfo(Vec<LinkInfo>),
119 Wireless(LinkWirelessEvent),
120 ProtoInfoBridge(Vec<LinkProtoInfoBridge>),
121 ProtoInfoInet6(Vec<LinkProtoInfoInet6>),
122 ProtoInfoUnknown(DefaultNla),
123 PropList(Vec<Prop>),
124 ProtoDownReason(Vec<LinkProtocolDownReason>),
125 Address(Vec<u8>),
126 Broadcast(Vec<u8>),
127 PermAddress(Vec<u8>),
130 IfName(String),
131 Qdisc(String),
132 IfAlias(String),
133 PhysPortName(String),
134 Mode(u8),
135 Carrier(u8),
136 ProtoDown(u8),
137 Mtu(u32),
138 Link(u32),
139 Controller(u32),
140 TxQueueLen(u32),
141 NetNsPid(u32),
142 NumVf(u32),
143 Group(u32),
144 NetNsFd(RawFd),
145 ExtMask(Vec<LinkExtentMask>),
146 Promiscuity(u32),
147 NumTxQueues(u32),
148 NumRxQueues(u32),
149 CarrierChanges(u32),
150 GsoMaxSegs(u32),
151 GsoMaxSize(u32),
152 MinMtu(u32),
154 MaxMtu(u32),
156 LinkNetNsId(i32),
157 OperState(State),
158 Stats(Stats),
159 Stats64(Stats64),
160 Map(Map),
161 AfSpecUnspec(Vec<AfSpecUnspec>),
164 AfSpecBridge(Vec<AfSpecBridge>),
165 AfSpecUnknown(Vec<u8>),
166 Other(DefaultNla),
167}
168
169impl Nla for LinkAttribute {
170 fn value_len(&self) -> usize {
171 match self {
172 Self::VfInfoList(v) => v.as_slice().buffer_len(),
173 Self::VfPorts(v) => v.as_slice().buffer_len(),
174 Self::PortSelf(v) => v.buffer_len(),
175 Self::PhysPortId(v) => v.buffer_len(),
176 Self::PhysSwitchId(v) => v.buffer_len(),
177 Self::Event(v) => v.buffer_len(),
178 Self::Wireless(v) => v.buffer_len(),
179 Self::ProtoInfoBridge(v) => v.as_slice().buffer_len(),
180 Self::ProtoInfoInet6(v) => v.as_slice().buffer_len(),
181 Self::ProtoDownReason(v) => v.as_slice().buffer_len(),
182
183 Self::Address(bytes)
184 | Self::Broadcast(bytes)
185 | Self::PermAddress(bytes)
186 | Self::AfSpecUnknown(bytes) => bytes.len(),
187
188 Self::IfName(string)
189 | Self::Qdisc(string)
190 | Self::IfAlias(string)
191 | Self::PhysPortName(string) => string.len() + 1,
192
193 Self::Mode(_) | Self::Carrier(_) | Self::ProtoDown(_) => 1,
194
195 Self::Mtu(_)
196 | Self::NewNetnsId(_)
197 | Self::IfNetnsId(_)
198 | Self::Link(_)
199 | Self::Controller(_)
200 | Self::TxQueueLen(_)
201 | Self::NetNsPid(_)
202 | Self::NumVf(_)
203 | Self::Group(_)
204 | Self::NetNsFd(_)
205 | Self::ExtMask(_)
206 | Self::Promiscuity(_)
207 | Self::NumTxQueues(_)
208 | Self::NumRxQueues(_)
209 | Self::CarrierChanges(_)
210 | Self::GsoMaxSegs(_)
211 | Self::GsoMaxSize(_)
212 | Self::LinkNetNsId(_)
213 | Self::MinMtu(_)
214 | Self::CarrierUpCount(_)
215 | Self::CarrierDownCount(_)
216 | Self::NewIfIndex(_)
217 | Self::MaxMtu(_) => 4,
218
219 Self::OperState(_) => 1,
220 Self::Stats(_) => LINK_STATS_LEN,
221 Self::Stats64(_) => LINK_STATS64_LEN,
222 Self::Map(nla) => nla.buffer_len(),
223 Self::LinkInfo(nlas) => nlas.as_slice().buffer_len(),
224 Self::Xdp(nlas) => nlas.as_slice().buffer_len(),
225 Self::PropList(nlas) => nlas.as_slice().buffer_len(),
226 Self::AfSpecUnspec(nlas) => nlas.as_slice().buffer_len(),
227 Self::AfSpecBridge(nlas) => nlas.as_slice().buffer_len(),
228 Self::ProtoInfoUnknown(attr) => attr.value_len(),
229 Self::Other(attr) => attr.value_len(),
230 }
231 }
232
233 fn emit_value(&self, buffer: &mut [u8]) {
234 match self {
235 Self::VfInfoList(v) => v.as_slice().emit(buffer),
236 Self::VfPorts(v) => v.as_slice().emit(buffer),
237 Self::PortSelf(v) => v.emit(buffer),
238 Self::PhysPortId(v) => v.emit(buffer),
239 Self::PhysSwitchId(v) => v.emit(buffer),
240 Self::Event(v) => v.emit(buffer),
241 Self::Wireless(v) => v.emit(buffer),
242 Self::ProtoInfoBridge(v) => v.as_slice().emit(buffer),
243 Self::ProtoInfoInet6(v) => v.as_slice().emit(buffer),
244 Self::ProtoDownReason(v) => v.as_slice().emit(buffer),
245 Self::Address(bytes)
246 | Self::Broadcast(bytes)
247 | Self::PermAddress(bytes)
248 | Self::AfSpecUnknown(bytes) => {
249 buffer.copy_from_slice(bytes.as_slice())
250 }
251
252 Self::IfName(string)
253 | Self::Qdisc(string)
254 | Self::IfAlias(string)
255 | Self::PhysPortName(string) => {
256 buffer[..string.len()].copy_from_slice(string.as_bytes());
257 buffer[string.len()] = 0;
258 }
259
260 Self::Mode(val) | Self::Carrier(val) | Self::ProtoDown(val) => {
261 buffer[0] = *val
262 }
263
264 Self::Mtu(value)
265 | Self::Link(value)
266 | Self::Controller(value)
267 | Self::TxQueueLen(value)
268 | Self::NetNsPid(value)
269 | Self::NumVf(value)
270 | Self::Group(value)
271 | Self::Promiscuity(value)
272 | Self::NumTxQueues(value)
273 | Self::NumRxQueues(value)
274 | Self::CarrierChanges(value)
275 | Self::CarrierUpCount(value)
276 | Self::CarrierDownCount(value)
277 | Self::GsoMaxSegs(value)
278 | Self::GsoMaxSize(value)
279 | Self::MinMtu(value)
280 | Self::MaxMtu(value) => NativeEndian::write_u32(buffer, *value),
281
282 Self::ExtMask(value) => NativeEndian::write_u32(
283 buffer,
284 u32::from(&VecLinkExtentMask(value.to_vec())),
285 ),
286
287 Self::LinkNetNsId(v)
288 | Self::NetNsFd(v)
289 | Self::NewNetnsId(v)
290 | Self::NewIfIndex(v)
291 | Self::IfNetnsId(v) => NativeEndian::write_i32(buffer, *v),
292 Self::Stats(nla) => nla.emit(buffer),
293 Self::Map(nla) => nla.emit(buffer),
294 Self::Stats64(nla) => nla.emit(buffer),
295 Self::OperState(state) => buffer[0] = (*state).into(),
296 Self::LinkInfo(nlas) => nlas.as_slice().emit(buffer),
297 Self::Xdp(nlas) => nlas.as_slice().emit(buffer),
298 Self::PropList(nlas) => nlas.as_slice().emit(buffer),
299 Self::AfSpecUnspec(nlas) => nlas.as_slice().emit(buffer),
300 Self::AfSpecBridge(nlas) => nlas.as_slice().emit(buffer),
301 Self::ProtoInfoUnknown(attr) | Self::Other(attr) => {
302 attr.emit_value(buffer)
303 }
304 }
305 }
306
307 fn kind(&self) -> u16 {
308 match self {
309 Self::VfInfoList(_) => IFLA_VFINFO_LIST,
310 Self::VfPorts(_) => IFLA_VF_PORTS,
311 Self::PortSelf(_) => IFLA_PORT_SELF,
312 Self::PhysPortId(_) => IFLA_PHYS_PORT_ID,
313 Self::PhysSwitchId(_) => IFLA_PHYS_SWITCH_ID,
314 Self::LinkInfo(_) => IFLA_LINKINFO,
315 Self::Wireless(_) => IFLA_WIRELESS,
316 Self::ProtoInfoBridge(_) | Self::ProtoInfoInet6(_) => IFLA_PROTINFO,
317 Self::ProtoInfoUnknown(attr) => attr.kind(),
318 Self::Xdp(_) => IFLA_XDP,
319 Self::Event(_) => IFLA_EVENT,
320 Self::NewNetnsId(_) => IFLA_NEW_NETNSID,
321 Self::IfNetnsId(_) => IFLA_IF_NETNSID,
322 Self::CarrierUpCount(_) => IFLA_CARRIER_UP_COUNT,
323 Self::CarrierDownCount(_) => IFLA_CARRIER_DOWN_COUNT,
324 Self::NewIfIndex(_) => IFLA_NEW_IFINDEX,
325 Self::PropList(_) => IFLA_PROP_LIST | NLA_F_NESTED,
326 Self::ProtoDownReason(_) => IFLA_PROTO_DOWN_REASON,
327 Self::Address(_) => IFLA_ADDRESS,
328 Self::Broadcast(_) => IFLA_BROADCAST,
329 Self::PermAddress(_) => IFLA_PERM_ADDRESS,
330 Self::IfName(_) => IFLA_IFNAME,
331 Self::Qdisc(_) => IFLA_QDISC,
332 Self::IfAlias(_) => IFLA_IFALIAS,
333 Self::PhysPortName(_) => IFLA_PHYS_PORT_NAME,
334 Self::Mode(_) => IFLA_LINKMODE,
335 Self::Carrier(_) => IFLA_CARRIER,
336 Self::ProtoDown(_) => IFLA_PROTO_DOWN,
337 Self::Mtu(_) => IFLA_MTU,
338 Self::Link(_) => IFLA_LINK,
339 Self::Controller(_) => IFLA_MASTER,
340 Self::TxQueueLen(_) => IFLA_TXQLEN,
341 Self::NetNsPid(_) => IFLA_NET_NS_PID,
342 Self::NumVf(_) => IFLA_NUM_VF,
343 Self::Group(_) => IFLA_GROUP,
344 Self::NetNsFd(_) => IFLA_NET_NS_FD,
345 Self::ExtMask(_) => IFLA_EXT_MASK,
346 Self::Promiscuity(_) => IFLA_PROMISCUITY,
347 Self::NumTxQueues(_) => IFLA_NUM_TX_QUEUES,
348 Self::NumRxQueues(_) => IFLA_NUM_RX_QUEUES,
349 Self::CarrierChanges(_) => IFLA_CARRIER_CHANGES,
350 Self::GsoMaxSegs(_) => IFLA_GSO_MAX_SEGS,
351 Self::GsoMaxSize(_) => IFLA_GSO_MAX_SIZE,
352 Self::MinMtu(_) => IFLA_MIN_MTU,
353 Self::MaxMtu(_) => IFLA_MAX_MTU,
354 Self::LinkNetNsId(_) => IFLA_LINK_NETNSID,
355 Self::OperState(_) => IFLA_OPERSTATE,
356 Self::Map(_) => IFLA_MAP,
357 Self::Stats(_) => IFLA_STATS,
358 Self::Stats64(_) => IFLA_STATS64,
359 Self::AfSpecUnspec(_)
360 | Self::AfSpecBridge(_)
361 | Self::AfSpecUnknown(_) => IFLA_AF_SPEC,
362 Self::Other(attr) => attr.kind(),
363 }
364 }
365}
366
367impl<'a, T: AsRef<[u8]> + ?Sized>
368 ParseableParametrized<NlaBuffer<&'a T>, AddressFamily> for LinkAttribute
369{
370 fn parse_with_param(
371 buf: &NlaBuffer<&'a T>,
372 interface_family: AddressFamily,
373 ) -> Result<Self, DecodeError> {
374 let payload = buf.value();
375 Ok(match buf.kind() {
376 IFLA_VFINFO_LIST => {
377 let err =
378 |payload| format!("invalid IFLA_VFINFO_LIST {payload:?}");
379 if !payload.is_empty() {
380 Self::VfInfoList(
381 VecLinkVfInfo::parse(
382 &NlaBuffer::new_checked(payload)
383 .context(err(payload))?,
384 )
385 .context(err(payload))?
386 .0,
387 )
388 } else {
389 Self::VfInfoList(vec![])
392 }
393 }
394 IFLA_VF_PORTS => {
395 let err =
396 |payload| format!("invalid IFLA_VF_PORTS {payload:?}");
397 Self::VfPorts(
398 VecLinkVfPort::parse(
399 &NlaBuffer::new_checked(payload)
400 .context(err(payload))?,
401 )
402 .context(err(payload))?
403 .0,
404 )
405 }
406 IFLA_PORT_SELF => {
407 let err =
408 |payload| format!("invalid IFLA_PORT_SELF {payload:?}");
409 Self::PortSelf(
410 LinkVfPort::parse(
411 &NlaBuffer::new_checked(payload)
412 .context(err(payload))?,
413 )
414 .context(err(payload))?,
415 )
416 }
417 IFLA_PHYS_PORT_ID => {
418 Self::PhysPortId(LinkPhysId::parse(payload).context(
419 format!("invalid IFLA_PHYS_PORT_ID value {payload:?}"),
420 )?)
421 }
422 IFLA_PHYS_SWITCH_ID => {
423 Self::PhysSwitchId(LinkPhysId::parse(payload).context(
424 format!("invalid IFLA_PHYS_SWITCH_ID value {payload:?}"),
425 )?)
426 }
427 IFLA_WIRELESS => Self::Wireless(
428 LinkWirelessEvent::parse(payload)
429 .context(format!("invalid IFLA_WIRELESS {payload:?}"))?,
430 ),
431 IFLA_PROTINFO => {
432 let err = |payload| {
433 format!("invalid IFLA_PROTINFO for AF_INET6 {payload:?}")
434 };
435 match interface_family {
436 AddressFamily::Inet6 => Self::ProtoInfoInet6(
437 VecLinkProtoInfoInet6::parse(
438 &NlaBuffer::new_checked(payload)
439 .context(err(payload))?,
440 )
441 .context(err(payload))?
442 .0,
443 ),
444 #[cfg(any(target_os = "linux", target_os = "fuchsia",))]
445 AddressFamily::Bridge => Self::ProtoInfoBridge(
446 VecLinkProtoInfoBridge::parse(&NlaBuffer::new_checked(
447 payload,
448 )?)
449 .context(format!(
450 "invalid IFLA_PROTINFO for AF_INET6 {payload:?}"
451 ))?
452 .0,
453 ),
454 _ => Self::ProtoInfoUnknown(
455 DefaultNla::parse(buf).context(format!(
456 "invalid IFLA_PROTINFO for \
457 {interface_family:?}: {payload:?}"
458 ))?,
459 ),
460 }
461 }
462 IFLA_EVENT => Self::Event(
463 LinkEvent::parse(payload)
464 .context(format!("invalid IFLA_EVENT {payload:?}"))?,
465 ),
466 IFLA_NEW_NETNSID => Self::NewNetnsId(
467 parse_i32(payload).context("invalid IFLA_NEW_NETNSID value")?,
468 ),
469 IFLA_IF_NETNSID => Self::IfNetnsId(
470 parse_i32(payload).context("invalid IFLA_IF_NETNSID value")?,
471 ),
472 IFLA_CARRIER_UP_COUNT => Self::CarrierUpCount(
473 parse_u32(payload)
474 .context("invalid IFLA_CARRIER_UP_COUNT value")?,
475 ),
476 IFLA_CARRIER_DOWN_COUNT => Self::CarrierDownCount(
477 parse_u32(payload)
478 .context("invalid IFLA_CARRIER_DOWN_COUNT value")?,
479 ),
480 IFLA_NEW_IFINDEX => Self::NewIfIndex(
481 parse_i32(payload).context("invalid IFLA_NEW_IFINDEX value")?,
482 ),
483
484 IFLA_PROP_LIST => {
485 let error_msg = "invalid IFLA_PROP_LIST value";
486 let mut nlas = vec![];
487 for nla in NlasIterator::new(payload) {
488 let nla = &nla.context(error_msg)?;
489 let parsed = Prop::parse(nla).context(error_msg)?;
490 nlas.push(parsed);
491 }
492 Self::PropList(nlas)
493 }
494 IFLA_PROTO_DOWN_REASON => {
495 let mut nlas = vec![];
496 for nla in NlasIterator::new(payload) {
497 let nla =
498 &nla.context("invalid IFLA_PROTO_DOWN_REASON value")?;
499 let parsed = LinkProtocolDownReason::parse(nla)?;
500 nlas.push(parsed);
501 }
502 Self::ProtoDownReason(nlas)
503 }
504 IFLA_ADDRESS => Self::Address(payload.to_vec()),
508 IFLA_BROADCAST => Self::Broadcast(payload.to_vec()),
509 IFLA_PERM_ADDRESS => Self::PermAddress(payload.to_vec()),
510 IFLA_IFNAME => Self::IfName(
512 parse_string(payload).context("invalid IFLA_IFNAME value")?,
513 ),
514 IFLA_QDISC => Self::Qdisc(
515 parse_string(payload).context("invalid IFLA_QDISC value")?,
516 ),
517 IFLA_IFALIAS => Self::IfAlias(
518 parse_string(payload).context("invalid IFLA_IFALIAS value")?,
519 ),
520 IFLA_PHYS_PORT_NAME => Self::PhysPortName(
521 parse_string(payload)
522 .context("invalid IFLA_PHYS_PORT_NAME value")?,
523 ),
524 IFLA_LINKMODE => Self::Mode(
525 parse_u8(payload).context("invalid IFLA_LINKMODE value")?,
526 ),
527 IFLA_CARRIER => Self::Carrier(
528 parse_u8(payload).context("invalid IFLA_CARRIER value")?,
529 ),
530 IFLA_PROTO_DOWN => Self::ProtoDown(
531 parse_u8(payload).context("invalid IFLA_PROTO_DOWN value")?,
532 ),
533
534 IFLA_MTU => {
535 Self::Mtu(parse_u32(payload).context("invalid IFLA_MTU value")?)
536 }
537 IFLA_LINK => Self::Link(
538 parse_u32(payload).context("invalid IFLA_LINK value")?,
539 ),
540 IFLA_MASTER => Self::Controller(
541 parse_u32(payload).context("invalid IFLA_MASTER value")?,
542 ),
543 IFLA_TXQLEN => Self::TxQueueLen(
544 parse_u32(payload).context("invalid IFLA_TXQLEN value")?,
545 ),
546 IFLA_NET_NS_PID => Self::NetNsPid(
547 parse_u32(payload).context("invalid IFLA_NET_NS_PID value")?,
548 ),
549 IFLA_NUM_VF => Self::NumVf(
550 parse_u32(payload).context("invalid IFLA_NUM_VF value")?,
551 ),
552 IFLA_GROUP => Self::Group(
553 parse_u32(payload).context("invalid IFLA_GROUP value")?,
554 ),
555 IFLA_NET_NS_FD => Self::NetNsFd(
556 parse_i32(payload).context("invalid IFLA_NET_NS_FD value")?,
557 ),
558 IFLA_EXT_MASK => Self::ExtMask(
559 VecLinkExtentMask::from(
560 parse_u32(payload)
561 .context("invalid IFLA_EXT_MASK value")?,
562 )
563 .0,
564 ),
565 IFLA_PROMISCUITY => Self::Promiscuity(
566 parse_u32(payload).context("invalid IFLA_PROMISCUITY value")?,
567 ),
568 IFLA_NUM_TX_QUEUES => Self::NumTxQueues(
569 parse_u32(payload)
570 .context("invalid IFLA_NUM_TX_QUEUES value")?,
571 ),
572 IFLA_NUM_RX_QUEUES => Self::NumRxQueues(
573 parse_u32(payload)
574 .context("invalid IFLA_NUM_RX_QUEUES value")?,
575 ),
576 IFLA_CARRIER_CHANGES => Self::CarrierChanges(
577 parse_u32(payload)
578 .context("invalid IFLA_CARRIER_CHANGES value")?,
579 ),
580 IFLA_GSO_MAX_SEGS => Self::GsoMaxSegs(
581 parse_u32(payload)
582 .context("invalid IFLA_GSO_MAX_SEGS value")?,
583 ),
584 IFLA_GSO_MAX_SIZE => Self::GsoMaxSize(
585 parse_u32(payload)
586 .context("invalid IFLA_GSO_MAX_SIZE value")?,
587 ),
588 IFLA_MIN_MTU => Self::MinMtu(
589 parse_u32(payload).context("invalid IFLA_MIN_MTU value")?,
590 ),
591 IFLA_MAX_MTU => Self::MaxMtu(
592 parse_u32(payload).context("invalid IFLA_MAX_MTU value")?,
593 ),
594 IFLA_LINK_NETNSID => Self::LinkNetNsId(
595 parse_i32(payload)
596 .context("invalid IFLA_LINK_NETNSID value")?,
597 ),
598 IFLA_OPERSTATE => Self::OperState(
599 parse_u8(payload)
600 .context("invalid IFLA_OPERSTATE value")?
601 .into(),
602 ),
603 IFLA_MAP => {
604 let err =
605 |payload| format!("Invalid IFLA_MAP value {:?}", payload);
606 Self::Map(
607 super::Map::parse(
608 &MapBuffer::new_checked(payload)
609 .context(err(payload))?,
610 )
611 .context(err(payload))?,
612 )
613 }
614 IFLA_STATS => Self::Stats(
615 super::Stats::parse(&StatsBuffer::new(
616 expand_buffer_if_small(
617 payload,
618 LINK_STATS_LEN,
619 "IFLA_STATS",
620 )
621 .as_slice(),
622 ))
623 .context(format!("Invalid IFLA_STATS value {:?}", payload))?,
624 ),
625 IFLA_STATS64 => {
626 let payload = expand_buffer_if_small(
627 payload,
628 LINK_STATS64_LEN,
629 "IFLA_STATS64",
630 );
631 Self::Stats64(
632 super::Stats64::parse(&Stats64Buffer::new(
633 payload.as_slice(),
634 ))
635 .context(format!(
636 "Invalid IFLA_STATS64 value {:?}",
637 payload
638 ))?,
639 )
640 }
641 IFLA_AF_SPEC => match interface_family {
642 AddressFamily::Unspec => {
643 let err = "invalid IFLA_AF_SPEC value for AF_UNSPEC";
644 Self::AfSpecUnspec(
645 VecAfSpecUnspec::parse(
646 &NlaBuffer::new_checked(&buf.value())
647 .context(err)?,
648 )
649 .context(err)?
650 .0,
651 )
652 }
653 #[cfg(any(target_os = "linux", target_os = "fuchsia",))]
654 AddressFamily::Bridge => {
655 let err = "invalid IFLA_AF_SPEC value for AF_BRIDGE";
656 Self::AfSpecBridge(
657 VecAfSpecBridge::parse(
658 &NlaBuffer::new_checked(&buf.value())
659 .context(err)?,
660 )
661 .context(err)?
662 .0,
663 )
664 }
665 _ => Self::AfSpecUnknown(payload.to_vec()),
666 },
667 IFLA_LINKINFO => {
668 let err = "invalid IFLA_LINKINFO value";
669 Self::LinkInfo(
670 VecLinkInfo::parse(
671 &NlaBuffer::new_checked(&buf.value()).context(err)?,
672 )
673 .context(err)?
674 .0,
675 )
676 }
677 IFLA_XDP => {
678 let err = "invalid IFLA_XDP value";
679 let buf = NlaBuffer::new_checked(payload).context(err)?;
680 Self::Xdp(VecLinkXdp::parse(&buf).context(err)?.0)
681 }
682 kind => Self::Other(
683 DefaultNla::parse(buf)
684 .context(format!("unknown NLA type {kind}"))?,
685 ),
686 })
687 }
688}