#![deny(unsafe_code)]
#![cfg(target_os = "linux")]
pub mod affinity;
pub mod descriptor;
pub mod error;
pub mod netif;
pub mod ring;
pub mod syscalls;
pub mod umem;
pub mod xsk;
#[cfg(feature = "io_uring")]
pub mod io_uring;
pub use affinity::{online_cpu_count, set_thread_affinity, set_thread_affinity_range, AffinityError};
pub use descriptor::{Descriptor, DescriptorEngine, DescriptorType, XdpDesc};
pub use error::{LinuxError, Result};
pub use netif::{if_nametoindex, NetIfError};
pub use ring::{RingOffsets, RingType, XDP_RING_NEED_WAKEUP, XskRing};
pub use syscalls::{
pipe2, recvmmsg, sendfile, sendmmsg, splice, splice_bidirectional, FdGuard, SpliceFlags,
MAX_BATCH_DATAGRAMS,
};
pub use umem::{UmemConfig, UmemManager};
pub use xsk::{XskConfig, XskSocket, XskState};
#[cfg(feature = "io_uring")]
pub use io_uring::{Completion, IoUringBatcher, UdpBatchIo};
use std::sync::atomic::{AtomicBool, Ordering};
#[allow(unsafe_code)]
pub fn page_size() -> usize {
let ps = unsafe { libc::sysconf(libc::_SC_PAGESIZE) };
if ps <= 0 {
4096usize
} else {
ps as usize
}
}
#[derive(Debug, Clone)]
pub struct LinuxPlatform {
pub kernel_version: String,
pub architecture: String,
}
impl LinuxPlatform {
pub fn new(kernel_version: String, architecture: String) -> Self {
Self {
kernel_version,
architecture,
}
}
pub fn supports_ebpf(&self) -> bool {
let major_minor: Vec<&str> = self.kernel_version.split('.').collect();
if major_minor.len() >= 2
&& let Ok(major) = major_minor[0].parse::<u32>()
&& let Ok(minor) = major_minor[1].parse::<u32>() {
return major > 4 || (major == 4 && minor >= 4);
}
false
}
pub fn supports_af_xdp(&self) -> bool {
let major_minor: Vec<&str> = self.kernel_version.split('.').collect();
if major_minor.len() >= 2
&& let Ok(major) = major_minor[0].parse::<u32>()
&& let Ok(minor) = major_minor[1].parse::<u32>() {
return major > 4 || (major == 4 && minor >= 18);
}
false
}
pub fn supports_hugepage(&self) -> bool {
if let Ok(content) = std::fs::read_to_string("/proc/meminfo") {
content.contains("HugePages_Total")
} else {
false
}
}
pub fn supports_xdp_native(&self) -> bool {
let major_minor: Vec<&str> = self.kernel_version.split('.').collect();
if major_minor.len() >= 2
&& let Ok(major) = major_minor[0].parse::<u32>()
&& let Ok(minor) = major_minor[1].parse::<u32>() {
return major > 5 || (major == 5 && minor >= 3);
}
false
}
pub fn detect_capabilities(&self) -> PlatformCapabilities {
PlatformCapabilities {
ebpf: self.supports_ebpf(),
af_xdp: self.supports_af_xdp(),
hugepage: self.supports_hugepage(),
xdp_native: self.supports_xdp_native(),
xdp_generic: self.supports_ebpf(), mlock: true, }
}
}
#[derive(Debug, Clone, Copy)]
#[derive(Default)]
pub struct PlatformCapabilities {
pub ebpf: bool,
pub af_xdp: bool,
pub hugepage: bool,
pub xdp_native: bool,
pub xdp_generic: bool,
pub mlock: bool,
}
static INITIALIZED: AtomicBool = AtomicBool::new(false);
pub fn init() -> Result<()> {
if INITIALIZED.swap(true, Ordering::SeqCst) {
return Ok(());
}
let kernel_version = get_kernel_version();
let platform = LinuxPlatform::new(kernel_version, get_architecture());
let caps = platform.detect_capabilities();
if !caps.ebpf {
return Err(LinuxError::Unsupported(
"eBPF not supported (kernel 4.4+ required)".to_string(),
));
}
Ok(())
}
#[allow(unsafe_code)]
fn get_kernel_version() -> String {
let mut utsname: libc::utsname = unsafe { std::mem::zeroed() };
let ret = unsafe { libc::uname(&mut utsname) };
if ret == 0 {
let release = unsafe {
std::ffi::CStr::from_ptr(utsname.release.as_ptr())
};
return release.to_string_lossy().to_string();
}
std::fs::read_to_string("/proc/sys/kernel/osrelease")
.unwrap_or_else(|_| "unknown".to_string())
.trim()
.to_string()
}
fn get_architecture() -> String {
if cfg!(target_arch = "x86_64") {
"x86_64".to_string()
} else if cfg!(target_arch = "aarch64") {
"aarch64".to_string()
} else {
"unknown".to_string()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_linux_platform_creation() {
let platform = LinuxPlatform::new("5.15.0".to_string(), "x86_64".to_string());
assert_eq!(platform.kernel_version, "5.15.0");
assert_eq!(platform.architecture, "x86_64");
}
#[test]
fn test_supports_ebpf() {
let modern = LinuxPlatform::new("5.15.0".to_string(), "x86_64".to_string());
assert!(modern.supports_ebpf());
let old = LinuxPlatform::new("4.1.0".to_string(), "x86_64".to_string());
assert!(!old.supports_ebpf());
let edge = LinuxPlatform::new("4.4.0".to_string(), "x86_64".to_string());
assert!(edge.supports_ebpf());
}
#[test]
fn test_supports_af_xdp() {
let modern = LinuxPlatform::new("5.15.0".to_string(), "x86_64".to_string());
assert!(modern.supports_af_xdp());
let old = LinuxPlatform::new("4.17.0".to_string(), "x86_64".to_string());
assert!(!old.supports_af_xdp());
}
#[test]
fn test_supports_xdp_native() {
let modern = LinuxPlatform::new("5.15.0".to_string(), "x86_64".to_string());
assert!(modern.supports_xdp_native());
let old = LinuxPlatform::new("5.2.0".to_string(), "x86_64".to_string());
assert!(!old.supports_xdp_native());
}
#[test]
fn test_detect_capabilities() {
let platform = LinuxPlatform::new("5.15.0".to_string(), "x86_64".to_string());
let caps = platform.detect_capabilities();
assert!(caps.ebpf);
assert!(caps.af_xdp);
assert!(caps.xdp_native);
assert!(caps.xdp_generic);
}
#[test]
fn test_platform_init() {
let result = init();
let _ = result;
}
#[test]
fn test_public_api_reexports() {
let _desc: Descriptor = Descriptor::default();
let _xdp: XdpDesc = XdpDesc::zero();
let _desc_type: DescriptorType = DescriptorType::DataFrame;
let _engine: DescriptorEngine = DescriptorEngine::new(1024).unwrap();
let _err: LinuxError = LinuxError::Unsupported("test".to_string());
let _result: Result<()> = Ok(());
let _ring: XskRing = XskRing::new(RingType::Rx, 16).unwrap();
let _ring_type: RingType = RingType::Fill;
let _offsets: RingOffsets = RingOffsets {
producer: 0,
consumer: 0,
desc: 0,
flags: 0,
len: 0,
};
let _umem_config: UmemConfig = UmemConfig::default();
let _xsk_config: XskConfig = XskConfig::default();
let _state: XskState = XskState::Created;
}
#[test]
fn test_platform_capabilities_default() {
let caps = PlatformCapabilities::default();
assert!(!caps.ebpf);
assert!(!caps.af_xdp);
assert!(!caps.hugepage);
assert!(!caps.xdp_native);
assert!(!caps.xdp_generic);
assert!(!caps.mlock);
}
#[test]
fn test_platform_capabilities_copy() {
let caps = PlatformCapabilities {
ebpf: true,
af_xdp: true,
hugepage: false,
xdp_native: true,
xdp_generic: true,
mlock: true,
};
let copied = caps;
assert!(copied.ebpf);
assert!(copied.af_xdp);
assert!(copied.xdp_native);
}
#[test]
fn test_linux_platform_clone() {
let platform = LinuxPlatform::new("5.15.0".to_string(), "x86_64".to_string());
let cloned = platform.clone();
assert_eq!(cloned.kernel_version, "5.15.0");
assert_eq!(cloned.architecture, "x86_64");
}
#[test]
fn test_kernel_version_boundary_4_4() {
let platform = LinuxPlatform::new("4.4.0".to_string(), "x86_64".to_string());
assert!(platform.supports_ebpf());
}
#[test]
fn test_kernel_version_boundary_4_3() {
let platform = LinuxPlatform::new("4.3.9".to_string(), "x86_64".to_string());
assert!(!platform.supports_ebpf());
}
#[test]
fn test_kernel_version_boundary_4_18() {
let platform = LinuxPlatform::new("4.18.0".to_string(), "x86_64".to_string());
assert!(platform.supports_af_xdp());
}
#[test]
fn test_kernel_version_boundary_4_17() {
let platform = LinuxPlatform::new("4.17.99".to_string(), "x86_64".to_string());
assert!(!platform.supports_af_xdp());
}
#[test]
fn test_kernel_version_boundary_5_3() {
let platform = LinuxPlatform::new("5.3.0".to_string(), "x86_64".to_string());
assert!(platform.supports_xdp_native());
}
#[test]
fn test_kernel_version_boundary_5_2() {
let platform = LinuxPlatform::new("5.2.99".to_string(), "x86_64".to_string());
assert!(!platform.supports_xdp_native());
}
#[test]
fn test_kernel_version_major_gt_4() {
let platform = LinuxPlatform::new("6.1.0".to_string(), "x86_64".to_string());
assert!(platform.supports_ebpf());
assert!(platform.supports_af_xdp());
assert!(platform.supports_xdp_native());
}
#[test]
fn test_invalid_kernel_version_format() {
let platform = LinuxPlatform::new("invalid".to_string(), "x86_64".to_string());
assert!(!platform.supports_ebpf());
assert!(!platform.supports_af_xdp());
assert!(!platform.supports_xdp_native());
}
#[test]
fn test_partial_kernel_version() {
let platform = LinuxPlatform::new("5".to_string(), "x86_64".to_string());
assert!(!platform.supports_ebpf());
}
#[test]
fn test_xdp_generic_equals_ebpf() {
let modern = LinuxPlatform::new("5.15.0".to_string(), "x86_64".to_string());
let caps = modern.detect_capabilities();
assert_eq!(caps.xdp_generic, caps.ebpf);
}
}