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