Skip to main content

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 &section {
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(&current_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}