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}