use std::os::unix::io::RawFd;
use anyhow::Context;
use byteorder::{ByteOrder, NativeEndian};
use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer, NlasIterator, NLA_F_NESTED};
use netlink_packet_utils::parsers::{parse_i32, parse_string, parse_u32, parse_u8};
use netlink_packet_utils::traits::{Emitable, Parseable, ParseableParametrized};
use netlink_packet_utils::DecodeError;
#[cfg(any(target_os = "linux", target_os = "fuchsia",))]
use super::af_spec::VecAfSpecBridge;
use super::af_spec::VecAfSpecUnspec;
use super::buffer_tool::expand_buffer_if_small;
use super::ext_mask::VecLinkExtentMask;
use super::link_info::VecLinkInfo;
#[cfg(any(target_os = "linux", target_os = "fuchsia",))]
use super::proto_info::VecLinkProtoInfoBridge;
use super::proto_info::VecLinkProtoInfoInet6;
use super::sriov::{VecLinkVfInfo, VecLinkVfPort};
use super::stats::LINK_STATS_LEN;
use super::stats64::LINK_STATS64_LEN;
use super::xdp::VecLinkXdp;
use super::{
AfSpecBridge, AfSpecUnspec, LinkEvent, LinkExtentMask, LinkInfo, LinkPhysId,
LinkProtoInfoBridge, LinkProtoInfoInet6, LinkProtocolDownReason, LinkVfInfo, LinkVfPort,
LinkWirelessEvent, LinkXdp, Map, MapBuffer, Prop, State, Stats, Stats64, Stats64Buffer,
StatsBuffer,
};
use crate::AddressFamily;
const IFLA_ADDRESS: u16 = 1;
const IFLA_BROADCAST: u16 = 2;
const IFLA_IFNAME: u16 = 3;
const IFLA_MTU: u16 = 4;
const IFLA_LINK: u16 = 5;
const IFLA_QDISC: u16 = 6;
const IFLA_STATS: u16 = 7;
const IFLA_MASTER: u16 = 10;
const IFLA_WIRELESS: u16 = 11;
const IFLA_PROTINFO: u16 = 12;
const IFLA_TXQLEN: u16 = 13;
const IFLA_MAP: u16 = 14;
const IFLA_OPERSTATE: u16 = 16;
const IFLA_LINKMODE: u16 = 17;
const IFLA_LINKINFO: u16 = 18;
const IFLA_NET_NS_PID: u16 = 19;
const IFLA_IFALIAS: u16 = 20;
const IFLA_NUM_VF: u16 = 21;
const IFLA_VFINFO_LIST: u16 = 22;
const IFLA_STATS64: u16 = 23;
const IFLA_VF_PORTS: u16 = 24;
const IFLA_PORT_SELF: u16 = 25;
const IFLA_AF_SPEC: u16 = 26;
const IFLA_GROUP: u16 = 27;
const IFLA_NET_NS_FD: u16 = 28;
const IFLA_EXT_MASK: u16 = 29;
const IFLA_PROMISCUITY: u16 = 30;
const IFLA_NUM_TX_QUEUES: u16 = 31;
const IFLA_NUM_RX_QUEUES: u16 = 32;
const IFLA_CARRIER: u16 = 33;
const IFLA_PHYS_PORT_ID: u16 = 34;
const IFLA_CARRIER_CHANGES: u16 = 35;
const IFLA_PHYS_SWITCH_ID: u16 = 36;
const IFLA_LINK_NETNSID: u16 = 37;
const IFLA_PHYS_PORT_NAME: u16 = 38;
const IFLA_PROTO_DOWN: u16 = 39;
const IFLA_GSO_MAX_SEGS: u16 = 40;
const IFLA_GSO_MAX_SIZE: u16 = 41;
const IFLA_XDP: u16 = 43;
const IFLA_EVENT: u16 = 44;
const IFLA_NEW_NETNSID: u16 = 45;
const IFLA_IF_NETNSID: u16 = 46;
const IFLA_CARRIER_UP_COUNT: u16 = 47;
const IFLA_CARRIER_DOWN_COUNT: u16 = 48;
const IFLA_NEW_IFINDEX: u16 = 49;
const IFLA_MIN_MTU: u16 = 50;
const IFLA_MAX_MTU: u16 = 51;
const IFLA_PROP_LIST: u16 = 52;
const IFLA_PERM_ADDRESS: u16 = 54;
const IFLA_PROTO_DOWN_REASON: u16 = 55;
#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub enum LinkAttribute {
VfInfoList(Vec<LinkVfInfo>),
VfPorts(Vec<LinkVfPort>),
PortSelf(LinkVfPort),
PhysPortId(LinkPhysId),
PhysSwitchId(LinkPhysId),
Xdp(Vec<LinkXdp>),
Event(LinkEvent),
NewNetnsId(i32),
IfNetnsId(i32),
CarrierUpCount(u32),
CarrierDownCount(u32),
NewIfIndex(i32),
LinkInfo(Vec<LinkInfo>),
Wireless(LinkWirelessEvent),
ProtoInfoBridge(Vec<LinkProtoInfoBridge>),
ProtoInfoInet6(Vec<LinkProtoInfoInet6>),
ProtoInfoUnknown(DefaultNla),
PropList(Vec<Prop>),
ProtoDownReason(Vec<LinkProtocolDownReason>),
Address(Vec<u8>),
Broadcast(Vec<u8>),
PermAddress(Vec<u8>),
IfName(String),
Qdisc(String),
IfAlias(String),
PhysPortName(String),
Mode(u8),
Carrier(u8),
ProtoDown(u8),
Mtu(u32),
Link(u32),
Controller(u32),
TxQueueLen(u32),
NetNsPid(u32),
NumVf(u32),
Group(u32),
NetNsFd(RawFd),
ExtMask(Vec<LinkExtentMask>),
Promiscuity(u32),
NumTxQueues(u32),
NumRxQueues(u32),
CarrierChanges(u32),
GsoMaxSegs(u32),
GsoMaxSize(u32),
MinMtu(u32),
MaxMtu(u32),
LinkNetNsId(i32),
OperState(State),
Stats(Stats),
Stats64(Stats64),
Map(Map),
AfSpecUnspec(Vec<AfSpecUnspec>),
AfSpecBridge(Vec<AfSpecBridge>),
AfSpecUnknown(Vec<u8>),
Other(DefaultNla),
}
impl Nla for LinkAttribute {
fn value_len(&self) -> usize {
match self {
Self::VfInfoList(v) => v.as_slice().buffer_len(),
Self::VfPorts(v) => v.as_slice().buffer_len(),
Self::PortSelf(v) => v.buffer_len(),
Self::PhysPortId(v) => v.buffer_len(),
Self::PhysSwitchId(v) => v.buffer_len(),
Self::Event(v) => v.buffer_len(),
Self::Wireless(v) => v.buffer_len(),
Self::ProtoInfoBridge(v) => v.as_slice().buffer_len(),
Self::ProtoInfoInet6(v) => v.as_slice().buffer_len(),
Self::ProtoDownReason(v) => v.as_slice().buffer_len(),
Self::Address(bytes)
| Self::Broadcast(bytes)
| Self::PermAddress(bytes)
| Self::AfSpecUnknown(bytes) => bytes.len(),
Self::IfName(string)
| Self::Qdisc(string)
| Self::IfAlias(string)
| Self::PhysPortName(string) => string.as_bytes().len() + 1,
Self::Mode(_) | Self::Carrier(_) | Self::ProtoDown(_) => 1,
Self::Mtu(_)
| Self::NewNetnsId(_)
| Self::IfNetnsId(_)
| Self::Link(_)
| Self::Controller(_)
| Self::TxQueueLen(_)
| Self::NetNsPid(_)
| Self::NumVf(_)
| Self::Group(_)
| Self::NetNsFd(_)
| Self::ExtMask(_)
| Self::Promiscuity(_)
| Self::NumTxQueues(_)
| Self::NumRxQueues(_)
| Self::CarrierChanges(_)
| Self::GsoMaxSegs(_)
| Self::GsoMaxSize(_)
| Self::LinkNetNsId(_)
| Self::MinMtu(_)
| Self::CarrierUpCount(_)
| Self::CarrierDownCount(_)
| Self::NewIfIndex(_)
| Self::MaxMtu(_) => 4,
Self::OperState(_) => 1,
Self::Stats(_) => LINK_STATS_LEN,
Self::Stats64(_) => LINK_STATS64_LEN,
Self::Map(nla) => nla.buffer_len(),
Self::LinkInfo(nlas) => nlas.as_slice().buffer_len(),
Self::Xdp(nlas) => nlas.as_slice().buffer_len(),
Self::PropList(nlas) => nlas.as_slice().buffer_len(),
Self::AfSpecUnspec(nlas) => nlas.as_slice().buffer_len(),
Self::AfSpecBridge(nlas) => nlas.as_slice().buffer_len(),
Self::ProtoInfoUnknown(attr) => attr.value_len(),
Self::Other(attr) => attr.value_len(),
}
}
fn emit_value(&self, buffer: &mut [u8]) {
match self {
Self::VfInfoList(v) => v.as_slice().emit(buffer),
Self::VfPorts(v) => v.as_slice().emit(buffer),
Self::PortSelf(v) => v.emit(buffer),
Self::PhysPortId(v) => v.emit(buffer),
Self::PhysSwitchId(v) => v.emit(buffer),
Self::Event(v) => v.emit(buffer),
Self::Wireless(v) => v.emit(buffer),
Self::ProtoInfoBridge(v) => v.as_slice().emit(buffer),
Self::ProtoInfoInet6(v) => v.as_slice().emit(buffer),
Self::ProtoDownReason(v) => v.as_slice().emit(buffer),
Self::Address(bytes)
| Self::Broadcast(bytes)
| Self::PermAddress(bytes)
| Self::AfSpecUnknown(bytes) => buffer.copy_from_slice(bytes.as_slice()),
Self::IfName(string)
| Self::Qdisc(string)
| Self::IfAlias(string)
| Self::PhysPortName(string) => {
buffer[..string.len()].copy_from_slice(string.as_bytes());
buffer[string.len()] = 0;
}
Self::Mode(val) | Self::Carrier(val) | Self::ProtoDown(val) => buffer[0] = *val,
Self::Mtu(value)
| Self::Link(value)
| Self::Controller(value)
| Self::TxQueueLen(value)
| Self::NetNsPid(value)
| Self::NumVf(value)
| Self::Group(value)
| Self::Promiscuity(value)
| Self::NumTxQueues(value)
| Self::NumRxQueues(value)
| Self::CarrierChanges(value)
| Self::CarrierUpCount(value)
| Self::CarrierDownCount(value)
| Self::GsoMaxSegs(value)
| Self::GsoMaxSize(value)
| Self::MinMtu(value)
| Self::MaxMtu(value) => NativeEndian::write_u32(buffer, *value),
Self::ExtMask(value) => {
NativeEndian::write_u32(buffer, u32::from(&VecLinkExtentMask(value.to_vec())))
}
Self::LinkNetNsId(v)
| Self::NetNsFd(v)
| Self::NewNetnsId(v)
| Self::NewIfIndex(v)
| Self::IfNetnsId(v) => NativeEndian::write_i32(buffer, *v),
Self::Stats(nla) => nla.emit(buffer),
Self::Map(nla) => nla.emit(buffer),
Self::Stats64(nla) => nla.emit(buffer),
Self::OperState(state) => buffer[0] = (*state).into(),
Self::LinkInfo(nlas) => nlas.as_slice().emit(buffer),
Self::Xdp(nlas) => nlas.as_slice().emit(buffer),
Self::PropList(nlas) => nlas.as_slice().emit(buffer),
Self::AfSpecUnspec(nlas) => nlas.as_slice().emit(buffer),
Self::AfSpecBridge(nlas) => nlas.as_slice().emit(buffer),
Self::ProtoInfoUnknown(attr) | Self::Other(attr) => attr.emit_value(buffer),
}
}
fn kind(&self) -> u16 {
match self {
Self::VfInfoList(_) => IFLA_VFINFO_LIST,
Self::VfPorts(_) => IFLA_VF_PORTS,
Self::PortSelf(_) => IFLA_PORT_SELF,
Self::PhysPortId(_) => IFLA_PHYS_PORT_ID,
Self::PhysSwitchId(_) => IFLA_PHYS_SWITCH_ID,
Self::LinkInfo(_) => IFLA_LINKINFO,
Self::Wireless(_) => IFLA_WIRELESS,
Self::ProtoInfoBridge(_) | Self::ProtoInfoInet6(_) => IFLA_PROTINFO,
Self::ProtoInfoUnknown(attr) => attr.kind(),
Self::Xdp(_) => IFLA_XDP,
Self::Event(_) => IFLA_EVENT,
Self::NewNetnsId(_) => IFLA_NEW_NETNSID,
Self::IfNetnsId(_) => IFLA_IF_NETNSID,
Self::CarrierUpCount(_) => IFLA_CARRIER_UP_COUNT,
Self::CarrierDownCount(_) => IFLA_CARRIER_DOWN_COUNT,
Self::NewIfIndex(_) => IFLA_NEW_IFINDEX,
Self::PropList(_) => IFLA_PROP_LIST | NLA_F_NESTED,
Self::ProtoDownReason(_) => IFLA_PROTO_DOWN_REASON,
Self::Address(_) => IFLA_ADDRESS,
Self::Broadcast(_) => IFLA_BROADCAST,
Self::PermAddress(_) => IFLA_PERM_ADDRESS,
Self::IfName(_) => IFLA_IFNAME,
Self::Qdisc(_) => IFLA_QDISC,
Self::IfAlias(_) => IFLA_IFALIAS,
Self::PhysPortName(_) => IFLA_PHYS_PORT_NAME,
Self::Mode(_) => IFLA_LINKMODE,
Self::Carrier(_) => IFLA_CARRIER,
Self::ProtoDown(_) => IFLA_PROTO_DOWN,
Self::Mtu(_) => IFLA_MTU,
Self::Link(_) => IFLA_LINK,
Self::Controller(_) => IFLA_MASTER,
Self::TxQueueLen(_) => IFLA_TXQLEN,
Self::NetNsPid(_) => IFLA_NET_NS_PID,
Self::NumVf(_) => IFLA_NUM_VF,
Self::Group(_) => IFLA_GROUP,
Self::NetNsFd(_) => IFLA_NET_NS_FD,
Self::ExtMask(_) => IFLA_EXT_MASK,
Self::Promiscuity(_) => IFLA_PROMISCUITY,
Self::NumTxQueues(_) => IFLA_NUM_TX_QUEUES,
Self::NumRxQueues(_) => IFLA_NUM_RX_QUEUES,
Self::CarrierChanges(_) => IFLA_CARRIER_CHANGES,
Self::GsoMaxSegs(_) => IFLA_GSO_MAX_SEGS,
Self::GsoMaxSize(_) => IFLA_GSO_MAX_SIZE,
Self::MinMtu(_) => IFLA_MIN_MTU,
Self::MaxMtu(_) => IFLA_MAX_MTU,
Self::LinkNetNsId(_) => IFLA_LINK_NETNSID,
Self::OperState(_) => IFLA_OPERSTATE,
Self::Map(_) => IFLA_MAP,
Self::Stats(_) => IFLA_STATS,
Self::Stats64(_) => IFLA_STATS64,
Self::AfSpecUnspec(_) | Self::AfSpecBridge(_) | Self::AfSpecUnknown(_) => IFLA_AF_SPEC,
Self::Other(attr) => attr.kind(),
}
}
}
impl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized<NlaBuffer<&'a T>, AddressFamily>
for LinkAttribute
{
type Error = DecodeError;
fn parse_with_param(
buf: &NlaBuffer<&'a T>,
interface_family: AddressFamily,
) -> Result<Self, DecodeError> {
let payload = buf.value();
Ok(match buf.kind() {
IFLA_VFINFO_LIST => {
let err = |payload| format!("invalid IFLA_VFINFO_LIST {payload:?}");
Self::VfInfoList(
VecLinkVfInfo::parse(&NlaBuffer::new_checked(payload).context(err(payload))?)
.context(err(payload))?
.0,
)
}
IFLA_VF_PORTS => {
let err = |payload| format!("invalid IFLA_VF_PORTS {payload:?}");
Self::VfPorts(
VecLinkVfPort::parse(&NlaBuffer::new_checked(payload).context(err(payload))?)
.context(err(payload))?
.0,
)
}
IFLA_PORT_SELF => {
let err = |payload| format!("invalid IFLA_PORT_SELF {payload:?}");
Self::PortSelf(
LinkVfPort::parse(&NlaBuffer::new_checked(payload).context(err(payload))?)
.context(err(payload))?,
)
}
IFLA_PHYS_PORT_ID => Self::PhysPortId(
LinkPhysId::parse(payload)
.context(format!("invalid IFLA_PHYS_PORT_ID value {payload:?}"))?,
),
IFLA_PHYS_SWITCH_ID => Self::PhysSwitchId(
LinkPhysId::parse(payload)
.context(format!("invalid IFLA_PHYS_SWITCH_ID value {payload:?}"))?,
),
IFLA_WIRELESS => Self::Wireless(
LinkWirelessEvent::parse(payload)
.context(format!("invalid IFLA_WIRELESS {payload:?}"))?,
),
IFLA_PROTINFO => {
let err = |payload| format!("invalid IFLA_PROTINFO for AF_INET6 {payload:?}");
match interface_family {
AddressFamily::Inet6 => Self::ProtoInfoInet6(
VecLinkProtoInfoInet6::parse(
&NlaBuffer::new_checked(payload).context(err(payload))?,
)
.context(err(payload))?
.0,
),
#[cfg(any(target_os = "linux", target_os = "fuchsia",))]
AddressFamily::Bridge => Self::ProtoInfoBridge(
VecLinkProtoInfoBridge::parse(&NlaBuffer::new_checked(payload)?)
.context(format!("invalid IFLA_PROTINFO for AF_INET6 {payload:?}"))?
.0,
),
_ => Self::ProtoInfoUnknown(DefaultNla::parse(buf).context(format!(
"invalid IFLA_PROTINFO for \
{interface_family:?}: {payload:?}"
))?),
}
}
IFLA_EVENT => Self::Event(
LinkEvent::parse(payload).context(format!("invalid IFLA_EVENT {payload:?}"))?,
),
IFLA_NEW_NETNSID => {
Self::NewNetnsId(parse_i32(payload).context("invalid IFLA_NEW_NETNSID value")?)
}
IFLA_IF_NETNSID => {
Self::IfNetnsId(parse_i32(payload).context("invalid IFLA_IF_NETNSID value")?)
}
IFLA_CARRIER_UP_COUNT => Self::CarrierUpCount(
parse_u32(payload).context("invalid IFLA_CARRIER_UP_COUNT value")?,
),
IFLA_CARRIER_DOWN_COUNT => Self::CarrierDownCount(
parse_u32(payload).context("invalid IFLA_CARRIER_DOWN_COUNT value")?,
),
IFLA_NEW_IFINDEX => {
Self::NewIfIndex(parse_i32(payload).context("invalid IFLA_NEW_IFINDEX value")?)
}
IFLA_PROP_LIST => {
let error_msg = "invalid IFLA_PROP_LIST value";
let mut nlas = vec![];
for nla in NlasIterator::new(payload) {
let nla = &nla.context(error_msg)?;
let parsed = Prop::parse(nla).context(error_msg)?;
nlas.push(parsed);
}
Self::PropList(nlas)
}
IFLA_PROTO_DOWN_REASON => {
let mut nlas = vec![];
for nla in NlasIterator::new(payload) {
let nla = &nla.context("invalid IFLA_PROTO_DOWN_REASON value")?;
let parsed = LinkProtocolDownReason::parse(nla)?;
nlas.push(parsed);
}
Self::ProtoDownReason(nlas)
}
IFLA_ADDRESS => Self::Address(payload.to_vec()),
IFLA_BROADCAST => Self::Broadcast(payload.to_vec()),
IFLA_PERM_ADDRESS => Self::PermAddress(payload.to_vec()),
IFLA_IFNAME => {
Self::IfName(parse_string(payload).context("invalid IFLA_IFNAME value")?)
}
IFLA_QDISC => Self::Qdisc(parse_string(payload).context("invalid IFLA_QDISC value")?),
IFLA_IFALIAS => {
Self::IfAlias(parse_string(payload).context("invalid IFLA_IFALIAS value")?)
}
IFLA_PHYS_PORT_NAME => Self::PhysPortName(
parse_string(payload).context("invalid IFLA_PHYS_PORT_NAME value")?,
),
IFLA_LINKMODE => Self::Mode(parse_u8(payload).context("invalid IFLA_LINKMODE value")?),
IFLA_CARRIER => Self::Carrier(parse_u8(payload).context("invalid IFLA_CARRIER value")?),
IFLA_PROTO_DOWN => {
Self::ProtoDown(parse_u8(payload).context("invalid IFLA_PROTO_DOWN value")?)
}
IFLA_MTU => Self::Mtu(parse_u32(payload).context("invalid IFLA_MTU value")?),
IFLA_LINK => Self::Link(parse_u32(payload).context("invalid IFLA_LINK value")?),
IFLA_MASTER => {
Self::Controller(parse_u32(payload).context("invalid IFLA_MASTER value")?)
}
IFLA_TXQLEN => {
Self::TxQueueLen(parse_u32(payload).context("invalid IFLA_TXQLEN value")?)
}
IFLA_NET_NS_PID => {
Self::NetNsPid(parse_u32(payload).context("invalid IFLA_NET_NS_PID value")?)
}
IFLA_NUM_VF => Self::NumVf(parse_u32(payload).context("invalid IFLA_NUM_VF value")?),
IFLA_GROUP => Self::Group(parse_u32(payload).context("invalid IFLA_GROUP value")?),
IFLA_NET_NS_FD => {
Self::NetNsFd(parse_i32(payload).context("invalid IFLA_NET_NS_FD value")?)
}
IFLA_EXT_MASK => Self::ExtMask(
VecLinkExtentMask::from(parse_u32(payload).context("invalid IFLA_EXT_MASK value")?)
.0,
),
IFLA_PROMISCUITY => {
Self::Promiscuity(parse_u32(payload).context("invalid IFLA_PROMISCUITY value")?)
}
IFLA_NUM_TX_QUEUES => {
Self::NumTxQueues(parse_u32(payload).context("invalid IFLA_NUM_TX_QUEUES value")?)
}
IFLA_NUM_RX_QUEUES => {
Self::NumRxQueues(parse_u32(payload).context("invalid IFLA_NUM_RX_QUEUES value")?)
}
IFLA_CARRIER_CHANGES => Self::CarrierChanges(
parse_u32(payload).context("invalid IFLA_CARRIER_CHANGES value")?,
),
IFLA_GSO_MAX_SEGS => {
Self::GsoMaxSegs(parse_u32(payload).context("invalid IFLA_GSO_MAX_SEGS value")?)
}
IFLA_GSO_MAX_SIZE => {
Self::GsoMaxSize(parse_u32(payload).context("invalid IFLA_GSO_MAX_SIZE value")?)
}
IFLA_MIN_MTU => Self::MinMtu(parse_u32(payload).context("invalid IFLA_MIN_MTU value")?),
IFLA_MAX_MTU => Self::MaxMtu(parse_u32(payload).context("invalid IFLA_MAX_MTU value")?),
IFLA_LINK_NETNSID => {
Self::LinkNetNsId(parse_i32(payload).context("invalid IFLA_LINK_NETNSID value")?)
}
IFLA_OPERSTATE => {
Self::OperState(parse_u8(payload).context("invalid IFLA_OPERSTATE value")?.into())
}
IFLA_MAP => {
let err = |payload| format!("Invalid IFLA_MAP value {:?}", payload);
Self::Map(
super::Map::parse(&MapBuffer::new_checked(payload).context(err(payload))?)
.context(err(payload))?,
)
}
IFLA_STATS => Self::Stats(
super::Stats::parse(&StatsBuffer::new(
expand_buffer_if_small(payload, LINK_STATS_LEN, "IFLA_STATS").as_slice(),
))
.context(format!("Invalid IFLA_STATS value {:?}", payload))?,
),
IFLA_STATS64 => {
let payload = expand_buffer_if_small(payload, LINK_STATS64_LEN, "IFLA_STATS64");
Self::Stats64(
super::Stats64::parse(&Stats64Buffer::new(payload.as_slice()))
.context(format!("Invalid IFLA_STATS64 value {:?}", payload))?,
)
}
IFLA_AF_SPEC => match interface_family {
AddressFamily::Unspec => {
let err = "invalid IFLA_AF_SPEC value for AF_UNSPEC";
Self::AfSpecUnspec(
VecAfSpecUnspec::parse(&NlaBuffer::new_checked(&buf.value()).context(err)?)
.context(err)?
.0,
)
}
#[cfg(any(target_os = "linux", target_os = "fuchsia",))]
AddressFamily::Bridge => {
let err = "invalid IFLA_AF_SPEC value for AF_BRIDGE";
Self::AfSpecBridge(
VecAfSpecBridge::parse(&NlaBuffer::new_checked(&buf.value()).context(err)?)
.context(err)?
.0,
)
}
_ => Self::AfSpecUnknown(payload.to_vec()),
},
IFLA_LINKINFO => {
let err = "invalid IFLA_LINKINFO value";
Self::LinkInfo(
VecLinkInfo::parse(&NlaBuffer::new_checked(&buf.value()).context(err)?)
.context(err)?
.0,
)
}
IFLA_XDP => {
let err = "invalid IFLA_XDP value";
let buf = NlaBuffer::new_checked(payload).context(err)?;
Self::Xdp(VecLinkXdp::parse(&buf).context(err)?.0)
}
kind => {
Self::Other(DefaultNla::parse(buf).context(format!("unknown NLA type {kind}"))?)
}
})
}
}