1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use aya_ebpf_cty::c_long;
use crate::{btf_maps::btf_map_def, helpers::bpf_current_task_under_cgroup};
btf_map_def!(
/// A BTF-compatible array of cgroups.
///
/// `CgroupArray` stores cgroups, set from userspace by writing a cgroup
/// directory file descriptor into a slot. eBPF programs use it with the
/// `bpf_skb_under_cgroup` and `bpf_current_task_under_cgroup` helpers to
/// test whether a packet or the current task belongs to one of those
/// cgroups.
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 4.8.
///
/// # Example
///
/// ```rust
/// use aya_ebpf::{btf_maps::CgroupArray, macros::btf_map};
///
/// #[btf_map]
/// static CGROUPS: CgroupArray<8> = CgroupArray::new();
/// ```
pub struct CgroupArray<; const MAX_ENTRIES: usize, const FLAGS: usize = 0>,
map_type: BPF_MAP_TYPE_CGROUP_ARRAY,
max_entries: MAX_ENTRIES,
map_flags: FLAGS,
key_type: u32,
value_type: u32,
);
impl<const MAX_ENTRIES: usize, const FLAGS: usize> CgroupArray<MAX_ENTRIES, FLAGS> {
const _CHECK: () = {
assert!(
MAX_ENTRIES > 0,
"CgroupArray max_entries must be greater than zero."
);
};
/// Returns whether the current task is a descendant of the cgroup at `index`.
///
/// Wraps the `bpf_current_task_under_cgroup` helper, which requires kernel
/// 4.9 or newer. This is only callable from tracing programs, for example
/// kprobes and tracepoints.
pub fn current_task_under_cgroup(&self, index: u32) -> Result<bool, c_long> {
let () = Self::_CHECK;
// SAFETY: `self` is a valid pointer managed by aya.
let ret = unsafe { bpf_current_task_under_cgroup(self.as_ptr().cast(), index) };
match ret {
1 => Ok(true),
0 => Ok(false),
ret => Err(ret),
}
}
}
impl<const MAX_ENTRIES: usize, const FLAGS: usize> crate::programs::tc::sealed::CgroupArrayMap
for CgroupArray<MAX_ENTRIES, FLAGS>
{
fn as_ptr(&self) -> *mut core::ffi::c_void {
// `skb_under_cgroup` reaches the map only through this method, so it is
// the sole enforcement site for `_CHECK` on that path.
let () = Self::_CHECK;
self.as_ptr()
}
}