netlink_packet_route/link/
attribute.rs

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