netlink_packet_route/link/
attribute.rs

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