Skip to main content

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    /// Add a buffer to the set of objects to link.
56    pub fn add_buf(&mut self, buf: &[u8]) -> Result<()> {
57        let opts = null_mut();
58        // SAFETY: `linker` and `buf` are valid pointers.
59        let err = unsafe {
60            libbpf_sys::bpf_linker__add_buf(
61                self.linker.as_ptr(),
62                buf.as_ptr() as *mut _,
63                buf.len() as _,
64                opts,
65            )
66        };
67        if err != 0 {
68            Err(Error::from_raw_os_error(err)).context("bpf_linker__add_buf failed")
69        } else {
70            Ok(())
71        }
72    }
73
74    /// Link all BPF object files [added](Self::add_file) to this object into
75    /// a single one.
76    pub fn link(&self) -> Result<()> {
77        // SAFETY: `linker` is a valid pointer.
78        let err = unsafe { libbpf_sys::bpf_linker__finalize(self.linker.as_ptr()) };
79        if err != 0 {
80            return Err(Error::from_raw_os_error(err)).context("bpf_linker__finalize failed");
81        }
82        Ok(())
83    }
84}
85
86impl AsRawLibbpf for Linker {
87    type LibbpfType = libbpf_sys::bpf_linker;
88
89    /// Retrieve the underlying [`libbpf_sys::bpf_linker`].
90    fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
91        self.linker
92    }
93}
94
95// SAFETY: `bpf_linker` can be sent to a different thread.
96unsafe impl Send for Linker {}
97
98impl Drop for Linker {
99    fn drop(&mut self) {
100        // SAFETY: `linker` is a valid pointer returned by `bpf_linker__new`.
101        unsafe { libbpf_sys::bpf_linker__free(self.linker.as_ptr()) }
102    }
103}
104
105#[cfg(test)]
106mod test {
107    use super::*;
108
109    /// Check that `Linker` is `Send`.
110    #[test]
111    fn linker_is_send() {
112        fn test<T>()
113        where
114            T: Send,
115        {
116        }
117
118        test::<Linker>();
119    }
120}