use super::MEMPOOL;
use crate::dpdk::{DpdkError, MempoolError};
use crate::ffi::{self, ToResult};
use crate::packets::{Internal, Packet};
use crate::{ensure, trace};
use anyhow::Result;
use std::fmt;
use std::mem;
use std::os::raw;
use std::ptr::{self, NonNull};
use std::slice;
use thiserror::Error;
pub trait SizeOf {
fn size_of() -> usize;
}
impl SizeOf for () {
fn size_of() -> usize {
std::mem::size_of::<()>()
}
}
impl SizeOf for u8 {
fn size_of() -> usize {
std::mem::size_of::<u8>()
}
}
impl SizeOf for [u8; 2] {
fn size_of() -> usize {
std::mem::size_of::<[u8; 2]>()
}
}
impl SizeOf for [u8; 16] {
fn size_of() -> usize {
std::mem::size_of::<[u8; 16]>()
}
}
impl SizeOf for ::std::net::Ipv6Addr {
fn size_of() -> usize {
std::mem::size_of::<std::net::Ipv6Addr>()
}
}
#[derive(Debug, Error)]
pub(crate) enum BufferError {
#[error("Offset {0} exceeds the buffer length {1}.")]
BadOffset(usize, usize),
#[error("Buffer is not resized.")]
NotResized,
#[error("Struct size {0} exceeds the remaining buffer length {1}.")]
OutOfBuffer(usize, usize),
}
pub struct Mbuf {
inner: MbufInner,
}
enum MbufInner {
Original(NonNull<ffi::rte_mbuf>),
Clone(NonNull<ffi::rte_mbuf>),
}
impl MbufInner {
fn ptr(&self) -> &NonNull<ffi::rte_mbuf> {
match self {
MbufInner::Original(raw) => raw,
MbufInner::Clone(raw) => raw,
}
}
fn ptr_mut(&mut self) -> &mut NonNull<ffi::rte_mbuf> {
match self {
MbufInner::Original(ref mut raw) => raw,
MbufInner::Clone(ref mut raw) => raw,
}
}
}
impl Mbuf {
#[inline]
pub fn new() -> Result<Self> {
let mempool = MEMPOOL.with(|tls| tls.get());
let raw =
unsafe { ffi::_rte_pktmbuf_alloc(mempool).into_result(|_| MempoolError::Exhausted)? };
Ok(Mbuf {
inner: MbufInner::Original(raw),
})
}
#[inline]
pub fn from_bytes(data: &[u8]) -> Result<Self> {
let mut mbuf = Mbuf::new()?;
mbuf.extend(0, data.len())?;
mbuf.write_data_slice(0, data)?;
Ok(mbuf)
}
#[inline]
pub(crate) unsafe fn from_ptr(ptr: *mut ffi::rte_mbuf) -> Self {
Mbuf {
inner: MbufInner::Original(NonNull::new_unchecked(ptr)),
}
}
#[inline]
fn raw(&self) -> &ffi::rte_mbuf {
unsafe { self.inner.ptr().as_ref() }
}
#[inline]
fn raw_mut(&mut self) -> &mut ffi::rte_mbuf {
unsafe { self.inner.ptr_mut().as_mut() }
}
#[inline]
pub fn data_len(&self) -> usize {
self.raw().data_len as usize
}
#[inline]
pub(crate) unsafe fn data_address(&self, offset: usize) -> *mut u8 {
let raw = self.raw();
(raw.buf_addr as *mut u8).offset(raw.data_off as isize + offset as isize)
}
#[inline]
fn tailroom(&self) -> usize {
let raw = self.raw();
(raw.buf_len - raw.data_off - raw.data_len) as usize
}
#[inline]
pub fn extend(&mut self, offset: usize, len: usize) -> Result<()> {
ensure!(len > 0, BufferError::NotResized);
ensure!(offset <= self.data_len(), BufferError::NotResized);
ensure!(len < self.tailroom(), BufferError::NotResized);
let to_copy = self.data_len() - offset;
if to_copy > 0 {
unsafe {
let src = self.data_address(offset);
let dst = self.data_address(offset + len);
ptr::copy(src, dst, to_copy);
}
}
self.raw_mut().data_len += len as u16;
self.raw_mut().pkt_len += len as u32;
Ok(())
}
#[inline]
pub fn shrink(&mut self, offset: usize, len: usize) -> Result<()> {
ensure!(len > 0, BufferError::NotResized);
ensure!(offset + len <= self.data_len(), BufferError::NotResized);
let to_copy = self.data_len() - offset - len;
if to_copy > 0 {
unsafe {
let src = self.data_address(offset + len);
let dst = self.data_address(offset);
ptr::copy(src, dst, to_copy);
}
}
self.raw_mut().data_len -= len as u16;
self.raw_mut().pkt_len -= len as u32;
Ok(())
}
#[inline]
pub fn resize(&mut self, offset: usize, len: isize) -> Result<()> {
if len < 0 {
self.shrink(offset, -len as usize)
} else {
self.extend(offset, len as usize)
}
}
#[inline]
pub fn truncate(&mut self, to_len: usize) -> Result<()> {
ensure!(to_len < self.data_len(), BufferError::NotResized);
self.raw_mut().data_len = to_len as u16;
self.raw_mut().pkt_len = to_len as u32;
Ok(())
}
#[inline]
pub fn read_data<T: SizeOf>(&self, offset: usize) -> Result<NonNull<T>> {
ensure!(
offset < self.data_len(),
BufferError::BadOffset(offset, self.data_len())
);
ensure!(
offset + T::size_of() <= self.data_len(),
BufferError::OutOfBuffer(T::size_of(), self.data_len() - offset)
);
unsafe {
let item = self.data_address(offset) as *mut T;
Ok(NonNull::new_unchecked(item))
}
}
#[inline]
pub fn write_data<T: SizeOf>(&mut self, offset: usize, item: &T) -> Result<NonNull<T>> {
ensure!(
offset + T::size_of() <= self.data_len(),
BufferError::OutOfBuffer(T::size_of(), self.data_len() - offset)
);
unsafe {
let src = item as *const T;
let dst = self.data_address(offset) as *mut T;
ptr::copy_nonoverlapping(src, dst, 1);
}
self.read_data(offset)
}
#[inline]
pub fn read_data_slice<T: SizeOf>(&self, offset: usize, count: usize) -> Result<NonNull<[T]>> {
ensure!(
offset < self.data_len(),
BufferError::BadOffset(offset, self.data_len())
);
ensure!(
offset + T::size_of() * count <= self.data_len(),
BufferError::OutOfBuffer(T::size_of() * count, self.data_len() - offset)
);
unsafe {
let item0 = self.data_address(offset) as *mut T;
let slice = slice::from_raw_parts_mut(item0, count) as *mut [T];
Ok(NonNull::new_unchecked(slice))
}
}
#[inline]
pub fn write_data_slice<T: SizeOf>(
&mut self,
offset: usize,
slice: &[T],
) -> Result<NonNull<[T]>> {
let count = slice.len();
ensure!(
offset + T::size_of() * count <= self.data_len(),
BufferError::OutOfBuffer(T::size_of() * count, self.data_len() - offset)
);
unsafe {
let src = slice.as_ptr();
let dst = self.data_address(offset) as *mut T;
ptr::copy_nonoverlapping(src, dst, count);
}
self.read_data_slice(offset, count)
}
#[inline]
pub(crate) fn into_ptr(self) -> *mut ffi::rte_mbuf {
let ptr = self.inner.ptr().as_ptr();
mem::forget(self);
ptr
}
pub fn alloc_bulk(len: usize) -> Result<Vec<Mbuf>> {
let mut ptrs = Vec::with_capacity(len);
let mempool = MEMPOOL.with(|tls| tls.get());
let mbufs = unsafe {
ffi::_rte_pktmbuf_alloc_bulk(mempool, ptrs.as_mut_ptr(), len as raw::c_uint)
.into_result(DpdkError::from_errno)?;
ptrs.set_len(len);
ptrs.into_iter()
.map(|ptr| Mbuf::from_ptr(ptr))
.collect::<Vec<_>>()
};
Ok(mbufs)
}
pub(crate) fn free_bulk(mbufs: Vec<Mbuf>) {
let ptrs = mbufs.into_iter().map(Mbuf::into_ptr).collect::<Vec<_>>();
super::mbuf_free_bulk(ptrs);
}
}
impl fmt::Debug for Mbuf {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let raw = self.raw();
f.debug_struct(&format!("mbuf@{:p}", raw.buf_addr))
.field("buf_len", &raw.buf_len)
.field("pkt_len", &raw.pkt_len)
.field("data_len", &raw.data_len)
.field("data_off", &raw.data_off)
.finish()
}
}
impl Drop for Mbuf {
fn drop(&mut self) {
match self.inner {
MbufInner::Original(_) => {
trace!("freeing mbuf@{:p}.", self.raw().buf_addr);
unsafe {
ffi::_rte_pktmbuf_free(self.raw_mut());
}
}
MbufInner::Clone(_) => (),
}
}
}
unsafe impl Send for Mbuf {}
impl Packet for Mbuf {
type Envelope = Mbuf;
#[inline]
fn envelope(&self) -> &Self::Envelope {
self
}
#[inline]
fn envelope_mut(&mut self) -> &mut Self::Envelope {
self
}
#[inline]
fn mbuf(&self) -> &Mbuf {
self
}
#[inline]
fn mbuf_mut(&mut self) -> &mut Mbuf {
self
}
#[inline]
fn offset(&self) -> usize {
0
}
#[inline]
fn header_len(&self) -> usize {
0
}
#[inline]
unsafe fn clone(&self, _internal: Internal) -> Self {
let raw = self.inner.ptr();
Mbuf {
inner: MbufInner::Clone(*raw),
}
}
#[inline]
fn try_parse(envelope: Self::Envelope, _internal: Internal) -> Result<Self> {
Ok(envelope)
}
#[inline]
fn try_push(envelope: Self::Envelope, _internal: Internal) -> Result<Self> {
Ok(envelope)
}
#[inline]
fn deparse(self) -> Self::Envelope {
self
}
#[inline]
fn remove(self) -> Result<Self::Envelope> {
Ok(self)
}
#[inline]
fn reset(self) -> Mbuf {
self
}
#[inline]
fn reconcile_all(&mut self) {}
}
#[cfg(test)]
mod tests {
use super::*;
const BUFFER: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
#[capsule::test]
fn new_from_bytes() {
let mbuf = Mbuf::from_bytes(&BUFFER).unwrap();
let slice = mbuf.read_data_slice::<u8>(0, 16).unwrap();
let slice = unsafe { slice.as_ref() };
assert_eq!(BUFFER, slice);
}
#[capsule::test]
fn extend_data_buffer_tail() {
let mut mbuf = Mbuf::new().unwrap();
assert!(mbuf.extend(0, 16).is_ok());
assert_eq!(16, mbuf.data_len());
assert!(mbuf.write_data_slice(0, &BUFFER).is_ok());
assert!(mbuf.extend(16, 8).is_ok());
assert_eq!(24, mbuf.data_len());
let slice = mbuf.read_data_slice::<u8>(0, 24).unwrap();
let slice = unsafe { slice.as_ref() };
assert_eq!(BUFFER, slice[..16]);
}
#[capsule::test]
fn extend_data_buffer_middle() {
let mut mbuf = Mbuf::new().unwrap();
assert!(mbuf.extend(0, 16).is_ok());
assert!(mbuf.write_data_slice(0, &BUFFER).is_ok());
assert!(mbuf.extend(4, 8).is_ok());
assert_eq!(24, mbuf.data_len());
let slice = mbuf.read_data_slice::<u8>(0, 24).unwrap();
let slice = unsafe { slice.as_ref() };
assert_eq!(BUFFER[..4], slice[..4]);
assert_eq!(BUFFER[4..12], slice[4..12]);
assert_eq!(BUFFER[4..], slice[12..24]);
}
#[capsule::test]
fn extend_data_buffer_too_much() {
let mut mbuf = Mbuf::new().unwrap();
assert!(mbuf.extend(0, 999_999).is_err());
}
#[capsule::test]
fn shrink_data_buffer_tail() {
let mut mbuf = Mbuf::new().unwrap();
assert!(mbuf.extend(0, 16).is_ok());
assert!(mbuf.write_data_slice(0, &BUFFER).is_ok());
assert!(mbuf.shrink(8, 8).is_ok());
assert_eq!(8, mbuf.data_len());
let slice = mbuf.read_data_slice::<u8>(0, 8).unwrap();
let slice = unsafe { slice.as_ref() };
assert_eq!(BUFFER[..8], slice[..8]);
}
#[capsule::test]
fn shrink_data_buffer_middle() {
let mut mbuf = Mbuf::new().unwrap();
assert!(mbuf.extend(0, 16).is_ok());
assert!(mbuf.write_data_slice(0, &BUFFER).is_ok());
assert!(mbuf.shrink(4, 8).is_ok());
assert_eq!(8, mbuf.data_len());
let slice = mbuf.read_data_slice::<u8>(0, 8).unwrap();
let slice = unsafe { slice.as_ref() };
assert_eq!(BUFFER[..4], slice[..4]);
assert_eq!(BUFFER[12..], slice[4..]);
}
#[capsule::test]
fn shrink_data_buffer_too_much() {
let mut mbuf = Mbuf::new().unwrap();
assert!(mbuf.extend(0, 200).is_ok());
assert!(mbuf.shrink(150, 100).is_err());
}
#[capsule::test]
fn truncate_data_buffer() {
let mut mbuf = Mbuf::new().unwrap();
assert!(mbuf.extend(0, 16).is_ok());
assert!(mbuf.write_data_slice(0, &BUFFER).is_ok());
assert!(mbuf.truncate(8).is_ok());
assert_eq!(8, mbuf.data_len());
let slice = mbuf.read_data_slice::<u8>(0, 8).unwrap();
let slice = unsafe { slice.as_ref() };
assert_eq!(BUFFER[..8], slice[..8]);
}
#[capsule::test]
fn read_and_write_data() {
let mut mbuf = Mbuf::new().unwrap();
assert!(mbuf.extend(0, 20).is_ok());
assert!(mbuf.write_data(0, &BUFFER).is_ok());
let item = mbuf.read_data::<[u8; 16]>(0).unwrap();
let item = unsafe { item.as_ref() };
assert_eq!(BUFFER, *item);
let item = mbuf.read_data::<[u8; 16]>(2).unwrap();
let item = unsafe { item.as_ref() };
assert!(BUFFER != *item);
assert!(mbuf.read_data::<[u8; 16]>(10).is_err());
}
#[capsule::test]
fn read_and_write_data_slice() {
let mut mbuf = Mbuf::new().unwrap();
assert!(mbuf.extend(0, 20).is_ok());
assert!(mbuf.write_data_slice(0, &BUFFER).is_ok());
let slice = mbuf.read_data_slice::<u8>(0, 16).unwrap();
let slice = unsafe { slice.as_ref() };
assert_eq!(BUFFER, *slice);
let slice = mbuf.read_data_slice::<u8>(2, 16).unwrap();
let slice = unsafe { slice.as_ref() };
assert!(BUFFER != *slice);
assert!(mbuf.read_data_slice::<u8>(10, 16).is_err());
}
#[capsule::test]
fn alloc_bulk() {
let mbufs = Mbuf::alloc_bulk(8).unwrap();
assert_eq!(8, mbufs.len());
for mbuf in mbufs {
assert_eq!(0, mbuf.data_len());
}
}
}