ring_buf.rs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. use core::{
  2. cell::UnsafeCell,
  3. mem,
  4. mem::MaybeUninit,
  5. ops::{Deref, DerefMut},
  6. };
  7. #[cfg(feature = "const_assert")]
  8. use const_assert::{Assert, IsTrue};
  9. use crate::{
  10. bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_RINGBUF},
  11. helpers::{
  12. bpf_ringbuf_discard, bpf_ringbuf_output, bpf_ringbuf_query, bpf_ringbuf_reserve,
  13. bpf_ringbuf_submit,
  14. },
  15. maps::PinningType,
  16. };
  17. #[repr(transparent)]
  18. pub struct RingBuf {
  19. def: UnsafeCell<bpf_map_def>,
  20. }
  21. unsafe impl Sync for RingBuf {}
  22. /// A ring buffer entry, returned from [`RingBuf::reserve`].
  23. ///
  24. /// You must [`submit`] or [`discard`] this entry before it gets dropped.
  25. ///
  26. /// [`submit`]: RingBufEntry::submit
  27. /// [`discard`]: RingBufEntry::discard
  28. #[must_use = "eBPF verifier requires ring buffer entries to be either submitted or discarded"]
  29. pub struct RingBufEntry<T: 'static>(&'static mut MaybeUninit<T>);
  30. impl<T> Deref for RingBufEntry<T> {
  31. type Target = MaybeUninit<T>;
  32. fn deref(&self) -> &Self::Target {
  33. self.0
  34. }
  35. }
  36. impl<T> DerefMut for RingBufEntry<T> {
  37. fn deref_mut(&mut self) -> &mut Self::Target {
  38. self.0
  39. }
  40. }
  41. impl<T> RingBufEntry<T> {
  42. /// Discard this ring buffer entry. The entry will be skipped by the userspace reader.
  43. pub fn discard(self, flags: u64) {
  44. unsafe { bpf_ringbuf_discard(self.0.as_mut_ptr() as *mut _, flags) };
  45. }
  46. /// Commit this ring buffer entry. The entry will be made visible to the userspace reader.
  47. pub fn submit(self, flags: u64) {
  48. unsafe { bpf_ringbuf_submit(self.0.as_mut_ptr() as *mut _, flags) };
  49. }
  50. }
  51. impl RingBuf {
  52. /// Declare an eBPF ring buffer.
  53. ///
  54. /// The linux kernel requires that `byte_size` be a power-of-2 multiple of the page size. The
  55. /// loading program may coerce the size when loading the map.
  56. pub const fn with_byte_size(byte_size: u32, flags: u32) -> Self {
  57. Self::new(byte_size, flags, PinningType::None)
  58. }
  59. /// Declare a pinned eBPF ring buffer.
  60. ///
  61. /// The linux kernel requires that `byte_size` be a power-of-2 multiple of the page size. The
  62. /// loading program may coerce the size when loading the map.
  63. pub const fn pinned(byte_size: u32, flags: u32) -> Self {
  64. Self::new(byte_size, flags, PinningType::ByName)
  65. }
  66. const fn new(byte_size: u32, flags: u32, pinning_type: PinningType) -> Self {
  67. Self {
  68. def: UnsafeCell::new(bpf_map_def {
  69. type_: BPF_MAP_TYPE_RINGBUF,
  70. key_size: 0,
  71. value_size: 0,
  72. max_entries: byte_size,
  73. map_flags: flags,
  74. id: 0,
  75. pinning: pinning_type as u32,
  76. }),
  77. }
  78. }
  79. /// Reserve memory in the ring buffer that can fit `T`.
  80. ///
  81. /// Returns `None` if the ring buffer is full.
  82. #[cfg(feature = "const_assert")]
  83. pub fn reserve<T: 'static>(&self, flags: u64) -> Option<RingBufEntry<T>>
  84. where
  85. Assert<{ 8 % mem::align_of::<T>() == 0 }>: IsTrue,
  86. {
  87. self.reserve_impl(flags)
  88. }
  89. /// Reserve memory in the ring buffer that can fit `T`.
  90. ///
  91. /// Returns `None` if the ring buffer is full.
  92. ///
  93. /// The kernel will reserve memory at an 8-bytes aligned boundary, so `mem::align_of<T>()` must
  94. /// be equal or smaller than 8. If you use this with a `T` that isn't properly aligned, this
  95. /// function will be compiled to a panic; depending on your panic_handler, this may make
  96. /// the eBPF program fail to load, or it may make it have undefined behavior.
  97. #[cfg(not(feature = "const_assert"))]
  98. pub fn reserve<T: 'static>(&self, flags: u64) -> Option<RingBufEntry<T>> {
  99. assert_eq!(8 % mem::align_of::<T>(), 0);
  100. self.reserve_impl(flags)
  101. }
  102. fn reserve_impl<T: 'static>(&self, flags: u64) -> Option<RingBufEntry<T>> {
  103. let ptr = unsafe {
  104. bpf_ringbuf_reserve(self.def.get() as *mut _, mem::size_of::<T>() as _, flags)
  105. } as *mut MaybeUninit<T>;
  106. unsafe { ptr.as_mut() }.map(|ptr| RingBufEntry(ptr))
  107. }
  108. /// Copy `data` to the ring buffer output.
  109. ///
  110. /// Consider using [`reserve`] and [`submit`] if `T` is statically sized and you want to save a
  111. /// copy from either a map buffer or the stack.
  112. ///
  113. /// Unlike [`reserve`], this function can handle dynamically sized types (which is hard to
  114. /// create in eBPF but still possible, e.g. by slicing an array).
  115. ///
  116. /// Note: `T` must be aligned to no more than 8 bytes; it's not possible to fulfill larger
  117. /// alignment requests. If you use this with a `T` that isn't properly aligned, this function will
  118. /// be compiled to a panic and silently make your eBPF program fail to load.
  119. /// See [here](https://github.com/torvalds/linux/blob/3f01e9fed/kernel/bpf/ringbuf.c#L418).
  120. ///
  121. /// [`reserve`]: RingBuf::reserve
  122. /// [`submit`]: RingBufEntry::submit
  123. pub fn output<T: ?Sized>(&self, data: &T, flags: u64) -> Result<(), i64> {
  124. assert_eq!(8 % mem::align_of_val(data), 0);
  125. let ret = unsafe {
  126. bpf_ringbuf_output(
  127. self.def.get() as *mut _,
  128. data as *const _ as *mut _,
  129. mem::size_of_val(data) as _,
  130. flags,
  131. )
  132. };
  133. if ret < 0 {
  134. Err(ret)
  135. } else {
  136. Ok(())
  137. }
  138. }
  139. /// Query various information about the ring buffer.
  140. ///
  141. /// Consult `bpf_ringbuf_query` documentation for a list of allowed flags.
  142. pub fn query(&self, flags: u64) -> u64 {
  143. unsafe { bpf_ringbuf_query(self.def.get() as *mut _, flags) }
  144. }
  145. }