use anyhow::Context;
use byteorder::{ByteOrder, NativeEndian};
use netlink_packet_utils::{
nla::{DefaultNla, Nla, NlaBuffer, NlasIterator},
parsers::{parse_i32, parse_mac, parse_u16, parse_u32},
traits::{Emitable, Parseable},
DecodeError,
};
const IFLA_MACVLAN_MODE: u16 = 1;
const IFLA_MACVLAN_FLAGS: u16 = 2;
const IFLA_MACVLAN_MACADDR_MODE: u16 = 3;
const IFLA_MACVLAN_MACADDR: u16 = 4;
const IFLA_MACVLAN_MACADDR_DATA: u16 = 5;
const IFLA_MACVLAN_MACADDR_COUNT: u16 = 6;
const IFLA_MACVLAN_BC_QUEUE_LEN: u16 = 7;
const IFLA_MACVLAN_BC_QUEUE_LEN_USED: u16 = 8;
const IFLA_MACVLAN_BC_CUTOFF: u16 = 9;
#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub enum InfoMacVlan {
Mode(u32),
Flags(u16),
MacAddrMode(u32),
MacAddr([u8; 6]),
MacAddrData(Vec<InfoMacVlan>),
MacAddrCount(u32),
BcQueueLen(u32),
BcQueueLenUsed(u32),
BcCutoff(i32),
Other(DefaultNla),
}
impl Nla for InfoMacVlan {
fn value_len(&self) -> usize {
use self::InfoMacVlan::*;
match self {
Mode(_) => 4,
Flags(_) => 2,
MacAddrMode(_) => 4,
MacAddr(_) => 6,
MacAddrData(ref nlas) => nlas.as_slice().buffer_len(),
MacAddrCount(_) => 4,
BcQueueLen(_) => 4,
BcQueueLenUsed(_) => 4,
BcCutoff(_) => 4,
Other(nla) => nla.value_len(),
}
}
fn emit_value(&self, buffer: &mut [u8]) {
use self::InfoMacVlan::*;
match self {
Mode(value) => NativeEndian::write_u32(buffer, *value),
Flags(value) => NativeEndian::write_u16(buffer, *value),
MacAddrMode(value) => NativeEndian::write_u32(buffer, *value),
MacAddr(bytes) => buffer.copy_from_slice(bytes),
MacAddrData(ref nlas) => nlas.as_slice().emit(buffer),
MacAddrCount(value) => NativeEndian::write_u32(buffer, *value),
BcQueueLen(value) => NativeEndian::write_u32(buffer, *value),
BcQueueLenUsed(value) => NativeEndian::write_u32(buffer, *value),
BcCutoff(value) => NativeEndian::write_i32(buffer, *value),
Other(nla) => nla.emit_value(buffer),
}
}
fn kind(&self) -> u16 {
use self::InfoMacVlan::*;
match self {
Mode(_) => IFLA_MACVLAN_MODE,
Flags(_) => IFLA_MACVLAN_FLAGS,
MacAddrMode(_) => IFLA_MACVLAN_MACADDR_MODE,
MacAddr(_) => IFLA_MACVLAN_MACADDR,
MacAddrData(_) => IFLA_MACVLAN_MACADDR_DATA,
MacAddrCount(_) => IFLA_MACVLAN_MACADDR_COUNT,
BcQueueLen(_) => IFLA_MACVLAN_BC_QUEUE_LEN,
BcQueueLenUsed(_) => IFLA_MACVLAN_BC_QUEUE_LEN_USED,
BcCutoff(_) => IFLA_MACVLAN_BC_CUTOFF,
Other(nla) => nla.kind(),
}
}
}
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoMacVlan {
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
use self::InfoMacVlan::*;
let payload = buf.value();
Ok(match buf.kind() {
IFLA_MACVLAN_MODE => Mode(
parse_u32(payload)
.context("invalid IFLA_MACVLAN_MODE value")?,
),
IFLA_MACVLAN_FLAGS => Flags(
parse_u16(payload)
.context("invalid IFLA_MACVLAN_FLAGS value")?,
),
IFLA_MACVLAN_MACADDR_MODE => MacAddrMode(
parse_u32(payload)
.context("invalid IFLA_MACVLAN_MACADDR_MODE value")?,
),
IFLA_MACVLAN_MACADDR => MacAddr(
parse_mac(payload)
.context("invalid IFLA_MACVLAN_MACADDR value")?,
),
IFLA_MACVLAN_MACADDR_DATA => {
let mut mac_data = Vec::new();
let err = "failed to parse IFLA_MACVLAN_MACADDR_DATA";
for nla in NlasIterator::new(payload) {
let nla = &nla.context(err)?;
let parsed = InfoMacVlan::parse(nla).context(err)?;
mac_data.push(parsed);
}
MacAddrData(mac_data)
}
IFLA_MACVLAN_MACADDR_COUNT => MacAddrCount(
parse_u32(payload)
.context("invalid IFLA_MACVLAN_MACADDR_COUNT value")?,
),
IFLA_MACVLAN_BC_QUEUE_LEN => BcQueueLen(
parse_u32(payload)
.context("invalid IFLA_MACVLAN_BC_QUEUE_LEN value")?,
),
IFLA_MACVLAN_BC_QUEUE_LEN_USED => BcQueueLenUsed(
parse_u32(payload)
.context("invalid IFLA_MACVLAN_BC_QUEUE_LEN_USED value")?,
),
IFLA_MACVLAN_BC_CUTOFF => BcCutoff(
parse_i32(payload)
.context("invalid IFLA_MACVLAN_BC_CUTOFF value")?,
),
kind => Other(DefaultNla::parse(buf).context(format!(
"unknown NLA type {kind} for IFLA_INFO_DATA(mac_vlan)"
))?),
})
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub enum InfoMacVtap {
Mode(u32),
Flags(u16),
MacAddrMode(u32),
MacAddr([u8; 6]),
MacAddrData(Vec<InfoMacVtap>),
MacAddrCount(u32),
BcQueueLen(u32),
BcQueueLenUsed(u32),
BcCutoff(i32),
Other(DefaultNla),
}
impl Nla for InfoMacVtap {
fn value_len(&self) -> usize {
use self::InfoMacVtap::*;
match self {
Mode(_) => 4,
Flags(_) => 2,
MacAddrMode(_) => 4,
MacAddr(_) => 6,
MacAddrData(ref nlas) => nlas.as_slice().buffer_len(),
MacAddrCount(_) => 4,
BcQueueLen(_) => 4,
BcQueueLenUsed(_) => 4,
BcCutoff(_) => 4,
Other(nla) => nla.value_len(),
}
}
fn emit_value(&self, buffer: &mut [u8]) {
use self::InfoMacVtap::*;
match self {
Mode(value) => NativeEndian::write_u32(buffer, *value),
Flags(value) => NativeEndian::write_u16(buffer, *value),
MacAddrMode(value) => NativeEndian::write_u32(buffer, *value),
MacAddr(bytes) => buffer.copy_from_slice(bytes),
MacAddrData(ref nlas) => nlas.as_slice().emit(buffer),
MacAddrCount(value) => NativeEndian::write_u32(buffer, *value),
BcQueueLen(value) => NativeEndian::write_u32(buffer, *value),
BcQueueLenUsed(value) => NativeEndian::write_u32(buffer, *value),
BcCutoff(value) => NativeEndian::write_i32(buffer, *value),
Other(nla) => nla.emit_value(buffer),
}
}
fn kind(&self) -> u16 {
use self::InfoMacVtap::*;
match self {
Mode(_) => IFLA_MACVLAN_MODE,
Flags(_) => IFLA_MACVLAN_FLAGS,
MacAddrMode(_) => IFLA_MACVLAN_MACADDR_MODE,
MacAddr(_) => IFLA_MACVLAN_MACADDR,
MacAddrData(_) => IFLA_MACVLAN_MACADDR_DATA,
MacAddrCount(_) => IFLA_MACVLAN_MACADDR_COUNT,
BcQueueLen(_) => IFLA_MACVLAN_BC_QUEUE_LEN,
BcQueueLenUsed(_) => IFLA_MACVLAN_BC_QUEUE_LEN_USED,
BcCutoff(_) => IFLA_MACVLAN_BC_CUTOFF,
Other(nla) => nla.kind(),
}
}
}
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoMacVtap {
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
use self::InfoMacVtap::*;
let payload = buf.value();
Ok(match buf.kind() {
IFLA_MACVLAN_MODE => Mode(
parse_u32(payload)
.context("invalid IFLA_MACVLAN_MODE value")?,
),
IFLA_MACVLAN_FLAGS => Flags(
parse_u16(payload)
.context("invalid IFLA_MACVLAN_FLAGS value")?,
),
IFLA_MACVLAN_MACADDR_MODE => MacAddrMode(
parse_u32(payload)
.context("invalid IFLA_MACVLAN_MACADDR_MODE value")?,
),
IFLA_MACVLAN_MACADDR => MacAddr(
parse_mac(payload)
.context("invalid IFLA_MACVLAN_MACADDR value")?,
),
IFLA_MACVLAN_MACADDR_DATA => {
let mut mac_data = Vec::new();
let err = "failed to parse IFLA_MACVLAN_MACADDR_DATA";
for nla in NlasIterator::new(payload) {
let nla = &nla.context(err)?;
let parsed = InfoMacVtap::parse(nla).context(err)?;
mac_data.push(parsed);
}
MacAddrData(mac_data)
}
IFLA_MACVLAN_MACADDR_COUNT => MacAddrCount(
parse_u32(payload)
.context("invalid IFLA_MACVLAN_MACADDR_COUNT value")?,
),
IFLA_MACVLAN_BC_QUEUE_LEN => BcQueueLen(
parse_u32(payload)
.context("invalid IFLA_MACVLAN_BC_QUEUE_LEN value")?,
),
IFLA_MACVLAN_BC_QUEUE_LEN_USED => BcQueueLenUsed(
parse_u32(payload)
.context("invalid IFLA_MACVLAN_BC_QUEUE_LEN_USED value")?,
),
IFLA_MACVLAN_BC_CUTOFF => BcCutoff(
parse_i32(payload)
.context("invalid IFLA_MACVLAN_BC_CUTOFF value")?,
),
kind => Other(DefaultNla::parse(buf).context(format!(
"unknown NLA type {kind} for IFLA_INFO_DATA(mac_vtap)"
))?),
})
}
}