use alloc::{boxed::Box, sync::Arc, vec, vec::Vec};
use core::ptr::NonNull;
use spin::Mutex;
use crate::{DevError, DevResult};
pub struct NetBufPtr {
raw_ptr: NonNull<u8>,
buf_ptr: NonNull<u8>,
len: usize,
}
impl NetBufPtr {
pub fn new(raw_ptr: NonNull<u8>, buf_ptr: NonNull<u8>, len: usize) -> Self {
Self {
raw_ptr,
buf_ptr,
len,
}
}
pub fn raw_ptr<T>(&self) -> *mut T {
self.raw_ptr.as_ptr() as *mut T
}
pub fn packet_len(&self) -> usize {
self.len
}
pub fn packet(&self) -> &[u8] {
unsafe { core::slice::from_raw_parts(self.buf_ptr.as_ptr() as *const u8, self.len) }
}
pub fn packet_mut(&mut self) -> &mut [u8] {
unsafe { core::slice::from_raw_parts_mut(self.buf_ptr.as_ptr(), self.len) }
}
}
const MIN_BUFFER_LEN: usize = 1526;
const MAX_BUFFER_LEN: usize = 65535;
pub type NetBufBox = Box<NetBuf>;
pub struct NetBuf {
header_len: usize,
packet_len: usize,
capacity: usize,
buf_ptr: NonNull<u8>,
pool_offset: usize,
pool: Arc<NetBufPool>,
}
unsafe impl Send for NetBuf {}
unsafe impl Sync for NetBuf {}
impl NetBuf {
const unsafe fn get_slice(&self, start: usize, len: usize) -> &[u8] {
unsafe { core::slice::from_raw_parts(self.buf_ptr.as_ptr().add(start), len) }
}
const unsafe fn get_slice_mut(&mut self, start: usize, len: usize) -> &mut [u8] {
unsafe { core::slice::from_raw_parts_mut(self.buf_ptr.as_ptr().add(start), len) }
}
pub const fn capacity(&self) -> usize {
self.capacity
}
pub const fn header_len(&self) -> usize {
self.header_len
}
pub const fn header(&self) -> &[u8] {
unsafe { self.get_slice(0, self.header_len) }
}
pub const fn packet(&self) -> &[u8] {
unsafe { self.get_slice(self.header_len, self.packet_len) }
}
pub const fn packet_mut(&mut self) -> &mut [u8] {
unsafe { self.get_slice_mut(self.header_len, self.packet_len) }
}
pub const fn packet_with_header(&self) -> &[u8] {
unsafe { self.get_slice(0, self.header_len + self.packet_len) }
}
pub const fn raw_buf(&self) -> &[u8] {
unsafe { self.get_slice(0, self.capacity) }
}
pub const fn raw_buf_mut(&mut self) -> &mut [u8] {
unsafe { self.get_slice_mut(0, self.capacity) }
}
pub fn set_header_len(&mut self, header_len: usize) {
debug_assert!(header_len + self.packet_len <= self.capacity);
self.header_len = header_len;
}
pub fn set_packet_len(&mut self, packet_len: usize) {
debug_assert!(self.header_len + packet_len <= self.capacity);
self.packet_len = packet_len;
}
pub fn into_buf_ptr(mut self: Box<Self>) -> NetBufPtr {
let buf_ptr = self.packet_mut().as_mut_ptr();
let len = self.packet_len;
NetBufPtr::new(
NonNull::new(Box::into_raw(self) as *mut u8).unwrap(),
NonNull::new(buf_ptr).unwrap(),
len,
)
}
pub unsafe fn from_buf_ptr(ptr: NetBufPtr) -> Box<Self> {
unsafe { Box::from_raw(ptr.raw_ptr::<Self>()) }
}
}
impl Drop for NetBuf {
fn drop(&mut self) {
self.pool.dealloc(self.pool_offset);
}
}
pub struct NetBufPool {
capacity: usize,
buf_len: usize,
pool: Vec<u8>,
free_list: Mutex<Vec<usize>>,
}
impl NetBufPool {
pub fn new(capacity: usize, buf_len: usize) -> DevResult<Arc<Self>> {
if capacity == 0 {
return Err(DevError::InvalidParam);
}
if !(MIN_BUFFER_LEN..=MAX_BUFFER_LEN).contains(&buf_len) {
return Err(DevError::InvalidParam);
}
let pool = vec![0; capacity * buf_len];
let mut free_list = Vec::with_capacity(capacity);
for i in 0..capacity {
free_list.push(i * buf_len);
}
Ok(Arc::new(Self {
capacity,
buf_len,
pool,
free_list: Mutex::new(free_list),
}))
}
pub const fn capacity(&self) -> usize {
self.capacity
}
pub const fn buffer_len(&self) -> usize {
self.buf_len
}
pub fn alloc(self: &Arc<Self>) -> Option<NetBuf> {
let pool_offset = self.free_list.lock().pop()?;
let buf_ptr =
unsafe { NonNull::new(self.pool.as_ptr().add(pool_offset) as *mut u8).unwrap() };
Some(NetBuf {
header_len: 0,
packet_len: 0,
capacity: self.buf_len,
buf_ptr,
pool_offset,
pool: Arc::clone(self),
})
}
pub fn alloc_boxed(self: &Arc<Self>) -> Option<NetBufBox> {
Some(Box::new(self.alloc()?))
}
fn dealloc(&self, pool_offset: usize) {
debug_assert_eq!(pool_offset % self.buf_len, 0);
self.free_list.lock().push(pool_offset);
}
}