ring_buf.rs 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. #![no_std]
  2. #![no_main]
  3. use aya_ebpf::{
  4. macros::{map, uprobe},
  5. maps::{PerCpuArray, RingBuf},
  6. programs::ProbeContext,
  7. };
  8. #[map]
  9. static RING_BUF: RingBuf = RingBuf::with_byte_size(0, 0);
  10. // This structure's definition is duplicated in userspace.
  11. #[repr(C)]
  12. struct Registers {
  13. dropped: u64,
  14. rejected: u64,
  15. }
  16. // Use a PerCpuArray to store the registers so that we can update the values from multiple CPUs
  17. // without needing synchronization. Atomics exist [1], but aren't exposed.
  18. //
  19. // [1]: https://lwn.net/Articles/838884/
  20. #[map]
  21. static REGISTERS: PerCpuArray<Registers> = PerCpuArray::with_max_entries(1, 0);
  22. #[uprobe]
  23. pub fn ring_buf_test(ctx: ProbeContext) {
  24. let Registers { dropped, rejected } = match REGISTERS.get_ptr_mut(0) {
  25. Some(regs) => unsafe { &mut *regs },
  26. None => return,
  27. };
  28. let mut entry = match RING_BUF.reserve::<u64>(0) {
  29. Some(entry) => entry,
  30. None => {
  31. *dropped += 1;
  32. return;
  33. }
  34. };
  35. // Write the first argument to the function back out to RING_BUF if it is even,
  36. // otherwise increment the counter in REJECTED. This exercises discarding data.
  37. let arg: u64 = match ctx.arg(0) {
  38. Some(arg) => arg,
  39. None => return,
  40. };
  41. if arg % 2 == 0 {
  42. entry.write(arg);
  43. entry.submit(0);
  44. } else {
  45. *rejected += 1;
  46. entry.discard(0);
  47. }
  48. }
  49. #[cfg(not(test))]
  50. #[panic_handler]
  51. fn panic(_info: &core::panic::PanicInfo) -> ! {
  52. loop {}
  53. }