Skip to main content

libbpf_rs/
object.rs

1use core::ffi::c_void;
2use std::cell::OnceCell;
3use std::ffi::CStr;
4use std::ffi::CString;
5use std::ffi::OsStr;
6use std::mem;
7use std::os::unix::ffi::OsStrExt as _;
8use std::path::Path;
9use std::ptr;
10use std::ptr::NonNull;
11
12use crate::map::map_fd;
13use crate::set_print;
14use crate::util;
15use crate::util::validate_bpf_ret;
16use crate::Btf;
17use crate::ErrorExt as _;
18use crate::Map;
19use crate::MapMut;
20use crate::OpenMap;
21use crate::OpenMapMut;
22use crate::OpenProgram;
23use crate::OpenProgramMut;
24use crate::PrintLevel;
25use crate::Program;
26use crate::ProgramMut;
27use crate::Result;
28
29
30/// An iterator over the maps in a BPF object.
31#[derive(Debug)]
32pub struct MapIter<'obj> {
33    obj: &'obj libbpf_sys::bpf_object,
34    last: *mut libbpf_sys::bpf_map,
35}
36
37impl<'obj> MapIter<'obj> {
38    /// Create a new iterator over the maps of the given BPF object.
39    pub fn new(obj: &'obj libbpf_sys::bpf_object) -> Self {
40        Self {
41            obj,
42            last: ptr::null_mut(),
43        }
44    }
45}
46
47impl Iterator for MapIter<'_> {
48    type Item = NonNull<libbpf_sys::bpf_map>;
49
50    fn next(&mut self) -> Option<Self::Item> {
51        self.last = unsafe { libbpf_sys::bpf_object__next_map(self.obj, self.last) };
52        NonNull::new(self.last)
53    }
54}
55
56
57/// An iterator over the programs in a BPF object.
58#[derive(Debug)]
59pub struct ProgIter<'obj> {
60    obj: &'obj libbpf_sys::bpf_object,
61    last: *mut libbpf_sys::bpf_program,
62}
63
64impl<'obj> ProgIter<'obj> {
65    /// Create a new iterator over the programs of the given BPF object.
66    pub fn new(obj: &'obj libbpf_sys::bpf_object) -> Self {
67        Self {
68            obj,
69            last: ptr::null_mut(),
70        }
71    }
72}
73
74impl Iterator for ProgIter<'_> {
75    type Item = NonNull<libbpf_sys::bpf_program>;
76
77    fn next(&mut self) -> Option<Self::Item> {
78        self.last = unsafe { libbpf_sys::bpf_object__next_program(self.obj, self.last) };
79        NonNull::new(self.last)
80    }
81}
82
83
84/// A trait implemented for types that are thin wrappers around `libbpf` types.
85///
86/// The trait provides access to the underlying `libbpf` (or `libbpf-sys`)
87/// object. In many cases, this enables direct usage of `libbpf-sys`
88/// functionality when higher-level bindings are not yet provided by this crate.
89pub trait AsRawLibbpf {
90    /// The underlying `libbpf` type.
91    type LibbpfType;
92
93    /// Retrieve the underlying `libbpf` object.
94    ///
95    /// # Warning
96    /// By virtue of working with a mutable raw pointer this method effectively
97    /// circumvents mutability and liveness checks. While by-design, usage is
98    /// meant as an escape-hatch more than anything else. If you find yourself
99    /// making use of it, please consider discussing your workflow with crate
100    /// maintainers to see if it would make sense to provide safer wrappers.
101    fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType>;
102}
103
104/// Builder for creating an [`OpenObject`]. Typically the entry point into libbpf-rs.
105#[derive(Debug)]
106pub struct ObjectBuilder {
107    name: Option<CString>,
108    pin_root_path: Option<CString>,
109    btf_custom_path: Option<CString>,
110
111    opts: OnceCell<libbpf_sys::bpf_object_open_opts>,
112}
113
114impl Default for ObjectBuilder {
115    fn default() -> Self {
116        Self {
117            name: None,
118            pin_root_path: None,
119            btf_custom_path: None,
120            opts: OnceCell::new(),
121        }
122    }
123}
124
125impl PartialEq for ObjectBuilder {
126    fn eq(&self, other: &Self) -> bool {
127        let Self {
128            name,
129            pin_root_path,
130            btf_custom_path,
131            opts,
132        } = self;
133
134        // `bpf_object_open_opts` doesn't implement `PartialEq` and we
135        // don't want to manually compare fields. Just render our
136        // objects "uncomparable" if it is present.
137        opts.get().is_none()
138            && other.opts.get().is_none()
139            && name == &other.name
140            && pin_root_path == &other.pin_root_path
141            && btf_custom_path == &other.btf_custom_path
142    }
143}
144
145impl ObjectBuilder {
146    fn opts(&self) -> &libbpf_sys::bpf_object_open_opts {
147        self.opts.get_or_init(|| libbpf_sys::bpf_object_open_opts {
148            sz: mem::size_of::<libbpf_sys::bpf_object_open_opts>() as libbpf_sys::size_t,
149            ..Default::default()
150        })
151    }
152
153    fn opts_mut(&mut self) -> &mut libbpf_sys::bpf_object_open_opts {
154        let _opts = self.opts();
155        // SANITY: We just made sure to initialize the object above.
156        self.opts.get_mut().unwrap()
157    }
158
159    /// Override the generated name that would have been inferred from the constructor.
160    pub fn name<T: AsRef<str>>(&mut self, name: T) -> Result<&mut Self> {
161        self.name = Some(util::str_to_cstring(name.as_ref())?);
162        self.opts_mut().object_name = self.name.as_ref().map_or(ptr::null(), |p| p.as_ptr());
163        Ok(self)
164    }
165
166    /// Set the `pin_root_path` for maps that are pinned by name.
167    ///
168    /// By default no path is set, which causes BPF to use `/sys/fs/bpf`.
169    pub fn pin_root_path<T: AsRef<Path>>(&mut self, path: T) -> Result<&mut Self> {
170        self.pin_root_path = Some(util::path_to_cstring(path)?);
171        self.opts_mut().pin_root_path = self
172            .pin_root_path
173            .as_ref()
174            .map_or(ptr::null(), |p| p.as_ptr());
175        Ok(self)
176    }
177
178    /// Set the `btf_custom_path`.
179    ///
180    /// By default, no path is set and libbpf probes to find the BTF file in a set
181    /// of well-known paths.
182    pub fn btf_custom_path<T: AsRef<Path>>(&mut self, path: T) -> Result<&mut Self> {
183        self.btf_custom_path = Some(util::path_to_cstring(path)?);
184        self.opts_mut().btf_custom_path = self
185            .btf_custom_path
186            .as_ref()
187            .map_or(ptr::null(), |p| p.as_ptr());
188        Ok(self)
189    }
190
191    /// Option to parse map definitions non-strictly, allowing extra attributes/data
192    pub fn relaxed_maps(&mut self, relaxed_maps: bool) -> &mut Self {
193        self.opts_mut().relaxed_maps = relaxed_maps;
194        self
195    }
196
197    /// Option to print debug output to stderr.
198    ///
199    /// Note: This function uses [`set_print`] internally and will overwrite any callbacks
200    /// currently in use.
201    pub fn debug(&mut self, dbg: bool) -> &mut Self {
202        if dbg {
203            set_print(Some((PrintLevel::Debug, |_, s| print!("{s}"))));
204        } else {
205            set_print(None);
206        }
207        self
208    }
209
210    /// Open an object using the provided path on the file system.
211    pub fn open_file<P: AsRef<Path>>(&mut self, path: P) -> Result<OpenObject> {
212        let path = path.as_ref();
213        let path_c = util::path_to_cstring(path)?;
214        let path_ptr = path_c.as_ptr();
215        let opts_ptr = self.as_libbpf_object().as_ptr();
216
217        let ptr = unsafe { libbpf_sys::bpf_object__open_file(path_ptr, opts_ptr) };
218        let ptr = validate_bpf_ret(ptr)
219            .with_context(|| format!("failed to open object from `{}`", path.display()))?;
220
221        let obj = unsafe { OpenObject::from_ptr(ptr) };
222        Ok(obj)
223    }
224
225    /// Open an object from memory.
226    pub fn open_memory(&mut self, mem: &[u8]) -> Result<OpenObject> {
227        let opts_ptr = self.as_libbpf_object().as_ptr();
228        let ptr = unsafe {
229            libbpf_sys::bpf_object__open_mem(
230                mem.as_ptr() as *const c_void,
231                mem.len() as libbpf_sys::size_t,
232                opts_ptr,
233            )
234        };
235        let ptr = validate_bpf_ret(ptr).context("failed to open object from memory")?;
236        let obj = unsafe { OpenObject::from_ptr(ptr) };
237        Ok(obj)
238    }
239}
240
241impl AsRawLibbpf for ObjectBuilder {
242    type LibbpfType = libbpf_sys::bpf_object_open_opts;
243
244    /// Retrieve the underlying [`libbpf_sys::bpf_object_open_opts`].
245    fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
246        // SAFETY: A reference is always a valid pointer.
247        unsafe { NonNull::new_unchecked(ptr::from_ref(self.opts()).cast_mut()) }
248    }
249}
250
251
252/// Represents an opened (but not yet loaded) BPF object file.
253///
254/// Use this object to access [`OpenMap`]s and [`OpenProgram`]s.
255#[derive(Debug)]
256#[repr(transparent)]
257pub struct OpenObject {
258    ptr: NonNull<libbpf_sys::bpf_object>,
259}
260
261impl OpenObject {
262    /// Takes ownership from pointer.
263    ///
264    /// # Safety
265    ///
266    /// Operations on the returned object are undefined if `ptr` is any one of:
267    ///     - null
268    ///     - points to an unopened `bpf_object`
269    ///     - points to a loaded `bpf_object`
270    ///
271    /// It is not safe to manipulate `ptr` after this operation.
272    pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self {
273        Self { ptr }
274    }
275
276    /// Takes underlying `libbpf_sys::bpf_object` pointer.
277    pub fn take_ptr(mut self) -> NonNull<libbpf_sys::bpf_object> {
278        let ptr = {
279            let Self { ptr } = &mut self;
280            *ptr
281        };
282        // avoid double free of self.ptr
283        mem::forget(self);
284        ptr
285    }
286
287    /// Retrieve the object's name.
288    pub fn name(&self) -> Option<&OsStr> {
289        // SAFETY: We ensured `ptr` is valid during construction.
290        let name_ptr = unsafe { libbpf_sys::bpf_object__name(self.ptr.as_ptr()) };
291        // SAFETY: `libbpf_get_error` is always safe to call.
292        let err = unsafe { libbpf_sys::libbpf_get_error(name_ptr as *const _) };
293        if err != 0 {
294            return None
295        }
296        let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
297        let str = OsStr::from_bytes(name_c_str.to_bytes());
298        Some(str)
299    }
300
301    /// Retrieve an iterator over all BPF maps in the object.
302    pub fn maps(&self) -> impl Iterator<Item = OpenMap<'_>> {
303        MapIter::new(unsafe { self.ptr.as_ref() }).map(|ptr| unsafe { OpenMap::new(ptr.as_ref()) })
304    }
305
306    /// Retrieve an iterator over all BPF maps in the object.
307    pub fn maps_mut(&mut self) -> impl Iterator<Item = OpenMapMut<'_>> {
308        MapIter::new(unsafe { self.ptr.as_ref() })
309            .map(|mut ptr| unsafe { OpenMapMut::new_mut(ptr.as_mut()) })
310    }
311
312    /// Retrieve an iterator over all BPF programs in the object.
313    pub fn progs(&self) -> impl Iterator<Item = OpenProgram<'_>> {
314        ProgIter::new(unsafe { self.ptr.as_ref() })
315            .map(|ptr| unsafe { OpenProgram::new(ptr.as_ref()) })
316    }
317
318    /// Retrieve an iterator over all BPF programs in the object.
319    pub fn progs_mut(&mut self) -> impl Iterator<Item = OpenProgramMut<'_>> {
320        ProgIter::new(unsafe { self.ptr.as_ref() })
321            .map(|mut ptr| unsafe { OpenProgramMut::new_mut(ptr.as_mut()) })
322    }
323
324    /// Load the maps and programs contained in this BPF object into the system.
325    pub fn load(self) -> Result<Object> {
326        let ret = unsafe { libbpf_sys::bpf_object__load(self.ptr.as_ptr()) };
327        let () = util::parse_ret(ret)?;
328
329        let obj = unsafe { Object::from_ptr(self.take_ptr()) };
330
331        Ok(obj)
332    }
333}
334
335// SAFETY: `bpf_object` is freely transferable between threads.
336unsafe impl Send for OpenObject {}
337// SAFETY: `bpf_object` has no interior mutability.
338unsafe impl Sync for OpenObject {}
339
340impl AsRawLibbpf for OpenObject {
341    type LibbpfType = libbpf_sys::bpf_object;
342
343    /// Retrieve the underlying [`libbpf_sys::bpf_object`].
344    fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
345        self.ptr
346    }
347}
348
349impl Drop for OpenObject {
350    fn drop(&mut self) {
351        // `self.ptr` may be null if `load()` was called. This is ok: libbpf noops
352        unsafe {
353            libbpf_sys::bpf_object__close(self.ptr.as_ptr());
354        }
355    }
356}
357
358
359/// Represents a loaded BPF object file.
360///
361/// An `Object` is logically in charge of all the contained [`Program`]s and [`Map`]s as well as
362/// the associated metadata and runtime state that underpins the userspace portions of BPF program
363/// execution. As a libbpf-rs user, you must keep the `Object` alive during the entire lifetime
364/// of your interaction with anything inside the `Object`.
365///
366/// Note that this is an explanation of the motivation -- Rust's lifetime system should already be
367/// enforcing this invariant.
368#[derive(Debug)]
369#[repr(transparent)]
370pub struct Object {
371    ptr: NonNull<libbpf_sys::bpf_object>,
372}
373
374impl Object {
375    /// Takes ownership from pointer.
376    ///
377    /// # Safety
378    ///
379    /// If `ptr` is not already loaded then further operations on the returned object are
380    /// undefined.
381    ///
382    /// It is not safe to manipulate `ptr` after this operation.
383    pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self {
384        Self { ptr }
385    }
386
387    /// Retrieve the object's name.
388    pub fn name(&self) -> Option<&OsStr> {
389        // SAFETY: We ensured `ptr` is valid during construction.
390        let name_ptr = unsafe { libbpf_sys::bpf_object__name(self.ptr.as_ptr()) };
391        // SAFETY: `libbpf_get_error` is always safe to call.
392        let err = unsafe { libbpf_sys::libbpf_get_error(name_ptr as *const _) };
393        if err != 0 {
394            return None
395        }
396        let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
397        let str = OsStr::from_bytes(name_c_str.to_bytes());
398        Some(str)
399    }
400
401    /// Parse the btf information associated with this bpf object.
402    pub fn btf(&self) -> Result<Option<Btf<'_>>> {
403        Btf::from_bpf_object(unsafe { &*self.ptr.as_ptr() })
404    }
405
406    /// Retrieve an iterator over all BPF maps in the object.
407    pub fn maps(&self) -> impl Iterator<Item = Map<'_>> {
408        MapIter::new(unsafe { self.ptr.as_ref() })
409            .filter(|ptr| map_fd(*ptr).is_some())
410            .map(|ptr| unsafe { Map::new(ptr.as_ref()) })
411    }
412
413    /// Retrieve an iterator over all BPF maps in the object.
414    pub fn maps_mut(&mut self) -> impl Iterator<Item = MapMut<'_>> {
415        MapIter::new(unsafe { self.ptr.as_ref() })
416            .filter(|ptr| map_fd(*ptr).is_some())
417            .map(|mut ptr| unsafe { MapMut::new_mut(ptr.as_mut()) })
418    }
419
420    /// Retrieve an iterator over all BPF programs in the object.
421    pub fn progs(&self) -> impl Iterator<Item = Program<'_>> {
422        ProgIter::new(unsafe { self.ptr.as_ref() }).map(|ptr| unsafe { Program::new(ptr.as_ref()) })
423    }
424
425    /// Retrieve an iterator over all BPF programs in the object.
426    pub fn progs_mut(&self) -> impl Iterator<Item = ProgramMut<'_>> {
427        ProgIter::new(unsafe { self.ptr.as_ref() })
428            .map(|mut ptr| unsafe { ProgramMut::new_mut(ptr.as_mut()) })
429    }
430}
431
432// SAFETY: `bpf_object` is freely transferable between threads.
433unsafe impl Send for Object {}
434// SAFETY: `bpf_object` has no interior mutability.
435unsafe impl Sync for Object {}
436
437impl AsRawLibbpf for Object {
438    type LibbpfType = libbpf_sys::bpf_object;
439
440    /// Retrieve the underlying [`libbpf_sys::bpf_object`].
441    fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
442        self.ptr
443    }
444}
445
446impl Drop for Object {
447    fn drop(&mut self) {
448        unsafe {
449            libbpf_sys::bpf_object__close(self.ptr.as_ptr());
450        }
451    }
452}