use libbpf_sys::{
XSK_RING_CONS__DEFAULT_NUM_DESCS, XSK_RING_PROD__DEFAULT_NUM_DESCS,
XSK_UMEM__DEFAULT_FRAME_HEADROOM, XSK_UMEM__DEFAULT_FRAME_SIZE,
};
use std::{error::Error, fmt};
use crate::util;
#[derive(Debug)]
pub enum UmemConfigError {
FrameCountInvalid { reason: &'static str },
CompSizeInvalid { reason: &'static str },
FillSizeInvalid { reason: &'static str },
FrameSizeInvalid { reason: &'static str },
}
impl fmt::Display for UmemConfigError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use UmemConfigError::*;
let reason = match self {
FrameCountInvalid { reason } => reason,
CompSizeInvalid { reason } => reason,
FillSizeInvalid { reason } => reason,
FrameSizeInvalid { reason } => reason,
};
write!(f, "{}", reason)
}
}
impl Error for UmemConfigError {}
#[derive(Debug, Clone, PartialEq)]
pub struct UmemConfig {
frame_count: u32,
frame_size: u32,
fill_queue_size: u32,
comp_queue_size: u32,
frame_headroom: u32,
use_huge_pages: bool,
}
impl Default for UmemConfig {
fn default() -> Self {
Self {
frame_count: 2048,
frame_size: XSK_UMEM__DEFAULT_FRAME_SIZE,
fill_queue_size: XSK_RING_PROD__DEFAULT_NUM_DESCS,
comp_queue_size: XSK_RING_CONS__DEFAULT_NUM_DESCS,
frame_headroom: XSK_UMEM__DEFAULT_FRAME_HEADROOM,
use_huge_pages: false,
}
}
}
impl UmemConfig {
pub fn new(
frame_count: u32,
frame_size: u32,
fill_queue_size: u32,
comp_queue_size: u32,
frame_headroom: u32,
use_huge_pages: bool,
) -> Result<Self, UmemConfigError> {
if frame_count == 0 {
return Err(UmemConfigError::FrameCountInvalid {
reason: "frame count must be greater than 0",
});
}
if !util::is_pow_of_two(fill_queue_size) {
return Err(UmemConfigError::FillSizeInvalid {
reason: "fill queue size must be a power of two",
});
}
if !util::is_pow_of_two(comp_queue_size) {
return Err(UmemConfigError::CompSizeInvalid {
reason: "comp queue size must be a power of two",
});
}
if frame_size < 2048 {
return Err(UmemConfigError::FrameSizeInvalid {
reason: "frame size must be greater than or equal to 2048",
});
}
Ok(UmemConfig {
frame_count,
frame_size,
fill_queue_size,
comp_queue_size,
frame_headroom,
use_huge_pages,
})
}
pub fn frame_count(&self) -> u32 {
self.frame_count
}
pub fn frame_size(&self) -> u32 {
self.frame_size
}
pub fn fill_queue_size(&self) -> u32 {
self.fill_queue_size
}
pub fn comp_queue_size(&self) -> u32 {
self.comp_queue_size
}
pub fn frame_headroom(&self) -> u32 {
self.frame_headroom
}
pub fn use_huge_pages(&self) -> bool {
self.use_huge_pages
}
pub fn umem_len(&self) -> usize {
(self.frame_count as usize)
.checked_mul(self.frame_size as usize)
.unwrap()
}
}
#[derive(Debug, Clone)]
pub struct UmemConfigBuilder {
frame_count: u32,
frame_size: u32,
fill_queue_size: u32,
comp_queue_size: u32,
frame_headroom: u32,
use_huge_pages: bool,
}
impl Default for UmemConfigBuilder {
fn default() -> Self {
Self {
frame_count: 2048,
frame_size: XSK_UMEM__DEFAULT_FRAME_SIZE,
fill_queue_size: XSK_RING_PROD__DEFAULT_NUM_DESCS,
comp_queue_size: XSK_RING_CONS__DEFAULT_NUM_DESCS,
frame_headroom: XSK_UMEM__DEFAULT_FRAME_HEADROOM,
use_huge_pages: false,
}
}
}
impl UmemConfigBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn frame_count(&mut self, frame_count: u32) -> &mut Self {
self.frame_count = frame_count;
self
}
pub fn frame_size(&mut self, frame_size: u32) -> &mut Self {
self.frame_size = frame_size;
self
}
pub fn fill_queue_size(&mut self, fill_queue_size: u32) -> &mut Self {
self.fill_queue_size = fill_queue_size;
self
}
pub fn comp_queue_size(&mut self, comp_queue_size: u32) -> &mut Self {
self.comp_queue_size = comp_queue_size;
self
}
pub fn frame_headroom(&mut self, frame_headroom: u32) -> &mut Self {
self.frame_headroom = frame_headroom;
self
}
pub fn use_huge_pages(&mut self, use_huge_pages: bool) -> &mut Self {
self.use_huge_pages = use_huge_pages;
self
}
pub fn build(&self) -> Result<UmemConfig, UmemConfigError> {
UmemConfig::new(
self.frame_count,
self.frame_size,
self.fill_queue_size,
self.comp_queue_size,
self.frame_headroom,
self.use_huge_pages,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn umem_len_doesnt_panic_when_frame_count_and_size_are_u32_max() {
UmemConfig::new(u32::MAX, u32::MAX, 8, 8, 0, false)
.unwrap()
.umem_len();
}
#[test]
fn umem_config_builder_test() {
let umem_config_default = UmemConfig::default();
let umem_config = UmemConfigBuilder::new()
.frame_count(umem_config_default.frame_count)
.frame_size(umem_config_default.frame_size)
.fill_queue_size(umem_config_default.fill_queue_size)
.comp_queue_size(umem_config_default.comp_queue_size)
.frame_headroom(umem_config_default.frame_headroom)
.use_huge_pages(umem_config_default.use_huge_pages)
.build()
.expect("failed to build umem config");
assert_eq!(umem_config_default, umem_config);
}
}