Skip to content

Commit

Permalink
Support for tc-flower
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-noland committed May 10, 2024
1 parent 8f2d6ec commit 61c14d4
Show file tree
Hide file tree
Showing 24 changed files with 5,410 additions and 30 deletions.
128 changes: 128 additions & 0 deletions src/enc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
use netlink_packet_utils::DecodeError;

/// An identifier for an encapsulation key used by a tunnel.
///
/// Examples include a VNIs for VXLAN and Geneve tunnels, ERSPAN/GRE keys, and
/// GTP tunnel keys.
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct EncKeyId(u32);

impl EncKeyId {
/// Create a new `EncKeyId` without checking the validity of the ID value.
///
/// # Safety
///
/// Failure to ensure the ID is within the valid range for the tunnel in
/// question may lead to semantically invalid netlink messages.
///
/// If you know the tunnel type (e.g., vxlan) and wish to confirm that the
/// ID is within the valid range of values for that tunnel type, use the
/// corresponding new method (e.g., `new_vxlan_vni`).
#[must_use]
pub const fn new_unchecked(id: u32) -> Self {
Self(id)
}

/// Create a new `EncKeyId` and confirm that it is within the valid range
/// of vxlan vni values.
///
/// # Errors
/// Returns an error if the ID is zero or greater than or equal to 2^24.
pub fn new_vxlan_vni(id: u32) -> Result<Self, DecodeError> {
crate::net::vxlan::Vni::new(id).map(Into::into)
}

/// Create a new `EncKeyId` and confirm that it is within the valid range
/// of geneve vni values.
///
/// # Errors
///
/// Returns an error if the ID is greater than or equal to 2^24.
pub fn new_geneve_vni(id: u32) -> Result<Self, DecodeError> {
match Self::new_nbit::<24>(id) {
Ok(id) => Ok(id),
Err(_) => Err(DecodeError::from(
"Geneve VNI must be less than 2^24, received {id}",
)),
}
}

/// Create a new `EncKeyId` in the space of valid GRE keys.
///
/// # Safety
///
/// Since GRE keys are 32 bits and all values are legal, this method is not
/// failable.
#[must_use]
pub fn new_gre_key(id: u32) -> Self {
Self(id)
}

/// Create a new `EncKeyId` and confirm that it is within the valid range
/// of gtp tunnel key values.
///
/// # Errors
///
/// Returns an error if the ID is zero.
pub fn new_gtp_key(id: u32) -> Result<Self, DecodeError> {
if id == 0 {
return Err(DecodeError::from(
"zero is not a legal GTP tunnel key",
));
}
Ok(Self(id))
}

/// Create a new `EncKeyId` and confirm that it is within the valid range
/// of N bit values.
///
/// # Errors
///
/// Returns an error if the ID is greater than or equal to 2^N.
const fn new_nbit<const N: usize>(id: u32) -> Result<Self, KeyTooLarge> {
if id >= (1 << N) {
return Err(KeyTooLarge);
};
Ok(Self(id))
}
}

impl From<EncKeyId> for u32 {
fn from(id: EncKeyId) -> u32 {
id.0
}
}

impl AsRef<u32> for EncKeyId {
fn as_ref(&self) -> &u32 {
&self.0
}
}

impl From<u32> for EncKeyId {
/// Convert `u32` to an `EncKeyId`.
///
/// # Safety
///
/// This conversion is infallible but may produce a semantically invalid key
/// depending on the tunnel type.
///
/// If you know the tunnel type (e.g., vxlan) and wish to confirm that the
/// ID is within the valid range of values for that tunnel type, use the
/// corresponding "new" method on the `EncKeyId` type (e.g.,
/// `EncKeyId::new_vxlan_vni`).
fn from(id: u32) -> Self {
Self(id)
}
}

#[derive(Debug)]
#[must_use]
struct KeyTooLarge;

