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::util;
9use crate::util::validate_bpf_ret;
10use crate::AsRawLibbpf;
11use crate::ErrorExt as _;
12use crate::Program;
13use crate::Result;
14
15#[derive(Debug)]
20#[must_use = "not using this `Link` will detach the underlying program immediately"]
21pub struct Link {
22 ptr: NonNull<libbpf_sys::bpf_link>,
23}
24
25impl Link {
26 pub(crate) unsafe fn new(ptr: NonNull<libbpf_sys::bpf_link>) -> Self {
32 Link { ptr }
33 }
34
35 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
37 let path_c = util::path_to_cstring(path)?;
38 let path_ptr = path_c.as_ptr();
39 let ptr = unsafe { libbpf_sys::bpf_link__open(path_ptr) };
40 let ptr = validate_bpf_ret(ptr).context("failed to open link")?;
41 let slf = unsafe { Self::new(ptr) };
42 Ok(slf)
43 }
44
45 pub unsafe fn from_ptr(ptr: NonNull<libbpf_sys::bpf_link>) -> Self {
51 unsafe { Self::new(ptr) }
52 }
53
54 pub fn update_prog(&mut self, prog: &Program<'_>) -> Result<()> {
56 let ret =
57 unsafe { libbpf_sys::bpf_link__update_program(self.ptr.as_ptr(), prog.ptr.as_ptr()) };
58 util::parse_ret(ret)
59 }
60
61 pub fn disconnect(&mut self) {
71 unsafe { libbpf_sys::bpf_link__disconnect(self.ptr.as_ptr()) }
72 }
73
74 pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
77 let path_c = util::path_to_cstring(path)?;
78 let path_ptr = path_c.as_ptr();
79
80 let ret = unsafe { libbpf_sys::bpf_link__pin(self.ptr.as_ptr(), path_ptr) };
81 util::parse_ret(ret)
82 }
83
84 pub fn unpin(&mut self) -> Result<()> {
87 let ret = unsafe { libbpf_sys::bpf_link__unpin(self.ptr.as_ptr()) };
88 util::parse_ret(ret)
89 }
90
91 pub fn pin_path(&self) -> Option<PathBuf> {
93 let path_ptr = unsafe { libbpf_sys::bpf_link__pin_path(self.ptr.as_ptr()) };
94 if path_ptr.is_null() {
95 return None;
96 }
97
98 let path = match util::c_ptr_to_string(path_ptr) {
99 Ok(p) => p,
100 Err(_) => return None,
101 };
102
103 Some(PathBuf::from(path.as_str()))
104 }
105
106 pub fn detach(&self) -> Result<()> {
108 let ret = unsafe { libbpf_sys::bpf_link__detach(self.ptr.as_ptr()) };
109 util::parse_ret(ret)
110 }
111}
112
113impl AsRawLibbpf for Link {
114 type LibbpfType = libbpf_sys::bpf_link;
115
116 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
118 self.ptr
119 }
120}
121
122unsafe impl Send for Link {}
124
125impl AsFd for Link {
126 #[inline]
127 fn as_fd(&self) -> BorrowedFd<'_> {
128 let fd = unsafe { libbpf_sys::bpf_link__fd(self.ptr.as_ptr()) };
129 unsafe { BorrowedFd::borrow_raw(fd) }
133 }
134}
135
136impl Drop for Link {
137 fn drop(&mut self) {
138 let _ = unsafe { libbpf_sys::bpf_link__destroy(self.ptr.as_ptr()) };
139 }
140}