dev_map_hash.rs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. use core::{cell::UnsafeCell, mem, num::NonZeroU32, ptr::NonNull};
  2. use aya_ebpf_bindings::bindings::bpf_devmap_val;
  3. use aya_ebpf_cty::c_void;
  4. use super::{dev_map::DevMapValue, try_redirect_map};
  5. use crate::{
  6. bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH},
  7. helpers::bpf_map_lookup_elem,
  8. maps::PinningType,
  9. };
  10. /// A map of network devices.
  11. ///
  12. /// XDP programs can use this map to redirect packets to other network devices. It is similar to
  13. /// [`DevMap`](super::DevMap), but is an hash map rather than an array. Keys do not need to be
  14. /// contiguous nor start at zero, but there is a hashing cost to every lookup.
  15. ///
  16. /// # Minimum kernel version
  17. ///
  18. /// The minimum kernel version required to use this feature is 5.4.
  19. ///
  20. /// # Examples
  21. ///
  22. /// ```rust,no_run
  23. /// use aya_ebpf::{bindings::xdp_action, macros::{map, xdp}, maps::DevMapHash, programs::XdpContext};
  24. ///
  25. /// #[map]
  26. /// static MAP: DevMapHash = DevMapHash::with_max_entries(1, 0);
  27. ///
  28. /// #[xdp]
  29. /// fn xdp(_ctx: XdpContext) -> u32 {
  30. /// MAP.redirect(42, xdp_action::XDP_PASS as u64).unwrap_or(xdp_action::XDP_DROP)
  31. /// }
  32. /// ```
  33. #[repr(transparent)]
  34. pub struct DevMapHash {
  35. def: UnsafeCell<bpf_map_def>,
  36. }
  37. unsafe impl Sync for DevMapHash {}
  38. impl DevMapHash {
  39. /// Creates a [`DevMapHash`] with a set maximum number of elements.
  40. ///
  41. /// # Examples
  42. ///
  43. /// ```rust,no_run
  44. /// use aya_ebpf::{macros::map, maps::DevMapHash};
  45. ///
  46. /// #[map]
  47. /// static MAP: DevMapHash = DevMapHash::with_max_entries(8, 0);
  48. /// ```
  49. pub const fn with_max_entries(max_entries: u32, flags: u32) -> DevMapHash {
  50. DevMapHash {
  51. def: UnsafeCell::new(bpf_map_def {
  52. type_: BPF_MAP_TYPE_DEVMAP_HASH,
  53. key_size: mem::size_of::<u32>() as u32,
  54. value_size: mem::size_of::<bpf_devmap_val>() as u32,
  55. max_entries,
  56. map_flags: flags,
  57. id: 0,
  58. pinning: PinningType::None as u32,
  59. }),
  60. }
  61. }
  62. /// Creates a [`DevMapHash`] with a set maximum number of elements that can be pinned to the BPF
  63. /// File System (bpffs).
  64. ///
  65. /// # Examples
  66. ///
  67. /// ```rust,no_run
  68. /// use aya_ebpf::{macros::map, maps::DevMapHash};
  69. ///
  70. /// #[map]
  71. /// static MAP: DevMapHash = DevMapHash::pinned(8, 0);
  72. /// ```
  73. pub const fn pinned(max_entries: u32, flags: u32) -> DevMapHash {
  74. DevMapHash {
  75. def: UnsafeCell::new(bpf_map_def {
  76. type_: BPF_MAP_TYPE_DEVMAP_HASH,
  77. key_size: mem::size_of::<u32>() as u32,
  78. value_size: mem::size_of::<bpf_devmap_val>() as u32,
  79. max_entries,
  80. map_flags: flags,
  81. id: 0,
  82. pinning: PinningType::ByName as u32,
  83. }),
  84. }
  85. }
  86. /// Retrieves the interface index with `key` in the map.
  87. ///
  88. /// To actually redirect a packet, see [`DevMapHash::redirect`].
  89. ///
  90. /// # Examples
  91. ///
  92. /// ```rust,no_run
  93. /// use aya_ebpf::{macros::map, maps::DevMapHash};
  94. ///
  95. /// #[map]
  96. /// static MAP: DevMapHash = DevMapHash::with_max_entries(1, 0);
  97. ///
  98. /// let target_if_index = MAP.get(42).unwrap().if_index;
  99. ///
  100. /// // redirect to ifindex
  101. /// ```
  102. #[inline(always)]
  103. pub fn get(&self, key: u32) -> Option<DevMapValue> {
  104. unsafe {
  105. let value =
  106. bpf_map_lookup_elem(self.def.get() as *mut _, &key as *const _ as *const c_void);
  107. NonNull::new(value as *mut bpf_devmap_val).map(|p| DevMapValue {
  108. if_index: p.as_ref().ifindex,
  109. // SAFETY: map writes use fd, map reads use id.
  110. // https://elixir.bootlin.com/linux/v6.2/source/include/uapi/linux/bpf.h#L6136
  111. prog_id: NonZeroU32::new(p.as_ref().bpf_prog.id),
  112. })
  113. }
  114. }
  115. /// Redirects the current packet on the interface at `key`.
  116. ///
  117. /// The lower two bits of `flags` are used for the return code if the map lookup fails, which
  118. /// can be used as the XDP program's return code if a CPU cannot be found.
  119. ///
  120. /// # Examples
  121. ///
  122. /// ```rust,no_run
  123. /// use aya_ebpf::{bindings::xdp_action, macros::{map, xdp}, maps::DevMapHash, programs::XdpContext};
  124. ///
  125. /// #[map]
  126. /// static MAP: DevMapHash = DevMapHash::with_max_entries(8, 0);
  127. ///
  128. /// #[xdp]
  129. /// fn xdp(_ctx: XdpContext) -> u32 {
  130. /// MAP.redirect(7, 0).unwrap_or(xdp_action::XDP_DROP)
  131. /// }
  132. /// ```
  133. #[inline(always)]
  134. pub fn redirect(&self, key: u32, flags: u64) -> Result<u32, u32> {
  135. try_redirect_map(&self.def, key, flags)
  136. }
  137. }