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