libbpf_rs/
user_ringbuf.rs1use libc::E2BIG;
2use libc::ENOSPC;
3use std::io;
4use std::ops::Deref;
5use std::ops::DerefMut;
6use std::os::fd::AsRawFd;
7use std::os::raw::c_uint;
8use std::os::raw::c_void;
9use std::ptr::null_mut;
10use std::ptr::NonNull;
11use std::slice::from_raw_parts;
12use std::slice::from_raw_parts_mut;
13
14use crate::AsRawLibbpf;
15use crate::Error;
16use crate::MapCore;
17use crate::MapType;
18use crate::Result;
19
20#[derive(Debug)]
27pub struct UserRingBufferSample<'slf> {
28 ptr: NonNull<c_void>,
30
31 size: usize,
33
34 rb: &'slf UserRingBuffer,
37
38 submitted: bool,
40}
41
42impl Deref for UserRingBufferSample<'_> {
43 type Target = [u8];
44
45 fn deref(&self) -> &Self::Target {
46 unsafe { from_raw_parts(self.ptr.as_ptr() as *const u8, self.size) }
47 }
48}
49
50impl DerefMut for UserRingBufferSample<'_> {
51 fn deref_mut(&mut self) -> &mut Self::Target {
52 unsafe { from_raw_parts_mut(self.ptr.as_ptr().cast::<u8>(), self.size) }
53 }
54}
55
56impl Drop for UserRingBufferSample<'_> {
57 #[doc(alias = "user_ring_buffer__discard")]
58 fn drop(&mut self) {
59 if !self.submitted {
62 unsafe {
63 libbpf_sys::user_ring_buffer__discard(self.rb.ptr.as_ptr(), self.ptr.as_ptr());
64 }
65 }
66 }
67}
68
69#[derive(Debug)]
72#[doc(alias = "user_ring_buffer")]
73pub struct UserRingBuffer {
74 ptr: NonNull<libbpf_sys::user_ring_buffer>,
76}
77
78impl UserRingBuffer {
79 #[doc(alias = "user_ring_buffer__new")]
85 pub fn new(map: &dyn MapCore) -> Result<Self> {
86 if map.map_type() != MapType::UserRingBuf {
87 return Err(Error::with_invalid_data("must use a UserRingBuf map"));
88 }
89
90 let fd = map.as_fd();
91 let raw_ptr = unsafe { libbpf_sys::user_ring_buffer__new(fd.as_raw_fd(), null_mut()) };
92
93 let ptr = NonNull::new(raw_ptr).ok_or_else(|| {
94 io::Error::last_os_error()
96 })?;
97
98 Ok(Self { ptr })
99 }
100
101 #[doc(alias = "user_ring_buffer__reserve")]
114 pub fn reserve(&self, size: usize) -> Result<UserRingBufferSample<'_>> {
115 let sample_ptr =
116 unsafe { libbpf_sys::user_ring_buffer__reserve(self.ptr.as_ptr(), size as c_uint) };
117
118 let ptr = NonNull::new(sample_ptr).ok_or_else(|| {
119 let errno = io::Error::last_os_error();
121 match errno.raw_os_error() {
122 Some(E2BIG) => Error::with_invalid_data("requested size is too large"),
123 Some(ENOSPC) => Error::with_invalid_data("not enough space in the ring buffer"),
124 _ => Error::from(errno),
125 }
126 })?;
127
128 Ok(UserRingBufferSample {
129 ptr,
130 size,
131 submitted: false,
132 rb: self,
133 })
134 }
135
136 #[doc(alias = "user_ring_buffer__submit")]
145 pub fn submit(&self, mut sample: UserRingBufferSample<'_>) -> Result<()> {
146 unsafe {
147 libbpf_sys::user_ring_buffer__submit(self.ptr.as_ptr(), sample.ptr.as_ptr());
148 }
149
150 sample.submitted = true;
151
152 Ok(())
156 }
157}
158
159impl AsRawLibbpf for UserRingBuffer {
160 type LibbpfType = libbpf_sys::user_ring_buffer;
161
162 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
164 self.ptr
165 }
166}
167
168impl Drop for UserRingBuffer {
169 #[doc(alias = "user_ring_buffer__free")]
170 fn drop(&mut self) {
171 unsafe {
172 libbpf_sys::user_ring_buffer__free(self.ptr.as_ptr());
173 }
174 }
175}