bpf_rs/
program.rs

1use std::{ffi::CStr, os::raw, ptr, time::Duration};
2
3use bpf_rs_macros::Display;
4#[cfg(feature = "serde")]
5use bpf_rs_macros::SerializeFromDisplay;
6
7use crate::{BpfHelper, Error, StaticName};
8use libbpf_sys::{libbpf_probe_bpf_helper, libbpf_probe_bpf_prog_type};
9use num_enum::{IntoPrimitive, TryFromPrimitive};
10
11/// eBPF program type variants. Based off of [kernel header's](https://github.com/torvalds/linux/blob/b253435746d9a4a701b5f09211b9c14d3370d0da/include/uapi/linux/bpf.h#L922)
12/// `enum bpf_prog_type`
13#[non_exhaustive]
14#[repr(u32)]
15#[derive(Debug, Display, TryFromPrimitive, IntoPrimitive, Clone, Copy, PartialEq, Eq, Hash)]
16#[cfg_attr(feature = "serde", derive(SerializeFromDisplay))]
17pub enum ProgramType {
18    Unspec = 0,
19    SocketFilter,
20    Kprobe,
21    SchedCls,
22    SchedAct,
23    Tracepoint,
24    Xdp,
25    PerfEvent,
26    CgroupSkb,
27    CgroupSock,
28    LwtIn,
29    LwtOut,
30    LwtXmit,
31    SockOps,
32    SkSkb,
33    CgroupDevice,
34    SkMsg,
35    RawTracepoint,
36    CgroupSockAddr,
37    LwtSeg6local,
38    LircMode2,
39    SkReuseport,
40    FlowDissector,
41    CgroupSysctl,
42    RawTracepointWritable,
43    CgroupSockopt,
44    Tracing,
45    StructOps,
46    Ext,
47    Lsm,
48    SkLookup,
49    Syscall,
50}
51
52impl ProgramType {
53    /// Determines if the eBPF program type is supported on the current platform
54    pub fn probe(&self) -> Result<bool, Error> {
55        match unsafe { libbpf_probe_bpf_prog_type((*self).into(), ptr::null()) } {
56            negative if negative < 0 => Err(Error::Code(negative)),
57            0 => Ok(false),
58            1 => Ok(true),
59            positive if positive > 1 => Err(Error::Unknown(positive)),
60            _ => unreachable!(),
61        }
62    }
63
64    /// Determines if the eBPF program helper function can be used my supported program types.
65    ///
66    /// **Note**: Due to libbpf's `libbpf_probe_bpf_helper`, this may return Ok(true) for unsupported program
67    /// types. It is recommended to verify if the program type is supported before probing for helper
68    /// support.
69    pub fn probe_helper(&self, helper: BpfHelper) -> Result<bool, Error> {
70        match unsafe { libbpf_probe_bpf_helper((*self).into(), helper.into(), ptr::null()) } {
71            negative if negative < 0 => Err(Error::Code(negative)),
72            0 => Ok(false),
73            1 => Ok(true),
74            positive if positive > 1 => Err(Error::Unknown(positive)),
75            _ => unreachable!(),
76        }
77    }
78
79    /// Returns an ordered iterator over the [`ProgramType`] variants. The order is determined by the kernel
80    /// header's [enum values](https://github.com/torvalds/linux/blob/b253435746d9a4a701b5f09211b9c14d3370d0da/include/uapi/linux/bpf.h#L922).
81    ///
82    /// **Note**: Skips [`ProgramType::Unspec`] since it's an invalid program type
83    pub fn iter() -> impl Iterator<Item = ProgramType> {
84        ProgramTypeIter(1)
85    }
86}
87
88// TODO: look into using libbpf_bpf_prog_type_str
89impl StaticName for ProgramType {
90    /// Based off of bpftool's
91    /// [`prog_type_name`](https://github.com/libbpf/bpftool/blob/9443d42430017ed2d04d7ab411131525ced62d6a/src/prog.c#L39),
92    /// returns a human-readable name of the eBPF program type.
93    fn name(&self) -> &'static str {
94        match *self {
95            ProgramType::Unspec => "unspec",
96            ProgramType::SocketFilter => "socket_filter",
97            ProgramType::Kprobe => "kprobe",
98            ProgramType::SchedCls => "sched_cls",
99            ProgramType::SchedAct => "sched_act",
100            ProgramType::Tracepoint => "tracepoint",
101            ProgramType::Xdp => "xdp",
102            ProgramType::PerfEvent => "perf_event",
103            ProgramType::CgroupSkb => "cgroup_skb",
104            ProgramType::CgroupSock => "cgroup_sock",
105            ProgramType::LwtIn => "lwt_in",
106            ProgramType::LwtOut => "lwt_out",
107            ProgramType::LwtXmit => "lwt_xmit",
108            ProgramType::SockOps => "sock_ops",
109            ProgramType::SkSkb => "sk_skb",
110            ProgramType::CgroupDevice => "cgroup_device",
111            ProgramType::SkMsg => "sk_msg",
112            ProgramType::RawTracepoint => "raw_tracepoint",
113            ProgramType::CgroupSockAddr => "cgroup_sock_addr",
114            ProgramType::LwtSeg6local => "lwt_seg6local",
115            ProgramType::LircMode2 => "lirc_mode2",
116            ProgramType::SkReuseport => "sk_reuseport",
117            ProgramType::FlowDissector => "flow_dissector",
118            ProgramType::CgroupSysctl => "cgroup_sysctl",
119            ProgramType::RawTracepointWritable => "raw_tracepoint_writable",
120            ProgramType::CgroupSockopt => "cgroup_sockopt",
121            ProgramType::Tracing => "tracing",
122            ProgramType::StructOps => "struct_ops",
123            ProgramType::Ext => "ext",
124            ProgramType::Lsm => "lsm",
125            ProgramType::SkLookup => "sk_lookup",
126            ProgramType::Syscall => "syscall",
127        }
128    }
129}
130
131struct ProgramTypeIter(u32);
132
133impl Iterator for ProgramTypeIter {
134    type Item = ProgramType;
135
136    fn next(&mut self) -> Option<Self::Item> {
137        let next = self.0;
138        if next > ProgramType::Syscall.into() {
139            None
140        } else {
141            self.0 += 1;
142            ProgramType::try_from_primitive(next).ok()
143        }
144    }
145}
146
147/// eBPF program object info. Similar to (but not the same) kernel header's
148/// [struct bpf_prog_info](https://github.com/torvalds/linux/blob/672c0c5173427e6b3e2a9bbb7be51ceeec78093a/include/uapi/linux/bpf.h#L5840)
149#[derive(Debug)]
150#[repr(C)]
151pub struct ProgramInfo {
152    /// Name of eBPF program
153    ///
154    /// **Note**: This is usually set on program load but is not required so it may be an
155    /// empty string.
156    pub name: String,
157    /// Each eBPF program has a unique program type that determines its functionality and
158    /// available features, such as helper functions.
159    ///
160    /// For more information, see [Marsden's blog post](https://blogs.oracle.com/linux/post/bpf-a-tour-of-program-types).
161    pub ty: ProgramType,
162    /// A SHA hash over the eBPF program instructions which can be used to
163    /// correlate back to the original object file
164    ///
165    /// Multiple eBPF programs may share the same xlated instructions and therefore
166    /// may have the same hashes so these are not guaranteed to be unique to each
167    /// eBPF program. For that, you may want to use [`ProgramInfo::id`].
168    pub tag: [u8; 8],
169    /// A unique identifier for the eBPF program
170    ///
171    /// Unique here meaning since the boot time of the machine. The counter used
172    /// to generate these identifiers resets back to 0 to reboot and the identifiers
173    /// are reused.
174    pub id: u32,
175    /// The amount of instructions that were JIT-ed.
176    ///
177    /// This is useful when attempting to dump the JIT code of the program to
178    /// pre-allocate the needed memory to write the instructions to.
179    pub jited_prog_len: u32,
180    /// The amount of instructions that were interpreted (post-translation by the verifier)
181    ///
182    /// This is useful when attempting to dump the xlated code of the program to
183    /// pre-allocate the needed memory to write the instructions to.
184    pub xlated_prog_len: u32,
185    // REFACTOR: Should be a Rust pointer
186    /// A u64-encoded pointer to the memory region containing JIT-ed instructions.
187    pub jited_prog_insns: u64,
188    // REFACTOR: Should be a Rust pointer
189    /// A u64-encoded pointer to the memory region contained Xlated instructions.
190    pub xlated_prog_insns: u64,
191    pub load_time: Duration,
192    /// User id of the creator of the program
193    pub created_by_uid: u32,
194    /// The count of maps currently used by the program
195    pub nr_map_ids: u32,
196    // TODO: Should be a Rust pointer
197    /// A u64-encoded pointer to the memory region containing ids to maps used by the program.
198    pub map_ids: u64,
199    pub ifindex: u32,
200    /// If the eBPF program has a GPL compatible license
201    ///
202    /// If the eBPF program has a proprietary license, then some features such
203    /// as helper functions or even ability to create certain program types are not
204    /// available.
205    ///
206    /// For more information, see the [kernel docs](https://www.kernel.org/doc/html/latest/bpf/bpf_licensing.html).
207    pub gpl_compatible: bool,
208    pub netns_dev: u64,
209    pub netns_ino: u64,
210    pub nr_jited_ksyms: u32,
211    pub nr_jited_func_lens: u32,
212    pub jited_ksyms: u64,
213    pub jited_func_lens: u64,
214    pub btf_id: u32,
215    pub func_info_rec_size: u32,
216    pub func_info: u64,
217    pub nr_func_info: u32,
218    pub nr_line_info: u32,
219    pub line_info: u64,
220    pub jited_line_info: u64,
221    pub nr_jited_line_info: u32,
222    pub line_info_rec_size: u32,
223    pub jited_line_info_rec_size: u32,
224    pub nr_prog_tags: u32,
225    pub prog_tags: u64,
226    pub run_time_ns: u64,
227    pub run_cnt: u64,
228}
229
230/// Collection of eBPF program license types (e.g. GPL)
231///
232/// Mostly a smaller wrapper for FFI use cases
233#[non_exhaustive]
234pub enum ProgramLicense {
235    GPL,
236}
237
238impl ProgramLicense {
239    /// Accepted license string with a nul byte at the end
240    pub fn as_str_with_nul(&self) -> &'static str {
241        match *self {
242            ProgramLicense::GPL => "GPL\0",
243        }
244    }
245
246    /// For FFI (such as using with `libbpf_sys`)
247    pub fn as_ptr(&self) -> *const raw::c_char {
248        CStr::from_bytes_with_nul(self.as_str_with_nul().as_bytes())
249            .unwrap()
250            .as_ptr()
251    }
252}