use std::sync::Arc;
use std::{marker::PhantomData, u64};
use errno::errno;
use libc::{
c_int, c_void, mmap, munmap, MAP_ANONYMOUS, MAP_FAILED, MAP_HUGETLB, MAP_PRIVATE, PROT_READ,
PROT_WRITE,
};
use crate::buf_mmap::BufMmap;
use crate::AF_XDP_RESERVED;
#[derive(Debug)]
pub struct MmapArea<'a, T: std::default::Default + std::marker::Copy> {
phantom: PhantomData<&'a T>,
buf_num: usize,
buf_len: usize,
ptr: *mut c_void,
}
unsafe impl<'a, T: std::default::Default + std::marker::Copy> Send for MmapArea<'a, T> {}
unsafe impl<'a, T: std::default::Default + std::marker::Copy> Sync for MmapArea<'a, T> {}
#[derive(Debug)]
pub enum MmapError {
Failed,
}
#[derive(Default, Debug)]
pub struct MmapAreaOptions {
pub huge_tlb: bool,
}
impl<'a, T: std::default::Default + std::marker::Copy> MmapArea<'a, T> {
pub fn new(
buf_num: usize,
buf_len: usize,
options: MmapAreaOptions,
) -> Result<(Arc<MmapArea<'a, T>>, Vec<BufMmap<'a, T>>), MmapError> {
let ptr: *mut c_void;
let mut flags: c_int = MAP_PRIVATE | MAP_ANONYMOUS;
if options.huge_tlb {
flags = flags | MAP_HUGETLB
}
unsafe {
ptr = mmap(
0 as *mut c_void,
buf_num * buf_len,
PROT_READ | PROT_WRITE,
flags,
-1,
0,
);
}
if ptr == MAP_FAILED {
return Err(MmapError::Failed);
}
let ma = Arc::new(MmapArea {
buf_num,
buf_len,
ptr,
phantom: PhantomData,
});
let mut bufs = Vec::with_capacity(buf_num);
let buf_len_available = buf_len - AF_XDP_RESERVED as usize;
for i in 0..buf_num {
let buf: BufMmap<T>;
unsafe {
let addr = (i * buf_len) as u64 + AF_XDP_RESERVED as u64;
let ptr = ma.ptr.offset(addr as isize);
buf = BufMmap::<T> {
addr: addr,
len: 0,
data: std::slice::from_raw_parts_mut(ptr as *mut u8, buf_len_available),
user: Default::default(),
};
}
bufs.push(buf);
}
Ok((ma, bufs))
}
pub fn get_ptr(&self) -> *mut c_void {
self.ptr
}
pub fn get_buf_num(&self) -> usize {
self.buf_num
}
pub(crate) fn get_buf_len(&self) -> usize {
self.buf_len
}
}
impl<'a, T: std::default::Default + std::marker::Copy> Drop for MmapArea<'a, T> {
fn drop(&mut self) {
let r: c_int;
if self.ptr == MAP_FAILED {
return;
}
unsafe {
r = munmap(self.ptr, self.buf_num * self.buf_len);
}
if r != 0 {
let errno = errno().0;
println!("munmap failed errno: {}", errno);
}
}
}
#[cfg(test)]
mod tests {
use std::convert::TryInto;
use std::sync::Arc;
use super::{MmapArea, MmapAreaOptions, MmapError};
use crate::buf::Buf;
use crate::buf_mmap::BufMmap;
use crate::AF_XDP_RESERVED;
#[derive(Default, Copy, Clone, Debug)]
struct BufCustom {}
#[test]
fn bufs_to_pool() {
const BUF_NUM: usize = 1024;
const BUF_LEN: usize = 2048;
let options = MmapAreaOptions { huge_tlb: false };
let r: Result<(Arc<MmapArea<BufCustom>>, Vec<BufMmap<BufCustom>>), MmapError> =
MmapArea::new(BUF_NUM, BUF_LEN, options);
let (area, bufs) = match r {
Ok((area, bufs)) => (area, bufs),
Err(err) => panic!("{:?}", err),
};
assert_eq!(area.buf_num, BUF_NUM);
assert_eq!(area.buf_len, BUF_LEN);
assert_eq!(bufs.len(), BUF_NUM);
for buf in bufs {
if buf.get_data().len() != BUF_LEN - AF_XDP_RESERVED as usize {
panic!(
"expected buf len {} found {}",
BUF_LEN,
buf.get_data().len()
);
}
}
}
#[test]
fn buf_values() {
const BUF_NUM: usize = 1024;
const BUF_LEN: usize = 2048;
let options = MmapAreaOptions { huge_tlb: false };
let r: Result<(Arc<MmapArea<BufCustom>>, Vec<BufMmap<BufCustom>>), MmapError> =
MmapArea::new(BUF_NUM, BUF_LEN, options);
let (area, mut bufs) = match r {
Ok((area, buf_pool)) => (area, buf_pool),
Err(err) => panic!("{:?}", err),
};
assert_eq!(area.buf_num, BUF_NUM);
assert_eq!(area.buf_len, BUF_LEN);
assert_eq!(bufs.len(), BUF_NUM);
let base: u64 = 3983989832773837873;
for (i, buf) in bufs.iter_mut().enumerate() {
let val = i as u64 + base;
let bytes = val.to_ne_bytes();
buf.data[0] = bytes[0];
buf.data[1] = bytes[1];
buf.data[2] = bytes[2];
buf.data[3] = bytes[3];
buf.data[4] = bytes[4];
buf.data[5] = bytes[5];
buf.data[6] = bytes[6];
buf.data[7] = bytes[7];
}
for (i, buf) in bufs.iter_mut().enumerate() {
let val: u64 = i as u64 + base;
let (int_bytes, _rest) = buf.data.split_at(std::mem::size_of::<u64>());
let val2 = u64::from_ne_bytes(int_bytes.try_into().unwrap());
assert_eq!(val, val2);
}
}
#[test]
fn buf_values2() {
const BUF_NUM: usize = 256;
const BUF_LEN: usize = 2048;
let options = MmapAreaOptions { huge_tlb: false };
let r: Result<(Arc<MmapArea<BufCustom>>, Vec<BufMmap<BufCustom>>), MmapError> =
MmapArea::new(BUF_NUM, BUF_LEN, options);
let (area, mut bufs) = match r {
Ok((area, buf_pool)) => (area, buf_pool),
Err(err) => panic!("{:?}", err),
};
assert_eq!(area.buf_num, BUF_NUM);
assert_eq!(area.buf_len, BUF_LEN);
assert_eq!(bufs.len(), BUF_NUM);
for (i, buf) in bufs.iter_mut().enumerate() {
for j in 0..BUF_LEN - AF_XDP_RESERVED as usize {
buf.data[j] = i as u8;
}
}
for (i, buf) in bufs.iter_mut().enumerate() {
for j in 0..BUF_LEN - AF_XDP_RESERVED as usize {
assert_eq!(buf.data[j], i as u8);
}
}
}
}