hash_map.rs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. use super::Result;
  2. use crate::bpf::map::util::{round_up, BpfMapUpdateElemFlags};
  3. use crate::bpf::map::{BpfCallBackFn, BpfMapCommonOps, BpfMapMeta};
  4. use crate::mm::percpu::{PerCpu, PerCpuVar};
  5. use crate::smp::cpu::ProcessorId;
  6. use alloc::{collections::BTreeMap, vec::Vec};
  7. use core::fmt::Debug;
  8. use system_error::SystemError;
  9. type BpfHashMapKey = Vec<u8>;
  10. type BpfHashMapValue = Vec<u8>;
  11. /// The hash map type is a generic map type with no restrictions on the structure of the key and value.
  12. /// Hash-maps are implemented using a hash table, allowing for lookups with arbitrary keys.
  13. ///
  14. /// See https://ebpf-docs.dylanreimerink.nl/linux/map-type/BPF_MAP_TYPE_HASH/
  15. #[derive(Debug)]
  16. pub struct BpfHashMap {
  17. _max_entries: u32,
  18. _key_size: u32,
  19. _value_size: u32,
  20. data: BTreeMap<BpfHashMapKey, BpfHashMapValue>,
  21. }
  22. impl BpfHashMap {
  23. pub fn new(attr: &BpfMapMeta) -> Result<Self> {
  24. if attr.value_size == 0 || attr.max_entries == 0 {
  25. return Err(SystemError::EINVAL);
  26. }
  27. let value_size = round_up(attr.value_size as usize, 8);
  28. Ok(Self {
  29. _max_entries: attr.max_entries,
  30. _key_size: attr.key_size,
  31. _value_size: value_size as u32,
  32. data: BTreeMap::new(),
  33. })
  34. }
  35. }
  36. impl BpfMapCommonOps for BpfHashMap {
  37. fn lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>> {
  38. let value = self.data.get(key).map(|v| v.as_slice());
  39. Ok(value)
  40. }
  41. fn update_elem(&mut self, key: &[u8], value: &[u8], flags: u64) -> Result<()> {
  42. let _flags = BpfMapUpdateElemFlags::from_bits_truncate(flags);
  43. self.data.insert(key.to_vec(), value.to_vec());
  44. Ok(())
  45. }
  46. fn delete_elem(&mut self, key: &[u8]) -> Result<()> {
  47. self.data.remove(key);
  48. Ok(())
  49. }
  50. fn for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, flags: u64) -> Result<u32> {
  51. if flags != 0 {
  52. return Err(SystemError::EINVAL);
  53. }
  54. let mut total_used = 0;
  55. for (key, value) in self.data.iter() {
  56. let res = cb(key, value, ctx);
  57. // return value: 0 - continue, 1 - stop and return
  58. if res != 0 {
  59. break;
  60. }
  61. total_used += 1;
  62. }
  63. Ok(total_used)
  64. }
  65. fn lookup_and_delete_elem(&mut self, key: &[u8], value: &mut [u8]) -> Result<()> {
  66. let v = self
  67. .data
  68. .get(key)
  69. .map(|v| v.as_slice())
  70. .ok_or(SystemError::ENOENT)?;
  71. value.copy_from_slice(v);
  72. self.data.remove(key);
  73. Ok(())
  74. }
  75. fn get_next_key(&self, key: Option<&[u8]>, next_key: &mut [u8]) -> Result<()> {
  76. let mut iter = self.data.iter();
  77. if let Some(key) = key {
  78. for (k, _) in iter.by_ref() {
  79. if k.as_slice() == key {
  80. break;
  81. }
  82. }
  83. }
  84. let res = iter.next();
  85. match res {
  86. Some((k, _)) => {
  87. next_key.copy_from_slice(k.as_slice());
  88. Ok(())
  89. }
  90. None => Err(SystemError::ENOENT),
  91. }
  92. }
  93. }
  94. /// This is the per-CPU variant of the [BpfHashMap] map type.
  95. ///
  96. /// See https://ebpf-docs.dylanreimerink.nl/linux/map-type/BPF_MAP_TYPE_PERCPU_HASH/
  97. pub struct PerCpuHashMap {
  98. per_cpu_maps: PerCpuVar<BpfHashMap>,
  99. }
  100. impl Debug for PerCpuHashMap {
  101. fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
  102. f.debug_struct("PerCpuHashMap")
  103. .field("maps", &self.per_cpu_maps)
  104. .finish()
  105. }
  106. }
  107. impl PerCpuHashMap {
  108. pub fn new(attr: &BpfMapMeta) -> Result<Self> {
  109. let num_cpus = PerCpu::MAX_CPU_NUM;
  110. let mut data = Vec::with_capacity(num_cpus as usize);
  111. for _ in 0..num_cpus {
  112. let array_map = BpfHashMap::new(attr)?;
  113. data.push(array_map);
  114. }
  115. let per_cpu_maps = PerCpuVar::new(data).ok_or(SystemError::EINVAL)?;
  116. Ok(PerCpuHashMap { per_cpu_maps })
  117. }
  118. }
  119. impl BpfMapCommonOps for PerCpuHashMap {
  120. fn lookup_elem(&mut self, key: &[u8]) -> Result<Option<&[u8]>> {
  121. self.per_cpu_maps.get_mut().lookup_elem(key)
  122. }
  123. fn update_elem(&mut self, key: &[u8], value: &[u8], flags: u64) -> Result<()> {
  124. self.per_cpu_maps.get_mut().update_elem(key, value, flags)
  125. }
  126. fn delete_elem(&mut self, key: &[u8]) -> Result<()> {
  127. self.per_cpu_maps.get_mut().delete_elem(key)
  128. }
  129. fn for_each_elem(&mut self, cb: BpfCallBackFn, ctx: *const u8, flags: u64) -> Result<u32> {
  130. self.per_cpu_maps.get_mut().for_each_elem(cb, ctx, flags)
  131. }
  132. fn lookup_and_delete_elem(&mut self, key: &[u8], value: &mut [u8]) -> Result<()> {
  133. self.per_cpu_maps
  134. .get_mut()
  135. .lookup_and_delete_elem(key, value)
  136. }
  137. fn lookup_percpu_elem(&mut self, key: &[u8], cpu: u32) -> Result<Option<&[u8]>> {
  138. unsafe {
  139. self.per_cpu_maps
  140. .force_get_mut(ProcessorId::new(cpu))
  141. .lookup_elem(key)
  142. }
  143. }
  144. fn get_next_key(&self, key: Option<&[u8]>, next_key: &mut [u8]) -> Result<()> {
  145. self.per_cpu_maps.get_mut().get_next_key(key, next_key)
  146. }
  147. fn first_value_ptr(&self) -> Result<*const u8> {
  148. self.per_cpu_maps.get_mut().first_value_ptr()
  149. }
  150. }