use std::net::{Ipv4Addr, Ipv6Addr};
use anyhow::Context;
use byteorder::{BigEndian, ByteOrder, NativeEndian};
use netlink_packet_utils::{
nla::{DefaultNla, Nla, NlaBuffer},
parsers::{parse_u16_be, parse_u32, parse_u32_be, parse_u8},
traits::Parseable,
DecodeError,
};
const IFLA_GENEVE_ID: u16 = 1;
const IFLA_GENEVE_REMOTE: u16 = 2;
const IFLA_GENEVE_TTL: u16 = 3;
const IFLA_GENEVE_TOS: u16 = 4;
const IFLA_GENEVE_PORT: u16 = 5;
const IFLA_GENEVE_COLLECT_METADATA: u16 = 6;
const IFLA_GENEVE_REMOTE6: u16 = 7;
const IFLA_GENEVE_UDP_CSUM: u16 = 8;
const IFLA_GENEVE_UDP_ZERO_CSUM6_TX: u16 = 9;
const IFLA_GENEVE_UDP_ZERO_CSUM6_RX: u16 = 10;
const IFLA_GENEVE_LABEL: u16 = 11;
const IFLA_GENEVE_TTL_INHERIT: u16 = 12;
const IFLA_GENEVE_DF: u16 = 13;
const IFLA_GENEVE_INNER_PROTO_INHERIT: u16 = 14;
const GENEVE_DF_UNSET: u8 = 0;
const GENEVE_DF_SET: u8 = 1;
const GENEVE_DF_INHERIT: u8 = 2;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[non_exhaustive]
pub enum GeneveDf {
Unset,
Set,
Inherit,
Other(u8),
}
impl From<u8> for GeneveDf {
fn from(d: u8) -> Self {
match d {
GENEVE_DF_UNSET => Self::Unset,
GENEVE_DF_SET => Self::Set,
GENEVE_DF_INHERIT => Self::Inherit,
_ => Self::Other(d),
}
}
}
impl From<GeneveDf> for u8 {
fn from(d: GeneveDf) -> Self {
match d {
GeneveDf::Unset => GENEVE_DF_UNSET,
GeneveDf::Set => GENEVE_DF_SET,
GeneveDf::Inherit => GENEVE_DF_INHERIT,
GeneveDf::Other(value) => value,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub enum InfoGeneve {
Id(u32),
Remote(Ipv4Addr),
Remote6(Ipv6Addr),
Ttl(u8),
Tos(u8),
Port(u16),
CollectMetadata,
UdpCsum(bool),
UdpZeroCsum6Tx(bool),
UdpZeroCsum6Rx(bool),
Label(u32),
TtlInherit(bool),
Df(GeneveDf),
InnerProtoInherit,
Other(DefaultNla),
}
impl Nla for InfoGeneve {
fn value_len(&self) -> usize {
use self::InfoGeneve::*;
match self {
Id(_) | Remote(_) | Label(_) => 4,
Remote6(_) => 16,
Ttl(_) | Tos(_) | UdpCsum(_) | UdpZeroCsum6Tx(_)
| UdpZeroCsum6Rx(_) | TtlInherit(_) | Df(_) => 1,
Port(_) => 2,
CollectMetadata | InnerProtoInherit => 0,
Other(nla) => nla.value_len(),
}
}
fn emit_value(&self, buffer: &mut [u8]) {
use self::InfoGeneve::*;
match self {
Id(value) => NativeEndian::write_u32(buffer, *value),
Remote(value) => buffer.copy_from_slice(&value.octets()),
Remote6(value) => buffer.copy_from_slice(&value.octets()),
Ttl(value) | Tos(value) => buffer[0] = *value,
Port(value) => BigEndian::write_u16(buffer, *value),
CollectMetadata | InnerProtoInherit => (),
UdpCsum(value)
| UdpZeroCsum6Tx(value)
| UdpZeroCsum6Rx(value)
| TtlInherit(value) => buffer[0] = *value as u8,
Label(value) => BigEndian::write_u32(buffer, *value),
Df(value) => buffer[0] = (*value).into(),
Other(nla) => nla.emit_value(buffer),
}
}
fn kind(&self) -> u16 {
use self::InfoGeneve::*;
match self {
Id(_) => IFLA_GENEVE_ID,
Remote(_) => IFLA_GENEVE_REMOTE,
Remote6(_) => IFLA_GENEVE_REMOTE6,
Ttl(_) => IFLA_GENEVE_TTL,
Tos(_) => IFLA_GENEVE_TOS,
Port(_) => IFLA_GENEVE_PORT,
CollectMetadata => IFLA_GENEVE_COLLECT_METADATA,
UdpCsum(_) => IFLA_GENEVE_UDP_CSUM,
UdpZeroCsum6Tx(_) => IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
UdpZeroCsum6Rx(_) => IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
Label(_) => IFLA_GENEVE_LABEL,
TtlInherit(_) => IFLA_GENEVE_TTL_INHERIT,
Df(_) => IFLA_GENEVE_DF,
InnerProtoInherit => IFLA_GENEVE_INNER_PROTO_INHERIT,
Other(nla) => nla.kind(),
}
}
}
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoGeneve {
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
use self::InfoGeneve::*;
let payload = buf.value();
Ok(match buf.kind() {
IFLA_GENEVE_ID => {
Id(parse_u32(payload)
.context("invalid IFLA_GENEVE_ID value")?)
}
IFLA_GENEVE_REMOTE => {
if payload.len() == 4 {
let mut data = [0u8; 4];
data.copy_from_slice(&payload[0..4]);
Remote(Ipv4Addr::from(data))
} else {
return Err(DecodeError::from(format!(
"Invalid IFLA_GENEVE_REMOTE, got unexpected length \
of IPv4 address payload {:?}",
payload
)));
}
}
IFLA_GENEVE_REMOTE6 => {
if payload.len() == 16 {
let mut data = [0u8; 16];
data.copy_from_slice(&payload[0..16]);
Remote6(Ipv6Addr::from(data))
} else {
return Err(DecodeError::from(format!(
"Invalid IFLA_GENEVE_REMOTE6, got unexpected length \
of IPv6 address payload {:?}",
payload
)));
}
}
IFLA_GENEVE_TTL => {
Ttl(parse_u8(payload)
.context("invalid IFLA_GENEVE_TTL value")?)
}
IFLA_GENEVE_TOS => {
Tos(parse_u8(payload)
.context("invalid IFLA_GENEVE_TOS value")?)
}
IFLA_GENEVE_PORT => Port(
parse_u16_be(payload)
.context("invalid IFLA_GENEVE_PORT value")?,
),
IFLA_GENEVE_COLLECT_METADATA => CollectMetadata,
IFLA_GENEVE_UDP_CSUM => UdpCsum(
parse_u8(payload)
.context("invalid IFLA_GENEVE_UDP_CSUM value")?
> 0,
),
IFLA_GENEVE_UDP_ZERO_CSUM6_TX => UdpZeroCsum6Tx(
parse_u8(payload)
.context("invalid IFLA_GENEVE_UDP_ZERO_CSUM6_TX value")?
> 0,
),
IFLA_GENEVE_UDP_ZERO_CSUM6_RX => UdpZeroCsum6Rx(
parse_u8(payload)
.context("invalid IFLA_GENEVE_UDP_ZERO_CSUM6_RX value")?
> 0,
),
IFLA_GENEVE_LABEL => Label(
parse_u32_be(payload)
.context("invalid IFLA_GENEVE_LABEL value")?,
),
IFLA_GENEVE_TTL_INHERIT => TtlInherit(
parse_u8(payload)
.context("invalid IFLA_GENEVE_TTL_INHERIT value")?
> 0,
),
IFLA_GENEVE_DF => Df(parse_u8(payload)
.context("invalid IFLA_GENEVE_DF value")?
.into()),
IFLA_GENEVE_INNER_PROTO_INHERIT => InnerProtoInherit,
kind => Other(
DefaultNla::parse(buf)
.context(format!("unknown NLA type {kind}"))?,
),
})
}
}