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