libbpf_rs/
object.rs

1use core::ffi::c_void;
2use std::ffi::CStr;
3use std::ffi::CString;
4use std::ffi::OsStr;
5use std::mem;
6use std::os::unix::ffi::OsStrExt as _;
7use std::path::Path;
8use std::ptr;
9use std::ptr::addr_of;
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
110    opts: libbpf_sys::bpf_object_open_opts,
111}
112
113impl Default for ObjectBuilder {
114    fn default() -> Self {
115        let opts = libbpf_sys::bpf_object_open_opts {
116            sz: mem::size_of::<libbpf_sys::bpf_object_open_opts>() as libbpf_sys::size_t,
117            object_name: ptr::null(),
118            relaxed_maps: false,
119            pin_root_path: ptr::null(),
120            kconfig: ptr::null(),
121            btf_custom_path: ptr::null(),
122            kernel_log_buf: ptr::null_mut(),
123            kernel_log_size: 0,
124            kernel_log_level: 0,
125            ..Default::default()
126        };
127        Self {
128            name: None,
129            pin_root_path: None,
130            opts,
131        }
132    }
133}
134
135impl ObjectBuilder {
136    /// Override the generated name that would have been inferred from the constructor.
137    pub fn name<T: AsRef<str>>(&mut self, name: T) -> Result<&mut Self> {
138        self.name = Some(util::str_to_cstring(name.as_ref())?);
139        self.opts.object_name = self.name.as_ref().map_or(ptr::null(), |p| p.as_ptr());
140        Ok(self)
141    }
142
143    /// Set the pin_root_path for maps that are pinned by name.
144    ///
145    /// By default, this is NULL which bpf translates to /sys/fs/bpf
146    pub fn pin_root_path<T: AsRef<Path>>(&mut self, path: T) -> Result<&mut Self> {
147        self.pin_root_path = Some(util::path_to_cstring(path)?);
148        self.opts.pin_root_path = self
149            .pin_root_path
150            .as_ref()
151            .map_or(ptr::null(), |p| p.as_ptr());
152        Ok(self)
153    }
154
155    /// Option to parse map definitions non-strictly, allowing extra attributes/data
156    pub fn relaxed_maps(&mut self, relaxed_maps: bool) -> &mut Self {
157        self.opts.relaxed_maps = relaxed_maps;
158        self
159    }
160
161    /// Option to print debug output to stderr.
162    ///
163    /// Note: This function uses [`set_print`] internally and will overwrite any callbacks
164    /// currently in use.
165    pub fn debug(&mut self, dbg: bool) -> &mut Self {
166        if dbg {
167            set_print(Some((PrintLevel::Debug, |_, s| print!("{s}"))));
168        } else {
169            set_print(None);
170        }
171        self
172    }
173
174    /// Open an object using the provided path on the file system.
175    pub fn open_file<P: AsRef<Path>>(&mut self, path: P) -> Result<OpenObject> {
176        let path = path.as_ref();
177        let path_c = util::path_to_cstring(path)?;
178        let path_ptr = path_c.as_ptr();
179        let opts_ptr = self.as_libbpf_object().as_ptr();
180
181        let ptr = unsafe { libbpf_sys::bpf_object__open_file(path_ptr, opts_ptr) };
182        let ptr = validate_bpf_ret(ptr)
183            .with_context(|| format!("failed to open object from `{}`", path.display()))?;
184
185        let obj = unsafe { OpenObject::from_ptr(ptr) };
186        Ok(obj)
187    }
188
189    /// Open an object from memory.
190    pub fn open_memory(&mut self, mem: &[u8]) -> Result<OpenObject> {
191        let opts_ptr = self.as_libbpf_object().as_ptr();
192        let ptr = unsafe {
193            libbpf_sys::bpf_object__open_mem(
194                mem.as_ptr() as *const c_void,
195                mem.len() as libbpf_sys::size_t,
196                opts_ptr,
197            )
198        };
199        let ptr = validate_bpf_ret(ptr).context("failed to open object from memory")?;
200        let obj = unsafe { OpenObject::from_ptr(ptr) };
201        Ok(obj)
202    }
203}
204
205impl AsRawLibbpf for ObjectBuilder {
206    type LibbpfType = libbpf_sys::bpf_object_open_opts;
207
208    /// Retrieve the underlying [`libbpf_sys::bpf_object_open_opts`].
209    fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
210        // SAFETY: A reference is always a valid pointer.
211        unsafe { NonNull::new_unchecked(addr_of!(self.opts).cast_mut()) }
212    }
213}
214
215
216/// Represents an opened (but not yet loaded) BPF object file.
217///
218/// Use this object to access [`OpenMap`]s and [`OpenProgram`]s.
219#[derive(Debug)]
220#[repr(transparent)]
221pub struct OpenObject {
222    ptr: NonNull<libbpf_sys::bpf_object>,
223}
224
225impl OpenObject {
226    /// Takes ownership from pointer.
227    ///
228    /// # Safety
229    ///
230    /// Operations on the returned object are undefined if `ptr` is any one of:
231    ///     - null
232    ///     - points to an unopened `bpf_object`
233    ///     - points to a loaded `bpf_object`
234    ///
235    /// It is not safe to manipulate `ptr` after this operation.
236    pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self {
237        Self { ptr }
238    }
239
240    /// Takes underlying `libbpf_sys::bpf_object` pointer.
241    pub fn take_ptr(mut self) -> NonNull<libbpf_sys::bpf_object> {
242        let ptr = {
243            let Self { ptr } = &mut self;
244            *ptr
245        };
246        // avoid double free of self.ptr
247        mem::forget(self);
248        ptr
249    }
250
251    /// Retrieve the object's name.
252    pub fn name(&self) -> Option<&OsStr> {
253        // SAFETY: We ensured `ptr` is valid during construction.
254        let name_ptr = unsafe { libbpf_sys::bpf_object__name(self.ptr.as_ptr()) };
255        // SAFETY: `libbpf_get_error` is always safe to call.
256        let err = unsafe { libbpf_sys::libbpf_get_error(name_ptr as *const _) };
257        if err != 0 {
258            return None
259        }
260        let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
261        let str = OsStr::from_bytes(name_c_str.to_bytes());
262        Some(str)
263    }
264
265    /// Retrieve an iterator over all BPF maps in the object.
266    pub fn maps(&self) -> impl Iterator<Item = OpenMap<'_>> {
267        MapIter::new(unsafe { self.ptr.as_ref() }).map(|ptr| unsafe { OpenMap::new(ptr.as_ref()) })
268    }
269
270    /// Retrieve an iterator over all BPF maps in the object.
271    pub fn maps_mut(&mut self) -> impl Iterator<Item = OpenMapMut<'_>> {
272        MapIter::new(unsafe { self.ptr.as_ref() })
273            .map(|mut ptr| unsafe { OpenMapMut::new_mut(ptr.as_mut()) })
274    }
275
276    /// Retrieve an iterator over all BPF programs in the object.
277    pub fn progs(&self) -> impl Iterator<Item = OpenProgram<'_>> {
278        ProgIter::new(unsafe { self.ptr.as_ref() })
279            .map(|ptr| unsafe { OpenProgram::new(ptr.as_ref()) })
280    }
281
282    /// Retrieve an iterator over all BPF programs in the object.
283    pub fn progs_mut(&mut self) -> impl Iterator<Item = OpenProgramMut<'_>> {
284        ProgIter::new(unsafe { self.ptr.as_ref() })
285            .map(|mut ptr| unsafe { OpenProgramMut::new_mut(ptr.as_mut()) })
286    }
287
288    /// Load the maps and programs contained in this BPF object into the system.
289    pub fn load(self) -> Result<Object> {
290        let ret = unsafe { libbpf_sys::bpf_object__load(self.ptr.as_ptr()) };
291        let () = util::parse_ret(ret)?;
292
293        let obj = unsafe { Object::from_ptr(self.take_ptr()) };
294
295        Ok(obj)
296    }
297}
298
299impl AsRawLibbpf for OpenObject {
300    type LibbpfType = libbpf_sys::bpf_object;
301
302    /// Retrieve the underlying [`libbpf_sys::bpf_object`].
303    fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
304        self.ptr
305    }
306}
307
308impl Drop for OpenObject {
309    fn drop(&mut self) {
310        // `self.ptr` may be null if `load()` was called. This is ok: libbpf noops
311        unsafe {
312            libbpf_sys::bpf_object__close(self.ptr.as_ptr());
313        }
314    }
315}
316
317/// Represents a loaded BPF object file.
318///
319/// An `Object` is logically in charge of all the contained [`Program`]s and [`Map`]s as well as
320/// the associated metadata and runtime state that underpins the userspace portions of BPF program
321/// execution. As a libbpf-rs user, you must keep the `Object` alive during the entire lifetime
322/// of your interaction with anything inside the `Object`.
323///
324/// Note that this is an explanation of the motivation -- Rust's lifetime system should already be
325/// enforcing this invariant.
326#[derive(Debug)]
327#[repr(transparent)]
328pub struct Object {
329    ptr: NonNull<libbpf_sys::bpf_object>,
330}
331
332impl Object {
333    /// Takes ownership from pointer.
334    ///
335    /// # Safety
336    ///
337    /// If `ptr` is not already loaded then further operations on the returned object are
338    /// undefined.
339    ///
340    /// It is not safe to manipulate `ptr` after this operation.
341    pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_object>) -> Self {
342        Self { ptr }
343    }
344
345    /// Retrieve the object's name.
346    pub fn name(&self) -> Option<&OsStr> {
347        // SAFETY: We ensured `ptr` is valid during construction.
348        let name_ptr = unsafe { libbpf_sys::bpf_object__name(self.ptr.as_ptr()) };
349        // SAFETY: `libbpf_get_error` is always safe to call.
350        let err = unsafe { libbpf_sys::libbpf_get_error(name_ptr as *const _) };
351        if err != 0 {
352            return None
353        }
354        let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
355        let str = OsStr::from_bytes(name_c_str.to_bytes());
356        Some(str)
357    }
358
359    /// Parse the btf information associated with this bpf object.
360    pub fn btf(&self) -> Result<Option<Btf<'_>>> {
361        Btf::from_bpf_object(unsafe { &*self.ptr.as_ptr() })
362    }
363
364    /// Retrieve an iterator over all BPF maps in the object.
365    pub fn maps(&self) -> impl Iterator<Item = Map<'_>> {
366        MapIter::new(unsafe { self.ptr.as_ref() })
367            .filter(|ptr| map_fd(*ptr).is_some())
368            .map(|ptr| unsafe { Map::new(ptr.as_ref()) })
369    }
370
371    /// Retrieve an iterator over all BPF maps in the object.
372    pub fn maps_mut(&mut self) -> impl Iterator<Item = MapMut<'_>> {
373        MapIter::new(unsafe { self.ptr.as_ref() })
374            .filter(|ptr| map_fd(*ptr).is_some())
375            .map(|mut ptr| unsafe { MapMut::new_mut(ptr.as_mut()) })
376    }
377
378    /// Retrieve an iterator over all BPF programs in the object.
379    pub fn progs(&self) -> impl Iterator<Item = Program<'_>> {
380        ProgIter::new(unsafe { self.ptr.as_ref() }).map(|ptr| unsafe { Program::new(ptr.as_ref()) })
381    }
382
383    /// Retrieve an iterator over all BPF programs in the object.
384    pub fn progs_mut(&self) -> impl Iterator<Item = ProgramMut<'_>> {
385        ProgIter::new(unsafe { self.ptr.as_ref() })
386            .map(|mut ptr| unsafe { ProgramMut::new_mut(ptr.as_mut()) })
387    }
388}
389
390impl AsRawLibbpf for Object {
391    type LibbpfType = libbpf_sys::bpf_object;
392
393    /// Retrieve the underlying [`libbpf_sys::bpf_object`].
394    fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
395        self.ptr
396    }
397}
398
399impl Drop for Object {
400    fn drop(&mut self) {
401        unsafe {
402            libbpf_sys::bpf_object__close(self.ptr.as_ptr());
403        }
404    }
405}