ebpf_user/
ringbuf.rs

1use std::time::Duration;
2use super::{skeleton::MapRef, kind};
3
4pub struct RingBufferRef(MapRef);
5
6impl kind::AppItem for RingBufferRef {
7    const MAP: usize = 1;
8    const PROG: usize = 0;
9
10    fn named(name: &'static str) -> Self {
11        RingBufferRef(MapRef::named(name))
12    }
13
14    fn kind_mut(&mut self) -> kind::AppItemKindMut<'_> {
15        kind::AppItemKindMut::Map(&mut self.0)
16    }
17}
18
19pub struct RingBufferRegistry {
20    inner: *mut libbpf_sys::ring_buffer,
21    callbacks: Vec<Box<dyn FnMut(&[u8])>>,
22}
23
24impl Default for RingBufferRegistry {
25    fn default() -> Self {
26        use std::ptr;
27
28        RingBufferRegistry {
29            inner: ptr::null_mut(),
30            callbacks: Vec::with_capacity(256),
31        }
32    }
33}
34
35impl Drop for RingBufferRegistry {
36    fn drop(&mut self) {
37        if !self.inner.is_null() {
38            unsafe { libbpf_sys::ring_buffer__free(self.inner) };
39        }
40    }
41}
42
43impl RingBufferRegistry {
44    unsafe extern "C" fn cb(ctx: *mut cty::c_void, data: *mut cty::c_void, size: u64) -> i32 {
45        use std::slice;
46
47        let ctx = ctx as *mut Box<dyn FnMut(&[u8]) + 'static>;
48        let s = slice::from_raw_parts(data as *mut u8 as *const u8, size as _);
49        (*ctx)(s);
50        0
51    }
52
53    pub fn add<F>(&mut self, rb: &RingBufferRef, cb: F) -> Result<(), i32>
54    where
55        F: for<'r> FnMut(&'r [u8]) + 'static,
56    {
57        self.add_fd(rb.0.fd(), cb)
58    }
59
60    pub fn add_fd<F>(&mut self, map_fd: i32, cb: F) -> Result<(), i32>
61    where
62        F: for<'r> FnMut(&'r [u8]) + 'static,
63    {
64        use std::ptr;
65
66        let cb: Box<dyn FnMut(&[u8]) + 'static> = Box::new(cb);
67        self.callbacks.push(cb);
68        let ctx = self.callbacks.last_mut().unwrap() as *mut _;
69        if self.inner.is_null() {
70            self.inner = unsafe {
71                libbpf_sys::ring_buffer__new(map_fd, Some(Self::cb), ctx as _, ptr::null_mut())
72            };
73            Ok(())
74        } else {
75            let c = unsafe {
76                libbpf_sys::ring_buffer__add(self.inner, map_fd, Some(Self::cb), ctx as _)
77            };
78            if c != 0 {
79                Err(c)
80            } else {
81                Ok(())
82            }
83        }
84    }
85
86    pub fn poll(&self, timeout: Duration) -> Result<usize, i32> {
87        if self.inner.is_null() {
88            return Ok(0);
89        }
90
91        let c = unsafe { libbpf_sys::ring_buffer__poll(self.inner, timeout.as_millis() as i32) };
92
93        if c < 0 {
94            Err(c)
95        } else {
96            Ok(c as _)
97        }
98    }
99
100    pub fn consume(&self) -> Result<usize, i32> {
101        if self.inner.is_null() {
102            return Ok(0);
103        }
104
105        let c = unsafe { libbpf_sys::ring_buffer__consume(self.inner) };
106
107        if c < 0 {
108            Err(c)
109        } else {
110            Ok(c as _)
111        }
112    }
113
114    pub fn epoll_fd(&self) -> Option<i32> {
115        if self.inner.is_null() {
116            None
117        } else {
118            Some(unsafe { libbpf_sys::ring_buffer__epoll_fd(self.inner) })
119        }
120    }
121}