aya_friday/bpf.rs
1use std::{
2 borrow::Cow,
3 collections::{HashMap, HashSet},
4 fs, io, iter,
5 os::fd::{AsFd as _, AsRawFd as _},
6 path::{Path, PathBuf},
7 sync::{Arc, LazyLock},
8};
9
10use aya_obj::{
11 EbpfSectionKind, Features, Object, ParseError, ProgramSection,
12 btf::{Btf, BtfError, BtfFeatures, BtfRelocationError},
13 generated::{BPF_F_SLEEPABLE, BPF_F_XDP_HAS_FRAGS, bpf_map_type},
14 relocation::EbpfRelocationError,
15};
16use log::{debug, warn};
17use thiserror::Error;
18
19use crate::{
20 maps::{Map, MapData, MapError},
21 programs::{
22 BtfTracePoint, CgroupDevice, CgroupSkb, CgroupSock, CgroupSockAddr, CgroupSockopt,
23 CgroupSysctl, Extension, FEntry, FExit, FlowDissector, Iter, KProbe, LircMode2, Lsm,
24 LsmCgroup, PerfEvent, ProbeKind, Program, ProgramData, ProgramError, RawTracePoint,
25 SchedClassifier, SkLookup, SkMsg, SkReuseport, SkSkb, SockOps, SocketFilter, TracePoint,
26 UProbe, Xdp,
27 },
28 sys::{
29 bpf_load_btf, is_bpf_cookie_supported, is_bpf_global_data_supported,
30 is_btf_datasec_supported, is_btf_datasec_zero_supported, is_btf_decl_tag_supported,
31 is_btf_enum64_supported, is_btf_float_supported, is_btf_func_global_supported,
32 is_btf_func_supported, is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported,
33 is_probe_read_kernel_supported, is_prog_id_supported, is_prog_name_supported,
34 retry_with_verifier_logs,
35 },
36 util::{bytes_of, bytes_of_slice, nr_cpus, page_size},
37};
38
39/// Marker trait for types that can safely be converted to and from byte slices.
40///
41/// # Safety
42///
43/// This trait is unsafe because it allows for the conversion of types to and
44/// from byte slices.
45pub unsafe trait Pod: Copy + 'static {}
46
47macro_rules! unsafe_impl_pod {
48 ($($struct_name:ident),+ $(,)?) => {
49 $(
50 unsafe impl Pod for $struct_name { }
51 )+
52 }
53}
54
55unsafe_impl_pod!(i8, u8, i16, u16, i32, u32, i64, u64, u128, i128);
56
57// It only makes sense that an array of POD types is itself POD
58unsafe impl<T: Pod, const N: usize> Pod for [T; N] {}
59
60pub use aya_obj::maps::{PinningType, bpf_map_def};
61
62pub(crate) static FEATURES: LazyLock<Features> = LazyLock::new(detect_features);
63
64fn detect_features() -> Features {
65 let btf = is_btf_supported().then(|| {
66 BtfFeatures::new(
67 is_btf_func_supported(),
68 is_btf_func_global_supported(),
69 is_btf_datasec_supported(),
70 is_btf_datasec_zero_supported(),
71 is_btf_float_supported(),
72 is_btf_decl_tag_supported(),
73 is_btf_type_tag_supported(),
74 is_btf_enum64_supported(),
75 )
76 });
77 let f = Features::new(
78 is_prog_name_supported(),
79 is_probe_read_kernel_supported(),
80 is_perf_link_supported(),
81 is_bpf_global_data_supported(),
82 is_bpf_cookie_supported(),
83 is_prog_id_supported(bpf_map_type::BPF_MAP_TYPE_CPUMAP),
84 is_prog_id_supported(bpf_map_type::BPF_MAP_TYPE_DEVMAP),
85 btf,
86 );
87 debug!("BPF Feature Detection: {f:#?}");
88 f
89}
90
91/// Returns a reference to the detected BPF features.
92pub fn features() -> &'static Features {
93 &FEATURES
94}
95
96/// Builder style API for advanced loading of eBPF programs.
97///
98/// Loading eBPF code involves a few steps, including loading maps and applying
99/// relocations. You can use `EbpfLoader` to customize some of the loading
100/// options.
101///
102/// # Examples
103///
104/// ```no_run
105/// use aya::{EbpfLoader, Btf};
106/// use std::fs;
107///
108/// let bpf = EbpfLoader::new()
109/// // load the BTF data from /sys/kernel/btf/vmlinux
110/// .btf(Btf::from_sys_fs().ok().as_ref())
111/// // load pinned maps from /sys/fs/bpf/my-program
112/// .default_map_pin_directory("/sys/fs/bpf/my-program")
113/// // finally load the code
114/// .load_file("file.o")?;
115/// # Ok::<(), aya::EbpfError>(())
116/// ```
117#[derive(Debug)]
118pub struct EbpfLoader<'a> {
119 btf: Option<Cow<'a, Btf>>,
120 default_map_pin_directory: Option<PathBuf>,
121 globals: HashMap<&'a str, (&'a [u8], bool)>,
122 // Max entries overrides the max_entries field of the map that matches the provided name
123 // before the map is created.
124 max_entries: HashMap<&'a str, u32>,
125 // Map pin path overrides the pin path of the map that matches the provided name before
126 // it is created.
127 map_pin_path_by_name: HashMap<&'a str, Cow<'a, Path>>,
128
129 extensions: HashSet<&'a str>,
130 verifier_log_level: VerifierLogLevel,
131 allow_unsupported_maps: bool,
132}
133
134/// Builder style API for advanced loading of eBPF programs.
135#[deprecated(since = "0.13.0", note = "use `EbpfLoader` instead")]
136pub type BpfLoader<'a> = EbpfLoader<'a>;
137
138bitflags::bitflags! {
139 /// Used to set the verifier log level flags in [EbpfLoader](EbpfLoader::verifier_log_level()).
140 #[derive(Clone, Copy, Debug)]
141 pub struct VerifierLogLevel: u32 {
142 /// Sets no verifier logging.
143 const DISABLE = 0;
144 /// Enables debug verifier logging.
145 const DEBUG = 1;
146 /// Enables verbose verifier logging.
147 const VERBOSE = 2 | Self::DEBUG.bits();
148 /// Enables verifier stats.
149 const STATS = 4;
150 }
151}
152
153impl Default for VerifierLogLevel {
154 fn default() -> Self {
155 Self::DEBUG | Self::STATS
156 }
157}
158
159impl<'a> EbpfLoader<'a> {
160 /// Creates a new loader instance.
161 pub fn new() -> Self {
162 Self {
163 btf: Btf::from_sys_fs().ok().map(Cow::Owned),
164 default_map_pin_directory: None,
165 globals: HashMap::new(),
166 max_entries: HashMap::new(),
167 map_pin_path_by_name: HashMap::new(),
168 extensions: HashSet::new(),
169 verifier_log_level: VerifierLogLevel::default(),
170 allow_unsupported_maps: false,
171 }
172 }
173
174 /// Sets the target [BTF](Btf) info.
175 ///
176 /// The loader defaults to loading `BTF` info using [`Btf::from_sys_fs`].
177 /// Use this method if you want to load `BTF` from a custom location or
178 /// pass `None` to disable `BTF` relocations entirely.
179 /// # Example
180 ///
181 /// ```no_run
182 /// use aya::{EbpfLoader, Btf, Endianness};
183 ///
184 /// let bpf = EbpfLoader::new()
185 /// // load the BTF data from a custom location
186 /// .btf(Btf::parse_file("/custom_btf_file", Endianness::default()).ok().as_ref())
187 /// .load_file("file.o")?;
188 ///
189 /// # Ok::<(), aya::EbpfError>(())
190 /// ```
191 pub fn btf(&mut self, btf: Option<&'a Btf>) -> &mut Self {
192 self.btf = btf.map(Cow::Borrowed);
193 self
194 }
195
196 /// Allows programs containing unsupported maps to be loaded.
197 ///
198 /// By default programs containing unsupported maps will fail to load. This
199 /// method can be used to configure the loader so that unsupported maps will
200 /// be loaded, but won't be accessible from userspace. Can be useful when
201 /// using unsupported maps that are only accessed from eBPF code and don't
202 /// require any userspace interaction.
203 ///
204 /// # Example
205 ///
206 /// ```no_run
207 /// use aya::EbpfLoader;
208 ///
209 /// let bpf = EbpfLoader::new()
210 /// .allow_unsupported_maps()
211 /// .load_file("file.o")?;
212 /// # Ok::<(), aya::EbpfError>(())
213 /// ```
214 ///
215 pub const fn allow_unsupported_maps(&mut self) -> &mut Self {
216 self.allow_unsupported_maps = true;
217 self
218 }
219
220 /// Sets the base directory path for pinned maps.
221 ///
222 /// Pinned maps will be loaded from `path/MAP_NAME`.
223 /// The caller is responsible for ensuring the directory exists.
224 ///
225 /// Note that if a path is provided for a specific map via [`EbpfLoader::map_pin_path`],
226 /// it will take precedence over this path.
227 ///
228 /// # Example
229 ///
230 /// ```no_run
231 /// use aya::EbpfLoader;
232 ///
233 /// let bpf = EbpfLoader::new()
234 /// .default_map_pin_directory("/sys/fs/bpf/my-program")
235 /// .load_file("file.o")?;
236 /// # Ok::<(), aya::EbpfError>(())
237 /// ```
238 ///
239 pub fn default_map_pin_directory<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
240 self.default_map_pin_directory = Some(path.as_ref().to_owned());
241 self
242 }
243
244 /// Override the value of a global variable.
245 ///
246 /// If the `must_exist` argument is `true`, [`EbpfLoader::load`] will fail with [`ParseError::SymbolNotFound`] if the loaded object code does not contain the variable.
247 ///
248 /// From Rust eBPF, a global variable can be defined using `Global` - please refer to the `aya-ebpf` documentation.
249 ///
250 /// The type of a global variable must be `Pod` (plain old data), for instance `u8`, `u32` and
251 /// all other primitive types. You may use custom types as well, but you must ensure that those
252 /// types are `#[repr(C)]` and only contain other `Pod` types.
253 ///
254 /// The type used here and in the eBPF must be the same (or have a compatible layout).
255 ///
256 /// From C eBPF, you would annotate a global variable as `volatile const`.
257 ///
258 /// # Example
259 ///
260 /// ```no_run
261 /// use aya::EbpfLoader;
262 ///
263 /// let bpf = EbpfLoader::new()
264 /// .override_global("VERSION", &2, true)
265 /// .override_global("PIDS", &[1234u16, 5678], true)
266 /// .load_file("file.o")?;
267 /// # Ok::<(), aya::EbpfError>(())
268 /// ```
269 ///
270 pub fn override_global<T: Into<GlobalData<'a>>>(
271 &mut self,
272 name: &'a str,
273 value: T,
274 must_exist: bool,
275 ) -> &mut Self {
276 self.globals.insert(name, (value.into().bytes, must_exist));
277 self
278 }
279
280 /// Override the value of a global variable.
281 #[deprecated(since = "0.13.2", note = "please use `override_global` instead")]
282 pub fn set_global<T: Into<GlobalData<'a>>>(
283 &mut self,
284 name: &'a str,
285 value: T,
286 must_exist: bool,
287 ) -> &mut Self {
288 self.override_global(name, value, must_exist)
289 }
290
291 /// Set the `max_entries` for specified map.
292 ///
293 /// Overwrite the value of `max_entries` of the map that matches
294 /// the provided name before the map is created.
295 ///
296 /// # Example
297 ///
298 /// ```no_run
299 /// use aya::EbpfLoader;
300 ///
301 /// let bpf = EbpfLoader::new()
302 /// .map_max_entries("map", 64)
303 /// .load_file("file.o")?;
304 /// # Ok::<(), aya::EbpfError>(())
305 /// ```
306 ///
307 pub fn map_max_entries(&mut self, name: &'a str, size: u32) -> &mut Self {
308 self.max_entries.insert(name, size);
309 self
310 }
311
312 /// Set the `max_entries` for specified map.
313 #[deprecated(since = "0.13.2", note = "please use `map_max_entries` instead")]
314 pub fn set_max_entries(&mut self, name: &'a str, size: u32) -> &mut Self {
315 self.map_max_entries(name, size)
316 }
317
318 /// Set the pin path for the map that matches the provided name.
319 ///
320 /// Note that this is an absolute path to the pinned map; it is not a prefix
321 /// to be combined with the map name, and it is not relative to the
322 /// configured base directory for pinned maps.
323 ///
324 /// Each call to this function with the same name overwrites the path to the
325 /// pinned map; last one wins.
326 ///
327 /// # Example
328 ///
329 /// ```no_run
330 /// # use std::path::Path;
331 ///
332 /// # let mut loader = aya::EbpfLoader::new();
333 /// # let pin_path = Path::new("/sys/fs/bpf/my-pinned-map");
334 /// let bpf = loader
335 /// .map_pin_path("map", pin_path)
336 /// .load_file("file.o")?;
337 /// # Ok::<(), aya::EbpfError>(())
338 /// ```
339 ///
340 pub fn map_pin_path<P: Into<Cow<'a, Path>>>(&mut self, name: &'a str, path: P) -> &mut Self {
341 self.map_pin_path_by_name.insert(name, path.into());
342 self
343 }
344
345 /// Treat the provided program as an [`Extension`]
346 ///
347 /// When attempting to load the program with the provided `name`
348 /// the program type is forced to be ] [`Extension`] and is not
349 /// inferred from the ELF section name.
350 ///
351 /// # Example
352 ///
353 /// ```no_run
354 /// use aya::EbpfLoader;
355 ///
356 /// let bpf = EbpfLoader::new()
357 /// .extension("myfunc")
358 /// .load_file("file.o")?;
359 /// # Ok::<(), aya::EbpfError>(())
360 /// ```
361 ///
362 pub fn extension(&mut self, name: &'a str) -> &mut Self {
363 self.extensions.insert(name);
364 self
365 }
366
367 /// Sets BPF verifier log level.
368 ///
369 /// # Example
370 ///
371 /// ```no_run
372 /// use aya::{EbpfLoader, VerifierLogLevel};
373 ///
374 /// let bpf = EbpfLoader::new()
375 /// .verifier_log_level(VerifierLogLevel::VERBOSE | VerifierLogLevel::STATS)
376 /// .load_file("file.o")?;
377 /// # Ok::<(), aya::EbpfError>(())
378 /// ```
379 ///
380 pub const fn verifier_log_level(&mut self, level: VerifierLogLevel) -> &mut Self {
381 self.verifier_log_level = level;
382 self
383 }
384
385 /// Loads eBPF bytecode from a file.
386 ///
387 /// # Examples
388 ///
389 /// ```no_run
390 /// use aya::EbpfLoader;
391 ///
392 /// let bpf = EbpfLoader::new().load_file("file.o")?;
393 /// # Ok::<(), aya::EbpfError>(())
394 /// ```
395 pub fn load_file<P: AsRef<Path>>(&mut self, path: P) -> Result<Ebpf, EbpfError> {
396 let path = path.as_ref();
397 self.load(&fs::read(path).map_err(|error| EbpfError::FileError {
398 path: path.to_owned(),
399 error,
400 })?)
401 }
402
403 /// Loads eBPF bytecode from a buffer.
404 ///
405 /// The buffer needs to be 4-bytes aligned. If you are bundling the bytecode statically
406 /// into your binary, it is recommended that you do so using
407 /// [`include_bytes_aligned`](crate::include_bytes_aligned).
408 ///
409 /// # Examples
410 ///
411 /// ```no_run
412 /// use aya::EbpfLoader;
413 /// use std::fs;
414 ///
415 /// let data = fs::read("file.o").unwrap();
416 /// let bpf = EbpfLoader::new().load(&data)?;
417 /// # Ok::<(), aya::EbpfError>(())
418 /// ```
419 pub fn load(&mut self, data: &[u8]) -> Result<Ebpf, EbpfError> {
420 let Self {
421 btf,
422 default_map_pin_directory,
423 globals,
424 max_entries,
425 extensions,
426 verifier_log_level,
427 allow_unsupported_maps,
428 map_pin_path_by_name,
429 } = self;
430 let mut obj = Object::parse(data)?;
431 obj.patch_map_data(globals.clone())?;
432
433 let btf_fd = if let Some(features) = &FEATURES.btf() {
434 if let Some(btf) = obj.fixup_and_sanitize_btf(features)? {
435 match load_btf(btf.to_bytes(), *verifier_log_level) {
436 Ok(btf_fd) => Some(Arc::new(btf_fd)),
437 // Only report an error here if the BTF is truly needed, otherwise proceed without.
438 Err(err) => {
439 for program in obj.programs.values() {
440 match program.section {
441 ProgramSection::Extension
442 | ProgramSection::FEntry { sleepable: _ }
443 | ProgramSection::FExit { sleepable: _ }
444 | ProgramSection::Lsm { sleepable: _ }
445 | ProgramSection::LsmCgroup
446 | ProgramSection::BtfTracePoint
447 | ProgramSection::Iter { sleepable: _ } => {
448 return Err(EbpfError::BtfError(err));
449 }
450 ProgramSection::KRetProbe
451 | ProgramSection::KProbe
452 | ProgramSection::UProbe { sleepable: _ }
453 | ProgramSection::URetProbe { sleepable: _ }
454 | ProgramSection::TracePoint
455 | ProgramSection::SocketFilter
456 | ProgramSection::Xdp {
457 frags: _,
458 attach_type: _,
459 }
460 | ProgramSection::SkMsg
461 | ProgramSection::SkSkbStream { kind: _ }
462 | ProgramSection::SockOps
463 | ProgramSection::SchedClassifier
464 | ProgramSection::CgroupSkb { attach_type: _ }
465 | ProgramSection::CgroupSockAddr { attach_type: _ }
466 | ProgramSection::CgroupSysctl
467 | ProgramSection::CgroupSockopt { attach_type: _ }
468 | ProgramSection::LircMode2
469 | ProgramSection::PerfEvent
470 | ProgramSection::RawTracePoint
471 | ProgramSection::SkLookup
472 | ProgramSection::SkReuseport { attach_type: _ }
473 | ProgramSection::FlowDissector
474 | ProgramSection::CgroupSock { attach_type: _ }
475 | ProgramSection::CgroupDevice => {}
476 }
477 }
478
479 if obj.has_btf_relocations() {
480 return Err(EbpfError::BtfError(err));
481 }
482
483 warn!("object BTF couldn't be loaded in the kernel: {err}");
484
485 None
486 }
487 }
488 } else {
489 None
490 }
491 } else {
492 None
493 };
494
495 if let Some(btf) = &btf {
496 obj.relocate_btf(btf)?;
497 // Resolve `extern "C"` calls that hit kernel kfuncs. Has to run
498 // before `relocate_calls` so the latter doesn't trip over the
499 // unresolved-symbol relocations we patch here.
500 obj.relocate_kfuncs(btf)?;
501 }
502
503 const fn is_map_of_maps(map_type: bpf_map_type) -> bool {
504 matches!(
505 map_type,
506 bpf_map_type::BPF_MAP_TYPE_ARRAY_OF_MAPS | bpf_map_type::BPF_MAP_TYPE_HASH_OF_MAPS
507 )
508 }
509
510 // The kernel requires inner_map_fd when creating map-of-maps, so inner
511 // maps must be created first. Partition into regular maps and map-of-maps.
512 let mut regular_maps: Vec<(String, aya_obj::Map)> = Vec::new();
513 let mut maps_of_maps: Vec<(String, aya_obj::Map)> = Vec::new();
514
515 for (name, map_obj) in obj.maps.drain() {
516 if let (false, EbpfSectionKind::Bss | EbpfSectionKind::Data | EbpfSectionKind::Rodata) =
517 (FEATURES.bpf_global_data(), map_obj.section_kind())
518 {
519 continue;
520 }
521 let map_type: bpf_map_type = map_obj.map_type().try_into().map_err(MapError::from)?;
522 if is_map_of_maps(map_type) {
523 maps_of_maps.push((name, map_obj));
524 } else {
525 regular_maps.push((name, map_obj));
526 }
527 }
528
529 let mut maps: HashMap<String, MapData> = HashMap::new();
530
531 // Regular maps first, so they're available as inner maps below.
532 for ((name, mut map_obj), is_map_of_maps) in regular_maps
533 .into_iter()
534 .zip(iter::repeat(false))
535 .chain(maps_of_maps.into_iter().zip(iter::repeat(true)))
536 {
537 let num_cpus = || {
538 Ok(nr_cpus().map_err(|(path, error)| EbpfError::FileError {
539 path: PathBuf::from(path),
540 error,
541 })? as u32)
542 };
543 let map_type: bpf_map_type = map_obj.map_type().try_into().map_err(MapError::from)?;
544 if let Some(max_entries_val) = max_entries_override(
545 map_type,
546 max_entries.get(name.as_str()).copied(),
547 || map_obj.max_entries(),
548 num_cpus,
549 || page_size() as u32,
550 )? {
551 map_obj.set_max_entries(max_entries_val)
552 }
553 if let Some(value_size) = value_size_override(map_type) {
554 map_obj.set_value_size(value_size)
555 }
556
557 let btf_fd = btf_fd.as_deref().map(|fd| fd.as_fd());
558
559 // Defer inner map creation to avoid a BPF_MAP_CREATE when the outer map is already pinned.
560 let inner_map_obj = if is_map_of_maps {
561 Some(map_obj.inner().ok_or_else(|| {
562 EbpfError::MapError(MapError::MissingInnerMapDefinition {
563 outer_name: name.clone(),
564 })
565 })?)
566 } else {
567 None
568 };
569 let mut map = if let Some(pin_path) = map_pin_path_by_name.get(name.as_str()) {
570 MapData::create_pinned_by_name(pin_path, map_obj, &name, btf_fd, inner_map_obj)?
571 } else {
572 match map_obj.pinning() {
573 PinningType::None => {
574 let btf_inner_map;
575 let inner_map_fd = if let Some(inner) = inner_map_obj {
576 btf_inner_map =
577 MapData::create(inner, &format!("{name}.inner"), btf_fd)?;
578 Some(btf_inner_map.fd().as_fd())
579 } else {
580 None
581 };
582 MapData::create_with_inner_map_fd(map_obj, &name, btf_fd, inner_map_fd)?
583 }
584 PinningType::ByName => {
585 // pin maps in /sys/fs/bpf by default to align with libbpf
586 // behavior https://github.com/libbpf/libbpf/blob/v1.2.2/src/libbpf.c#L2161.
587 let path = default_map_pin_directory
588 .as_deref()
589 .unwrap_or_else(|| Path::new("/sys/fs/bpf"));
590 let path = path.join(&name);
591
592 MapData::create_pinned_by_name(path, map_obj, &name, btf_fd, inner_map_obj)?
593 }
594 }
595 };
596 map.finalize()?;
597 maps.insert(name, map);
598 }
599
600 let text_sections = obj
601 .functions
602 .keys()
603 .map(|(section_index, _)| *section_index)
604 .collect();
605
606 obj.relocate_maps(
607 maps.iter()
608 .map(|(s, data)| (s.as_str(), data.fd().as_fd().as_raw_fd(), data.obj())),
609 &text_sections,
610 )?;
611 obj.relocate_calls(&text_sections)?;
612 obj.sanitize_functions(&FEATURES);
613
614 let programs = obj
615 .programs
616 .drain()
617 .map(|(name, prog_obj)| {
618 let function_obj = obj.functions[&prog_obj.function_key()].clone();
619
620 let prog_name = FEATURES.bpf_name().then(|| name.clone().into());
621 let section = prog_obj.section.clone();
622 let obj = (prog_obj, function_obj);
623
624 let btf_fd = btf_fd.as_ref().map(Arc::clone);
625 let program = if extensions.contains(name.as_str()) {
626 Program::Extension(Extension {
627 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
628 })
629 } else {
630 match §ion {
631 ProgramSection::KProbe => Program::KProbe(KProbe {
632 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
633 kind: ProbeKind::Entry,
634 }),
635 ProgramSection::KRetProbe => Program::KProbe(KProbe {
636 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
637 kind: ProbeKind::Return,
638 }),
639 ProgramSection::UProbe { sleepable } => {
640 let mut data =
641 ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level);
642 if *sleepable {
643 data.flags = BPF_F_SLEEPABLE;
644 }
645 Program::UProbe(UProbe {
646 data,
647 kind: ProbeKind::Entry,
648 })
649 }
650 ProgramSection::URetProbe { sleepable } => {
651 let mut data =
652 ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level);
653 if *sleepable {
654 data.flags = BPF_F_SLEEPABLE;
655 }
656 Program::UProbe(UProbe {
657 data,
658 kind: ProbeKind::Return,
659 })
660 }
661 ProgramSection::TracePoint => Program::TracePoint(TracePoint {
662 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
663 }),
664 ProgramSection::SocketFilter => Program::SocketFilter(SocketFilter {
665 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
666 }),
667 ProgramSection::Xdp {
668 frags, attach_type, ..
669 } => {
670 let mut data =
671 ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level);
672 if *frags {
673 data.flags = BPF_F_XDP_HAS_FRAGS;
674 }
675 Program::Xdp(Xdp {
676 data,
677 attach_type: *attach_type,
678 })
679 }
680 ProgramSection::SkMsg => Program::SkMsg(SkMsg {
681 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
682 }),
683 ProgramSection::CgroupSysctl => Program::CgroupSysctl(CgroupSysctl {
684 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
685 }),
686 ProgramSection::CgroupSockopt { attach_type, .. } => {
687 Program::CgroupSockopt(CgroupSockopt {
688 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
689 attach_type: *attach_type,
690 })
691 }
692 ProgramSection::SkSkbStream { kind } => Program::SkSkb(SkSkb {
693 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
694 kind: *kind,
695 }),
696 ProgramSection::SockOps => Program::SockOps(SockOps {
697 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
698 }),
699 ProgramSection::SchedClassifier => {
700 Program::SchedClassifier(SchedClassifier {
701 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
702 })
703 }
704 ProgramSection::CgroupSkb { attach_type } => {
705 Program::CgroupSkb(CgroupSkb {
706 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
707 attach_type: *attach_type,
708 })
709 }
710 ProgramSection::CgroupSockAddr { attach_type, .. } => {
711 Program::CgroupSockAddr(CgroupSockAddr {
712 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
713 attach_type: *attach_type,
714 })
715 }
716 ProgramSection::LircMode2 => Program::LircMode2(LircMode2 {
717 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
718 }),
719 ProgramSection::PerfEvent => Program::PerfEvent(PerfEvent {
720 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
721 }),
722 ProgramSection::RawTracePoint => Program::RawTracePoint(RawTracePoint {
723 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
724 }),
725 ProgramSection::Lsm { sleepable } => {
726 let mut data =
727 ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level);
728 if *sleepable {
729 data.flags = BPF_F_SLEEPABLE;
730 }
731 Program::Lsm(Lsm { data })
732 }
733 ProgramSection::LsmCgroup => Program::LsmCgroup(LsmCgroup {
734 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
735 }),
736 ProgramSection::BtfTracePoint => Program::BtfTracePoint(BtfTracePoint {
737 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
738 }),
739 ProgramSection::FEntry { sleepable } => {
740 let mut data =
741 ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level);
742 if *sleepable {
743 data.flags = BPF_F_SLEEPABLE;
744 }
745 Program::FEntry(FEntry { data })
746 }
747 ProgramSection::FExit { sleepable } => {
748 let mut data =
749 ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level);
750 if *sleepable {
751 data.flags = BPF_F_SLEEPABLE;
752 }
753 Program::FExit(FExit { data })
754 }
755 ProgramSection::FlowDissector => Program::FlowDissector(FlowDissector {
756 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
757 }),
758 ProgramSection::Extension => Program::Extension(Extension {
759 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
760 }),
761 ProgramSection::SkLookup => Program::SkLookup(SkLookup {
762 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
763 }),
764 ProgramSection::SkReuseport { attach_type } => {
765 Program::SkReuseport(SkReuseport {
766 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
767 attach_type: *attach_type,
768 })
769 }
770 ProgramSection::CgroupSock { attach_type, .. } => {
771 Program::CgroupSock(CgroupSock {
772 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
773 attach_type: *attach_type,
774 })
775 }
776 ProgramSection::CgroupDevice => Program::CgroupDevice(CgroupDevice {
777 data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
778 }),
779 ProgramSection::Iter { sleepable } => {
780 let mut data =
781 ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level);
782 if *sleepable {
783 data.flags = BPF_F_SLEEPABLE;
784 }
785 Program::Iter(Iter { data })
786 }
787 }
788 };
789 (name, program)
790 })
791 .collect();
792 let maps = maps
793 .drain()
794 .map(|data| parse_map(data, *allow_unsupported_maps))
795 .collect::<Result<HashMap<String, Map>, EbpfError>>()?;
796
797 Ok(Ebpf { maps, programs })
798 }
799}
800
801fn parse_map(
802 data: (String, MapData),
803 allow_unsupported_maps: bool,
804) -> Result<(String, Map), EbpfError> {
805 let (name, map) = data;
806 let map_type = bpf_map_type::try_from(map.obj().map_type()).map_err(MapError::from)?;
807 let map = match map_type {
808 bpf_map_type::BPF_MAP_TYPE_ARRAY => Map::Array(map),
809 bpf_map_type::BPF_MAP_TYPE_PERCPU_ARRAY => Map::PerCpuArray(map),
810 bpf_map_type::BPF_MAP_TYPE_PROG_ARRAY => Map::ProgramArray(map),
811 bpf_map_type::BPF_MAP_TYPE_CGROUP_ARRAY => Map::CgroupArray(map),
812 bpf_map_type::BPF_MAP_TYPE_HASH => Map::HashMap(map),
813 bpf_map_type::BPF_MAP_TYPE_LRU_HASH => Map::LruHashMap(map),
814 bpf_map_type::BPF_MAP_TYPE_PERCPU_HASH => Map::PerCpuHashMap(map),
815 bpf_map_type::BPF_MAP_TYPE_LRU_PERCPU_HASH => Map::PerCpuLruHashMap(map),
816 bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY => Map::PerfEventArray(map),
817 bpf_map_type::BPF_MAP_TYPE_REUSEPORT_SOCKARRAY => Map::ReusePortSockArray(map),
818 bpf_map_type::BPF_MAP_TYPE_RINGBUF => Map::RingBuf(map),
819 bpf_map_type::BPF_MAP_TYPE_SOCKHASH => Map::SockHash(map),
820 bpf_map_type::BPF_MAP_TYPE_SOCKMAP => Map::SockMap(map),
821 bpf_map_type::BPF_MAP_TYPE_BLOOM_FILTER => Map::BloomFilter(map),
822 bpf_map_type::BPF_MAP_TYPE_LPM_TRIE => Map::LpmTrie(map),
823 bpf_map_type::BPF_MAP_TYPE_STACK => Map::Stack(map),
824 bpf_map_type::BPF_MAP_TYPE_STACK_TRACE => Map::StackTraceMap(map),
825 bpf_map_type::BPF_MAP_TYPE_QUEUE => Map::Queue(map),
826 bpf_map_type::BPF_MAP_TYPE_CPUMAP => Map::CpuMap(map),
827 bpf_map_type::BPF_MAP_TYPE_DEVMAP => Map::DevMap(map),
828 bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH => Map::DevMapHash(map),
829 bpf_map_type::BPF_MAP_TYPE_XSKMAP => Map::XskMap(map),
830 bpf_map_type::BPF_MAP_TYPE_SK_STORAGE => Map::SkStorage(map),
831 bpf_map_type::BPF_MAP_TYPE_INODE_STORAGE => Map::InodeStorage(map),
832 bpf_map_type::BPF_MAP_TYPE_ARRAY_OF_MAPS => Map::ArrayOfMaps(map),
833 bpf_map_type::BPF_MAP_TYPE_HASH_OF_MAPS => Map::HashOfMaps(map),
834 m_type => {
835 if allow_unsupported_maps {
836 Map::Unsupported(map)
837 } else {
838 return Err(EbpfError::MapError(MapError::Unsupported {
839 name,
840 map_type: m_type,
841 }));
842 }
843 }
844 };
845
846 Ok((name, map))
847}
848
849/// Computes the value which should be used to override the `max_entries` value of the map
850/// based on the user-provided override and the rules for that map type.
851fn max_entries_override(
852 map_type: bpf_map_type,
853 user_override: Option<u32>,
854 current_value: impl Fn() -> u32,
855 num_cpus: impl Fn() -> Result<u32, EbpfError>,
856 page_size: impl Fn() -> u32,
857) -> Result<Option<u32>, EbpfError> {
858 let max_entries = || user_override.unwrap_or_else(¤t_value);
859 Ok(match map_type {
860 bpf_map_type::BPF_MAP_TYPE_PERF_EVENT_ARRAY if max_entries() == 0 => Some(num_cpus()?),
861 bpf_map_type::BPF_MAP_TYPE_RINGBUF => Some(adjust_to_page_size(max_entries(), page_size()))
862 .filter(|adjusted| *adjusted != max_entries())
863 .or(user_override),
864 _ => user_override,
865 })
866}
867
868/// Computes the value which should be used to override the `value_size` value of the map
869/// based on the rules for that map type.
870fn value_size_override(map_type: bpf_map_type) -> Option<u32> {
871 match map_type {
872 bpf_map_type::BPF_MAP_TYPE_CPUMAP => Some(if FEATURES.cpumap_prog_id() { 8 } else { 4 }),
873 bpf_map_type::BPF_MAP_TYPE_DEVMAP | bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH => {
874 Some(if FEATURES.devmap_prog_id() { 8 } else { 4 })
875 }
876 bpf_map_type::BPF_MAP_TYPE_RINGBUF => Some(0),
877 _ => None,
878 }
879}
880
881// Adjusts the byte size of a RingBuf map to match a power-of-two multiple of the page size.
882//
883// This mirrors the logic used by libbpf.
884// See https://github.com/libbpf/libbpf/blob/ec6f716eda43/src/libbpf.c#L2461-L2463
885const fn adjust_to_page_size(byte_size: u32, page_size: u32) -> u32 {
886 // If the byte_size is zero, return zero and let the verifier reject the map
887 // when it is loaded. This is the behavior of libbpf.
888 if byte_size == 0 {
889 return 0;
890 }
891 // TODO: Replace with primitive method when int_roundings (https://github.com/rust-lang/rust/issues/88581)
892 // is stabilized.
893 const fn div_ceil(n: u32, rhs: u32) -> u32 {
894 let d = n / rhs;
895 let r = n % rhs;
896 if r > 0 && rhs > 0 { d + 1 } else { d }
897 }
898 let pages_needed = div_ceil(byte_size, page_size);
899 page_size * pages_needed.next_power_of_two()
900}
901
902#[cfg(test)]
903mod tests {
904 use aya_obj::generated::bpf_map_type::*;
905
906 const PAGE_SIZE: u32 = 4096;
907 const NUM_CPUS: u32 = 4;
908
909 #[test]
910 fn test_adjust_to_page_size() {
911 use super::adjust_to_page_size;
912 for (exp, input) in [
913 (0, 0),
914 (4096, 1),
915 (4096, 4095),
916 (4096, 4096),
917 (8192, 4097),
918 (8192, 8192),
919 (16384, 8193),
920 ] {
921 assert_eq!(exp, adjust_to_page_size(input, PAGE_SIZE));
922 }
923 }
924
925 #[test]
926 fn test_max_entries_override() {
927 use super::max_entries_override;
928 for (map_type, user_override, current_value, exp) in [
929 (BPF_MAP_TYPE_RINGBUF, Some(1), 1, Some(PAGE_SIZE)),
930 (BPF_MAP_TYPE_RINGBUF, None, 1, Some(PAGE_SIZE)),
931 (BPF_MAP_TYPE_RINGBUF, None, PAGE_SIZE, None),
932 (BPF_MAP_TYPE_PERF_EVENT_ARRAY, None, 1, None),
933 (BPF_MAP_TYPE_PERF_EVENT_ARRAY, Some(42), 1, Some(42)),
934 (BPF_MAP_TYPE_PERF_EVENT_ARRAY, Some(0), 1, Some(NUM_CPUS)),
935 (BPF_MAP_TYPE_PERF_EVENT_ARRAY, None, 0, Some(NUM_CPUS)),
936 (BPF_MAP_TYPE_PERF_EVENT_ARRAY, None, 42, None),
937 (BPF_MAP_TYPE_ARRAY, None, 1, None),
938 (BPF_MAP_TYPE_ARRAY, Some(2), 1, Some(2)),
939 ] {
940 assert_eq!(
941 exp,
942 max_entries_override(
943 map_type,
944 user_override,
945 || current_value,
946 || Ok(NUM_CPUS),
947 || PAGE_SIZE,
948 )
949 .unwrap()
950 );
951 }
952 }
953}
954
955impl Default for EbpfLoader<'_> {
956 fn default() -> Self {
957 EbpfLoader::new()
958 }
959}
960
961/// The main entry point into the library, used to work with eBPF programs and maps.
962#[derive(Debug)]
963pub struct Ebpf {
964 maps: HashMap<String, Map>,
965 programs: HashMap<String, Program>,
966}
967
968/// The main entry point into the library, used to work with eBPF programs and maps.
969#[deprecated(since = "0.13.0", note = "use `Ebpf` instead")]
970pub type Bpf = Ebpf;
971
972impl Ebpf {
973 /// Loads eBPF bytecode from a file.
974 ///
975 /// Parses the given object code file and initializes the [maps](crate::maps) defined in it. If
976 /// the kernel supports [BTF](Btf) debug info, it is automatically loaded from
977 /// `/sys/kernel/btf/vmlinux`.
978 ///
979 /// For more loading options, see [`EbpfLoader`].
980 ///
981 /// # Examples
982 ///
983 /// ```no_run
984 /// use aya::Ebpf;
985 ///
986 /// let bpf = Ebpf::load_file("file.o")?;
987 /// # Ok::<(), aya::EbpfError>(())
988 /// ```
989 pub fn load_file<P: AsRef<Path>>(path: P) -> Result<Self, EbpfError> {
990 EbpfLoader::new()
991 .btf(Btf::from_sys_fs().ok().as_ref())
992 .load_file(path)
993 }
994
995 /// Loads eBPF bytecode from a buffer.
996 ///
997 /// Parses the object code contained in `data` and initializes the
998 /// [maps](crate::maps) defined in it. If the kernel supports [BTF](Btf)
999 /// debug info, it is automatically loaded from `/sys/kernel/btf/vmlinux`.
1000 ///
1001 /// The buffer needs to be 4-bytes aligned. If you are bundling the bytecode statically
1002 /// into your binary, it is recommended that you do so using
1003 /// [`include_bytes_aligned`](crate::include_bytes_aligned).
1004 ///
1005 /// For more loading options, see [`EbpfLoader`].
1006 ///
1007 /// # Examples
1008 ///
1009 /// ```no_run
1010 /// use aya::{Ebpf, Btf};
1011 /// use std::fs;
1012 ///
1013 /// let data = fs::read("file.o").unwrap();
1014 /// // load the BTF data from /sys/kernel/btf/vmlinux
1015 /// let bpf = Ebpf::load(&data)?;
1016 /// # Ok::<(), aya::EbpfError>(())
1017 /// ```
1018 pub fn load(data: &[u8]) -> Result<Self, EbpfError> {
1019 EbpfLoader::new()
1020 .btf(Btf::from_sys_fs().ok().as_ref())
1021 .load(data)
1022 }
1023
1024 /// Returns a reference to the map with the given name.
1025 ///
1026 /// The returned type is mostly opaque. In order to do anything useful with it you need to
1027 /// convert it to a [typed map](crate::maps).
1028 ///
1029 /// For more details and examples on maps and their usage, see the [maps module
1030 /// documentation][crate::maps].
1031 pub fn map(&self, name: &str) -> Option<&Map> {
1032 self.maps.get(name)
1033 }
1034
1035 /// Returns a mutable reference to the map with the given name.
1036 ///
1037 /// The returned type is mostly opaque. In order to do anything useful with it you need to
1038 /// convert it to a [typed map](crate::maps).
1039 ///
1040 /// For more details and examples on maps and their usage, see the [maps module
1041 /// documentation][crate::maps].
1042 pub fn map_mut(&mut self, name: &str) -> Option<&mut Map> {
1043 self.maps.get_mut(name)
1044 }
1045
1046 /// Takes ownership of a map with the given name.
1047 ///
1048 /// Use this when borrowing with [`map`](crate::Ebpf::map) or [`map_mut`](crate::Ebpf::map_mut)
1049 /// is not possible (eg when using the map from an async task). The returned
1050 /// map will be closed on `Drop`, therefore the caller is responsible for
1051 /// managing its lifetime.
1052 ///
1053 /// The returned type is mostly opaque. In order to do anything useful with it you need to
1054 /// convert it to a [typed map](crate::maps).
1055 ///
1056 /// For more details and examples on maps and their usage, see the [maps module
1057 /// documentation][crate::maps].
1058 pub fn take_map(&mut self, name: &str) -> Option<Map> {
1059 self.maps.remove(name)
1060 }
1061
1062 /// An iterator over all the maps.
1063 ///
1064 /// # Examples
1065 /// ```no_run
1066 /// # let mut bpf = aya::Ebpf::load(&[])?;
1067 /// for (name, map) in bpf.maps() {
1068 /// println!(
1069 /// "found map `{}`",
1070 /// name,
1071 /// );
1072 /// }
1073 /// # Ok::<(), aya::EbpfError>(())
1074 /// ```
1075 pub fn maps(&self) -> impl Iterator<Item = (&str, &Map)> {
1076 self.maps.iter().map(|(name, map)| (name.as_str(), map))
1077 }
1078
1079 /// A mutable iterator over all the maps.
1080 ///
1081 /// # Examples
1082 /// ```no_run
1083 /// # use std::path::Path;
1084 /// # #[derive(thiserror::Error, Debug)]
1085 /// # enum Error {
1086 /// # #[error(transparent)]
1087 /// # Ebpf(#[from] aya::EbpfError),
1088 /// # #[error(transparent)]
1089 /// # Pin(#[from] aya::pin::PinError)
1090 /// # }
1091 /// # let mut bpf = aya::Ebpf::load(&[])?;
1092 /// # let pin_path = Path::new("/tmp/pin_path");
1093 /// for (_, map) in bpf.maps_mut() {
1094 /// map.pin(pin_path)?;
1095 /// }
1096 /// # Ok::<(), Error>(())
1097 /// ```
1098 pub fn maps_mut(&mut self) -> impl Iterator<Item = (&str, &mut Map)> {
1099 self.maps.iter_mut().map(|(name, map)| (name.as_str(), map))
1100 }
1101
1102 /// Attempts to get mutable references to `N` maps at once.
1103 ///
1104 /// Returns an array of length `N` with the results of each query, in the same order
1105 /// as the requested map names. For soundness, at most one mutable reference will be
1106 /// returned to any map. `None` will be used if a map with the given name is missing.
1107 ///
1108 /// This method performs a check to ensure that there are no duplicate map names,
1109 /// which currently has a time-complexity of *O(n²)*. Be careful when passing a large
1110 /// number of names.
1111 ///
1112 /// # Panics
1113 ///
1114 /// Panics if any names are duplicated.
1115 ///
1116 /// # Examples
1117 /// ```no_run
1118 /// # let mut bpf = aya::Ebpf::load(&[])?;
1119 /// match bpf.maps_disjoint_mut(["MAP1", "MAP2"]) {
1120 /// [Some(m1), Some(m2)] => println!("Got MAP1 and MAP2"),
1121 /// [Some(m1), None] => println!("Got only MAP1"),
1122 /// [None, Some(m2)] => println!("Got only MAP2"),
1123 /// [None, None] => println!("No maps"),
1124 /// }
1125 /// # Ok::<(), aya::EbpfError>(())
1126 /// ```
1127 pub fn maps_disjoint_mut<const N: usize>(&mut self, names: [&str; N]) -> [Option<&mut Map>; N] {
1128 self.maps.get_disjoint_mut(names)
1129 }
1130
1131 /// Returns a reference to the program with the given name.
1132 ///
1133 /// You can use this to inspect a program and its properties. To load and attach a program, use
1134 /// [`program_mut`](Self::program_mut) instead.
1135 ///
1136 /// For more details on programs and their usage, see the [programs module
1137 /// documentation](crate::programs).
1138 ///
1139 /// # Examples
1140 ///
1141 /// ```no_run
1142 /// # let bpf = aya::Ebpf::load(&[])?;
1143 /// let program = bpf.program("SSL_read").unwrap();
1144 /// println!("program SSL_read is of type {:?}", program.prog_type());
1145 /// # Ok::<(), aya::EbpfError>(())
1146 /// ```
1147 pub fn program(&self, name: &str) -> Option<&Program> {
1148 self.programs.get(name)
1149 }
1150
1151 /// Returns a mutable reference to the program with the given name.
1152 ///
1153 /// Used to get a program before loading and attaching it. For more details on programs and
1154 /// their usage, see the [programs module documentation](crate::programs).
1155 ///
1156 /// # Examples
1157 ///
1158 /// ```no_run
1159 /// # let mut bpf = aya::Ebpf::load(&[])?;
1160 /// use aya::programs::{uprobe::UProbeScope, UProbe};
1161 ///
1162 /// let program: &mut UProbe = bpf.program_mut("SSL_read").unwrap().try_into()?;
1163 /// program.load()?;
1164 /// program.attach("SSL_read", "libssl", UProbeScope::AllProcesses)?;
1165 /// # Ok::<(), aya::EbpfError>(())
1166 /// ```
1167 pub fn program_mut(&mut self, name: &str) -> Option<&mut Program> {
1168 self.programs.get_mut(name)
1169 }
1170
1171 /// An iterator over all the programs.
1172 ///
1173 /// # Examples
1174 /// ```no_run
1175 /// # let bpf = aya::Ebpf::load(&[])?;
1176 /// for (name, program) in bpf.programs() {
1177 /// println!(
1178 /// "found program `{}` of type `{:?}`",
1179 /// name,
1180 /// program.prog_type()
1181 /// );
1182 /// }
1183 /// # Ok::<(), aya::EbpfError>(())
1184 /// ```
1185 pub fn programs(&self) -> impl Iterator<Item = (&str, &Program)> {
1186 self.programs.iter().map(|(s, p)| (s.as_str(), p))
1187 }
1188
1189 /// An iterator mutably referencing all of the programs.
1190 ///
1191 /// # Examples
1192 /// ```no_run
1193 /// # use std::path::Path;
1194 /// # #[derive(thiserror::Error, Debug)]
1195 /// # enum Error {
1196 /// # #[error(transparent)]
1197 /// # Ebpf(#[from] aya::EbpfError),
1198 /// # #[error(transparent)]
1199 /// # Pin(#[from] aya::pin::PinError)
1200 /// # }
1201 /// # let mut bpf = aya::Ebpf::load(&[])?;
1202 /// # let pin_path = Path::new("/tmp/pin_path");
1203 /// for (_, program) in bpf.programs_mut() {
1204 /// program.pin(pin_path)?;
1205 /// }
1206 /// # Ok::<(), Error>(())
1207 /// ```
1208 pub fn programs_mut(&mut self) -> impl Iterator<Item = (&str, &mut Program)> {
1209 self.programs.iter_mut().map(|(s, p)| (s.as_str(), p))
1210 }
1211}
1212
1213/// The error type returned by [`Ebpf::load_file`] and [`Ebpf::load`].
1214#[derive(Debug, Error)]
1215pub enum EbpfError {
1216 /// Error loading file
1217 #[error("error loading {path}")]
1218 FileError {
1219 /// The file path
1220 path: PathBuf,
1221 #[source]
1222 /// The original [`io::Error`]
1223 error: io::Error,
1224 },
1225
1226 /// Unexpected pinning type
1227 #[error("unexpected pinning type {name}")]
1228 UnexpectedPinningType {
1229 /// The value encountered
1230 name: u32,
1231 },
1232
1233 /// Error parsing BPF object
1234 #[error("error parsing BPF object: {0}")]
1235 ParseError(#[from] ParseError),
1236
1237 /// Error parsing BTF object
1238 #[error("BTF error: {0}")]
1239 BtfError(#[from] BtfError),
1240
1241 /// Error performing relocations
1242 #[error("error relocating function")]
1243 RelocationError(#[from] EbpfRelocationError),
1244
1245 /// Error performing relocations
1246 #[error("error relocating section")]
1247 BtfRelocationError(#[from] BtfRelocationError),
1248
1249 /// No BTF parsed for object
1250 #[error("no BTF parsed for object")]
1251 NoBTF,
1252
1253 #[error("map error: {0}")]
1254 /// A map error
1255 MapError(#[from] MapError),
1256
1257 #[error("program error: {0}")]
1258 /// A program error
1259 ProgramError(#[from] ProgramError),
1260}
1261
1262/// The error type returned by [`Bpf::load_file`] and [`Bpf::load`].
1263#[deprecated(since = "0.13.0", note = "use `EbpfError` instead")]
1264pub type BpfError = EbpfError;
1265
1266fn load_btf(
1267 raw_btf: Vec<u8>,
1268 verifier_log_level: VerifierLogLevel,
1269) -> Result<crate::MockableFd, BtfError> {
1270 let (ret, verifier_log) = retry_with_verifier_logs(10, |logger| {
1271 bpf_load_btf(raw_btf.as_slice(), logger, verifier_log_level)
1272 });
1273 ret.map_err(|io_error| BtfError::LoadError {
1274 io_error,
1275 verifier_log,
1276 })
1277}
1278
1279/// Global data that can be exported to eBPF programs before they are loaded.
1280///
1281/// Valid global data includes `Pod` types and slices of `Pod` types. See also
1282/// [`EbpfLoader::override_global`].
1283pub struct GlobalData<'a> {
1284 bytes: &'a [u8],
1285}
1286
1287impl<'a, T: Pod> From<&'a [T]> for GlobalData<'a> {
1288 fn from(s: &'a [T]) -> Self {
1289 GlobalData {
1290 bytes: bytes_of_slice(s),
1291 }
1292 }
1293}
1294
1295impl<'a, T: Pod> From<&'a T> for GlobalData<'a> {
1296 fn from(v: &'a T) -> Self {
1297 GlobalData {
1298 // Safety: v is Pod
1299 bytes: bytes_of(v),
1300 }
1301 }
1302}