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#[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 pub(crate) unsafe fn new(ptr: NonNull<libbpf_sys::bpf_link>) -> Self {
34 Self { ptr }
35 }
36
37 #[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 pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_link>) -> Self {
54 unsafe { Self::new(ptr) }
55 }
56
57 #[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 #[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 #[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 #[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 #[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 #[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 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 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
132 self.ptr
133 }
134}
135
136unsafe impl Send for Link {}
138unsafe 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 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}