netlink-packet-route 0.32.1

netlink packet types
Documentation
// SPDX-License-Identifier: MIT

use std::net::{Ipv4Addr, Ipv6Addr};

use netlink_packet_core::{
    emit_u16_be, emit_u32, emit_u32_be, parse_u16_be, parse_u32, parse_u32_be,
    parse_u8, DecodeError, DefaultNla, ErrorContext, Nla, NlaBuffer, Parseable,
};

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,
        }
    }
}

impl std::fmt::Display for GeneveDf {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Unset => f.write_str("unset"),
            Self::Set => f.write_str("set"),
            Self::Inherit => f.write_str("inherit"),
            Self::Other(v) => write!(f, "{v}"),
        }
    }
}

impl std::str::FromStr for GeneveDf {
    type Err = DecodeError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(match s {
            "unset" => Self::Unset,
            "set" => Self::Set,
            "inherit" => Self::Inherit,
            _ => {
                return Err(DecodeError::from(format!(
                    "unknown GENEVE DF: {s}"
                )))
            }
        })
    }
}

#[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 {
        match self {
            Self::Id(_) | Self::Remote(_) | Self::Label(_) => 4,
            Self::Remote6(_) => 16,
            Self::Ttl(_)
            | Self::Tos(_)
            | Self::UdpCsum(_)
            | Self::UdpZeroCsum6Tx(_)
            | Self::UdpZeroCsum6Rx(_)
            | Self::TtlInherit(_)
            | Self::Df(_) => 1,
            Self::Port(_) => 2,
            Self::CollectMetadata | Self::InnerProtoInherit => 0,
            Self::Other(nla) => nla.value_len(),
        }
    }

    fn emit_value(&self, buffer: &mut [u8]) {
        match self {
            Self::Id(value) => emit_u32(buffer, *value).unwrap(),
            Self::Remote(value) => buffer.copy_from_slice(&value.octets()),
            Self::Remote6(value) => buffer.copy_from_slice(&value.octets()),
            Self::Ttl(value) | Self::Tos(value) => buffer[0] = *value,
            Self::Port(value) => emit_u16_be(buffer, *value).unwrap(),
            Self::CollectMetadata | Self::InnerProtoInherit => (),
            Self::UdpCsum(value)
            | Self::UdpZeroCsum6Tx(value)
            | Self::UdpZeroCsum6Rx(value)
            | Self::TtlInherit(value) => buffer[0] = *value as u8,
            Self::Label(value) => emit_u32_be(buffer, *value).unwrap(),
            Self::Df(value) => buffer[0] = (*value).into(),
            Self::Other(nla) => nla.emit_value(buffer),
        }
    }

    fn kind(&self) -> u16 {
        match self {
            Self::Id(_) => IFLA_GENEVE_ID,
            Self::Remote(_) => IFLA_GENEVE_REMOTE,
            Self::Remote6(_) => IFLA_GENEVE_REMOTE6,
            Self::Ttl(_) => IFLA_GENEVE_TTL,
            Self::Tos(_) => IFLA_GENEVE_TOS,
            Self::Port(_) => IFLA_GENEVE_PORT,
            Self::CollectMetadata => IFLA_GENEVE_COLLECT_METADATA,
            Self::UdpCsum(_) => IFLA_GENEVE_UDP_CSUM,
            Self::UdpZeroCsum6Tx(_) => IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
            Self::UdpZeroCsum6Rx(_) => IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
            Self::Label(_) => IFLA_GENEVE_LABEL,
            Self::TtlInherit(_) => IFLA_GENEVE_TTL_INHERIT,
            Self::Df(_) => IFLA_GENEVE_DF,
            Self::InnerProtoInherit => IFLA_GENEVE_INNER_PROTO_INHERIT,
            Self::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> {
        let payload = buf.value();
        Ok(match buf.kind() {
            IFLA_GENEVE_ID => Self::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]);
                    Self::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]);
                    Self::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 => Self::Ttl(
                parse_u8(payload).context("invalid IFLA_GENEVE_TTL value")?,
            ),
            IFLA_GENEVE_TOS => Self::Tos(
                parse_u8(payload).context("invalid IFLA_GENEVE_TOS value")?,
            ),
            IFLA_GENEVE_PORT => Self::Port(
                parse_u16_be(payload)
                    .context("invalid IFLA_GENEVE_PORT value")?,
            ),
            IFLA_GENEVE_COLLECT_METADATA => Self::CollectMetadata,
            IFLA_GENEVE_UDP_CSUM => Self::UdpCsum(
                parse_u8(payload)
                    .context("invalid IFLA_GENEVE_UDP_CSUM value")?
                    > 0,
            ),
            IFLA_GENEVE_UDP_ZERO_CSUM6_TX => Self::UdpZeroCsum6Tx(
                parse_u8(payload)
                    .context("invalid IFLA_GENEVE_UDP_ZERO_CSUM6_TX value")?
                    > 0,
            ),
            IFLA_GENEVE_UDP_ZERO_CSUM6_RX => Self::UdpZeroCsum6Rx(
                parse_u8(payload)
                    .context("invalid IFLA_GENEVE_UDP_ZERO_CSUM6_RX value")?
                    > 0,
            ),
            IFLA_GENEVE_LABEL => Self::Label(
                parse_u32_be(payload)
                    .context("invalid IFLA_GENEVE_LABEL value")?,
            ),
            IFLA_GENEVE_TTL_INHERIT => Self::TtlInherit(
                parse_u8(payload)
                    .context("invalid IFLA_GENEVE_TTL_INHERIT value")?
                    > 0,
            ),
            IFLA_GENEVE_DF => Self::Df(
                parse_u8(payload)
                    .context("invalid IFLA_GENEVE_DF value")?
                    .into(),
            ),
            IFLA_GENEVE_INNER_PROTO_INHERIT => Self::InnerProtoInherit,
            kind => Self::Other(
                DefaultNla::parse(buf)
                    .context(format!("unknown NLA type {kind}"))?,
            ),
        })
    }
}