use crate::dpdk;
use crate::memory::mempool::MempoolError;
use crate::protocols::packet::{Packet, PacketHeader, PacketParseError};
use std::fmt;
use std::ptr::NonNull;
use std::slice;
use anyhow::{bail, Result};
use thiserror::Error;
#[derive(Clone)]
pub struct Mbuf {
raw: NonNull<dpdk::rte_mbuf>,
}
impl Mbuf {
pub(crate) fn new_unchecked(mbuf: *mut dpdk::rte_mbuf) -> Mbuf {
unsafe {
Mbuf {
raw: NonNull::new_unchecked(mbuf),
}
}
}
pub(crate) fn new(mbuf: *mut dpdk::rte_mbuf) -> Result<Mbuf> {
Ok(Mbuf {
raw: NonNull::new(mbuf).ok_or(MempoolError::Exhausted)?,
})
}
pub(crate) fn from_bytes(data: &[u8], mp: *mut dpdk::rte_mempool) -> Result<Mbuf> {
let mut mbuf = unsafe { Mbuf::new(dpdk::rte_pktmbuf_alloc(mp))? };
if data.len() <= mbuf.raw().buf_len.into() {
mbuf.raw_mut().data_len += data.len() as u16;
mbuf.raw_mut().pkt_len += data.len() as u32;
unsafe {
let src = data.as_ptr();
let dst = mbuf.get_data_address(0) as *mut u8;
std::ptr::copy_nonoverlapping(src, dst, data.len());
}
} else {
bail!(MbufError::WritePastBuffer);
}
Ok(mbuf)
}
pub(crate) fn raw(&self) -> &dpdk::rte_mbuf {
unsafe { self.raw.as_ref() }
}
fn raw_mut(&mut self) -> &mut dpdk::rte_mbuf {
unsafe { self.raw.as_mut() }
}
#[allow(dead_code)]
pub(crate) fn timestamp(&self) -> usize {
unimplemented!();
}
pub fn data_len(&self) -> usize {
self.raw().data_len as usize
}
pub fn data(&self) -> &[u8] {
let ptr = self.get_data_address(0);
unsafe { slice::from_raw_parts(ptr, self.data_len()) as &[u8] }
}
pub fn get_data_slice(&self, offset: usize, count: usize) -> Result<&[u8]> {
if offset < self.data_len() {
if offset + count <= self.data_len() {
let ptr = self.get_data_address(offset);
unsafe { Ok(slice::from_raw_parts(ptr, count) as &[u8]) }
} else {
bail!(MbufError::ReadPastBuffer)
}
} else {
bail!(MbufError::BadOffset)
}
}
pub(crate) fn get_data<T: PacketHeader>(&self, offset: usize) -> Result<*const T> {
if offset < self.data_len() {
if offset + T::size_of() <= self.data_len() {
Ok(self.get_data_address(offset) as *const T)
} else {
bail!(MbufError::ReadPastBuffer)
}
} else {
bail!(MbufError::BadOffset)
}
}
fn get_data_address(&self, offset: usize) -> *const u8 {
let raw = self.raw();
unsafe { (raw.buf_addr as *const u8).offset(raw.data_off as isize + offset as isize) }
}
#[allow(dead_code)]
pub(crate) fn rss_hash(&self) -> u32 {
unsafe { self.raw().__bindgen_anon_2.hash.rss }
}
#[allow(dead_code)]
pub(crate) fn mark(&self) -> u32 {
unsafe { self.raw().__bindgen_anon_2.hash.fdir.hi }
}
#[allow(dead_code)]
pub(crate) fn add_mark(&mut self, mark: u32) {
self.raw_mut().__bindgen_anon_2.hash.fdir.hi = mark;
}
#[allow(dead_code)]
pub fn has_mark(&mut self, _mark: u32) -> bool {
true
}
}
impl<'a> Packet<'a> for Mbuf {
fn mbuf(&self) -> &Mbuf {
self
}
fn header_len(&self) -> usize {
0
}
fn next_header_offset(&self) -> usize {
0
}
fn next_header(&self) -> Option<usize> {
None
}
fn parse_from(_outer: &'a impl Packet<'a>) -> Result<Self>
where
Self: Sized,
{
bail!(PacketParseError::InvalidProtocol)
}
}
impl Drop for Mbuf {
fn drop(&mut self) {
unsafe { dpdk::rte_pktmbuf_free(self.raw()) };
}
}
impl fmt::Debug for Mbuf {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let raw = self.raw();
f.debug_struct("Mbuf")
.field("buf_addr", &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 fmt::Display for Mbuf {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for byte in 0..self.raw().data_len {
write!(
f,
"{:02x} ",
self.get_data_slice(byte as usize, 1).unwrap()[0]
)?;
if byte % 16 == 15 {
writeln!(f,)?;
}
}
Ok(())
}
}
#[derive(Error, Debug)]
pub(crate) enum MbufError {
#[error("Offset exceeds Mbuf segment buffer length")]
BadOffset,
#[error("Data read exceeds Mbuf segment buffer")]
ReadPastBuffer,
#[error("Data write exceeds Mbuf segment buffer")]
WritePastBuffer,
}