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