mod kni;
mod mbuf;
mod mempool;
mod port;
#[cfg(feature = "metrics")]
mod stats;
#[allow(unreachable_pub)] pub use self::kni::*;
#[allow(unreachable_pub)]
pub use self::mbuf::*;
pub(crate) use self::mempool::*;
#[allow(unreachable_pub)]
pub use self::port::*;
#[cfg(feature = "metrics")]
pub(crate) use self::stats::*;
use crate::debug;
use crate::ffi::{self, AsStr, ToCString, ToResult};
use crate::net::MacAddr;
use anyhow::Result;
use std::cell::Cell;
use std::fmt;
use std::mem;
use std::os::raw;
use thiserror::Error;
#[derive(Debug, Error)]
#[error("{0}")]
pub(crate) struct DpdkError(String);
impl DpdkError {
#[inline]
pub(crate) fn new() -> Self {
DpdkError::from_errno(-1)
}
#[inline]
fn from_errno(errno: raw::c_int) -> Self {
let errno = if errno == -1 {
unsafe { ffi::_rte_errno() }
} else {
-errno
};
DpdkError(unsafe { ffi::rte_strerror(errno).as_str().into() })
}
}
#[derive(Copy, Clone, Eq, Hash, PartialEq)]
pub struct SocketId(raw::c_int);
impl SocketId {
pub const ANY: Self = SocketId(-1);
#[inline]
pub fn current() -> SocketId {
unsafe { SocketId(ffi::rte_socket_id() as raw::c_int) }
}
#[inline]
pub fn all() -> Vec<SocketId> {
unsafe {
(0..ffi::rte_socket_count())
.map(|idx| ffi::rte_socket_id_by_idx(idx))
.filter(|&sid| sid != -1)
.map(SocketId)
.collect::<Vec<_>>()
}
}
#[allow(clippy::trivially_copy_pass_by_ref)]
#[inline]
pub(crate) fn raw(&self) -> raw::c_int {
self.0
}
}
impl fmt::Debug for SocketId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "socket{}", self.0)
}
}
#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct CoreId(usize);
impl CoreId {
pub const ANY: Self = CoreId(std::usize::MAX);
#[inline]
pub(crate) fn new(i: usize) -> CoreId {
CoreId(i)
}
#[inline]
pub fn current() -> CoreId {
CURRENT_CORE_ID.with(|tls| tls.get())
}
#[allow(clippy::trivially_copy_pass_by_ref)]
#[inline]
pub fn socket_id(&self) -> SocketId {
unsafe { SocketId(ffi::numa_node_of_cpu(self.0 as raw::c_int)) }
}
#[allow(clippy::trivially_copy_pass_by_ref)]
#[inline]
pub(crate) fn raw(&self) -> usize {
self.0
}
#[allow(clippy::trivially_copy_pass_by_ref)]
#[inline]
pub(crate) fn set_thread_affinity(&self) -> Result<()> {
unsafe {
let mut set: libc::cpu_set_t = mem::zeroed();
libc::CPU_SET(self.0, &mut set);
let mut set: ffi::rte_cpuset_t = mem::transmute(set);
ffi::rte_thread_set_affinity(&mut set).into_result(DpdkError::from_errno)?;
}
CURRENT_CORE_ID.with(|tls| tls.set(*self));
Ok(())
}
}
impl fmt::Debug for CoreId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "core{}", self.0)
}
}
thread_local! {
static CURRENT_CORE_ID: Cell<CoreId> = Cell::new(CoreId::ANY);
}
pub(crate) fn eal_init(args: Vec<String>) -> Result<()> {
debug!(arguments=?args);
let len = args.len() as raw::c_int;
let args = args
.into_iter()
.map(|s| s.into_cstring())
.collect::<Vec<_>>();
let mut ptrs = args
.iter()
.map(|s| s.as_ptr() as *mut raw::c_char)
.collect::<Vec<_>>();
let res = unsafe { ffi::rte_eal_init(len, ptrs.as_mut_ptr()) };
debug!("EAL parsed {} arguments.", res);
res.into_result(DpdkError::from_errno).map(|_| ())
}
pub(crate) fn eal_cleanup() -> Result<()> {
unsafe {
ffi::rte_eal_cleanup()
.into_result(DpdkError::from_errno)
.map(|_| ())
}
}
fn eth_macaddr_get(port_id: u16) -> MacAddr {
let mut addr = ffi::rte_ether_addr::default();
unsafe {
ffi::rte_eth_macaddr_get(port_id, &mut addr);
}
addr.addr_bytes.into()
}
pub(crate) fn mbuf_free_bulk(mbufs: Vec<*mut ffi::rte_mbuf>) {
assert!(!mbufs.is_empty());
let mut to_free = Vec::with_capacity(mbufs.len());
let pool = unsafe { (*mbufs[0]).pool };
for mbuf in mbufs.into_iter() {
if pool == unsafe { (*mbuf).pool } {
to_free.push(mbuf as *mut raw::c_void);
} else {
unsafe {
let len = to_free.len();
ffi::_rte_mempool_put_bulk(pool, to_free.as_ptr(), len as u32);
to_free.set_len(0);
}
to_free.push(mbuf as *mut raw::c_void);
}
}
unsafe {
let len = to_free.len();
ffi::_rte_mempool_put_bulk(pool, to_free.as_ptr(), len as u32);
to_free.set_len(0);
}
}