libbpf_rs/
linker.rs

1use std::path::Path;
2use std::ptr::null_mut;
3use std::ptr::NonNull;
4
5use crate::util::path_to_cstring;
6use crate::util::validate_bpf_ret;
7use crate::AsRawLibbpf;
8use crate::Error;
9use crate::ErrorExt as _;
10use crate::Result;
11
12/// A type used for linking multiple BPF object files into a single one.
13///
14/// Please refer to
15/// <https://lwn.net/ml/bpf/20210310040431.916483-6-andrii@kernel.org/> for
16/// additional details.
17#[derive(Debug)]
18pub struct Linker {
19    /// The `libbpf` linker object.
20    linker: NonNull<libbpf_sys::bpf_linker>,
21}
22
23impl Linker {
24    /// Instantiate a `Linker` object.
25    pub fn new<P>(output: P) -> Result<Self>
26    where
27        P: AsRef<Path>,
28    {
29        let output = path_to_cstring(output)?;
30        let opts = null_mut();
31        // SAFETY: `output` is a valid pointer and `opts` is accepted as NULL.
32        let ptr = unsafe { libbpf_sys::bpf_linker__new(output.as_ptr(), opts) };
33        let ptr = validate_bpf_ret(ptr).context("failed to attach iterator")?;
34        let slf = Self { linker: ptr };
35        Ok(slf)
36    }
37
38    /// Add a file to the set of files to link.
39    pub fn add_file<P>(&mut self, file: P) -> Result<()>
40    where
41        P: AsRef<Path>,
42    {
43        let file = path_to_cstring(file)?;
44        let opts = null_mut();
45        // SAFETY: `linker` and `file` are a valid pointers.
46        let err =
47            unsafe { libbpf_sys::bpf_linker__add_file(self.linker.as_ptr(), file.as_ptr(), opts) };
48        if err != 0 {
49            Err(Error::from_raw_os_error(err)).context("bpf_linker__add_file failed")
50        } else {
51            Ok(())
52        }
53    }
54
55    /// Link all BPF object files [added](Self::add_file) to this object into
56    /// a single one.
57    pub fn link(&self) -> Result<()> {
58        // SAFETY: `linker` is a valid pointer.
59        let err = unsafe { libbpf_sys::bpf_linker__finalize(self.linker.as_ptr()) };
60        if err != 0 {
61            return Err(Error::from_raw_os_error(err)).context("bpf_linker__finalize failed");
62        }
63        Ok(())
64    }
65}
66
67impl AsRawLibbpf for Linker {
68    type LibbpfType = libbpf_sys::bpf_linker;
69
70    /// Retrieve the underlying [`libbpf_sys::bpf_linker`].
71    fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
72        self.linker
73    }
74}
75
76// SAFETY: `bpf_linker` can be sent to a different thread.
77unsafe impl Send for Linker {}
78
79impl Drop for Linker {
80    fn drop(&mut self) {
81        // SAFETY: `linker` is a valid pointer returned by `bpf_linker__new`.
82        unsafe { libbpf_sys::bpf_linker__free(self.linker.as_ptr()) }
83    }
84}
85
86#[cfg(test)]
87mod test {
88    use super::*;
89
90    /// Check that `Linker` is `Send`.
91    #[test]
92    fn linker_is_send() {
93        fn test<T>()
94        where
95            T: Send,
96        {
97        }
98
99        test::<Linker>();
100    }
101}