use libc::E2BIG;
use libc::ENOSPC;
use std::io;
use std::ops::Deref;
use std::ops::DerefMut;
use std::os::fd::AsRawFd;
use std::os::raw::c_uint;
use std::os::raw::c_void;
use std::ptr::null_mut;
use std::ptr::NonNull;
use std::slice::from_raw_parts;
use std::slice::from_raw_parts_mut;
use crate::AsRawLibbpf;
use crate::Error;
use crate::MapCore;
use crate::MapType;
use crate::Result;
#[derive(Debug)]
pub struct UserRingBufferSample<'slf> {
ptr: NonNull<c_void>,
size: usize,
rb: &'slf UserRingBuffer,
submitted: bool,
}
impl Deref for UserRingBufferSample<'_> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
unsafe { from_raw_parts(self.ptr.as_ptr() as *const u8, self.size) }
}
}
impl DerefMut for UserRingBufferSample<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { from_raw_parts_mut(self.ptr.as_ptr() as *mut u8, self.size) }
}
}
impl Drop for UserRingBufferSample<'_> {
fn drop(&mut self) {
if !self.submitted {
unsafe {
libbpf_sys::user_ring_buffer__discard(self.rb.ptr.as_ptr(), self.ptr.as_ptr());
}
}
}
}
#[derive(Debug)]
pub struct UserRingBuffer {
ptr: NonNull<libbpf_sys::user_ring_buffer>,
}
impl UserRingBuffer {
pub fn new(map: &dyn MapCore) -> Result<Self> {
if map.map_type() != MapType::UserRingBuf {
return Err(Error::with_invalid_data("must use a UserRingBuf map"));
}
let fd = map.as_fd();
let raw_ptr = unsafe { libbpf_sys::user_ring_buffer__new(fd.as_raw_fd(), null_mut()) };
let ptr = NonNull::new(raw_ptr).ok_or_else(|| {
io::Error::last_os_error()
})?;
Ok(Self { ptr })
}
pub fn reserve(&self, size: usize) -> Result<UserRingBufferSample<'_>> {
let sample_ptr =
unsafe { libbpf_sys::user_ring_buffer__reserve(self.ptr.as_ptr(), size as c_uint) };
let ptr = NonNull::new(sample_ptr).ok_or_else(|| {
let errno = io::Error::last_os_error();
match errno.raw_os_error() {
Some(E2BIG) => Error::with_invalid_data("requested size is too large"),
Some(ENOSPC) => Error::with_invalid_data("not enough space in the ring buffer"),
_ => Error::from(errno),
}
})?;
Ok(UserRingBufferSample {
ptr,
size,
submitted: false,
rb: self,
})
}
pub fn submit(&self, mut sample: UserRingBufferSample<'_>) -> Result<()> {
unsafe {
libbpf_sys::user_ring_buffer__submit(self.ptr.as_ptr(), sample.ptr.as_ptr());
}
sample.submitted = true;
Ok(())
}
}
impl AsRawLibbpf for UserRingBuffer {
type LibbpfType = libbpf_sys::user_ring_buffer;
fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
self.ptr
}
}
impl Drop for UserRingBuffer {
fn drop(&mut self) {
unsafe {
libbpf_sys::user_ring_buffer__free(self.ptr.as_ptr());
}
}
}