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