Skip to main content

aya_friday/maps/array/
program_array.rs

1//! An array of eBPF program file descriptors used as a jump table.
2
3use std::{
4    borrow::{Borrow, BorrowMut},
5    os::fd::{AsFd as _, AsRawFd as _, RawFd},
6};
7
8use crate::{
9    maps::{MapData, MapError, MapKeys, check_bounds, check_kv_size, hash_map},
10    programs::ProgramFd,
11};
12
13/// An array of eBPF program file descriptors used as a jump table.
14///
15/// eBPF programs can jump to other programs calling `bpf_tail_call(ctx,
16/// prog_array, index)`. You can use [`ProgramArray`] to configure which
17/// programs correspond to which jump indexes.
18///
19/// # Minimum kernel version
20///
21/// The minimum kernel version required to use this feature is 4.2.
22///
23/// # Examples
24/// ```no_run
25/// # let mut bpf = aya::Ebpf::load(&[])?;
26/// use aya::maps::ProgramArray;
27/// use aya::programs::CgroupSkb;
28///
29/// let mut prog_array = ProgramArray::try_from(bpf.take_map("JUMP_TABLE").unwrap())?;
30/// let prog_0: &CgroupSkb = bpf.program("example_prog_0").unwrap().try_into()?;
31/// let prog_0_fd =  prog_0.fd().unwrap();
32/// let prog_1: &CgroupSkb = bpf.program("example_prog_1").unwrap().try_into()?;
33/// let prog_1_fd = prog_1.fd().unwrap();
34/// let prog_2: &CgroupSkb = bpf.program("example_prog_2").unwrap().try_into()?;
35/// let prog_2_fd = prog_2.fd().unwrap();
36/// let flags = 0;
37///
38/// // bpf_tail_call(ctx, JUMP_TABLE, 0) will jump to prog_0
39/// prog_array.set(0, prog_0_fd, flags);
40///
41/// // bpf_tail_call(ctx, JUMP_TABLE, 1) will jump to prog_1
42/// prog_array.set(1, prog_1_fd, flags);
43///
44/// // bpf_tail_call(ctx, JUMP_TABLE, 2) will jump to prog_2
45/// prog_array.set(2, prog_2_fd, flags);
46/// # Ok::<(), aya::EbpfError>(())
47/// ```
48#[doc(alias = "BPF_MAP_TYPE_PROG_ARRAY")]
49pub struct ProgramArray<T> {
50    pub(crate) inner: T,
51}
52
53impl<T: Borrow<MapData>> ProgramArray<T> {
54    pub(crate) fn new(map: T) -> Result<Self, MapError> {
55        let data = map.borrow();
56        check_kv_size::<u32, RawFd>(data)?;
57
58        Ok(Self { inner: map })
59    }
60
61    /// An iterator over the indices of the array that point to a program.
62    pub fn indices(&self) -> MapKeys<'_, u32> {
63        MapKeys::new(self.inner.borrow())
64    }
65}
66
67impl<T: BorrowMut<MapData>> ProgramArray<T> {
68    /// Sets the target program file descriptor for the given index in the jump table.
69    ///
70    /// When an eBPF program calls `bpf_tail_call(ctx, prog_array, index)`, control
71    /// flow will jump to `program`.
72    pub fn set(&mut self, index: u32, program: &ProgramFd, flags: u64) -> Result<(), MapError> {
73        let data = self.inner.borrow_mut();
74        check_bounds(data, index)?;
75        hash_map::insert(data, &index, &program.as_fd().as_raw_fd(), flags)
76    }
77
78    /// Clears the value at index in the jump table.
79    ///
80    /// Calling `bpf_tail_call(ctx, prog_array, index)` on an index that has been cleared returns an
81    /// error.
82    pub fn clear_index(&mut self, index: &u32) -> Result<(), MapError> {
83        let data = self.inner.borrow_mut();
84        check_bounds(data, *index)?;
85        hash_map::remove(data, index)
86    }
87}