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::{
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;
42// No kernel code is using IFLA_COST
43// const IFLA_COST: u16 = 8;
44// No kernel code is using IFLA_PRIORITY
45// const IFLA_PRIORITY: u16 = 9;
46const IFLA_MASTER: u16 = 10;
47const IFLA_WIRELESS: u16 = 11;
48const IFLA_PROTINFO: u16 = 12;
49const IFLA_TXQLEN: u16 = 13;
50const IFLA_MAP: u16 = 14;
51// No kernel code is using IFLA_WEIGHT
52// const IFLA_WEIGHT: u16 = 15;
53const 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;
79// const IFLA_PAD: u16 = 42;
80const 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/* TODO:(Gris Ge)
94const IFLA_PARENT_DEV_NAME: u16 = 56;
95const IFLA_PARENT_DEV_BUS_NAME: u16 = 57;
96const IFLA_GRO_MAX_SIZE: u16 = 58;
97const IFLA_TSO_MAX_SIZE: u16 = 59;
98const IFLA_TSO_MAX_SEGS: u16 = 60;
99const IFLA_ALLMULTI: u16 = 61;
100const IFLA_DEVLINK_PORT: u16 = 62;
101*/
102
103#[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    /// Permanent hardware address of the device. The provides the same
128    /// information as the ethtool ioctl interface.
129    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    /// The minimum MTU for the device.
153    MinMtu(u32),
154    /// The maximum MTU for the device.
155    MaxMtu(u32),
156    LinkNetNsId(i32),
157    OperState(State),
158    Stats(Stats),
159    Stats64(Stats64),
160    Map(Map),
161    // AF_SPEC (the type of af_spec depends on the interface family of the
162    // message)
163    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                    // Empty IFLA_VFINFO_LIST, this is likely a netdevsim device
390                    // no need to parse it, it is empty
391                    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            // HW address (we parse them as Vec for now, because for IP over
505            // GRE, the HW address is an IP instead of a MAC for
506            // example
507            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            // String
511            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}