Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRAFT: tc flower support #111

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
83 changes: 63 additions & 20 deletions src/message.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
// SPDX-License-Identifier: MIT

use anyhow::Context;
use netlink_packet_core::{
NetlinkDeserializable, NetlinkHeader, NetlinkPayload, NetlinkSerializable,
};
use netlink_packet_utils::{
DecodeError, Emitable, Parseable, ParseableParametrized,
};

use netlink_packet_core::{
NetlinkDeserializable, NetlinkHeader, NetlinkPayload, NetlinkSerializable,
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 Expand Up @@ -46,9 +47,9 @@ const RTM_GETTCLASS: u16 = 42;
const RTM_NEWTFILTER: u16 = 44;
const RTM_DELTFILTER: u16 = 45;
const RTM_GETTFILTER: u16 = 46;
// const RTM_NEWACTION: u16 = 48;
// const RTM_DELACTION: u16 = 49;
// const RTM_GETACTION: u16 = 50;
const RTM_NEWACTION: u16 = 48;
const RTM_DELACTION: u16 = 49;
const RTM_GETACTION: u16 = 50;
const RTM_NEWPREFIX: u16 = 52;
// const RTM_GETMULTICAST: u16 = 58;
// const RTM_GETANYCAST: u16 = 62;
Expand Down Expand Up @@ -192,18 +193,16 @@ impl<'a, T: AsRef<[u8]> + ?Sized>
let msg = match RouteMessageBuffer::new_checked(&buf.inner()) {
Ok(buf) => RouteMessage::parse(&buf)
.context("invalid route message")?,
// HACK: iproute2 sends invalid RTM_GETROUTE message, where
// the header is limited to the
// interface family (1 byte) and 3 bytes of padding.
// HACK: iproute2 sends an invalid RTM_GETROUTE message,
// where the header is limited to the interface family
// (1 byte) and 3 bytes of padding.
Err(e) => {
// Not only does iproute2 sends invalid messages, it's
// also inconsistent in
// doing so: for link and address messages, the length
// advertised in the
// netlink header includes the 3 bytes of padding but it
// does not seem to be the case
// for the route message, hence the buf.length() == 1
// check.
// Not only does iproute2 send invalid messages, it's
// also inconsistent in doing so: for link and address
// messages, the length advertised in the netlink header
// includes the 3 bytes of padding, but it does not seem
// to be the case for the route message, hence the
// `buf.length() == 1` check.
if (buf.inner().len() == 4 || buf.inner().len() == 1)
&& message_type == RTM_GETROUTE
{
Expand Down Expand Up @@ -252,6 +251,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized>
_ => unreachable!(),
}
}

// TC Messages
RTM_NEWQDISC | RTM_DELQDISC | RTM_GETQDISC | RTM_NEWTCLASS
| RTM_DELTCLASS | RTM_GETTCLASS | RTM_NEWTFILTER
Expand Down Expand Up @@ -291,6 +291,21 @@ impl<'a, T: AsRef<[u8]> + ?Sized>
}
}

// TC action messages
RTM_NEWACTION | RTM_DELACTION | RTM_GETACTION => {
let msg = TcActionMessage::parse(
&TcActionMessageBuffer::new_checked(&buf.inner())
.context("invalid tc action message buffer")?,
)
.context("invalid tc action message")?;
match message_type {
RTM_NEWACTION => RouteNetlinkMessage::NewTrafficAction(msg),
RTM_DELACTION => RouteNetlinkMessage::DelTrafficAction(msg),
RTM_GETACTION => RouteNetlinkMessage::GetTrafficAction(msg),
_ => unreachable!(),
}
}

// ND ID Messages
RTM_NEWNSID | RTM_GETNSID | RTM_DELNSID => {
let err = "invalid nsid message";
Expand Down Expand Up @@ -348,6 +363,9 @@ pub enum RouteNetlinkMessage {
NewTrafficFilter(TcMessage),
DelTrafficFilter(TcMessage),
GetTrafficFilter(TcMessage),
NewTrafficAction(TcActionMessage),
DelTrafficAction(TcActionMessage),
GetTrafficAction(TcActionMessage),
NewTrafficChain(TcMessage),
DelTrafficChain(TcMessage),
GetTrafficChain(TcMessage),
Expand Down Expand Up @@ -460,6 +478,18 @@ impl RouteNetlinkMessage {
matches!(self, RouteNetlinkMessage::GetTrafficFilter(_))
}

pub fn is_new_action(&self) -> bool {
matches!(self, RouteNetlinkMessage::NewTrafficAction(_))
}

pub fn is_del_action(&self) -> bool {
matches!(self, RouteNetlinkMessage::DelTrafficAction(_))
}

pub fn is_get_action(&self) -> bool {
matches!(self, RouteNetlinkMessage::GetTrafficAction(_))
}

pub fn is_new_chain(&self) -> bool {
matches!(self, RouteNetlinkMessage::NewTrafficChain(_))
}
Expand Down Expand Up @@ -528,6 +558,9 @@ impl RouteNetlinkMessage {
NewTrafficFilter(_) => RTM_NEWTFILTER,
DelTrafficFilter(_) => RTM_DELTFILTER,
GetTrafficFilter(_) => RTM_GETTFILTER,
NewTrafficAction(_) => RTM_NEWACTION,
DelTrafficAction(_) => RTM_DELACTION,
GetTrafficAction(_) => RTM_GETACTION,
NewTrafficChain(_) => RTM_NEWCHAIN,
DelTrafficChain(_) => RTM_DELCHAIN,
GetTrafficChain(_) => RTM_GETCHAIN,
Expand Down Expand Up @@ -598,7 +631,12 @@ impl Emitable for RouteNetlinkMessage {
| NewRule(ref msg)
| DelRule(ref msg)
| GetRule(ref msg)
=> msg.buffer_len()
=> msg.buffer_len(),

| NewTrafficAction(ref msg)
| DelTrafficAction(ref msg)
| GetTrafficAction(ref msg)
=> msg.buffer_len(),
}
}

Expand Down Expand Up @@ -658,7 +696,12 @@ impl Emitable for RouteNetlinkMessage {
| NewRule(ref msg)
| DelRule(ref msg)
| GetRule(ref msg)
=> msg.emit(buffer)
=> msg.emit(buffer),

| NewTrafficAction(ref msg)
| DelTrafficAction(ref msg)
| GetTrafficAction(ref msg)
=> msg.emit(buffer),
}
}
}
Expand Down
Loading