1 use std::fmt::Debug; 2 use std::os::unix::io::AsFd; 3 use std::os::unix::io::BorrowedFd; 4 use std::path::Path; 5 use std::path::PathBuf; 6 use std::ptr::NonNull; 7 8 use crate::util; 9 use crate::util::validate_bpf_ret; 10 use crate::AsRawLibbpf; 11 use crate::ErrorExt as _; 12 use crate::Program; 13 use 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 pub struct Link { 21 ptr: NonNull<libbpf_sys::bpf_link>, 22 } 23 24 impl 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`]. new(ptr: NonNull<libbpf_sys::bpf_link>) -> Self30 pub(crate) unsafe fn new(ptr: NonNull<libbpf_sys::bpf_link>) -> Self { 31 Link { ptr } 32 } 33 34 /// Create link from BPF FS file. open<P: AsRef<Path>>(path: P) -> Result<Self>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. from_ptr(ptr: NonNull<libbpf_sys::bpf_link>) -> Self49 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`. update_prog(&mut self, prog: &Program<'_>) -> Result<()>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. disconnect(&mut self)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. pin<P: AsRef<Path>>(&mut self, path: P) -> Result<()>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 unpin(&mut self) -> Result<()>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. pin_path(&self) -> Option<PathBuf>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. detach(&self) -> Result<()>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 112 impl AsRawLibbpf for Link { 113 type LibbpfType = libbpf_sys::bpf_link; 114 115 /// Retrieve the underlying [`libbpf_sys::bpf_link`]. as_libbpf_object(&self) -> NonNull<Self::LibbpfType>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. 122 unsafe impl Send for Link {} 123 124 impl AsFd for Link { 125 #[inline] as_fd(&self) -> BorrowedFd<'_>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 135 impl Drop for Link { drop(&mut self)136 fn drop(&mut self) { 137 let _ = unsafe { libbpf_sys::bpf_link__destroy(self.ptr.as_ptr()) }; 138 } 139 } 140