Skip to main content

libbpf_rs/
link.rs

1use std::fmt::Debug;
2use std::os::unix::io::AsFd;
3use std::os::unix::io::BorrowedFd;
4use std::path::Path;
5use std::path::PathBuf;
6use std::ptr::NonNull;
7
8use crate::query::LinkInfo;
9use crate::util;
10use crate::util::validate_bpf_ret;
11use crate::AsRawLibbpf;
12use crate::ErrorExt as _;
13use crate::Program;
14use crate::Result;
15
16/// Represents an attached [`Program`].
17///
18/// This struct is used to model ownership. The underlying program will be detached
19/// when this object is dropped if nothing else is holding a reference count.
20#[derive(Debug)]
21#[must_use = "not using this `Link` will detach the underlying program immediately"]
22#[doc(alias = "bpf_link")]
23pub struct Link {
24    ptr: NonNull<libbpf_sys::bpf_link>,
25}
26
27impl Link {
28    /// Create a new [`Link`] from a [`libbpf_sys::bpf_link`].
29    ///
30    /// # Safety
31    ///
32    /// `ptr` must point to a correctly initialized [`libbpf_sys::bpf_link`].
33    pub(crate) unsafe fn new(ptr: NonNull<libbpf_sys::bpf_link>) -> Self {
34        Self { ptr }
35    }
36
37    /// Create link from BPF FS file.
38    #[doc(alias = "bpf_link__open")]
39    pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
40        let path_c = util::path_to_cstring(path)?;
41        let path_ptr = path_c.as_ptr();
42        let ptr = unsafe { libbpf_sys::bpf_link__open(path_ptr) };
43        let ptr = validate_bpf_ret(ptr).context("failed to open link")?;
44        let slf = unsafe { Self::new(ptr) };
45        Ok(slf)
46    }
47
48    /// Takes ownership from pointer.
49    ///
50    /// # Safety
51    ///
52    /// It is not safe to manipulate `ptr` after this operation.
53    pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_link>) -> Self {
54        unsafe { Self::new(ptr) }
55    }
56
57    /// Replace the underlying prog with `prog`.
58    #[doc(alias = "bpf_link__update_program")]
59    pub fn update_prog(&mut self, prog: &Program<'_>) -> Result<()> {
60        let ret =
61            unsafe { libbpf_sys::bpf_link__update_program(self.ptr.as_ptr(), prog.ptr.as_ptr()) };
62        util::parse_ret(ret)
63    }
64
65    /// Release "ownership" of underlying BPF resource (typically, a BPF program
66    /// attached to some BPF hook, e.g., tracepoint, kprobe, etc). Disconnected
67    /// links, when destructed through `bpf_link__destroy()` call won't attempt to
68    /// detach/unregistered that BPF resource. This is useful in situations where,
69    /// say, attached BPF program has to outlive userspace program that attached it
70    /// in the system. Depending on type of BPF program, though, there might be
71    /// additional steps (like pinning BPF program in BPF FS) necessary to ensure
72    /// exit of userspace program doesn't trigger automatic detachment and clean up
73    /// inside the kernel.
74    #[doc(alias = "bpf_link__disconnect")]
75    pub fn disconnect(&mut self) {
76        unsafe { libbpf_sys::bpf_link__disconnect(self.ptr.as_ptr()) }
77    }
78
79    /// [Pin](https://facebookmicrosites.github.io/bpf/blog/2018/08/31/object-lifetime.html#bpffs)
80    /// this link to bpffs.
81    #[doc(alias = "bpf_link__pin")]
82    pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
83        let path_c = util::path_to_cstring(path)?;
84        let path_ptr = path_c.as_ptr();
85
86        let ret = unsafe { libbpf_sys::bpf_link__pin(self.ptr.as_ptr(), path_ptr) };
87        util::parse_ret(ret)
88    }
89
90    /// [Unpin](https://facebookmicrosites.github.io/bpf/blog/2018/08/31/object-lifetime.html#bpffs)
91    /// from bpffs
92    #[doc(alias = "bpf_link__unpin")]
93    pub fn unpin(&mut self) -> Result<()> {
94        let ret = unsafe { libbpf_sys::bpf_link__unpin(self.ptr.as_ptr()) };
95        util::parse_ret(ret)
96    }
97
98    /// Returns path to BPF FS file or `None` if not pinned.
99    #[doc(alias = "bpf_link__pin_path")]
100    pub fn pin_path(&self) -> Option<PathBuf> {
101        let path_ptr = unsafe { libbpf_sys::bpf_link__pin_path(self.ptr.as_ptr()) };
102        if path_ptr.is_null() {
103            return None;
104        }
105
106        let path = match util::c_ptr_to_string(path_ptr) {
107            Ok(p) => p,
108            Err(_) => return None,
109        };
110
111        Some(PathBuf::from(path.as_str()))
112    }
113
114    /// Detach the link.
115    #[doc(alias = "bpf_link__detach")]
116    pub fn detach(&self) -> Result<()> {
117        let ret = unsafe { libbpf_sys::bpf_link__detach(self.ptr.as_ptr()) };
118        util::parse_ret(ret)
119    }
120
121    /// Get information about this link.
122    pub fn info(&self) -> Result<LinkInfo> {
123        LinkInfo::from_fd(self.as_fd())
124    }
125}
126
127impl AsRawLibbpf for Link {
128    type LibbpfType = libbpf_sys::bpf_link;
129
130    /// Retrieve the underlying [`libbpf_sys::bpf_link`].
131    fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
132        self.ptr
133    }
134}
135
136// SAFETY: `bpf_link` objects can safely be sent to a different thread.
137unsafe impl Send for Link {}
138// SAFETY: `bpf_link` has no interior mutability.
139unsafe impl Sync for Link {}
140
141impl AsFd for Link {
142    #[inline]
143    #[doc(alias = "bpf_link__fd")]
144    fn as_fd(&self) -> BorrowedFd<'_> {
145        let fd = unsafe { libbpf_sys::bpf_link__fd(self.ptr.as_ptr()) };
146        // SAFETY: `bpf_link__fd` always returns a valid fd and the underlying
147        //         libbpf object is not destroyed until the object is dropped,
148        //         which means the fd remains valid as well.
149        unsafe { BorrowedFd::borrow_raw(fd) }
150    }
151}
152
153impl Drop for Link {
154    #[doc(alias = "bpf_link__destroy")]
155    fn drop(&mut self) {
156        let _ = unsafe { libbpf_sys::bpf_link__destroy(self.ptr.as_ptr()) };
157    }
158}