use netlink_packet_core::{
emit_u32, parse_string, parse_u32, DecodeError, DefaultNla, Emitable,
ErrorContext, Nla, NlaBuffer, NlasIterator, Parseable,
ParseableParametrized, NLA_F_NESTED,
};
use super::{
TcActionMirror, TcActionMirrorOption, TcActionNat, TcActionNatOption,
TcActionTunnelKey, TcActionTunnelKeyOption,
};
use crate::tc::TcStats2;
const TCA_ACT_TAB: u16 = 1;
#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub struct TcAction {
pub tab: u16,
pub attributes: Vec<TcActionAttribute>,
}
impl Default for TcAction {
fn default() -> Self {
Self {
tab: TCA_ACT_TAB,
attributes: Vec::new(),
}
}
}
impl Nla for TcAction {
fn value_len(&self) -> usize {
self.attributes.as_slice().buffer_len()
}
fn emit_value(&self, buffer: &mut [u8]) {
self.attributes.as_slice().emit(buffer);
}
fn kind(&self) -> u16 {
self.tab
}
}
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for TcAction {
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
let kind = match NlasIterator::new(buf.value())
.filter_map(|nla| {
let nla = match nla {
Ok(nla) => nla,
Err(e) => {
return Some(
Err(e).context("failed to parse action nla"),
)
}
};
match nla.kind() {
TCA_ACT_KIND => Some(
parse_string(nla.value())
.context("failed to parse TCA_ACT_KIND"),
),
_ => None,
}
})
.collect::<Result<Vec<_>, _>>()
{
Ok(kinds) => {
if kinds.is_empty() {
return Err(DecodeError::from("Missing TCA_ACT_KIND"));
}
if kinds.len() > 1 {
return Err(DecodeError::from("Duplicate TCA_ACT_KIND"));
}
kinds[0].clone()
}
Err(e) => return Err(DecodeError::from(e.to_string())),
};
let attributes = NlasIterator::new(buf.value())
.map(|nla| {
TcActionAttribute::parse_with_param(&nla?, kind.as_str())
})
.collect::<Result<Vec<_>, _>>()?;
Ok(Self {
tab: buf.kind(),
attributes,
})
}
}
const TCA_ACT_KIND: u16 = 1;
const TCA_ACT_OPTIONS: u16 = 2;
const TCA_ACT_INDEX: u16 = 3;
const TCA_ACT_STATS: u16 = 4;
const TCA_ACT_COOKIE: u16 = 6;
const TCA_ACT_IN_HW_COUNT: u16 = 10;
#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub enum TcActionAttribute {
Kind(String),
Options(Vec<TcActionOption>),
Index(u32),
Stats(Vec<TcStats2>),
Cookie(Vec<u8>),
InHwCount(u32),
Other(DefaultNla),
}
impl Nla for TcActionAttribute {
fn value_len(&self) -> usize {
match self {
Self::Cookie(bytes) => bytes.len(),
Self::Kind(k) => k.len() + 1,
Self::Options(opt) => opt.as_slice().buffer_len(),
Self::Index(_) | Self::InHwCount(_) => 4,
Self::Stats(s) => s.as_slice().buffer_len(),
Self::Other(attr) => attr.value_len(),
}
}
fn emit_value(&self, buffer: &mut [u8]) {
match self {
Self::Cookie(bytes) => buffer.copy_from_slice(bytes.as_slice()),
Self::Kind(string) => {
buffer[..string.len()].copy_from_slice(string.as_bytes());
buffer[string.len()] = 0;
}
Self::Options(opt) => opt.as_slice().emit(buffer),
Self::Index(value) | Self::InHwCount(value) => {
emit_u32(buffer, *value).unwrap();
}
Self::Stats(s) => s.as_slice().emit(buffer),
Self::Other(attr) => attr.emit_value(buffer),
}
}
fn kind(&self) -> u16 {
match self {
Self::Kind(_) => TCA_ACT_KIND,
Self::Options(_) => TCA_ACT_OPTIONS | NLA_F_NESTED,
Self::Index(_) => TCA_ACT_INDEX,
Self::Stats(_) => TCA_ACT_STATS,
Self::Cookie(_) => TCA_ACT_COOKIE,
Self::InHwCount(_) => TCA_ACT_IN_HW_COUNT,
Self::Other(nla) => nla.kind(),
}
}
}
impl<'a, T, P> ParseableParametrized<NlaBuffer<&'a T>, P> for TcActionAttribute
where
T: AsRef<[u8]> + ?Sized,
P: AsRef<str>,
{
fn parse_with_param(
buf: &NlaBuffer<&'a T>,
kind: P,
) -> Result<Self, DecodeError> {
Ok(match buf.kind() {
TCA_ACT_KIND => {
let buf_value = buf.value();
TcActionAttribute::Kind(
parse_string(buf_value)
.context("failed to parse TCA_ACT_KIND")?,
)
}
TCA_ACT_OPTIONS => TcActionAttribute::Options(
NlasIterator::new(buf.value())
.map(|nla| {
let nla = nla.context("invalid TCA_ACT_OPTIONS")?;
TcActionOption::parse_with_param(&nla, kind.as_ref())
.context("failed to parse TCA_ACT_OPTIONS")
})
.collect::<Result<Vec<_>, _>>()?,
),
TCA_ACT_INDEX => TcActionAttribute::Index(
parse_u32(buf.value())
.context("failed to parse TCA_ACT_INDEX")?,
),
TCA_ACT_STATS => TcActionAttribute::Stats(
NlasIterator::new(buf.value())
.map(|nla| {
let nla = nla.context("invalid TCA_ACT_STATS")?;
TcStats2::parse_with_param(&nla, kind.as_ref())
.context("failed to parse TCA_ACT_STATS")
})
.collect::<Result<Vec<_>, _>>()?,
),
TCA_ACT_COOKIE => TcActionAttribute::Cookie(buf.value().to_vec()),
TCA_ACT_IN_HW_COUNT => TcActionAttribute::InHwCount(
parse_u32(buf.value())
.context("failed to parse TCA_ACT_IN_HW_COUNT")?,
),
_ => TcActionAttribute::Other(
DefaultNla::parse(buf).context("failed to parse action nla")?,
),
})
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub enum TcActionOption {
Mirror(TcActionMirrorOption),
Nat(TcActionNatOption),
TunnelKey(TcActionTunnelKeyOption),
Other(DefaultNla),
}
impl Nla for TcActionOption {
fn value_len(&self) -> usize {
match self {
Self::Mirror(nla) => nla.value_len(),
Self::Nat(nla) => nla.value_len(),
Self::TunnelKey(nla) => nla.value_len(),
Self::Other(nla) => nla.value_len(),
}
}
fn emit_value(&self, buffer: &mut [u8]) {
match self {
Self::Mirror(nla) => nla.emit_value(buffer),
Self::Nat(nla) => nla.emit_value(buffer),
Self::TunnelKey(nla) => nla.emit_value(buffer),
Self::Other(nla) => nla.emit_value(buffer),
}
}
fn kind(&self) -> u16 {
match self {
Self::Mirror(nla) => nla.kind(),
Self::Nat(nla) => nla.kind(),
Self::TunnelKey(nla) => nla.kind(),
Self::Other(nla) => nla.kind(),
}
}
}
impl<'a, T, S> ParseableParametrized<NlaBuffer<&'a T>, S> for TcActionOption
where
T: AsRef<[u8]> + ?Sized,
S: AsRef<str>,
{
fn parse_with_param(
buf: &NlaBuffer<&'a T>,
kind: S,
) -> Result<Self, DecodeError> {
Ok(match kind.as_ref() {
TcActionMirror::KIND => Self::Mirror(
TcActionMirrorOption::parse(buf)
.context("failed to parse mirror action")?,
),
TcActionNat::KIND => Self::Nat(
TcActionNatOption::parse(buf)
.context("failed to parse nat action")?,
),
TcActionTunnelKey::KIND => Self::TunnelKey(
TcActionTunnelKeyOption::parse(buf)
.context("failed to parse tunnel_key action")?,
),
_ => Self::Other(
DefaultNla::parse(buf)
.context("failed to parse action options")?,
),
})
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
#[non_exhaustive]
pub struct TcActionGeneric {
pub index: u32,
pub capab: u32,
pub action: TcActionType,
pub refcnt: i32,
pub bindcnt: i32,
}
impl TcActionGeneric {
pub(crate) const BUF_LEN: usize = 20;
}
buffer!(TcActionGenericBuffer(TcActionGeneric::BUF_LEN) {
index: (u32, 0..4),
capab: (u32, 4..8),
action: (i32, 8..12),
refcnt: (i32, 12..16),
bindcnt: (i32, 16..20),
});
impl Emitable for TcActionGeneric {
fn buffer_len(&self) -> usize {
Self::BUF_LEN
}
fn emit(&self, buffer: &mut [u8]) {
let mut packet = TcActionGenericBuffer::new(buffer);
packet.set_index(self.index);
packet.set_capab(self.capab);
packet.set_action(self.action.into());
packet.set_refcnt(self.refcnt);
packet.set_bindcnt(self.bindcnt);
}
}
impl<T: AsRef<[u8]>> Parseable<TcActionGenericBuffer<T>> for TcActionGeneric {
fn parse(buf: &TcActionGenericBuffer<T>) -> Result<Self, DecodeError> {
Ok(Self {
index: buf.index(),
capab: buf.capab(),
action: buf.action().into(),
refcnt: buf.refcnt(),
bindcnt: buf.bindcnt(),
})
}
}
const TC_ACT_UNSPEC: i32 = -1;
const TC_ACT_OK: i32 = 0;
const TC_ACT_RECLASSIFY: i32 = 1;
const TC_ACT_SHOT: i32 = 2;
const TC_ACT_PIPE: i32 = 3;
const TC_ACT_STOLEN: i32 = 4;
const TC_ACT_QUEUED: i32 = 5;
const TC_ACT_REPEAT: i32 = 6;
const TC_ACT_REDIRECT: i32 = 7;
const TC_ACT_TRAP: i32 = 8;
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
#[non_exhaustive]
pub enum TcActionType {
#[default]
Unspec,
Ok,
Reclassify,
Shot,
Pipe,
Stolen,
Queued,
Repeat,
Redirect,
Trap,
Other(i32),
}
impl From<i32> for TcActionType {
fn from(d: i32) -> Self {
match d {
TC_ACT_UNSPEC => Self::Unspec,
TC_ACT_OK => Self::Ok,
TC_ACT_RECLASSIFY => Self::Reclassify,
TC_ACT_SHOT => Self::Shot,
TC_ACT_PIPE => Self::Pipe,
TC_ACT_STOLEN => Self::Stolen,
TC_ACT_QUEUED => Self::Queued,
TC_ACT_REPEAT => Self::Repeat,
TC_ACT_REDIRECT => Self::Redirect,
TC_ACT_TRAP => Self::Trap,
_ => Self::Other(d),
}
}
}
impl From<TcActionType> for i32 {
fn from(v: TcActionType) -> i32 {
match v {
TcActionType::Unspec => TC_ACT_UNSPEC,
TcActionType::Ok => TC_ACT_OK,
TcActionType::Reclassify => TC_ACT_RECLASSIFY,
TcActionType::Shot => TC_ACT_SHOT,
TcActionType::Pipe => TC_ACT_PIPE,
TcActionType::Stolen => TC_ACT_STOLEN,
TcActionType::Queued => TC_ACT_QUEUED,
TcActionType::Repeat => TC_ACT_REPEAT,
TcActionType::Redirect => TC_ACT_REDIRECT,
TcActionType::Trap => TC_ACT_TRAP,
TcActionType::Other(d) => d,
}
}
}
pub const TC_TCF_BUF_LEN: usize = 32;
#[derive(Debug, PartialEq, Eq, Clone, Default)]
pub struct Tcf {
pub install: u64,
pub lastuse: u64,
pub expires: u64,
pub firstuse: u64,
}
buffer!(TcfBuffer(TC_TCF_BUF_LEN) {
install: (u64, 0..8),
lastuse: (u64, 8..16),
expires: (u64, 16..24),
firstuse: (u64, 24..32),
});
impl<T: AsRef<[u8]> + ?Sized> Parseable<TcfBuffer<&T>> for Tcf {
fn parse(buf: &TcfBuffer<&T>) -> Result<Self, DecodeError> {
Ok(Self {
install: buf.install(),
lastuse: buf.lastuse(),
expires: buf.expires(),
firstuse: buf.firstuse(),
})
}
}
impl Emitable for Tcf {
fn buffer_len(&self) -> usize {
TC_TCF_BUF_LEN
}
fn emit(&self, buffer: &mut [u8]) {
let mut packet = TcfBuffer::new(buffer);
packet.set_install(self.install);
packet.set_lastuse(self.lastuse);
packet.set_expires(self.expires);
packet.set_firstuse(self.firstuse);
}
}