impl From<crate::net::vxlan::Vni> for EncKeyId {
fn from(vni: crate::net::vxlan::Vni) -> Self {
Self(vni.into())
}
}
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,22 @@ mod address_family_linux;
#[cfg(any(target_os = "linux", target_os = "fuchsia"))]
pub use self::address_family_linux::AddressFamily;

mod enc;
pub use self::enc::*;

#[cfg(target_os = "freebsd")]
mod address_family_freebsd;
#[cfg(target_os = "freebsd")]
pub use self::address_family_freebsd::AddressFamily;
pub mod net;

#[cfg(not(any(
target_os = "linux",
target_os = "fuchsia",
target_os = "freebsd",
)))]
mod address_family_fallback;

#[cfg(not(any(
target_os = "linux",
target_os = "fuchsia",
Expand Down
5 changes: 3 additions & 2 deletions src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use netlink_packet_utils::{
DecodeError, Emitable, Parseable, ParseableParametrized,
};

use crate::tc::{TcActionMessage, TcActionMessageBuffer};
use crate::tc::{
TcActionMessage, TcActionMessageBuffer, TcMessage, TcMessageBuffer,
};
use crate::{
address::{AddressHeader, AddressMessage, AddressMessageBuffer},
link::{LinkMessage, LinkMessageBuffer},
Expand All @@ -18,7 +20,6 @@ use crate::{
prefix::{PrefixMessage, PrefixMessageBuffer},
route::{RouteHeader, RouteMessage, RouteMessageBuffer},
rule::{RuleMessage, RuleMessageBuffer},
tc::{TcMessage, TcMessageBuffer},
};

const RTM_NEWLINK: u16 = 16;
Expand Down
138 changes: 138 additions & 0 deletions src/net/arp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
const RESERVED: u8 = 0;
const REQUEST: u8 = 1;
const REPLY: u8 = 2;
const REQUEST_REVERSE: u8 = 3;
const REPLY_REVERSE: u8 = 4;
const DRARP_REQUEST: u8 = 5;
const DRARP_REPLY: u8 = 6;
const DRARP_ERROR: u8 = 7;
const IN_ARP_REQUEST: u8 = 8;
const IN_ARP_REPLY: u8 = 9;
const ARP_NAK: u8 = 10;
const MARS_REQUEST: u8 = 11;
const MARS_MULTI: u8 = 12;
const MARS_MSERV: u8 = 13;
const MARS_JOIN: u8 = 14;
const MARS_LEAVE: u8 = 15;
const MARS_NAK: u8 = 16;
const MARS_UNSERV: u8 = 17;
const MARS_SJOIN: u8 = 18;
const MARS_SLEAVE: u8 = 19;
const MARS_GROUP_LIST_REQUEST: u8 = 20;
const MARS_GROUP_LIST_REPLY: u8 = 21;
const MARS_REDIRECT_MAP: u8 = 22;
const MAPO_SUNARP: u8 = 23;
const OP_EXP1: u8 = 24;
const OP_EXP2: u8 = 25;

/// Enum of ARP operation codes.
///
/// List from [iana.org][1]
///
/// [1]: https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml
#[derive(Debug, PartialEq, Eq, Clone, Copy, Ord, PartialOrd, Hash)]
#[non_exhaustive]
#[repr(u8)]
pub enum Operation {
Reserved = RESERVED,
Request = REQUEST,
Reply = REPLY,
RequestReverse = REQUEST_REVERSE,
ReplyReverse = REPLY_REVERSE,
DrarpRequest = DRARP_REQUEST,
DrarpReply = DRARP_REPLY,
DrarpError = DRARP_ERROR,
InArpRequest = IN_ARP_REQUEST,
InArpReply = IN_ARP_REPLY,
ArpNak = ARP_NAK,
MarsRequest = MARS_REQUEST,
MarsMulti = MARS_MULTI,
MarsMServ = MARS_MSERV,
MarsJoin = MARS_JOIN,
MarsLeave = MARS_LEAVE,
MarsNAK = MARS_NAK,
MarsUnserv = MARS_UNSERV,
MarsSJoin = MARS_SJOIN,
MarsSLeave = MARS_SLEAVE,
MarsGroupListRequest = MARS_GROUP_LIST_REQUEST,
MarsGroupListReply = MARS_GROUP_LIST_REPLY,
MarsRedirectMap = MARS_REDIRECT_MAP,
MapoSUnarp = MAPO_SUNARP,
OpExp1 = OP_EXP1,
OpExp2 = OP_EXP2,
Other(u8),
}

impl AsRef<u8> for Operation {
fn as_ref(&self) -> &u8 {
match self {
Operation::Reserved => &RESERVED,
Operation::Request => &REQUEST,
Operation::Reply => &REPLY,
Operation::RequestReverse => &REQUEST_REVERSE,
Operation::ReplyReverse => &REPLY_REVERSE,
Operation::DrarpRequest => &DRARP_REQUEST,
Operation::DrarpReply => &DRARP_REPLY,
Operation::DrarpError => &DRARP_ERROR,
Operation::InArpRequest => &IN_ARP_REQUEST,
Operation::InArpReply => &IN_ARP_REPLY,
Operation::ArpNak => &ARP_NAK,
Operation::MarsRequest => &MARS_REQUEST,
Operation::MarsMulti => &MARS_MULTI,
Operation::MarsMServ => &MARS_MSERV,
Operation::MarsJoin => &MARS_JOIN,
Operation::MarsLeave => &MARS_LEAVE,
Operation::MarsNAK => &MARS_NAK,
Operation::MarsUnserv => &MARS_UNSERV,
Operation::MarsSJoin => &MARS_SJOIN,
Operation::MarsSLeave => &MARS_SLEAVE,
Operation::MarsGroupListRequest => &MARS_GROUP_LIST_REQUEST,
Operation::MarsGroupListReply => &MARS_GROUP_LIST_REPLY,
Operation::MarsRedirectMap => &MARS_REDIRECT_MAP,
Operation::MapoSUnarp => &MAPO_SUNARP,
Operation::OpExp1 => &OP_EXP1,
Operation::OpExp2 => &OP_EXP2,
Operation::Other(x) => x,
}
}
}

impl From<u8> for Operation {
fn from(value: u8) -> Self {
match value {
RESERVED => Operation::Reserved,
REQUEST => Operation::Request,
REPLY => Operation::Reply,
REQUEST_REVERSE => Operation::RequestReverse,
REPLY_REVERSE => Operation::ReplyReverse,
DRARP_REQUEST => Operation::DrarpRequest,
DRARP_REPLY => Operation::DrarpReply,
DRARP_ERROR => Operation::DrarpError,
IN_ARP_REQUEST => Operation::InArpRequest,
IN_ARP_REPLY => Operation::InArpReply,
ARP_NAK => Operation::ArpNak,
MARS_REQUEST => Operation::MarsRequest,
MARS_MULTI => Operation::MarsMulti,
MARS_MSERV => Operation::MarsMServ,
MARS_JOIN => Operation::MarsJoin,
MARS_LEAVE => Operation::MarsLeave,
MARS_NAK => Operation::MarsNAK,
MARS_UNSERV => Operation::MarsUnserv,
MARS_SJOIN => Operation::MarsSJoin,
MARS_SLEAVE => Operation::MarsSLeave,
MARS_GROUP_LIST_REQUEST => Operation::MarsGroupListRequest,
MARS_GROUP_LIST_REPLY => Operation::MarsGroupListReply,
MARS_REDIRECT_MAP => Operation::MarsRedirectMap,
MAPO_SUNARP => Operation::MapoSUnarp,
OP_EXP1 => Operation::OpExp1,
OP_EXP2 => Operation::OpExp2,
x => Operation::Other(x),
}
}
}

impl From<Operation> for u8 {
fn from(value: Operation) -> Self {
*value.as_ref()
}
}
Loading

0 comments on commit 61c14d4

Please sign in to comment.