use crate::afpacket::ffi;
pub mod bpf;
pub mod bpf_builder;
pub(crate) mod bpf_compile;
pub mod bpf_interp;
pub mod ipnet;
pub use bpf::{BpfFilter, BpfInsn, BuildError};
pub use bpf_builder::BpfFilterBuilder;
pub use ipnet::{IpNet, ParseIpNetError};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FanoutMode {
Hash,
LoadBalance,
Cpu,
Rollover,
Random,
QueueMapping,
Ebpf,
}
impl FanoutMode {
pub(crate) const fn as_raw(self) -> u32 {
match self {
Self::Hash => ffi::PACKET_FANOUT_HASH,
Self::LoadBalance => ffi::PACKET_FANOUT_LB,
Self::Cpu => ffi::PACKET_FANOUT_CPU,
Self::Rollover => ffi::PACKET_FANOUT_ROLLOVER,
Self::Random => ffi::PACKET_FANOUT_RND,
Self::QueueMapping => ffi::PACKET_FANOUT_QM,
Self::Ebpf => ffi::PACKET_FANOUT_EBPF,
}
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FanoutFlags: u16 {
const ROLLOVER = 0x1000;
const UNIQUE_ID = 0x2000;
const IGNORE_OUTGOING = 0x4000;
const DEFRAG = 0x8000;
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum TimestampSource {
#[default]
Software,
RawHardware,
SysHardware,
}
impl TimestampSource {
pub(crate) const fn as_raw(self) -> libc::c_int {
match self {
Self::Software => 0,
Self::RawHardware => 1,
Self::SysHardware => 2,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RingProfile {
Default,
HighThroughput,
LowLatency,
LowMemory,
JumboFrames,
}
impl RingProfile {
#[inline]
pub(crate) fn params(self) -> (usize, usize, usize, u32) {
match self {
Self::Default => (1 << 22, 64, 2048, 60),
Self::HighThroughput => (1 << 22, 256, 2048, 60),
Self::LowLatency => (1 << 18, 64, 2048, 1),
Self::LowMemory => (1 << 20, 16, 2048, 100),
Self::JumboFrames => (1 << 22, 64, 65536, 60),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fanout_mode_as_raw() {
assert_eq!(FanoutMode::Hash.as_raw(), 0);
assert_eq!(FanoutMode::LoadBalance.as_raw(), 1);
assert_eq!(FanoutMode::Cpu.as_raw(), 2);
assert_eq!(FanoutMode::Rollover.as_raw(), 3);
assert_eq!(FanoutMode::Random.as_raw(), 4);
assert_eq!(FanoutMode::QueueMapping.as_raw(), 5);
}
#[test]
fn fanout_flags_bitwise() {
let flags = FanoutFlags::ROLLOVER | FanoutFlags::DEFRAG;
assert_eq!(flags.bits(), 0x9000);
assert!(flags.contains(FanoutFlags::ROLLOVER));
assert!(flags.contains(FanoutFlags::DEFRAG));
assert!(!flags.contains(FanoutFlags::UNIQUE_ID));
}
#[test]
fn timestamp_source_default() {
assert_eq!(TimestampSource::default(), TimestampSource::Software);
assert_eq!(TimestampSource::Software.as_raw(), 0);
}
#[test]
fn ring_profile_params_valid() {
for profile in [
RingProfile::Default,
RingProfile::HighThroughput,
RingProfile::LowLatency,
RingProfile::LowMemory,
RingProfile::JumboFrames,
] {
let (block_size, block_count, frame_size, timeout_ms) = profile.params();
assert!(block_size.is_power_of_two(), "{profile:?} block_size");
assert!(block_size % 4096 == 0, "{profile:?} page-aligned");
assert!(block_count > 0, "{profile:?} block_count");
assert!(
frame_size >= 68,
"{profile:?} frame_size >= TPACKET3_HDRLEN"
);
assert!(frame_size % 16 == 0, "{profile:?} frame_size aligned");
assert!(
frame_size <= block_size,
"{profile:?} frame_size <= block_size"
);
let _ = timeout_ms;
}
}
}