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"]
22pub struct Link {
23 ptr: NonNull<libbpf_sys::bpf_link>,
24}
25
26impl Link {
27 pub(crate) unsafe fn new(ptr: NonNull<libbpf_sys::bpf_link>) -> Self {
33 Self { ptr }
34 }
35
36 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 pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_link>) -> Self {
52 unsafe { Self::new(ptr) }
53 }
54
55 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 pub fn disconnect(&mut self) {
72 unsafe { libbpf_sys::bpf_link__disconnect(self.ptr.as_ptr()) }
73 }
74
75 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 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 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 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 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 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
124 self.ptr
125 }
126}
127
128unsafe impl Send for Link {}
130unsafe 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 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}