mod.rs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  1. //! Data structures used to setup and share data with eBPF programs.
  2. //!
  3. //! The eBPF platform provides data structures - maps in eBPF speak - that are
  4. //! used to setup and share data with eBPF programs. When you call
  5. //! [`Bpf::load_file`](crate::Bpf::load_file) or
  6. //! [`Bpf::load`](crate::Bpf::load), all the maps defined in the eBPF code get
  7. //! initialized and can then be accessed using [`Bpf::map`](crate::Bpf::map),
  8. //! [`Bpf::map_mut`](crate::Bpf::map_mut), or [`Bpf::take_map`](crate::Bpf::take_map).
  9. //!
  10. //! # Typed maps
  11. //!
  12. //! The eBPF API includes many map types each supporting different operations.
  13. //! [`Bpf::map`](crate::Bpf::map), [`Bpf::map_mut`](crate::Bpf::map_mut), and
  14. //! [`Bpf::take_map`](crate::Bpf::take_map) always return the
  15. //! opaque [`&Map`](crate::maps::Map), [`&mut Map`](crate::maps::Map), and [`Map`](crate::maps::Map)
  16. //! types respectively. Those three types can be converted to *typed maps* using
  17. //! the [`TryFrom`](std::convert::TryFrom) or [`TryInto`](std::convert::TryInto)
  18. //! trait. For example:
  19. //!
  20. //! ```no_run
  21. //! # let mut bpf = aya::Bpf::load(&[])?;
  22. //! use aya::maps::SockMap;
  23. //! use aya::programs::SkMsg;
  24. //!
  25. //! let intercept_egress = SockMap::try_from(bpf.map_mut("INTERCEPT_EGRESS").unwrap())?;
  26. //! let map_fd = intercept_egress.fd()?;
  27. //! let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
  28. //! prog.load()?;
  29. //! prog.attach(map_fd)?;
  30. //!
  31. //! # Ok::<(), aya::BpfError>(())
  32. //! ```
  33. //!
  34. //! # Maps and `Pod` values
  35. //!
  36. //! Many map operations copy data from kernel space to user space and vice
  37. //! versa. Because of that, all map values must be plain old data and therefore
  38. //! implement the [Pod] trait.
  39. use std::{
  40. ffi::CString,
  41. fmt, io,
  42. marker::PhantomData,
  43. mem,
  44. ops::Deref,
  45. os::fd::{AsRawFd, RawFd},
  46. path::Path,
  47. ptr,
  48. };
  49. use crate::util::KernelVersion;
  50. use libc::{getrlimit, rlimit, RLIMIT_MEMLOCK, RLIM_INFINITY};
  51. use log::warn;
  52. use thiserror::Error;
  53. use crate::{
  54. obj::{self, parse_map_info},
  55. pin::PinError,
  56. sys::{
  57. bpf_create_map, bpf_get_object, bpf_map_get_info_by_fd, bpf_map_get_next_key,
  58. bpf_pin_object,
  59. },
  60. util::nr_cpus,
  61. PinningType, Pod,
  62. };
  63. pub mod array;
  64. pub mod bloom_filter;
  65. pub mod hash_map;
  66. pub mod lpm_trie;
  67. pub mod perf;
  68. pub mod queue;
  69. pub mod sock;
  70. pub mod stack;
  71. pub mod stack_trace;
  72. pub use array::{Array, PerCpuArray, ProgramArray};
  73. pub use bloom_filter::BloomFilter;
  74. pub use hash_map::{HashMap, PerCpuHashMap};
  75. pub use lpm_trie::LpmTrie;
  76. #[cfg(feature = "async")]
  77. #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
  78. pub use perf::AsyncPerfEventArray;
  79. pub use perf::PerfEventArray;
  80. pub use queue::Queue;
  81. pub use sock::{SockHash, SockMap};
  82. pub use stack::Stack;
  83. pub use stack_trace::StackTraceMap;
  84. #[derive(Error, Debug)]
  85. /// Errors occuring from working with Maps
  86. pub enum MapError {
  87. /// Invalid map type encontered
  88. #[error("invalid map type {map_type}")]
  89. InvalidMapType {
  90. /// The map type
  91. map_type: u32,
  92. },
  93. /// Invalid map name encountered
  94. #[error("invalid map name `{name}`")]
  95. InvalidName {
  96. /// The map name
  97. name: String,
  98. },
  99. /// The map has not been created
  100. #[error("the map has not been created")]
  101. NotCreated,
  102. /// The map has already been created
  103. #[error("the map `{name}` has already been created")]
  104. AlreadyCreated {
  105. /// Map name
  106. name: String,
  107. },
  108. /// Failed to create map
  109. #[error("failed to create map `{name}` with code {code}")]
  110. CreateError {
  111. /// Map name
  112. name: String,
  113. /// Error code
  114. code: libc::c_long,
  115. #[source]
  116. /// Original io::Error
  117. io_error: io::Error,
  118. },
  119. /// Invalid key size
  120. #[error("invalid key size {size}, expected {expected}")]
  121. InvalidKeySize {
  122. /// Size encountered
  123. size: usize,
  124. /// Size expected
  125. expected: usize,
  126. },
  127. /// Invalid value size
  128. #[error("invalid value size {size}, expected {expected}")]
  129. InvalidValueSize {
  130. /// Size encountered
  131. size: usize,
  132. /// Size expected
  133. expected: usize,
  134. },
  135. /// Index is out of bounds
  136. #[error("the index is {index} but `max_entries` is {max_entries}")]
  137. OutOfBounds {
  138. /// Index accessed
  139. index: u32,
  140. /// Map size
  141. max_entries: u32,
  142. },
  143. /// Key not found
  144. #[error("key not found")]
  145. KeyNotFound,
  146. /// Element not found
  147. #[error("element not found")]
  148. ElementNotFound,
  149. /// Progam Not Loaded
  150. #[error("the program is not loaded")]
  151. ProgramNotLoaded,
  152. /// Syscall failed
  153. #[error("the `{call}` syscall failed")]
  154. SyscallError {
  155. /// Syscall Name
  156. call: &'static str,
  157. /// Original io::Error
  158. io_error: io::Error,
  159. },
  160. /// Could not pin map by name
  161. #[error("map `{name:?}` requested pinning by name. pinning failed")]
  162. PinError {
  163. /// The map name
  164. name: Option<String>,
  165. /// The reason for the failure
  166. #[source]
  167. error: PinError,
  168. },
  169. }
  170. /// A map file descriptor.
  171. pub struct MapFd(RawFd);
  172. impl AsRawFd for MapFd {
  173. fn as_raw_fd(&self) -> RawFd {
  174. self.0
  175. }
  176. }
  177. #[derive(PartialEq, Eq, PartialOrd, Ord)]
  178. struct RlimitSize(usize);
  179. impl fmt::Display for RlimitSize {
  180. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  181. if self.0 < 1024 {
  182. write!(f, "{} bytes", self.0)
  183. } else if self.0 < 1024 * 1024 {
  184. write!(f, "{} KiB", self.0 / 1024)
  185. } else {
  186. write!(f, "{} MiB", self.0 / 1024 / 1024)
  187. }
  188. }
  189. }
  190. /// Raises a warning about rlimit. Should be used only if creating a map was not
  191. /// successful.
  192. fn maybe_warn_rlimit() {
  193. let mut limit = std::mem::MaybeUninit::<rlimit>::uninit();
  194. let ret = unsafe { getrlimit(RLIMIT_MEMLOCK, limit.as_mut_ptr()) };
  195. if ret == 0 {
  196. let limit = unsafe { limit.assume_init() };
  197. let limit: RlimitSize = RlimitSize(limit.rlim_cur.try_into().unwrap());
  198. if limit.0 == RLIM_INFINITY.try_into().unwrap() {
  199. return;
  200. }
  201. warn!(
  202. "RLIMIT_MEMLOCK value is {}, not RLIM_INFNITY; if experiencing problems with creating \
  203. maps, try raising RMILIT_MEMLOCK either to RLIM_INFINITY or to a higher value sufficient \
  204. for size of your maps",
  205. limit
  206. );
  207. }
  208. }
  209. /// eBPF map types.
  210. #[derive(Debug)]
  211. pub enum Map {
  212. /// A [`Array`] map
  213. Array(MapData),
  214. /// A [`PerCpuArray`] map
  215. PerCpuArray(MapData),
  216. /// A [`ProgramArray`] map
  217. ProgramArray(MapData),
  218. /// A [`HashMap`] map
  219. HashMap(MapData),
  220. /// A [`PerCpuHashMap`] map
  221. PerCpuHashMap(MapData),
  222. /// A [`HashMap`] map that uses a LRU eviction policy.
  223. LruHashMap(MapData),
  224. /// A [`PerCpuHashMap`] map that uses a LRU eviction policy.
  225. PerCpuLruHashMap(MapData),
  226. /// A [`PerfEventArray`] map
  227. PerfEventArray(MapData),
  228. /// A [`SockMap`] map
  229. SockMap(MapData),
  230. /// A [`SockHash`] map
  231. SockHash(MapData),
  232. /// A [`BloomFilter`] map
  233. BloomFilter(MapData),
  234. /// A [`LpmTrie`] map
  235. LpmTrie(MapData),
  236. /// A [`Stack`] map
  237. Stack(MapData),
  238. /// A [`StackTraceMap`] map
  239. StackTraceMap(MapData),
  240. /// A [`Queue`] map
  241. Queue(MapData),
  242. }
  243. impl Map {
  244. /// Returns the low level map type.
  245. fn map_type(&self) -> u32 {
  246. match self {
  247. Map::Array(map) => map.obj.map_type(),
  248. Map::PerCpuArray(map) => map.obj.map_type(),
  249. Map::ProgramArray(map) => map.obj.map_type(),
  250. Map::HashMap(map) => map.obj.map_type(),
  251. Map::LruHashMap(map) => map.obj.map_type(),
  252. Map::PerCpuHashMap(map) => map.obj.map_type(),
  253. Map::PerCpuLruHashMap(map) => map.obj.map_type(),
  254. Map::PerfEventArray(map) => map.obj.map_type(),
  255. Map::SockHash(map) => map.obj.map_type(),
  256. Map::SockMap(map) => map.obj.map_type(),
  257. Map::BloomFilter(map) => map.obj.map_type(),
  258. Map::LpmTrie(map) => map.obj.map_type(),
  259. Map::Stack(map) => map.obj.map_type(),
  260. Map::StackTraceMap(map) => map.obj.map_type(),
  261. Map::Queue(map) => map.obj.map_type(),
  262. }
  263. }
  264. }
  265. macro_rules! impl_try_from_map {
  266. ($($tx:ident from Map::$ty:ident),+ $(,)?) => {
  267. $(
  268. impl<'a> TryFrom<&'a Map> for $tx<&'a MapData> {
  269. type Error = MapError;
  270. fn try_from(map: &'a Map) -> Result<$tx<&'a MapData>, MapError> {
  271. match map {
  272. Map::$ty(m) => {
  273. $tx::new(m)
  274. },
  275. _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
  276. }
  277. }
  278. }
  279. impl<'a,> TryFrom<&'a mut Map> for $tx<&'a mut MapData> {
  280. type Error = MapError;
  281. fn try_from(map: &'a mut Map) -> Result<$tx<&'a mut MapData>, MapError> {
  282. match map {
  283. Map::$ty(m) => {
  284. $tx::new(m)
  285. },
  286. _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
  287. }
  288. }
  289. }
  290. impl TryFrom<Map> for $tx<MapData> {
  291. type Error = MapError;
  292. fn try_from(map: Map) -> Result<$tx<MapData>, MapError> {
  293. match map {
  294. Map::$ty(m) => {
  295. $tx::new(m)
  296. },
  297. _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
  298. }
  299. }
  300. }
  301. )+
  302. }
  303. }
  304. impl_try_from_map!(
  305. ProgramArray from Map::ProgramArray,
  306. SockMap from Map::SockMap,
  307. PerfEventArray from Map::PerfEventArray,
  308. StackTraceMap from Map::StackTraceMap,
  309. );
  310. #[cfg(feature = "async")]
  311. #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
  312. impl_try_from_map!(
  313. AsyncPerfEventArray from Map::PerfEventArray,
  314. );
  315. macro_rules! impl_try_from_map_generic_key_or_value {
  316. ($($ty:ident),+ $(,)?) => {
  317. $(
  318. impl<'a, V:Pod> TryFrom<&'a Map> for $ty<&'a MapData, V> {
  319. type Error = MapError;
  320. fn try_from(map: &'a Map) -> Result<$ty<&'a MapData , V>, MapError> {
  321. match map {
  322. Map::$ty(m) => {
  323. $ty::new(m)
  324. },
  325. _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
  326. }
  327. }
  328. }
  329. impl<'a,V: Pod> TryFrom<&'a mut Map> for $ty<&'a mut MapData, V> {
  330. type Error = MapError;
  331. fn try_from(map: &'a mut Map) -> Result<$ty<&'a mut MapData, V>, MapError> {
  332. match map {
  333. Map::$ty(m) => {
  334. $ty::new(m)
  335. },
  336. _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
  337. }
  338. }
  339. }
  340. impl<V: Pod> TryFrom<Map> for $ty<MapData, V> {
  341. type Error = MapError;
  342. fn try_from(map: Map) -> Result<$ty<MapData, V>, MapError> {
  343. match map {
  344. Map::$ty(m) => {
  345. $ty::new(m)
  346. },
  347. _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
  348. }
  349. }
  350. }
  351. )+
  352. }
  353. }
  354. impl_try_from_map_generic_key_or_value!(Array, PerCpuArray, SockHash, BloomFilter, Queue, Stack,);
  355. macro_rules! impl_try_from_map_generic_key_and_value {
  356. ($($ty:ident),+ $(,)?) => {
  357. $(
  358. impl<'a, V: Pod, K: Pod> TryFrom<&'a Map> for $ty<&'a MapData, V, K> {
  359. type Error = MapError;
  360. fn try_from(map: &'a Map) -> Result<$ty<&'a MapData,V,K>, MapError> {
  361. match map {
  362. Map::$ty(m) => {
  363. $ty::new(m)
  364. },
  365. _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
  366. }
  367. }
  368. }
  369. impl<'a,V: Pod,K: Pod> TryFrom<&'a mut Map> for $ty<&'a mut MapData, V, K> {
  370. type Error = MapError;
  371. fn try_from(map: &'a mut Map) -> Result<$ty<&'a mut MapData, V, K>, MapError> {
  372. match map {
  373. Map::$ty(m) => {
  374. $ty::new(m)
  375. },
  376. _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}),
  377. }
  378. }
  379. }
  380. impl<V: Pod, K: Pod> TryFrom<Map> for $ty<MapData, V, K> {
  381. type Error = MapError;
  382. fn try_from(map: Map) -> Result<$ty<MapData, V, K>, MapError> {
  383. match map {
  384. Map::$ty(m) => $ty::new(m),
  385. _ => Err(MapError::InvalidMapType { map_type: map.map_type() }),
  386. }
  387. }
  388. }
  389. )+
  390. }
  391. }
  392. impl_try_from_map_generic_key_and_value!(HashMap, PerCpuHashMap, LpmTrie);
  393. pub(crate) fn check_bounds(map: &MapData, index: u32) -> Result<(), MapError> {
  394. let max_entries = map.obj.max_entries();
  395. if index >= max_entries {
  396. Err(MapError::OutOfBounds { index, max_entries })
  397. } else {
  398. Ok(())
  399. }
  400. }
  401. pub(crate) fn check_kv_size<K, V>(map: &MapData) -> Result<(), MapError> {
  402. let size = mem::size_of::<K>();
  403. let expected = map.obj.key_size() as usize;
  404. if size != expected {
  405. return Err(MapError::InvalidKeySize { size, expected });
  406. }
  407. let size = mem::size_of::<V>();
  408. let expected = map.obj.value_size() as usize;
  409. if size != expected {
  410. return Err(MapError::InvalidValueSize { size, expected });
  411. };
  412. Ok(())
  413. }
  414. pub(crate) fn check_v_size<V>(map: &MapData) -> Result<(), MapError> {
  415. let size = mem::size_of::<V>();
  416. let expected = map.obj.value_size() as usize;
  417. if size != expected {
  418. return Err(MapError::InvalidValueSize { size, expected });
  419. };
  420. Ok(())
  421. }
  422. /// A generic handle to a BPF map.
  423. ///
  424. /// You should never need to use this unless you're implementing a new map type.
  425. #[derive(Debug)]
  426. pub struct MapData {
  427. pub(crate) obj: obj::Map,
  428. pub(crate) fd: Option<RawFd>,
  429. pub(crate) btf_fd: Option<RawFd>,
  430. /// Indicates if this map has been pinned to bpffs
  431. pub pinned: bool,
  432. }
  433. impl MapData {
  434. /// Creates a new map with the provided `name`
  435. pub fn create(&mut self, name: &str) -> Result<RawFd, MapError> {
  436. if self.fd.is_some() {
  437. return Err(MapError::AlreadyCreated { name: name.into() });
  438. }
  439. let c_name = CString::new(name).map_err(|_| MapError::InvalidName { name: name.into() })?;
  440. #[cfg(not(test))]
  441. let kernel_version = KernelVersion::current().unwrap();
  442. #[cfg(test)]
  443. let kernel_version = KernelVersion::new(0xff, 0xff, 0xff);
  444. let fd = bpf_create_map(&c_name, &self.obj, self.btf_fd, kernel_version).map_err(
  445. |(code, io_error)| {
  446. if kernel_version < KernelVersion::new(5, 11, 0) {
  447. maybe_warn_rlimit();
  448. }
  449. MapError::CreateError {
  450. name: name.into(),
  451. code,
  452. io_error,
  453. }
  454. },
  455. )? as RawFd;
  456. self.fd = Some(fd);
  457. Ok(fd)
  458. }
  459. pub(crate) fn open_pinned<P: AsRef<Path>>(
  460. &mut self,
  461. name: &str,
  462. path: P,
  463. ) -> Result<RawFd, MapError> {
  464. if self.fd.is_some() {
  465. return Err(MapError::AlreadyCreated { name: name.into() });
  466. }
  467. let map_path = path.as_ref().join(name);
  468. let path_string = CString::new(map_path.to_str().unwrap()).unwrap();
  469. let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| MapError::SyscallError {
  470. call: "BPF_OBJ_GET",
  471. io_error,
  472. })? as RawFd;
  473. self.fd = Some(fd);
  474. Ok(fd)
  475. }
  476. /// Loads a map from a pinned path in bpffs.
  477. pub fn from_pin<P: AsRef<Path>>(path: P) -> Result<MapData, MapError> {
  478. let path_string =
  479. CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| {
  480. MapError::PinError {
  481. name: None,
  482. error: PinError::InvalidPinPath {
  483. error: e.to_string(),
  484. },
  485. }
  486. })?;
  487. let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| MapError::SyscallError {
  488. call: "BPF_OBJ_GET",
  489. io_error,
  490. })? as RawFd;
  491. let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| MapError::SyscallError {
  492. call: "BPF_MAP_GET_INFO_BY_FD",
  493. io_error,
  494. })?;
  495. Ok(MapData {
  496. obj: parse_map_info(info, PinningType::ByName),
  497. fd: Some(fd),
  498. btf_fd: None,
  499. pinned: true,
  500. })
  501. }
  502. /// Loads a map from a [`RawFd`].
  503. ///
  504. /// If loading from a BPF Filesystem (bpffs) you should use [`Map::from_pin`](crate::maps::MapData::from_pin).
  505. /// This API is intended for cases where you have received a valid BPF FD from some other means.
  506. /// For example, you received an FD over Unix Domain Socket.
  507. pub fn from_fd(fd: RawFd) -> Result<MapData, MapError> {
  508. let info = bpf_map_get_info_by_fd(fd).map_err(|io_error| MapError::SyscallError {
  509. call: "BPF_OBJ_GET",
  510. io_error,
  511. })?;
  512. Ok(MapData {
  513. obj: parse_map_info(info, PinningType::None),
  514. fd: Some(fd),
  515. btf_fd: None,
  516. pinned: false,
  517. })
  518. }
  519. pub(crate) fn fd_or_err(&self) -> Result<RawFd, MapError> {
  520. self.fd.ok_or(MapError::NotCreated)
  521. }
  522. pub(crate) fn pin<P: AsRef<Path>>(&mut self, name: &str, path: P) -> Result<(), PinError> {
  523. if self.pinned {
  524. return Err(PinError::AlreadyPinned { name: name.into() });
  525. }
  526. let map_path = path.as_ref().join(name);
  527. let fd = self.fd.ok_or(PinError::NoFd {
  528. name: name.to_string(),
  529. })?;
  530. let path_string = CString::new(map_path.to_string_lossy().into_owned()).map_err(|e| {
  531. PinError::InvalidPinPath {
  532. error: e.to_string(),
  533. }
  534. })?;
  535. bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| PinError::SyscallError {
  536. name: "BPF_OBJ_PIN",
  537. io_error,
  538. })?;
  539. self.pinned = true;
  540. Ok(())
  541. }
  542. /// Returns the file descriptor of the map.
  543. ///
  544. /// Can be converted to [`RawFd`] using [`AsRawFd`].
  545. pub fn fd(&self) -> Option<MapFd> {
  546. self.fd.map(MapFd)
  547. }
  548. }
  549. impl Drop for MapData {
  550. fn drop(&mut self) {
  551. // TODO: Replace this with an OwnedFd once that is stabilized.
  552. if let Some(fd) = self.fd.take() {
  553. unsafe { libc::close(fd) };
  554. }
  555. }
  556. }
  557. impl Clone for MapData {
  558. fn clone(&self) -> MapData {
  559. MapData {
  560. obj: self.obj.clone(),
  561. fd: self.fd.map(|fd| unsafe { libc::dup(fd) }),
  562. btf_fd: self.btf_fd,
  563. pinned: self.pinned,
  564. }
  565. }
  566. }
  567. /// An iterable map
  568. pub trait IterableMap<K: Pod, V> {
  569. /// Get a generic map handle
  570. fn map(&self) -> &MapData;
  571. /// Get the value for the provided `key`
  572. fn get(&self, key: &K) -> Result<V, MapError>;
  573. }
  574. /// Iterator returned by `map.keys()`.
  575. pub struct MapKeys<'coll, K: Pod> {
  576. map: &'coll MapData,
  577. err: bool,
  578. key: Option<K>,
  579. }
  580. impl<'coll, K: Pod> MapKeys<'coll, K> {
  581. fn new(map: &'coll MapData) -> MapKeys<'coll, K> {
  582. MapKeys {
  583. map,
  584. err: false,
  585. key: None,
  586. }
  587. }
  588. }
  589. impl<K: Pod> Iterator for MapKeys<'_, K> {
  590. type Item = Result<K, MapError>;
  591. fn next(&mut self) -> Option<Result<K, MapError>> {
  592. if self.err {
  593. return None;
  594. }
  595. let fd = match self.map.fd_or_err() {
  596. Ok(fd) => fd,
  597. Err(e) => {
  598. self.err = true;
  599. return Some(Err(e));
  600. }
  601. };
  602. match bpf_map_get_next_key(fd, self.key.as_ref()) {
  603. Ok(Some(key)) => {
  604. self.key = Some(key);
  605. Some(Ok(key))
  606. }
  607. Ok(None) => {
  608. self.key = None;
  609. None
  610. }
  611. Err((_, io_error)) => {
  612. self.err = true;
  613. Some(Err(MapError::SyscallError {
  614. call: "bpf_map_get_next_key",
  615. io_error,
  616. }))
  617. }
  618. }
  619. }
  620. }
  621. /// Iterator returned by `map.iter()`.
  622. pub struct MapIter<'coll, K: Pod, V, I: IterableMap<K, V>> {
  623. keys: MapKeys<'coll, K>,
  624. map: &'coll I,
  625. _v: PhantomData<V>,
  626. }
  627. impl<'coll, K: Pod, V, I: IterableMap<K, V>> MapIter<'coll, K, V, I> {
  628. fn new(map: &'coll I) -> MapIter<'coll, K, V, I> {
  629. MapIter {
  630. keys: MapKeys::new(map.map()),
  631. map,
  632. _v: PhantomData,
  633. }
  634. }
  635. }
  636. impl<K: Pod, V, I: IterableMap<K, V>> Iterator for MapIter<'_, K, V, I> {
  637. type Item = Result<(K, V), MapError>;
  638. fn next(&mut self) -> Option<Self::Item> {
  639. loop {
  640. match self.keys.next() {
  641. Some(Ok(key)) => match self.map.get(&key) {
  642. Ok(value) => return Some(Ok((key, value))),
  643. Err(MapError::KeyNotFound) => continue,
  644. Err(e) => return Some(Err(e)),
  645. },
  646. Some(Err(e)) => return Some(Err(e)),
  647. None => return None,
  648. }
  649. }
  650. }
  651. }
  652. pub(crate) struct PerCpuKernelMem {
  653. bytes: Vec<u8>,
  654. }
  655. impl PerCpuKernelMem {
  656. pub(crate) fn as_mut_ptr(&mut self) -> *mut u8 {
  657. self.bytes.as_mut_ptr()
  658. }
  659. }
  660. /// A slice of per-CPU values.
  661. ///
  662. /// Used by maps that implement per-CPU storage like [`PerCpuHashMap`].
  663. ///
  664. /// # Examples
  665. ///
  666. /// ```no_run
  667. /// # #[derive(thiserror::Error, Debug)]
  668. /// # enum Error {
  669. /// # #[error(transparent)]
  670. /// # IO(#[from] std::io::Error),
  671. /// # #[error(transparent)]
  672. /// # Map(#[from] aya::maps::MapError),
  673. /// # #[error(transparent)]
  674. /// # Bpf(#[from] aya::BpfError)
  675. /// # }
  676. /// # let bpf = aya::Bpf::load(&[])?;
  677. /// use aya::maps::PerCpuValues;
  678. /// use aya::util::nr_cpus;
  679. ///
  680. /// let values = PerCpuValues::try_from(vec![42u32; nr_cpus()?])?;
  681. /// # Ok::<(), Error>(())
  682. /// ```
  683. #[derive(Debug)]
  684. pub struct PerCpuValues<T: Pod> {
  685. values: Box<[T]>,
  686. }
  687. impl<T: Pod> TryFrom<Vec<T>> for PerCpuValues<T> {
  688. type Error = io::Error;
  689. fn try_from(values: Vec<T>) -> Result<Self, Self::Error> {
  690. let nr_cpus = nr_cpus()?;
  691. if values.len() != nr_cpus {
  692. return Err(io::Error::new(
  693. io::ErrorKind::InvalidInput,
  694. format!("not enough values ({}), nr_cpus: {}", values.len(), nr_cpus),
  695. ));
  696. }
  697. Ok(PerCpuValues {
  698. values: values.into_boxed_slice(),
  699. })
  700. }
  701. }
  702. impl<T: Pod> PerCpuValues<T> {
  703. pub(crate) fn alloc_kernel_mem() -> Result<PerCpuKernelMem, io::Error> {
  704. let value_size = (mem::size_of::<T>() + 7) & !7;
  705. Ok(PerCpuKernelMem {
  706. bytes: vec![0u8; nr_cpus()? * value_size],
  707. })
  708. }
  709. pub(crate) unsafe fn from_kernel_mem(mem: PerCpuKernelMem) -> PerCpuValues<T> {
  710. let mem_ptr = mem.bytes.as_ptr() as usize;
  711. let value_size = (mem::size_of::<T>() + 7) & !7;
  712. let mut values = Vec::new();
  713. let mut offset = 0;
  714. while offset < mem.bytes.len() {
  715. values.push(ptr::read_unaligned((mem_ptr + offset) as *const _));
  716. offset += value_size;
  717. }
  718. PerCpuValues {
  719. values: values.into_boxed_slice(),
  720. }
  721. }
  722. pub(crate) fn build_kernel_mem(&self) -> Result<PerCpuKernelMem, io::Error> {
  723. let mut mem = PerCpuValues::<T>::alloc_kernel_mem()?;
  724. let mem_ptr = mem.as_mut_ptr() as usize;
  725. let value_size = (mem::size_of::<T>() + 7) & !7;
  726. for i in 0..self.values.len() {
  727. unsafe { ptr::write_unaligned((mem_ptr + i * value_size) as *mut _, self.values[i]) };
  728. }
  729. Ok(mem)
  730. }
  731. }
  732. impl<T: Pod> Deref for PerCpuValues<T> {
  733. type Target = Box<[T]>;
  734. fn deref(&self) -> &Self::Target {
  735. &self.values
  736. }
  737. }
  738. #[cfg(test)]
  739. mod tests {
  740. use libc::EFAULT;
  741. use matches::assert_matches;
  742. use crate::{
  743. bpf_map_def,
  744. generated::{bpf_cmd, bpf_map_type::BPF_MAP_TYPE_HASH},
  745. maps::MapData,
  746. obj::{maps::LegacyMap, BpfSectionKind},
  747. sys::{override_syscall, Syscall},
  748. };
  749. use super::*;
  750. fn new_obj_map() -> obj::Map {
  751. obj::Map::Legacy(LegacyMap {
  752. def: bpf_map_def {
  753. map_type: BPF_MAP_TYPE_HASH as u32,
  754. key_size: 4,
  755. value_size: 4,
  756. max_entries: 1024,
  757. ..Default::default()
  758. },
  759. section_index: 0,
  760. section_kind: BpfSectionKind::Maps,
  761. symbol_index: Some(0),
  762. data: Vec::new(),
  763. })
  764. }
  765. fn new_map() -> MapData {
  766. MapData {
  767. obj: new_obj_map(),
  768. fd: None,
  769. pinned: false,
  770. btf_fd: None,
  771. }
  772. }
  773. #[test]
  774. fn test_create() {
  775. override_syscall(|call| match call {
  776. Syscall::Bpf {
  777. cmd: bpf_cmd::BPF_MAP_CREATE,
  778. ..
  779. } => Ok(42),
  780. _ => Err((-1, io::Error::from_raw_os_error(EFAULT))),
  781. });
  782. let mut map = new_map();
  783. assert_matches!(map.create("foo"), Ok(42));
  784. assert_eq!(map.fd, Some(42));
  785. assert_matches!(map.create("foo"), Err(MapError::AlreadyCreated { .. }));
  786. }
  787. #[test]
  788. fn test_create_failed() {
  789. override_syscall(|_| Err((-42, io::Error::from_raw_os_error(EFAULT))));
  790. let mut map = new_map();
  791. let ret = map.create("foo");
  792. assert_matches!(ret, Err(MapError::CreateError { .. }));
  793. if let Err(MapError::CreateError {
  794. name,
  795. code,
  796. io_error,
  797. }) = ret
  798. {
  799. assert_eq!(name, "foo");
  800. assert_eq!(code, -42);
  801. assert_eq!(io_error.raw_os_error(), Some(EFAULT));
  802. }
  803. assert_eq!(map.fd, None);
  804. }
  805. }