1#![allow(rustdoc::private_intra_doc_links)]
4
5use std::ffi::c_void;
6use std::ffi::CStr;
7use std::ffi::CString;
8use std::ffi::OsStr;
9use std::marker::PhantomData;
10use std::mem;
11use std::mem::size_of;
12use std::mem::size_of_val;
13use std::mem::transmute;
14use std::ops::Deref;
15use std::os::unix::ffi::OsStrExt as _;
16use std::os::unix::io::AsFd;
17use std::os::unix::io::AsRawFd;
18use std::os::unix::io::BorrowedFd;
19use std::os::unix::io::FromRawFd;
20use std::os::unix::io::OwnedFd;
21use std::path::Path;
22use std::ptr;
23use std::ptr::NonNull;
24use std::slice;
25use std::time::Duration;
26
27use libbpf_sys::bpf_func_id;
28
29use crate::netfilter;
30use crate::util;
31use crate::util::validate_bpf_ret;
32use crate::util::BpfObjectType;
33use crate::AsRawLibbpf;
34use crate::Error;
35use crate::ErrorExt as _;
36use crate::Link;
37use crate::Mut;
38use crate::RawTracepointOpts;
39use crate::Result;
40use crate::TracepointCategory;
41use crate::TracepointOpts;
42
43#[derive(Clone, Debug, Default)]
45pub struct UprobeOpts {
46 pub ref_ctr_offset: usize,
48 pub cookie: u64,
50 pub retprobe: bool,
52 pub func_name: Option<String>,
64 #[doc(hidden)]
65 pub _non_exhaustive: (),
66}
67
68#[derive(Clone, Debug, Default)]
70pub struct UsdtOpts {
71 pub cookie: u64,
73 #[doc(hidden)]
74 pub _non_exhaustive: (),
75}
76
77impl From<UsdtOpts> for libbpf_sys::bpf_usdt_opts {
78 fn from(opts: UsdtOpts) -> Self {
79 let UsdtOpts {
80 cookie,
81 _non_exhaustive,
82 } = opts;
83 #[allow(clippy::needless_update)]
84 libbpf_sys::bpf_usdt_opts {
85 sz: size_of::<Self>() as _,
86 usdt_cookie: cookie,
87 ..Default::default()
89 }
90 }
91}
92
93#[derive(Clone, Debug, Default)]
95pub struct KprobeOpts {
96 pub cookie: u64,
98 #[doc(hidden)]
99 pub _non_exhaustive: (),
100}
101
102impl From<KprobeOpts> for libbpf_sys::bpf_kprobe_opts {
103 fn from(opts: KprobeOpts) -> Self {
104 let KprobeOpts {
105 cookie,
106 _non_exhaustive,
107 } = opts;
108
109 #[allow(clippy::needless_update)]
110 libbpf_sys::bpf_kprobe_opts {
111 sz: size_of::<Self>() as _,
112 bpf_cookie: cookie,
113 ..Default::default()
115 }
116 }
117}
118
119#[derive(Clone, Debug, Default)]
121pub struct KprobeMultiOpts {
122 pub symbols: Vec<String>,
124 pub cookies: Vec<u64>,
126 pub retprobe: bool,
128 #[doc(hidden)]
129 pub _non_exhaustive: (),
130}
131
132#[derive(Clone, Debug, Default)]
134pub struct PerfEventOpts {
135 pub cookie: u64,
137 pub force_ioctl_attach: bool,
139 #[doc(hidden)]
140 pub _non_exhaustive: (),
141}
142
143impl From<PerfEventOpts> for libbpf_sys::bpf_perf_event_opts {
144 fn from(opts: PerfEventOpts) -> Self {
145 let PerfEventOpts {
146 cookie,
147 force_ioctl_attach,
148 _non_exhaustive,
149 } = opts;
150
151 #[allow(clippy::needless_update)]
152 libbpf_sys::bpf_perf_event_opts {
153 sz: size_of::<Self>() as _,
154 bpf_cookie: cookie,
155 force_ioctl_attach,
156 ..Default::default()
158 }
159 }
160}
161
162pub type OpenProgram<'obj> = OpenProgramImpl<'obj>;
164pub type OpenProgramMut<'obj> = OpenProgramImpl<'obj, Mut>;
166
167#[derive(Debug)]
171#[repr(transparent)]
172pub struct OpenProgramImpl<'obj, T = ()> {
173 ptr: NonNull<libbpf_sys::bpf_program>,
174 _phantom: PhantomData<&'obj T>,
175}
176
177impl<'obj> OpenProgram<'obj> {
178 pub fn new(prog: &'obj libbpf_sys::bpf_program) -> Self {
180 Self {
183 ptr: unsafe { NonNull::new_unchecked(prog as *const _ as *mut _) },
184 _phantom: PhantomData,
185 }
186 }
187
188 pub fn prog_type(&self) -> ProgramType {
190 ProgramType::from(unsafe { libbpf_sys::bpf_program__type(self.ptr.as_ptr()) })
191 }
192
193 pub fn name(&self) -> &OsStr {
195 let name_ptr = unsafe { libbpf_sys::bpf_program__name(self.ptr.as_ptr()) };
196 let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
197 OsStr::from_bytes(name_c_str.to_bytes())
199 }
200
201 pub fn section(&self) -> &OsStr {
203 let p = unsafe { libbpf_sys::bpf_program__section_name(self.ptr.as_ptr()) };
205 let section_c_str = unsafe { CStr::from_ptr(p) };
208 let section = OsStr::from_bytes(section_c_str.to_bytes());
209 section
210 }
211
212 pub fn insn_cnt(&self) -> usize {
218 unsafe { libbpf_sys::bpf_program__insn_cnt(self.ptr.as_ptr()) as usize }
219 }
220
221 pub fn insns(&self) -> &[libbpf_sys::bpf_insn] {
231 let count = self.insn_cnt();
232 let ptr = unsafe { libbpf_sys::bpf_program__insns(self.ptr.as_ptr()) };
233 unsafe { slice::from_raw_parts(ptr, count) }
234 }
235}
236
237impl<'obj> OpenProgramMut<'obj> {
238 pub fn new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self {
240 Self {
241 ptr: unsafe { NonNull::new_unchecked(prog as *mut _) },
242 _phantom: PhantomData,
243 }
244 }
245
246 pub fn set_prog_type(&mut self, prog_type: ProgramType) {
248 let rc = unsafe { libbpf_sys::bpf_program__set_type(self.ptr.as_ptr(), prog_type as u32) };
249 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
250 }
251
252 pub fn set_attach_type(&mut self, attach_type: ProgramAttachType) {
254 let rc = unsafe {
255 libbpf_sys::bpf_program__set_expected_attach_type(self.ptr.as_ptr(), attach_type as u32)
256 };
257 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
258 }
259
260 pub fn set_ifindex(&mut self, idx: u32) {
264 unsafe { libbpf_sys::bpf_program__set_ifindex(self.ptr.as_ptr(), idx) }
265 }
266
267 pub fn set_log_level(&mut self, log_level: u32) {
276 let rc = unsafe { libbpf_sys::bpf_program__set_log_level(self.ptr.as_ptr(), log_level) };
277 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
278 }
279
280 pub fn set_autoload(&mut self, autoload: bool) {
283 let rc = unsafe { libbpf_sys::bpf_program__set_autoload(self.ptr.as_ptr(), autoload) };
284 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
285 }
286
287 pub fn set_autoattach(&mut self, autoattach: bool) {
290 unsafe { libbpf_sys::bpf_program__set_autoattach(self.ptr.as_ptr(), autoattach) };
291 }
292
293 #[allow(missing_docs)]
294 pub fn set_attach_target(
295 &mut self,
296 attach_prog_fd: i32,
297 attach_func_name: Option<String>,
298 ) -> Result<()> {
299 let name_c = if let Some(name) = attach_func_name {
300 Some(util::str_to_cstring(&name)?)
301 } else {
302 None
303 };
304 let name_ptr = name_c.as_ref().map_or(ptr::null(), |name| name.as_ptr());
305 let ret = unsafe {
306 libbpf_sys::bpf_program__set_attach_target(self.ptr.as_ptr(), attach_prog_fd, name_ptr)
307 };
308 util::parse_ret(ret)
309 }
310
311 pub fn set_flags(&mut self, flags: u32) {
313 let rc = unsafe { libbpf_sys::bpf_program__set_flags(self.ptr.as_ptr(), flags) };
314 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
315 }
316}
317
318impl<'obj> Deref for OpenProgramMut<'obj> {
319 type Target = OpenProgram<'obj>;
320
321 fn deref(&self) -> &Self::Target {
322 unsafe { transmute::<&OpenProgramMut<'obj>, &OpenProgram<'obj>>(self) }
325 }
326}
327
328impl<T> AsRawLibbpf for OpenProgramImpl<'_, T> {
329 type LibbpfType = libbpf_sys::bpf_program;
330
331 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
333 self.ptr
334 }
335}
336
337#[non_exhaustive]
339#[repr(u32)]
340#[derive(Copy, Clone, Debug)]
341#[allow(missing_docs)]
343pub enum ProgramType {
344 Unspec = 0,
345 SocketFilter = libbpf_sys::BPF_PROG_TYPE_SOCKET_FILTER,
346 Kprobe = libbpf_sys::BPF_PROG_TYPE_KPROBE,
347 SchedCls = libbpf_sys::BPF_PROG_TYPE_SCHED_CLS,
348 SchedAct = libbpf_sys::BPF_PROG_TYPE_SCHED_ACT,
349 Tracepoint = libbpf_sys::BPF_PROG_TYPE_TRACEPOINT,
350 Xdp = libbpf_sys::BPF_PROG_TYPE_XDP,
351 PerfEvent = libbpf_sys::BPF_PROG_TYPE_PERF_EVENT,
352 CgroupSkb = libbpf_sys::BPF_PROG_TYPE_CGROUP_SKB,
353 CgroupSock = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCK,
354 LwtIn = libbpf_sys::BPF_PROG_TYPE_LWT_IN,
355 LwtOut = libbpf_sys::BPF_PROG_TYPE_LWT_OUT,
356 LwtXmit = libbpf_sys::BPF_PROG_TYPE_LWT_XMIT,
357 SockOps = libbpf_sys::BPF_PROG_TYPE_SOCK_OPS,
358 SkSkb = libbpf_sys::BPF_PROG_TYPE_SK_SKB,
359 CgroupDevice = libbpf_sys::BPF_PROG_TYPE_CGROUP_DEVICE,
360 SkMsg = libbpf_sys::BPF_PROG_TYPE_SK_MSG,
361 RawTracepoint = libbpf_sys::BPF_PROG_TYPE_RAW_TRACEPOINT,
362 CgroupSockAddr = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
363 LwtSeg6local = libbpf_sys::BPF_PROG_TYPE_LWT_SEG6LOCAL,
364 LircMode2 = libbpf_sys::BPF_PROG_TYPE_LIRC_MODE2,
365 SkReuseport = libbpf_sys::BPF_PROG_TYPE_SK_REUSEPORT,
366 FlowDissector = libbpf_sys::BPF_PROG_TYPE_FLOW_DISSECTOR,
367 CgroupSysctl = libbpf_sys::BPF_PROG_TYPE_CGROUP_SYSCTL,
368 RawTracepointWritable = libbpf_sys::BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
369 CgroupSockopt = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCKOPT,
370 Tracing = libbpf_sys::BPF_PROG_TYPE_TRACING,
371 StructOps = libbpf_sys::BPF_PROG_TYPE_STRUCT_OPS,
372 Ext = libbpf_sys::BPF_PROG_TYPE_EXT,
373 Lsm = libbpf_sys::BPF_PROG_TYPE_LSM,
374 SkLookup = libbpf_sys::BPF_PROG_TYPE_SK_LOOKUP,
375 Syscall = libbpf_sys::BPF_PROG_TYPE_SYSCALL,
376 Unknown = u32::MAX,
378}
379
380impl ProgramType {
381 pub fn is_supported(&self) -> Result<bool> {
386 let ret = unsafe { libbpf_sys::libbpf_probe_bpf_prog_type(*self as u32, ptr::null()) };
387 match ret {
388 0 => Ok(false),
389 1 => Ok(true),
390 _ => Err(Error::from_raw_os_error(-ret)),
391 }
392 }
393
394 pub fn is_helper_supported(&self, helper_id: bpf_func_id) -> Result<bool> {
400 let ret =
401 unsafe { libbpf_sys::libbpf_probe_bpf_helper(*self as u32, helper_id, ptr::null()) };
402 match ret {
403 0 => Ok(false),
404 1 => Ok(true),
405 _ => Err(Error::from_raw_os_error(-ret)),
406 }
407 }
408}
409
410impl From<u32> for ProgramType {
411 fn from(value: u32) -> Self {
412 use ProgramType::*;
413
414 match value {
415 x if x == Unspec as u32 => Unspec,
416 x if x == SocketFilter as u32 => SocketFilter,
417 x if x == Kprobe as u32 => Kprobe,
418 x if x == SchedCls as u32 => SchedCls,
419 x if x == SchedAct as u32 => SchedAct,
420 x if x == Tracepoint as u32 => Tracepoint,
421 x if x == Xdp as u32 => Xdp,
422 x if x == PerfEvent as u32 => PerfEvent,
423 x if x == CgroupSkb as u32 => CgroupSkb,
424 x if x == CgroupSock as u32 => CgroupSock,
425 x if x == LwtIn as u32 => LwtIn,
426 x if x == LwtOut as u32 => LwtOut,
427 x if x == LwtXmit as u32 => LwtXmit,
428 x if x == SockOps as u32 => SockOps,
429 x if x == SkSkb as u32 => SkSkb,
430 x if x == CgroupDevice as u32 => CgroupDevice,
431 x if x == SkMsg as u32 => SkMsg,
432 x if x == RawTracepoint as u32 => RawTracepoint,
433 x if x == CgroupSockAddr as u32 => CgroupSockAddr,
434 x if x == LwtSeg6local as u32 => LwtSeg6local,
435 x if x == LircMode2 as u32 => LircMode2,
436 x if x == SkReuseport as u32 => SkReuseport,
437 x if x == FlowDissector as u32 => FlowDissector,
438 x if x == CgroupSysctl as u32 => CgroupSysctl,
439 x if x == RawTracepointWritable as u32 => RawTracepointWritable,
440 x if x == CgroupSockopt as u32 => CgroupSockopt,
441 x if x == Tracing as u32 => Tracing,
442 x if x == StructOps as u32 => StructOps,
443 x if x == Ext as u32 => Ext,
444 x if x == Lsm as u32 => Lsm,
445 x if x == SkLookup as u32 => SkLookup,
446 x if x == Syscall as u32 => Syscall,
447 _ => Unknown,
448 }
449 }
450}
451
452#[non_exhaustive]
454#[repr(u32)]
455#[derive(Clone, Debug)]
456#[allow(missing_docs)]
458pub enum ProgramAttachType {
459 CgroupInetIngress = libbpf_sys::BPF_CGROUP_INET_INGRESS,
460 CgroupInetEgress = libbpf_sys::BPF_CGROUP_INET_EGRESS,
461 CgroupInetSockCreate = libbpf_sys::BPF_CGROUP_INET_SOCK_CREATE,
462 CgroupSockOps = libbpf_sys::BPF_CGROUP_SOCK_OPS,
463 SkSkbStreamParser = libbpf_sys::BPF_SK_SKB_STREAM_PARSER,
464 SkSkbStreamVerdict = libbpf_sys::BPF_SK_SKB_STREAM_VERDICT,
465 CgroupDevice = libbpf_sys::BPF_CGROUP_DEVICE,
466 SkMsgVerdict = libbpf_sys::BPF_SK_MSG_VERDICT,
467 CgroupInet4Bind = libbpf_sys::BPF_CGROUP_INET4_BIND,
468 CgroupInet6Bind = libbpf_sys::BPF_CGROUP_INET6_BIND,
469 CgroupInet4Connect = libbpf_sys::BPF_CGROUP_INET4_CONNECT,
470 CgroupInet6Connect = libbpf_sys::BPF_CGROUP_INET6_CONNECT,
471 CgroupInet4PostBind = libbpf_sys::BPF_CGROUP_INET4_POST_BIND,
472 CgroupInet6PostBind = libbpf_sys::BPF_CGROUP_INET6_POST_BIND,
473 CgroupUdp4Sendmsg = libbpf_sys::BPF_CGROUP_UDP4_SENDMSG,
474 CgroupUdp6Sendmsg = libbpf_sys::BPF_CGROUP_UDP6_SENDMSG,
475 LircMode2 = libbpf_sys::BPF_LIRC_MODE2,
476 FlowDissector = libbpf_sys::BPF_FLOW_DISSECTOR,
477 CgroupSysctl = libbpf_sys::BPF_CGROUP_SYSCTL,
478 CgroupUdp4Recvmsg = libbpf_sys::BPF_CGROUP_UDP4_RECVMSG,
479 CgroupUdp6Recvmsg = libbpf_sys::BPF_CGROUP_UDP6_RECVMSG,
480 CgroupGetsockopt = libbpf_sys::BPF_CGROUP_GETSOCKOPT,
481 CgroupSetsockopt = libbpf_sys::BPF_CGROUP_SETSOCKOPT,
482 TraceRawTp = libbpf_sys::BPF_TRACE_RAW_TP,
483 TraceFentry = libbpf_sys::BPF_TRACE_FENTRY,
484 TraceFexit = libbpf_sys::BPF_TRACE_FEXIT,
485 ModifyReturn = libbpf_sys::BPF_MODIFY_RETURN,
486 LsmMac = libbpf_sys::BPF_LSM_MAC,
487 TraceIter = libbpf_sys::BPF_TRACE_ITER,
488 CgroupInet4Getpeername = libbpf_sys::BPF_CGROUP_INET4_GETPEERNAME,
489 CgroupInet6Getpeername = libbpf_sys::BPF_CGROUP_INET6_GETPEERNAME,
490 CgroupInet4Getsockname = libbpf_sys::BPF_CGROUP_INET4_GETSOCKNAME,
491 CgroupInet6Getsockname = libbpf_sys::BPF_CGROUP_INET6_GETSOCKNAME,
492 XdpDevmap = libbpf_sys::BPF_XDP_DEVMAP,
493 CgroupInetSockRelease = libbpf_sys::BPF_CGROUP_INET_SOCK_RELEASE,
494 XdpCpumap = libbpf_sys::BPF_XDP_CPUMAP,
495 SkLookup = libbpf_sys::BPF_SK_LOOKUP,
496 Xdp = libbpf_sys::BPF_XDP,
497 SkSkbVerdict = libbpf_sys::BPF_SK_SKB_VERDICT,
498 SkReuseportSelect = libbpf_sys::BPF_SK_REUSEPORT_SELECT,
499 SkReuseportSelectOrMigrate = libbpf_sys::BPF_SK_REUSEPORT_SELECT_OR_MIGRATE,
500 PerfEvent = libbpf_sys::BPF_PERF_EVENT,
501 KprobeMulti = libbpf_sys::BPF_TRACE_KPROBE_MULTI,
502 NetkitPeer = libbpf_sys::BPF_NETKIT_PEER,
503 TraceUprobeMulti = libbpf_sys::BPF_TRACE_UPROBE_MULTI,
504 LsmCgroup = libbpf_sys::BPF_LSM_CGROUP,
505 TraceKprobeSession = libbpf_sys::BPF_TRACE_KPROBE_SESSION,
506 TcxIngress = libbpf_sys::BPF_TCX_INGRESS,
507 TcxEgress = libbpf_sys::BPF_TCX_EGRESS,
508 Netfilter = libbpf_sys::BPF_NETFILTER,
509 CgroupUnixGetsockname = libbpf_sys::BPF_CGROUP_UNIX_GETSOCKNAME,
510 CgroupUnixSendmsg = libbpf_sys::BPF_CGROUP_UNIX_SENDMSG,
511 NetkitPrimary = libbpf_sys::BPF_NETKIT_PRIMARY,
512 CgroupUnixRecvmsg = libbpf_sys::BPF_CGROUP_UNIX_RECVMSG,
513 CgroupUnixConnect = libbpf_sys::BPF_CGROUP_UNIX_CONNECT,
514 CgroupUnixGetpeername = libbpf_sys::BPF_CGROUP_UNIX_GETPEERNAME,
515 StructOps = libbpf_sys::BPF_STRUCT_OPS,
516 Unknown = u32::MAX,
518}
519
520impl From<u32> for ProgramAttachType {
521 fn from(value: u32) -> Self {
522 use ProgramAttachType::*;
523
524 match value {
525 x if x == CgroupInetIngress as u32 => CgroupInetIngress,
526 x if x == CgroupInetEgress as u32 => CgroupInetEgress,
527 x if x == CgroupInetSockCreate as u32 => CgroupInetSockCreate,
528 x if x == CgroupSockOps as u32 => CgroupSockOps,
529 x if x == SkSkbStreamParser as u32 => SkSkbStreamParser,
530 x if x == SkSkbStreamVerdict as u32 => SkSkbStreamVerdict,
531 x if x == CgroupDevice as u32 => CgroupDevice,
532 x if x == SkMsgVerdict as u32 => SkMsgVerdict,
533 x if x == CgroupInet4Bind as u32 => CgroupInet4Bind,
534 x if x == CgroupInet6Bind as u32 => CgroupInet6Bind,
535 x if x == CgroupInet4Connect as u32 => CgroupInet4Connect,
536 x if x == CgroupInet6Connect as u32 => CgroupInet6Connect,
537 x if x == CgroupInet4PostBind as u32 => CgroupInet4PostBind,
538 x if x == CgroupInet6PostBind as u32 => CgroupInet6PostBind,
539 x if x == CgroupUdp4Sendmsg as u32 => CgroupUdp4Sendmsg,
540 x if x == CgroupUdp6Sendmsg as u32 => CgroupUdp6Sendmsg,
541 x if x == LircMode2 as u32 => LircMode2,
542 x if x == FlowDissector as u32 => FlowDissector,
543 x if x == CgroupSysctl as u32 => CgroupSysctl,
544 x if x == CgroupUdp4Recvmsg as u32 => CgroupUdp4Recvmsg,
545 x if x == CgroupUdp6Recvmsg as u32 => CgroupUdp6Recvmsg,
546 x if x == CgroupGetsockopt as u32 => CgroupGetsockopt,
547 x if x == CgroupSetsockopt as u32 => CgroupSetsockopt,
548 x if x == TraceRawTp as u32 => TraceRawTp,
549 x if x == TraceFentry as u32 => TraceFentry,
550 x if x == TraceFexit as u32 => TraceFexit,
551 x if x == ModifyReturn as u32 => ModifyReturn,
552 x if x == LsmMac as u32 => LsmMac,
553 x if x == TraceIter as u32 => TraceIter,
554 x if x == CgroupInet4Getpeername as u32 => CgroupInet4Getpeername,
555 x if x == CgroupInet6Getpeername as u32 => CgroupInet6Getpeername,
556 x if x == CgroupInet4Getsockname as u32 => CgroupInet4Getsockname,
557 x if x == CgroupInet6Getsockname as u32 => CgroupInet6Getsockname,
558 x if x == XdpDevmap as u32 => XdpDevmap,
559 x if x == CgroupInetSockRelease as u32 => CgroupInetSockRelease,
560 x if x == XdpCpumap as u32 => XdpCpumap,
561 x if x == SkLookup as u32 => SkLookup,
562 x if x == Xdp as u32 => Xdp,
563 x if x == SkSkbVerdict as u32 => SkSkbVerdict,
564 x if x == SkReuseportSelect as u32 => SkReuseportSelect,
565 x if x == SkReuseportSelectOrMigrate as u32 => SkReuseportSelectOrMigrate,
566 x if x == PerfEvent as u32 => PerfEvent,
567 x if x == KprobeMulti as u32 => KprobeMulti,
568 x if x == NetkitPeer as u32 => NetkitPeer,
569 x if x == TraceUprobeMulti as u32 => TraceUprobeMulti,
570 x if x == LsmCgroup as u32 => LsmCgroup,
571 x if x == TraceKprobeSession as u32 => TraceKprobeSession,
572 x if x == TcxIngress as u32 => TcxIngress,
573 x if x == TcxEgress as u32 => TcxEgress,
574 x if x == Netfilter as u32 => Netfilter,
575 x if x == CgroupUnixGetsockname as u32 => CgroupUnixGetsockname,
576 x if x == CgroupUnixSendmsg as u32 => CgroupUnixSendmsg,
577 x if x == NetkitPrimary as u32 => NetkitPrimary,
578 x if x == CgroupUnixRecvmsg as u32 => CgroupUnixRecvmsg,
579 x if x == CgroupUnixConnect as u32 => CgroupUnixConnect,
580 x if x == CgroupUnixGetpeername as u32 => CgroupUnixGetpeername,
581 x if x == StructOps as u32 => StructOps,
582 _ => Unknown,
583 }
584 }
585}
586
587#[derive(Debug, Default)]
592pub struct Input<'dat> {
593 pub context_in: Option<&'dat mut [u8]>,
597 pub context_out: Option<&'dat mut [u8]>,
599 pub data_in: Option<&'dat [u8]>,
601 pub data_out: Option<&'dat mut [u8]>,
603 pub cpu: u32,
605 pub flags: u32,
607 pub repeat: u32,
610 #[doc(hidden)]
612 pub _non_exhaustive: (),
613}
614
615#[derive(Debug)]
620pub struct Output<'dat> {
621 pub return_value: u32,
623 pub context: Option<&'dat mut [u8]>,
625 pub data: Option<&'dat mut [u8]>,
627 pub duration: Duration,
629 #[doc(hidden)]
631 pub _non_exhaustive: (),
632}
633
634pub type Program<'obj> = ProgramImpl<'obj>;
636pub type ProgramMut<'obj> = ProgramImpl<'obj, Mut>;
638
639
640#[derive(Debug)]
648#[repr(transparent)]
649pub struct ProgramImpl<'obj, T = ()> {
650 pub(crate) ptr: NonNull<libbpf_sys::bpf_program>,
651 _phantom: PhantomData<&'obj T>,
652}
653
654impl<'obj> Program<'obj> {
655 pub fn new(prog: &'obj libbpf_sys::bpf_program) -> Self {
657 Self {
660 ptr: unsafe { NonNull::new_unchecked(prog as *const _ as *mut _) },
661 _phantom: PhantomData,
662 }
663 }
664
665 pub fn name(&self) -> &OsStr {
667 let name_ptr = unsafe { libbpf_sys::bpf_program__name(self.ptr.as_ptr()) };
668 let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
669 OsStr::from_bytes(name_c_str.to_bytes())
671 }
672
673 pub fn section(&self) -> &OsStr {
675 let p = unsafe { libbpf_sys::bpf_program__section_name(self.ptr.as_ptr()) };
677 let section_c_str = unsafe { CStr::from_ptr(p) };
680 let section = OsStr::from_bytes(section_c_str.to_bytes());
681 section
682 }
683
684 pub fn prog_type(&self) -> ProgramType {
686 ProgramType::from(unsafe { libbpf_sys::bpf_program__type(self.ptr.as_ptr()) })
687 }
688
689 #[deprecated = "renamed to Program::fd_from_id"]
690 #[allow(missing_docs)]
691 #[inline]
692 pub fn get_fd_by_id(id: u32) -> Result<OwnedFd> {
693 Self::fd_from_id(id)
694 }
695
696 pub fn fd_from_id(id: u32) -> Result<OwnedFd> {
698 let ret = unsafe { libbpf_sys::bpf_prog_get_fd_by_id(id) };
699 let fd = util::parse_ret_i32(ret)?;
700 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
704 }
705
706 #[deprecated = "renamed to Program::id_from_fd"]
708 #[allow(missing_docs)]
709 #[inline]
710 pub fn get_id_by_fd(fd: BorrowedFd<'_>) -> Result<u32> {
711 Self::id_from_fd(fd)
712 }
713
714 pub fn id_from_fd(fd: BorrowedFd<'_>) -> Result<u32> {
716 let mut prog_info = libbpf_sys::bpf_prog_info::default();
717 let prog_info_ptr: *mut libbpf_sys::bpf_prog_info = &mut prog_info;
718 let mut len = size_of::<libbpf_sys::bpf_prog_info>() as u32;
719 let ret = unsafe {
720 libbpf_sys::bpf_obj_get_info_by_fd(
721 fd.as_raw_fd(),
722 prog_info_ptr as *mut c_void,
723 &mut len,
724 )
725 };
726 util::parse_ret(ret)?;
727 Ok(prog_info.id)
728 }
729
730 pub fn fd_from_pinned_path<P: AsRef<Path>>(path: P) -> Result<OwnedFd> {
734 let path_c = util::path_to_cstring(&path)?;
735 let path_ptr = path_c.as_ptr();
736
737 let fd = unsafe { libbpf_sys::bpf_obj_get(path_ptr) };
738 let fd = util::parse_ret_i32(fd).with_context(|| {
739 format!(
740 "failed to retrieve BPF object from pinned path `{}`",
741 path.as_ref().display()
742 )
743 })?;
744 let fd = unsafe { OwnedFd::from_raw_fd(fd) };
745
746 let fd_type = util::object_type_from_fd(fd.as_fd())?;
750 match fd_type {
751 BpfObjectType::Program => Ok(fd),
752 other => Err(Error::with_invalid_data(format!(
753 "retrieved BPF fd is not a program fd: {other:#?}"
754 ))),
755 }
756 }
757
758 pub fn flags(&self) -> u32 {
760 unsafe { libbpf_sys::bpf_program__flags(self.ptr.as_ptr()) }
761 }
762
763 pub fn attach_type(&self) -> ProgramAttachType {
765 ProgramAttachType::from(unsafe {
766 libbpf_sys::bpf_program__expected_attach_type(self.ptr.as_ptr())
767 })
768 }
769
770 pub fn autoload(&self) -> bool {
772 unsafe { libbpf_sys::bpf_program__autoload(self.ptr.as_ptr()) }
773 }
774
775 pub fn log_level(&self) -> u32 {
777 unsafe { libbpf_sys::bpf_program__log_level(self.ptr.as_ptr()) }
778 }
779
780 pub fn insn_cnt(&self) -> usize {
784 unsafe { libbpf_sys::bpf_program__insn_cnt(self.ptr.as_ptr()) as usize }
785 }
786
787 pub fn insns(&self) -> &[libbpf_sys::bpf_insn] {
791 let count = self.insn_cnt();
792 let ptr = unsafe { libbpf_sys::bpf_program__insns(self.ptr.as_ptr()) };
793 unsafe { slice::from_raw_parts(ptr, count) }
794 }
795}
796
797impl<'obj> ProgramMut<'obj> {
798 pub fn new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self {
800 Self {
801 ptr: unsafe { NonNull::new_unchecked(prog as *mut _) },
802 _phantom: PhantomData,
803 }
804 }
805
806 pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
809 let path_c = util::path_to_cstring(path)?;
810 let path_ptr = path_c.as_ptr();
811
812 let ret = unsafe { libbpf_sys::bpf_program__pin(self.ptr.as_ptr(), path_ptr) };
813 util::parse_ret(ret)
814 }
815
816 pub fn unpin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
819 let path_c = util::path_to_cstring(path)?;
820 let path_ptr = path_c.as_ptr();
821
822 let ret = unsafe { libbpf_sys::bpf_program__unpin(self.ptr.as_ptr(), path_ptr) };
823 util::parse_ret(ret)
824 }
825
826 pub fn attach(&self) -> Result<Link> {
828 let ptr = unsafe { libbpf_sys::bpf_program__attach(self.ptr.as_ptr()) };
829 let ptr = validate_bpf_ret(ptr).context("failed to attach BPF program")?;
830 let link = unsafe { Link::new(ptr) };
832 Ok(link)
833 }
834
835 pub fn attach_cgroup(&self, cgroup_fd: i32) -> Result<Link> {
838 let ptr = unsafe { libbpf_sys::bpf_program__attach_cgroup(self.ptr.as_ptr(), cgroup_fd) };
839 let ptr = validate_bpf_ret(ptr).context("failed to attach cgroup")?;
840 let link = unsafe { Link::new(ptr) };
842 Ok(link)
843 }
844
845 pub fn attach_perf_event(&self, pfd: i32) -> Result<Link> {
847 let ptr = unsafe { libbpf_sys::bpf_program__attach_perf_event(self.ptr.as_ptr(), pfd) };
848 let ptr = validate_bpf_ret(ptr).context("failed to attach perf event")?;
849 let link = unsafe { Link::new(ptr) };
851 Ok(link)
852 }
853
854 pub fn attach_perf_event_with_opts(&self, pfd: i32, opts: PerfEventOpts) -> Result<Link> {
857 let libbpf_opts = libbpf_sys::bpf_perf_event_opts::from(opts);
858 let ptr = unsafe {
859 libbpf_sys::bpf_program__attach_perf_event_opts(self.ptr.as_ptr(), pfd, &libbpf_opts)
860 };
861 let ptr = validate_bpf_ret(ptr).context("failed to attach perf event")?;
862 let link = unsafe { Link::new(ptr) };
864 Ok(link)
865 }
866
867 pub fn attach_uprobe<T: AsRef<Path>>(
870 &self,
871 retprobe: bool,
872 pid: i32,
873 binary_path: T,
874 func_offset: usize,
875 ) -> Result<Link> {
876 let path = util::path_to_cstring(binary_path)?;
877 let path_ptr = path.as_ptr();
878 let ptr = unsafe {
879 libbpf_sys::bpf_program__attach_uprobe(
880 self.ptr.as_ptr(),
881 retprobe,
882 pid,
883 path_ptr,
884 func_offset as libbpf_sys::size_t,
885 )
886 };
887 let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe")?;
888 let link = unsafe { Link::new(ptr) };
890 Ok(link)
891 }
892
893 pub fn attach_uprobe_with_opts(
897 &self,
898 pid: i32,
899 binary_path: impl AsRef<Path>,
900 func_offset: usize,
901 opts: UprobeOpts,
902 ) -> Result<Link> {
903 let path = util::path_to_cstring(binary_path)?;
904 let path_ptr = path.as_ptr();
905 let UprobeOpts {
906 ref_ctr_offset,
907 cookie,
908 retprobe,
909 func_name,
910 _non_exhaustive,
911 } = opts;
912
913 let func_name: Option<CString> = if let Some(func_name) = func_name {
914 Some(util::str_to_cstring(&func_name)?)
915 } else {
916 None
917 };
918 let ptr = func_name
919 .as_ref()
920 .map_or(ptr::null(), |func_name| func_name.as_ptr());
921 let opts = libbpf_sys::bpf_uprobe_opts {
922 sz: size_of::<libbpf_sys::bpf_uprobe_opts>() as _,
923 ref_ctr_offset: ref_ctr_offset as libbpf_sys::size_t,
924 bpf_cookie: cookie,
925 retprobe,
926 func_name: ptr,
927 ..Default::default()
928 };
929
930 let ptr = unsafe {
931 libbpf_sys::bpf_program__attach_uprobe_opts(
932 self.ptr.as_ptr(),
933 pid,
934 path_ptr,
935 func_offset as libbpf_sys::size_t,
936 &opts as *const _,
937 )
938 };
939 let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe")?;
940 let link = unsafe { Link::new(ptr) };
942 Ok(link)
943 }
944
945 pub fn attach_kprobe<T: AsRef<str>>(&self, retprobe: bool, func_name: T) -> Result<Link> {
948 let func_name = util::str_to_cstring(func_name.as_ref())?;
949 let func_name_ptr = func_name.as_ptr();
950 let ptr = unsafe {
951 libbpf_sys::bpf_program__attach_kprobe(self.ptr.as_ptr(), retprobe, func_name_ptr)
952 };
953 let ptr = validate_bpf_ret(ptr).context("failed to attach kprobe")?;
954 let link = unsafe { Link::new(ptr) };
956 Ok(link)
957 }
958
959 pub fn attach_kprobe_with_opts<T: AsRef<str>>(
963 &self,
964 retprobe: bool,
965 func_name: T,
966 opts: KprobeOpts,
967 ) -> Result<Link> {
968 let func_name = util::str_to_cstring(func_name.as_ref())?;
969 let func_name_ptr = func_name.as_ptr();
970
971 let mut opts = libbpf_sys::bpf_kprobe_opts::from(opts);
972 opts.retprobe = retprobe;
973
974 let ptr = unsafe {
975 libbpf_sys::bpf_program__attach_kprobe_opts(
976 self.ptr.as_ptr(),
977 func_name_ptr,
978 &opts as *const _,
979 )
980 };
981 let ptr = validate_bpf_ret(ptr).context("failed to attach kprobe")?;
982 let link = unsafe { Link::new(ptr) };
984 Ok(link)
985 }
986
987 fn check_kprobe_multi_args<T: AsRef<str>>(symbols: &[T], cookies: &[u64]) -> Result<usize> {
988 if symbols.is_empty() {
989 return Err(Error::with_invalid_input("Symbols list cannot be empty"));
990 }
991
992 if !cookies.is_empty() && symbols.len() != cookies.len() {
993 return Err(Error::with_invalid_input(
994 "Symbols and cookies list must have the same size",
995 ));
996 }
997
998 Ok(symbols.len())
999 }
1000
1001 fn attach_kprobe_multi_impl(&self, opts: libbpf_sys::bpf_kprobe_multi_opts) -> Result<Link> {
1002 let ptr = unsafe {
1003 libbpf_sys::bpf_program__attach_kprobe_multi_opts(
1004 self.ptr.as_ptr(),
1005 ptr::null(),
1006 &opts as *const _,
1007 )
1008 };
1009 let ptr = validate_bpf_ret(ptr).context("failed to attach kprobe multi")?;
1010 let link = unsafe { Link::new(ptr) };
1012 Ok(link)
1013 }
1014
1015 pub fn attach_kprobe_multi<T: AsRef<str>>(
1019 &self,
1020 retprobe: bool,
1021 symbols: Vec<T>,
1022 ) -> Result<Link> {
1023 let cnt = Self::check_kprobe_multi_args(&symbols, &[])?;
1024
1025 let csyms = symbols
1026 .iter()
1027 .map(|s| util::str_to_cstring(s.as_ref()))
1028 .collect::<Result<Vec<_>>>()?;
1029 let mut syms = csyms.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
1030
1031 let opts = libbpf_sys::bpf_kprobe_multi_opts {
1032 sz: size_of::<libbpf_sys::bpf_kprobe_multi_opts>() as _,
1033 syms: syms.as_mut_ptr() as _,
1034 cnt: cnt as libbpf_sys::size_t,
1035 retprobe,
1036 ..Default::default()
1038 };
1039
1040 self.attach_kprobe_multi_impl(opts)
1041 }
1042
1043 pub fn attach_kprobe_multi_with_opts(&self, opts: KprobeMultiOpts) -> Result<Link> {
1047 let KprobeMultiOpts {
1048 symbols,
1049 mut cookies,
1050 retprobe,
1051 _non_exhaustive,
1052 } = opts;
1053
1054 let cnt = Self::check_kprobe_multi_args(&symbols, &cookies)?;
1055
1056 let csyms = symbols
1057 .iter()
1058 .map(|s| util::str_to_cstring(s.as_ref()))
1059 .collect::<Result<Vec<_>>>()?;
1060 let mut syms = csyms.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
1061
1062 let opts = libbpf_sys::bpf_kprobe_multi_opts {
1063 sz: size_of::<libbpf_sys::bpf_kprobe_multi_opts>() as _,
1064 syms: syms.as_mut_ptr() as _,
1065 cookies: if !cookies.is_empty() {
1066 cookies.as_mut_ptr() as _
1067 } else {
1068 ptr::null()
1069 },
1070 cnt: cnt as libbpf_sys::size_t,
1071 retprobe,
1072 ..Default::default()
1074 };
1075
1076 self.attach_kprobe_multi_impl(opts)
1077 }
1078
1079 pub fn attach_ksyscall<T: AsRef<str>>(&self, retprobe: bool, syscall_name: T) -> Result<Link> {
1081 let opts = libbpf_sys::bpf_ksyscall_opts {
1082 sz: size_of::<libbpf_sys::bpf_ksyscall_opts>() as _,
1083 retprobe,
1084 ..Default::default()
1085 };
1086
1087 let syscall_name = util::str_to_cstring(syscall_name.as_ref())?;
1088 let syscall_name_ptr = syscall_name.as_ptr();
1089 let ptr = unsafe {
1090 libbpf_sys::bpf_program__attach_ksyscall(self.ptr.as_ptr(), syscall_name_ptr, &opts)
1091 };
1092 let ptr = validate_bpf_ret(ptr).context("failed to attach ksyscall")?;
1093 let link = unsafe { Link::new(ptr) };
1095 Ok(link)
1096 }
1097
1098 fn attach_tracepoint_impl(
1099 &self,
1100 tp_category: &str,
1101 tp_name: &str,
1102 tp_opts: Option<TracepointOpts>,
1103 ) -> Result<Link> {
1104 let tp_category = util::str_to_cstring(tp_category)?;
1105 let tp_category_ptr = tp_category.as_ptr();
1106 let tp_name = util::str_to_cstring(tp_name)?;
1107 let tp_name_ptr = tp_name.as_ptr();
1108
1109 let tp_opts = tp_opts.map(libbpf_sys::bpf_tracepoint_opts::from);
1110 let opts = tp_opts.as_ref().map_or(ptr::null(), |opts| opts);
1111 let ptr = unsafe {
1112 libbpf_sys::bpf_program__attach_tracepoint_opts(
1113 self.ptr.as_ptr(),
1114 tp_category_ptr,
1115 tp_name_ptr,
1116 opts as *const _,
1117 )
1118 };
1119
1120 let ptr = validate_bpf_ret(ptr).context("failed to attach tracepoint")?;
1121 let link = unsafe { Link::new(ptr) };
1123 Ok(link)
1124 }
1125
1126 pub fn attach_tracepoint(
1129 &self,
1130 tp_category: TracepointCategory,
1131 tp_name: impl AsRef<str>,
1132 ) -> Result<Link> {
1133 self.attach_tracepoint_impl(tp_category.as_ref(), tp_name.as_ref(), None)
1134 }
1135
1136 pub fn attach_tracepoint_with_opts(
1140 &self,
1141 tp_category: TracepointCategory,
1142 tp_name: impl AsRef<str>,
1143 tp_opts: TracepointOpts,
1144 ) -> Result<Link> {
1145 self.attach_tracepoint_impl(tp_category.as_ref(), tp_name.as_ref(), Some(tp_opts))
1146 }
1147
1148 pub fn attach_raw_tracepoint<T: AsRef<str>>(&self, tp_name: T) -> Result<Link> {
1151 let tp_name = util::str_to_cstring(tp_name.as_ref())?;
1152 let tp_name_ptr = tp_name.as_ptr();
1153 let ptr = unsafe {
1154 libbpf_sys::bpf_program__attach_raw_tracepoint(self.ptr.as_ptr(), tp_name_ptr)
1155 };
1156 let ptr = validate_bpf_ret(ptr).context("failed to attach raw tracepoint")?;
1157 let link = unsafe { Link::new(ptr) };
1159 Ok(link)
1160 }
1161
1162 pub fn attach_raw_tracepoint_with_opts<T: AsRef<str>>(
1166 &self,
1167 tp_name: T,
1168 tp_opts: RawTracepointOpts,
1169 ) -> Result<Link> {
1170 let tp_name = util::str_to_cstring(tp_name.as_ref())?;
1171 let tp_name_ptr = tp_name.as_ptr();
1172 let mut tp_opts = libbpf_sys::bpf_raw_tracepoint_opts::from(tp_opts);
1173 let ptr = unsafe {
1174 libbpf_sys::bpf_program__attach_raw_tracepoint_opts(
1175 self.ptr.as_ptr(),
1176 tp_name_ptr,
1177 &mut tp_opts as *mut _,
1178 )
1179 };
1180 let ptr = validate_bpf_ret(ptr).context("failed to attach raw tracepoint")?;
1181 let link = unsafe { Link::new(ptr) };
1183 Ok(link)
1184 }
1185
1186 pub fn attach_lsm(&self) -> Result<Link> {
1188 let ptr = unsafe { libbpf_sys::bpf_program__attach_lsm(self.ptr.as_ptr()) };
1189 let ptr = validate_bpf_ret(ptr).context("failed to attach LSM")?;
1190 let link = unsafe { Link::new(ptr) };
1192 Ok(link)
1193 }
1194
1195 pub fn attach_trace(&self) -> Result<Link> {
1197 let ptr = unsafe { libbpf_sys::bpf_program__attach_trace(self.ptr.as_ptr()) };
1198 let ptr = validate_bpf_ret(ptr).context("failed to attach fentry/fexit kernel probe")?;
1199 let link = unsafe { Link::new(ptr) };
1201 Ok(link)
1202 }
1203
1204 pub fn attach_sockmap(&self, map_fd: i32) -> Result<()> {
1206 let err = unsafe {
1207 libbpf_sys::bpf_prog_attach(
1208 self.as_fd().as_raw_fd(),
1209 map_fd,
1210 self.attach_type() as u32,
1211 0,
1212 )
1213 };
1214 util::parse_ret(err)
1215 }
1216
1217 pub fn attach_xdp(&self, ifindex: i32) -> Result<Link> {
1219 let ptr = unsafe { libbpf_sys::bpf_program__attach_xdp(self.ptr.as_ptr(), ifindex) };
1220 let ptr = validate_bpf_ret(ptr).context("failed to attach XDP program")?;
1221 let link = unsafe { Link::new(ptr) };
1223 Ok(link)
1224 }
1225
1226 pub fn attach_netns(&self, netns_fd: i32) -> Result<Link> {
1228 let ptr = unsafe { libbpf_sys::bpf_program__attach_netns(self.ptr.as_ptr(), netns_fd) };
1229 let ptr = validate_bpf_ret(ptr).context("failed to attach network namespace program")?;
1230 let link = unsafe { Link::new(ptr) };
1232 Ok(link)
1233 }
1234
1235 pub fn attach_netfilter_with_opts(
1237 &self,
1238 netfilter_opt: netfilter::NetfilterOpts,
1239 ) -> Result<Link> {
1240 let netfilter_opts = libbpf_sys::bpf_netfilter_opts::from(netfilter_opt);
1241
1242 let ptr = unsafe {
1243 libbpf_sys::bpf_program__attach_netfilter(
1244 self.ptr.as_ptr(),
1245 &netfilter_opts as *const _,
1246 )
1247 };
1248
1249 let ptr = validate_bpf_ret(ptr).context("failed to attach netfilter program")?;
1250 let link = unsafe { Link::new(ptr) };
1252 Ok(link)
1253 }
1254
1255 fn attach_usdt_impl(
1256 &self,
1257 pid: i32,
1258 binary_path: &Path,
1259 usdt_provider: &str,
1260 usdt_name: &str,
1261 usdt_opts: Option<UsdtOpts>,
1262 ) -> Result<Link> {
1263 let path = util::path_to_cstring(binary_path)?;
1264 let path_ptr = path.as_ptr();
1265 let usdt_provider = util::str_to_cstring(usdt_provider)?;
1266 let usdt_provider_ptr = usdt_provider.as_ptr();
1267 let usdt_name = util::str_to_cstring(usdt_name)?;
1268 let usdt_name_ptr = usdt_name.as_ptr();
1269 let usdt_opts = usdt_opts.map(libbpf_sys::bpf_usdt_opts::from);
1270 let usdt_opts_ptr = usdt_opts
1271 .as_ref()
1272 .map(|opts| opts as *const _)
1273 .unwrap_or_else(ptr::null);
1274
1275 let ptr = unsafe {
1276 libbpf_sys::bpf_program__attach_usdt(
1277 self.ptr.as_ptr(),
1278 pid,
1279 path_ptr,
1280 usdt_provider_ptr,
1281 usdt_name_ptr,
1282 usdt_opts_ptr,
1283 )
1284 };
1285 let ptr = validate_bpf_ret(ptr).context("failed to attach USDT")?;
1286 let link = unsafe { Link::new(ptr) };
1288 Ok(link)
1289 }
1290
1291 pub fn attach_usdt(
1295 &self,
1296 pid: i32,
1297 binary_path: impl AsRef<Path>,
1298 usdt_provider: impl AsRef<str>,
1299 usdt_name: impl AsRef<str>,
1300 ) -> Result<Link> {
1301 self.attach_usdt_impl(
1302 pid,
1303 binary_path.as_ref(),
1304 usdt_provider.as_ref(),
1305 usdt_name.as_ref(),
1306 None,
1307 )
1308 }
1309
1310 pub fn attach_usdt_with_opts(
1314 &self,
1315 pid: i32,
1316 binary_path: impl AsRef<Path>,
1317 usdt_provider: impl AsRef<str>,
1318 usdt_name: impl AsRef<str>,
1319 usdt_opts: UsdtOpts,
1320 ) -> Result<Link> {
1321 self.attach_usdt_impl(
1322 pid,
1323 binary_path.as_ref(),
1324 usdt_provider.as_ref(),
1325 usdt_name.as_ref(),
1326 Some(usdt_opts),
1327 )
1328 }
1329
1330 pub fn attach_iter(&self, map_fd: BorrowedFd<'_>) -> Result<Link> {
1334 let mut linkinfo = libbpf_sys::bpf_iter_link_info::default();
1335 linkinfo.map.map_fd = map_fd.as_raw_fd() as _;
1336 let attach_opt = libbpf_sys::bpf_iter_attach_opts {
1337 link_info: &mut linkinfo as *mut libbpf_sys::bpf_iter_link_info,
1338 link_info_len: size_of::<libbpf_sys::bpf_iter_link_info>() as _,
1339 sz: size_of::<libbpf_sys::bpf_iter_attach_opts>() as _,
1340 ..Default::default()
1341 };
1342 let ptr = unsafe {
1343 libbpf_sys::bpf_program__attach_iter(
1344 self.ptr.as_ptr(),
1345 &attach_opt as *const libbpf_sys::bpf_iter_attach_opts,
1346 )
1347 };
1348
1349 let ptr = validate_bpf_ret(ptr).context("failed to attach iterator")?;
1350 let link = unsafe { Link::new(ptr) };
1352 Ok(link)
1353 }
1354
1355 pub fn test_run<'dat>(&self, input: Input<'dat>) -> Result<Output<'dat>> {
1361 unsafe fn slice_from_array<'t, T>(items: *mut T, num_items: usize) -> Option<&'t mut [T]> {
1362 if items.is_null() {
1363 None
1364 } else {
1365 Some(unsafe { slice::from_raw_parts_mut(items, num_items) })
1366 }
1367 }
1368
1369 let Input {
1370 context_in,
1371 mut context_out,
1372 data_in,
1373 mut data_out,
1374 cpu,
1375 flags,
1376 repeat,
1377 _non_exhaustive: (),
1378 } = input;
1379
1380 let mut opts = unsafe { mem::zeroed::<libbpf_sys::bpf_test_run_opts>() };
1381 opts.sz = size_of_val(&opts) as _;
1382 opts.ctx_in = context_in
1383 .as_ref()
1384 .map(|data| data.as_ptr().cast())
1385 .unwrap_or_else(ptr::null);
1386 opts.ctx_size_in = context_in.map(|data| data.len() as _).unwrap_or(0);
1387 opts.ctx_out = context_out
1388 .as_mut()
1389 .map(|data| data.as_mut_ptr().cast())
1390 .unwrap_or_else(ptr::null_mut);
1391 opts.ctx_size_out = context_out.map(|data| data.len() as _).unwrap_or(0);
1392 opts.data_in = data_in
1393 .map(|data| data.as_ptr().cast())
1394 .unwrap_or_else(ptr::null);
1395 opts.data_size_in = data_in.map(|data| data.len() as _).unwrap_or(0);
1396 opts.data_out = data_out
1397 .as_mut()
1398 .map(|data| data.as_mut_ptr().cast())
1399 .unwrap_or_else(ptr::null_mut);
1400 opts.data_size_out = data_out.map(|data| data.len() as _).unwrap_or(0);
1401 opts.cpu = cpu;
1402 opts.flags = flags;
1403 opts.repeat = repeat as i32;
1406
1407 let rc = unsafe { libbpf_sys::bpf_prog_test_run_opts(self.as_fd().as_raw_fd(), &mut opts) };
1408 let () = util::parse_ret(rc)?;
1409 let output = Output {
1410 return_value: opts.retval,
1411 context: unsafe { slice_from_array(opts.ctx_out.cast(), opts.ctx_size_out as _) },
1412 data: unsafe { slice_from_array(opts.data_out.cast(), opts.data_size_out as _) },
1413 duration: Duration::from_nanos(opts.duration.into()),
1414 _non_exhaustive: (),
1415 };
1416 Ok(output)
1417 }
1418}
1419
1420impl<'obj> Deref for ProgramMut<'obj> {
1421 type Target = Program<'obj>;
1422
1423 fn deref(&self) -> &Self::Target {
1424 unsafe { transmute::<&ProgramMut<'obj>, &Program<'obj>>(self) }
1427 }
1428}
1429
1430impl<T> AsFd for ProgramImpl<'_, T> {
1431 fn as_fd(&self) -> BorrowedFd<'_> {
1432 let fd = unsafe { libbpf_sys::bpf_program__fd(self.ptr.as_ptr()) };
1433 unsafe { BorrowedFd::borrow_raw(fd) }
1434 }
1435}
1436
1437impl<T> AsRawLibbpf for ProgramImpl<'_, T> {
1438 type LibbpfType = libbpf_sys::bpf_program;
1439
1440 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
1442 self.ptr
1443 }
1444}
1445
1446#[cfg(test)]
1447mod tests {
1448 use super::*;
1449
1450 use std::mem::discriminant;
1451
1452 #[test]
1453 fn program_type() {
1454 use ProgramType::*;
1455
1456 for t in [
1457 Unspec,
1458 SocketFilter,
1459 Kprobe,
1460 SchedCls,
1461 SchedAct,
1462 Tracepoint,
1463 Xdp,
1464 PerfEvent,
1465 CgroupSkb,
1466 CgroupSock,
1467 LwtIn,
1468 LwtOut,
1469 LwtXmit,
1470 SockOps,
1471 SkSkb,
1472 CgroupDevice,
1473 SkMsg,
1474 RawTracepoint,
1475 CgroupSockAddr,
1476 LwtSeg6local,
1477 LircMode2,
1478 SkReuseport,
1479 FlowDissector,
1480 CgroupSysctl,
1481 RawTracepointWritable,
1482 CgroupSockopt,
1483 Tracing,
1484 StructOps,
1485 Ext,
1486 Lsm,
1487 SkLookup,
1488 Syscall,
1489 Unknown,
1490 ] {
1491 assert_eq!(discriminant(&t), discriminant(&ProgramType::from(t as u32)));
1493 }
1494 }
1495
1496 #[test]
1497 fn program_attach_type() {
1498 use ProgramAttachType::*;
1499
1500 for t in [
1501 CgroupInetIngress,
1502 CgroupInetEgress,
1503 CgroupInetSockCreate,
1504 CgroupSockOps,
1505 SkSkbStreamParser,
1506 SkSkbStreamVerdict,
1507 CgroupDevice,
1508 SkMsgVerdict,
1509 CgroupInet4Bind,
1510 CgroupInet6Bind,
1511 CgroupInet4Connect,
1512 CgroupInet6Connect,
1513 CgroupInet4PostBind,
1514 CgroupInet6PostBind,
1515 CgroupUdp4Sendmsg,
1516 CgroupUdp6Sendmsg,
1517 LircMode2,
1518 FlowDissector,
1519 CgroupSysctl,
1520 CgroupUdp4Recvmsg,
1521 CgroupUdp6Recvmsg,
1522 CgroupGetsockopt,
1523 CgroupSetsockopt,
1524 TraceRawTp,
1525 TraceFentry,
1526 TraceFexit,
1527 ModifyReturn,
1528 LsmMac,
1529 TraceIter,
1530 CgroupInet4Getpeername,
1531 CgroupInet6Getpeername,
1532 CgroupInet4Getsockname,
1533 CgroupInet6Getsockname,
1534 XdpDevmap,
1535 CgroupInetSockRelease,
1536 XdpCpumap,
1537 SkLookup,
1538 Xdp,
1539 SkSkbVerdict,
1540 SkReuseportSelect,
1541 SkReuseportSelectOrMigrate,
1542 PerfEvent,
1543 Unknown,
1544 ] {
1545 assert_eq!(
1547 discriminant(&t),
1548 discriminant(&ProgramAttachType::from(t as u32))
1549 );
1550 }
1551 }
1552}