mod.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. mod array_map;
  2. mod hash_map;
  3. mod lru;
  4. mod queue;
  5. mod util;
  6. use super::Result;
  7. use crate::bpf::map::array_map::{ArrayMap, PerCpuArrayMap, PerfEventArrayMap};
  8. use crate::bpf::map::hash_map::PerCpuHashMap;
  9. use crate::bpf::map::util::{BpfMapGetNextKeyArg, BpfMapMeta, BpfMapUpdateArg};
  10. use crate::filesystem::vfs::file::{File, FileMode};
  11. use crate::filesystem::vfs::syscall::ModeType;
  12. use crate::filesystem::vfs::{FilePrivateData, FileSystem, FileType, IndexNode, Metadata};
  13. use crate::include::bindings::linux_bpf::{bpf_attr, bpf_map_type};
  14. use crate::libs::casting::DowncastArc;
  15. use crate::libs::spinlock::{SpinLock, SpinLockGuard};
  16. use crate::process::ProcessManager;
  17. use crate::syscall::user_access::{UserBufferReader, UserBufferWriter};
  18. use alloc::boxed::Box;
  19. use alloc::string::String;
  20. use alloc::sync::Arc;
  21. use alloc::vec::Vec;
  22. use core::any::Any;
  23. use core::fmt::Debug;
  24. use intertrait::CastFromSync;
  25. use log::{error, info};
  26. use system_error::SystemError;
  27. #[derive(Debug)]
  28. pub struct BpfMap {
  29. inner_map: SpinLock<Box<dyn BpfMapCommonOps>>,
  30. meta: BpfMapMeta,
  31. }
  32. pub type BpfCallBackFn = fn(key: &[u8], value: &[u8], ctx: *const u8) -> i32;
  33. pub trait BpfMapCommonOps: Send + Sync + Debug + CastFromSync {
  34. /// Lookup an element in the map.
  35. ///
  36. /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_map_lookup_elem/
  37. fn lookup_elem(&mut self, _key: &[u8]) -> Result<Option<&[u8]>> {
  38. Err(SystemError::ENOSYS)
  39. }
  40. /// Update an element in the map.
  41. ///
  42. /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_map_update_elem/
  43. fn update_elem(&mut self, _key: &[u8], _value: &[u8], _flags: u64) -> Result<()> {
  44. Err(SystemError::ENOSYS)
  45. }
  46. /// Delete an element from the map.
  47. ///
  48. /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_map_delete_elem/
  49. fn delete_elem(&mut self, _key: &[u8]) -> Result<()> {
  50. Err(SystemError::ENOSYS)
  51. }
  52. /// For each element in map, call callback_fn function with map,
  53. /// callback_ctx and other map-specific parameters.
  54. ///
  55. /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_for_each_map_elem/
  56. fn for_each_elem(&mut self, _cb: BpfCallBackFn, _ctx: *const u8, _flags: u64) -> Result<u32> {
  57. Err(SystemError::ENOSYS)
  58. }
  59. /// Look up an element with the given key in the map referred to by the file descriptor fd,
  60. /// and if found, delete the element.
  61. fn lookup_and_delete_elem(&mut self, _key: &[u8], _value: &mut [u8]) -> Result<()> {
  62. Err(SystemError::ENOSYS)
  63. }
  64. /// erform a lookup in percpu map for an entry associated to key on cpu.
  65. fn lookup_percpu_elem(&mut self, _key: &[u8], _cpu: u32) -> Result<Option<&[u8]>> {
  66. Err(SystemError::ENOSYS)
  67. }
  68. /// Get the next key in the map. If key is None, get the first key.
  69. ///
  70. /// Called from syscall
  71. fn get_next_key(&self, _key: Option<&[u8]>, _next_key: &mut [u8]) -> Result<()> {
  72. Err(SystemError::ENOSYS)
  73. }
  74. /// Push an element value in map.
  75. fn push_elem(&mut self, _value: &[u8], _flags: u64) -> Result<()> {
  76. Err(SystemError::ENOSYS)
  77. }
  78. /// Pop an element value from map.
  79. fn pop_elem(&mut self, _value: &mut [u8]) -> Result<()> {
  80. Err(SystemError::ENOSYS)
  81. }
  82. /// Peek an element value from map.
  83. fn peek_elem(&self, _value: &mut [u8]) -> Result<()> {
  84. Err(SystemError::ENOSYS)
  85. }
  86. /// Freeze the map.
  87. ///
  88. /// It's useful for .rodata maps.
  89. fn freeze(&self) -> Result<()> {
  90. Err(SystemError::ENOSYS)
  91. }
  92. /// Get the first value pointer.
  93. fn first_value_ptr(&self) -> Result<*const u8> {
  94. Err(SystemError::ENOSYS)
  95. }
  96. }
  97. impl DowncastArc for dyn BpfMapCommonOps {
  98. fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any> {
  99. self
  100. }
  101. }
  102. impl BpfMap {
  103. pub fn new(map: Box<dyn BpfMapCommonOps>, meta: BpfMapMeta) -> Self {
  104. assert_ne!(meta.key_size, 0);
  105. BpfMap {
  106. inner_map: SpinLock::new(map),
  107. meta,
  108. }
  109. }
  110. pub fn inner_map(&self) -> &SpinLock<Box<dyn BpfMapCommonOps>> {
  111. &self.inner_map
  112. }
  113. pub fn key_size(&self) -> usize {
  114. self.meta.key_size as usize
  115. }
  116. pub fn value_size(&self) -> usize {
  117. self.meta.value_size as usize
  118. }
  119. }
  120. impl IndexNode for BpfMap {
  121. fn open(&self, _data: SpinLockGuard<FilePrivateData>, _mode: &FileMode) -> Result<()> {
  122. Ok(())
  123. }
  124. fn close(&self, _data: SpinLockGuard<FilePrivateData>) -> Result<()> {
  125. Ok(())
  126. }
  127. fn read_at(
  128. &self,
  129. _offset: usize,
  130. _len: usize,
  131. _buf: &mut [u8],
  132. _data: SpinLockGuard<FilePrivateData>,
  133. ) -> Result<usize> {
  134. Err(SystemError::ENOSYS)
  135. }
  136. fn write_at(
  137. &self,
  138. _offset: usize,
  139. _len: usize,
  140. _buf: &[u8],
  141. _data: SpinLockGuard<FilePrivateData>,
  142. ) -> Result<usize> {
  143. Err(SystemError::ENOSYS)
  144. }
  145. fn metadata(&self) -> Result<Metadata> {
  146. let meta = Metadata {
  147. mode: ModeType::from_bits_truncate(0o755),
  148. file_type: FileType::File,
  149. ..Default::default()
  150. };
  151. Ok(meta)
  152. }
  153. fn resize(&self, _len: usize) -> Result<()> {
  154. Ok(())
  155. }
  156. fn fs(&self) -> Arc<dyn FileSystem> {
  157. todo!("BpfMap does not have a filesystem")
  158. }
  159. fn as_any_ref(&self) -> &dyn Any {
  160. self
  161. }
  162. fn list(&self) -> Result<Vec<String>> {
  163. Err(SystemError::ENOSYS)
  164. }
  165. fn absolute_path(&self) -> core::result::Result<String, SystemError> {
  166. Ok(String::from("BpfMap"))
  167. }
  168. }
  169. /// Create a map and return a file descriptor that refers to
  170. /// the map. The close-on-exec file descriptor flag
  171. /// is automatically enabled for the new file descriptor.
  172. ///
  173. /// See https://ebpf-docs.dylanreimerink.nl/linux/syscall/BPF_MAP_CREATE/
  174. pub fn bpf_map_create(attr: &bpf_attr) -> Result<usize> {
  175. let map_meta = BpfMapMeta::try_from(attr)?;
  176. info!("The map attr is {:#?}", map_meta);
  177. let map: Box<dyn BpfMapCommonOps> = match map_meta.map_type {
  178. bpf_map_type::BPF_MAP_TYPE_ARRAY => {
  179. let array_map = ArrayMap::new(&map_meta)?;
  180. Box::new(array_map)
  181. }
  182. bpf_map_type::BPF_MAP_TYPE_PERCPU_ARRAY => {
  183. let per_cpu_array_map = PerCpuArrayMap::new(&map_meta)?;
  184. Box::new(per_cpu_array_map)
  185. }
  186. bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY => {
  187. let perf_event_array_map = PerfEventArrayMap::new(&map_meta)?;
  188. Box::new(perf_event_array_map)
  189. }
  190. bpf_map_type::BPF_MAP_TYPE_CPUMAP
  191. | bpf_map_type::BPF_MAP_TYPE_DEVMAP
  192. | bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH => {
  193. error!("bpf map type {:?} not implemented", map_meta.map_type);
  194. Err(SystemError::EINVAL)?
  195. }
  196. bpf_map_type::BPF_MAP_TYPE_HASH => {
  197. let hash_map = hash_map::BpfHashMap::new(&map_meta)?;
  198. Box::new(hash_map)
  199. }
  200. bpf_map_type::BPF_MAP_TYPE_PERCPU_HASH => {
  201. let per_cpu_hash_map = PerCpuHashMap::new(&map_meta)?;
  202. Box::new(per_cpu_hash_map)
  203. }
  204. bpf_map_type::BPF_MAP_TYPE_QUEUE => {
  205. let queue_map = queue::QueueMap::new(&map_meta)?;
  206. Box::new(queue_map)
  207. }
  208. bpf_map_type::BPF_MAP_TYPE_STACK => {
  209. let stack_map = queue::StackMap::new(&map_meta)?;
  210. Box::new(stack_map)
  211. }
  212. bpf_map_type::BPF_MAP_TYPE_LRU_HASH => {
  213. let lru_hash_map = lru::LruMap::new(&map_meta)?;
  214. Box::new(lru_hash_map)
  215. }
  216. bpf_map_type::BPF_MAP_TYPE_LRU_PERCPU_HASH => {
  217. let lru_per_cpu_hash_map = lru::PerCpuLruMap::new(&map_meta)?;
  218. Box::new(lru_per_cpu_hash_map)
  219. }
  220. _ => {
  221. unimplemented!("bpf map type {:?} not implemented", map_meta.map_type)
  222. }
  223. };
  224. let bpf_map = BpfMap::new(map, map_meta);
  225. let fd_table = ProcessManager::current_pcb().fd_table();
  226. let file = File::new(Arc::new(bpf_map), FileMode::O_RDWR | FileMode::O_CLOEXEC)?;
  227. let fd = fd_table.write().alloc_fd(file, None).map(|x| x as usize)?;
  228. info!("create map with fd: [{}]", fd);
  229. Ok(fd)
  230. }
  231. /// Create or update an element (key/value pair) in a specified map.
  232. ///
  233. /// See https://ebpf-docs.dylanreimerink.nl/linux/syscall/BPF_MAP_UPDATE_ELEM/
  234. pub fn bpf_map_update_elem(attr: &bpf_attr) -> Result<usize> {
  235. let arg = BpfMapUpdateArg::from(attr);
  236. info!("<bpf_map_update_elem>: {:#x?}", arg);
  237. let map = get_map_file(arg.map_fd as i32)?;
  238. let meta = &map.meta;
  239. let key_size = meta.key_size as usize;
  240. let value_size = meta.value_size as usize;
  241. let key_buf = UserBufferReader::new(arg.key as *const u8, key_size, true)?;
  242. let value_buf = UserBufferReader::new(arg.value as *const u8, value_size, true)?;
  243. let key = key_buf.read_from_user(0)?;
  244. let value = value_buf.read_from_user(0)?;
  245. map.inner_map.lock().update_elem(key, value, arg.flags)?;
  246. info!("bpf_map_update_elem ok");
  247. Ok(0)
  248. }
  249. pub fn bpf_map_freeze(attr: &bpf_attr) -> Result<usize> {
  250. let arg = BpfMapUpdateArg::from(attr);
  251. let map_fd = arg.map_fd;
  252. info!("<bpf_map_freeze>: map_fd: {:}", map_fd);
  253. let map = get_map_file(map_fd as i32)?;
  254. map.inner_map.lock().freeze()?;
  255. Ok(0)
  256. }
  257. /// Look up an element by key in a specified map and return its value.
  258. ///
  259. /// See https://ebpf-docs.dylanreimerink.nl/linux/syscall/BPF_MAP_LOOKUP_ELEM/
  260. pub fn bpf_lookup_elem(attr: &bpf_attr) -> Result<usize> {
  261. let arg = BpfMapUpdateArg::from(attr);
  262. // info!("<bpf_lookup_elem>: {:#x?}", arg);
  263. let map = get_map_file(arg.map_fd as _)?;
  264. let meta = &map.meta;
  265. let key_size = meta.key_size as usize;
  266. let value_size = meta.value_size as usize;
  267. let key_buf = UserBufferReader::new(arg.key as *const u8, key_size, true)?;
  268. let mut value_buf = UserBufferWriter::new(arg.value as *mut u8, value_size, true)?;
  269. let key = key_buf.read_from_user(0)?;
  270. let mut inner = map.inner_map.lock();
  271. let r_value = inner.lookup_elem(key)?;
  272. if let Some(r_value) = r_value {
  273. value_buf.copy_to_user(r_value, 0)?;
  274. Ok(0)
  275. } else {
  276. Err(SystemError::ENOENT)
  277. }
  278. }
  279. /// Look up an element by key in a specified map and return the key of the next element.
  280. ///
  281. /// - If key is `None`, the operation returns zero and sets the next_key pointer to the key of the first element.
  282. /// - If key is `Some(T)`, the operation returns zero and sets the next_key pointer to the key of the next element.
  283. /// - If key is the last element, returns -1 and errno is set to ENOENT.
  284. ///
  285. /// See https://ebpf-docs.dylanreimerink.nl/linux/syscall/BPF_MAP_GET_NEXT_KEY/
  286. pub fn bpf_map_get_next_key(attr: &bpf_attr) -> Result<usize> {
  287. let arg = BpfMapGetNextKeyArg::from(attr);
  288. // info!("<bpf_map_get_next_key>: {:#x?}", arg);
  289. let map = get_map_file(arg.map_fd as i32)?;
  290. let meta = &map.meta;
  291. let key_size = meta.key_size as usize;
  292. let key = if let Some(key_ptr) = arg.key {
  293. let key_buf = UserBufferReader::new(key_ptr as *const u8, key_size, true)?;
  294. let key = key_buf.read_from_user(0)?.to_vec();
  295. Some(key)
  296. } else {
  297. None
  298. };
  299. let key = key.as_deref();
  300. let mut next_key_buf = UserBufferWriter::new(arg.next_key as *mut u8, key_size, true)?;
  301. let inner = map.inner_map.lock();
  302. let next_key = next_key_buf.buffer(0)?;
  303. inner.get_next_key(key, next_key)?;
  304. // info!("next_key: {:?}", next_key);
  305. Ok(0)
  306. }
  307. /// Look up and delete an element by key in a specified map.
  308. ///
  309. /// # WARN
  310. ///
  311. /// Not all map types (particularly array maps) support this operation,
  312. /// instead a zero value can be written to the map value. Check the map types page to check for support.
  313. ///
  314. /// See https://ebpf-docs.dylanreimerink.nl/linux/syscall/BPF_MAP_DELETE_ELEM/
  315. pub fn bpf_map_delete_elem(attr: &bpf_attr) -> Result<usize> {
  316. let arg = BpfMapUpdateArg::from(attr);
  317. // info!("<bpf_map_delete_elem>: {:#x?}", arg);
  318. let map = get_map_file(arg.map_fd as i32)?;
  319. let meta = &map.meta;
  320. let key_size = meta.key_size as usize;
  321. let key_buf = UserBufferReader::new(arg.key as *const u8, key_size, true)?;
  322. let key = key_buf.read_from_user(0)?;
  323. map.inner_map.lock().delete_elem(key)?;
  324. Ok(0)
  325. }
  326. /// Iterate and fetch multiple elements in a map.
  327. ///
  328. /// See https://ebpf-docs.dylanreimerink.nl/linux/syscall/BPF_MAP_LOOKUP_BATCH/
  329. pub fn bpf_map_lookup_batch(_attr: &bpf_attr) -> Result<usize> {
  330. todo!()
  331. }
  332. /// Look up an element with the given key in the map referred to by the file descriptor fd,
  333. /// and if found, delete the element.
  334. ///
  335. /// For BPF_MAP_TYPE_QUEUE and BPF_MAP_TYPE_STACK map types, the flags argument needs to be set to 0,
  336. /// but for other map types, it may be specified as:
  337. /// - BPF_F_LOCK : If this flag is set, the command will acquire the spin-lock of the map value we are looking up.
  338. ///
  339. /// If the map contains no spin-lock in its value, -EINVAL will be returned by the command.
  340. ///
  341. /// The BPF_MAP_TYPE_QUEUE and BPF_MAP_TYPE_STACK map types implement this command as a “pop” operation,
  342. /// deleting the top element rather than one corresponding to key.
  343. /// The key and key_len parameters should be zeroed when issuing this operation for these map types.
  344. ///
  345. /// This command is only valid for the following map types:
  346. /// - BPF_MAP_TYPE_QUEUE
  347. /// - BPF_MAP_TYPE_STACK
  348. /// - BPF_MAP_TYPE_HASH
  349. /// - BPF_MAP_TYPE_PERCPU_HASH
  350. /// - BPF_MAP_TYPE_LRU_HASH
  351. /// - BPF_MAP_TYPE_LRU_PERCPU_HASH
  352. ///
  353. ///
  354. /// See https://ebpf-docs.dylanreimerink.nl/linux/syscall/BPF_MAP_LOOKUP_AND_DELETE_ELEM/
  355. pub fn bpf_map_lookup_and_delete_elem(attr: &bpf_attr) -> Result<usize> {
  356. let arg = BpfMapUpdateArg::from(attr);
  357. // info!("<bpf_map_lookup_and_delete_elem>: {:#x?}", arg);
  358. let map = get_map_file(arg.map_fd as i32)?;
  359. let meta = &map.meta;
  360. let key_size = meta.key_size as usize;
  361. let value_size = meta.value_size as usize;
  362. let key_buf = UserBufferReader::new(arg.key as *const u8, key_size, true)?;
  363. let mut value_buf = UserBufferWriter::new(arg.value as *mut u8, value_size, true)?;
  364. let value = value_buf.buffer(0)?;
  365. let key = key_buf.read_from_user(0)?;
  366. let mut inner = map.inner_map.lock();
  367. inner.lookup_and_delete_elem(key, value)?;
  368. Ok(0)
  369. }
  370. fn get_map_file(fd: i32) -> Result<Arc<BpfMap>> {
  371. let fd_table = ProcessManager::current_pcb().fd_table();
  372. let map = fd_table
  373. .read()
  374. .get_file_by_fd(fd)
  375. .ok_or(SystemError::EBADF)?;
  376. let map = map
  377. .inode()
  378. .downcast_arc::<BpfMap>()
  379. .ok_or(SystemError::EINVAL)?;
  380. Ok(map)
  381. }