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::io::Read;
10use std::marker::PhantomData;
11use std::mem;
12use std::mem::size_of;
13use std::mem::size_of_val;
14use std::mem::transmute;
15use std::ops::Deref;
16use std::os::unix::ffi::OsStrExt as _;
17use std::os::unix::io::AsFd;
18use std::os::unix::io::AsRawFd;
19use std::os::unix::io::BorrowedFd;
20use std::os::unix::io::FromRawFd;
21use std::os::unix::io::OwnedFd;
22use std::path::Path;
23use std::ptr;
24use std::ptr::NonNull;
25use std::slice;
26use std::time::Duration;
27
28use libbpf_sys::bpf_func_id;
29
30use crate::netfilter;
31use crate::streams::Stream;
32use crate::util;
33use crate::util::validate_bpf_ret;
34use crate::util::BpfObjectType;
35use crate::AsRawLibbpf;
36use crate::Error;
37use crate::ErrorExt as _;
38use crate::Link;
39use crate::Map;
40use crate::Mut;
41use crate::RawTracepointOpts;
42use crate::Result;
43use crate::TracepointCategory;
44use crate::TracepointOpts;
45
46#[derive(Clone, Debug, Default)]
48pub struct UprobeOpts {
49 pub ref_ctr_offset: usize,
51 pub cookie: u64,
53 pub retprobe: bool,
55 pub func_name: Option<String>,
67 #[doc(hidden)]
68 pub _non_exhaustive: (),
69}
70
71#[derive(Clone, Debug, Default)]
73pub struct UprobeMultiOpts {
74 pub syms: Vec<String>,
76 pub offsets: Vec<usize>,
78 pub ref_ctr_offsets: Vec<usize>,
80 pub cookies: Vec<u64>,
82 pub retprobe: bool,
84 pub session: bool,
86 #[doc(hidden)]
87 pub _non_exhaustive: (),
88}
89
90#[derive(Clone, Debug, Default)]
92pub struct UsdtOpts {
93 pub cookie: u64,
95 #[doc(hidden)]
96 pub _non_exhaustive: (),
97}
98
99impl From<UsdtOpts> for libbpf_sys::bpf_usdt_opts {
100 fn from(opts: UsdtOpts) -> Self {
101 let UsdtOpts {
102 cookie,
103 _non_exhaustive,
104 } = opts;
105 #[allow(clippy::needless_update)]
106 Self {
107 sz: size_of::<Self>() as _,
108 usdt_cookie: cookie,
109 ..Default::default()
111 }
112 }
113}
114
115#[derive(Clone, Debug, Default)]
117pub struct KprobeOpts {
118 pub cookie: u64,
120 #[doc(hidden)]
121 pub _non_exhaustive: (),
122}
123
124impl From<KprobeOpts> for libbpf_sys::bpf_kprobe_opts {
125 fn from(opts: KprobeOpts) -> Self {
126 let KprobeOpts {
127 cookie,
128 _non_exhaustive,
129 } = opts;
130
131 #[allow(clippy::needless_update)]
132 Self {
133 sz: size_of::<Self>() as _,
134 bpf_cookie: cookie,
135 ..Default::default()
137 }
138 }
139}
140
141#[derive(Clone, Debug, Default)]
143pub struct KprobeMultiOpts {
144 pub symbols: Vec<String>,
146 pub cookies: Vec<u64>,
148 pub retprobe: bool,
150 #[doc(hidden)]
151 pub _non_exhaustive: (),
152}
153
154#[derive(Clone, Debug, Default)]
156pub struct PerfEventOpts {
157 pub cookie: u64,
159 pub force_ioctl_attach: bool,
161 #[doc(hidden)]
162 pub _non_exhaustive: (),
163}
164
165impl From<PerfEventOpts> for libbpf_sys::bpf_perf_event_opts {
166 fn from(opts: PerfEventOpts) -> Self {
167 let PerfEventOpts {
168 cookie,
169 force_ioctl_attach,
170 _non_exhaustive,
171 } = opts;
172
173 #[allow(clippy::needless_update)]
174 Self {
175 sz: size_of::<Self>() as _,
176 bpf_cookie: cookie,
177 force_ioctl_attach,
178 ..Default::default()
180 }
181 }
182}
183
184
185#[derive(Clone, Debug)]
187pub struct MapIterOpts<'fd> {
188 pub fd: BorrowedFd<'fd>,
190 #[doc(hidden)]
191 pub _non_exhaustive: (),
192}
193
194impl<'fd> MapIterOpts<'fd> {
195 pub fn from_fd(fd: BorrowedFd<'fd>) -> Self {
197 Self {
198 fd,
199 _non_exhaustive: (),
200 }
201 }
202}
203
204
205#[non_exhaustive]
207#[repr(u32)]
208#[derive(Clone, Debug, Default)]
209pub enum CgroupIterOrder {
210 #[default]
212 Default = libbpf_sys::BPF_CGROUP_ITER_ORDER_UNSPEC,
213 SelfOnly = libbpf_sys::BPF_CGROUP_ITER_SELF_ONLY,
215 DescendantsPre = libbpf_sys::BPF_CGROUP_ITER_DESCENDANTS_PRE,
217 DescendantsPost = libbpf_sys::BPF_CGROUP_ITER_DESCENDANTS_POST,
219 AncestorsUp = libbpf_sys::BPF_CGROUP_ITER_ANCESTORS_UP,
221}
222
223#[derive(Clone, Debug)]
225pub struct CgroupIterOpts<'fd> {
226 pub fd: BorrowedFd<'fd>,
228 pub order: CgroupIterOrder,
230 #[doc(hidden)]
231 pub _non_exhaustive: (),
232}
233
234impl<'fd> CgroupIterOpts<'fd> {
235 pub fn from_fd(fd: BorrowedFd<'fd>) -> Self {
237 Self {
238 fd,
239 order: CgroupIterOrder::default(),
240 _non_exhaustive: (),
241 }
242 }
243}
244
245
246#[non_exhaustive]
248#[derive(Clone, Debug)]
249pub enum IterOpts<'fd> {
250 None,
252 Map(MapIterOpts<'fd>),
254 Cgroup(CgroupIterOpts<'fd>),
256}
257
258
259pub type OpenProgram<'obj> = OpenProgramImpl<'obj>;
261pub type OpenProgramMut<'obj> = OpenProgramImpl<'obj, Mut>;
263
264
265#[derive(Debug)]
269#[repr(transparent)]
270pub struct OpenProgramImpl<'obj, T = ()> {
271 ptr: NonNull<libbpf_sys::bpf_program>,
272 _phantom: PhantomData<&'obj T>,
273}
274
275impl<'obj> OpenProgram<'obj> {
276 pub fn new(prog: &'obj libbpf_sys::bpf_program) -> Self {
278 Self {
281 ptr: unsafe { NonNull::new_unchecked(prog as *const _ as *mut _) },
282 _phantom: PhantomData,
283 }
284 }
285
286 pub fn prog_type(&self) -> ProgramType {
288 ProgramType::from(unsafe { libbpf_sys::bpf_program__type(self.ptr.as_ptr()) })
289 }
290
291 pub fn name(&self) -> &'obj OsStr {
293 let name_ptr = unsafe { libbpf_sys::bpf_program__name(self.ptr.as_ptr()) };
294 let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
295 OsStr::from_bytes(name_c_str.to_bytes())
297 }
298
299 pub fn section(&self) -> &'obj OsStr {
301 let p = unsafe { libbpf_sys::bpf_program__section_name(self.ptr.as_ptr()) };
303 let section_c_str = unsafe { CStr::from_ptr(p) };
306 let section = OsStr::from_bytes(section_c_str.to_bytes());
307 section
308 }
309
310 pub fn insn_cnt(&self) -> usize {
316 unsafe { libbpf_sys::bpf_program__insn_cnt(self.ptr.as_ptr()) as usize }
317 }
318
319 pub fn insns(&self) -> &'obj [libbpf_sys::bpf_insn] {
329 let count = self.insn_cnt();
330 let ptr = unsafe { libbpf_sys::bpf_program__insns(self.ptr.as_ptr()) };
331 unsafe { slice::from_raw_parts(ptr, count) }
332 }
333
334 pub fn autoload(&self) -> bool {
336 unsafe { libbpf_sys::bpf_program__autoload(self.ptr.as_ptr()) }
337 }
338}
339
340impl<'obj> OpenProgramMut<'obj> {
341 pub fn new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self {
343 Self {
344 ptr: unsafe { NonNull::new_unchecked(prog as *mut _) },
345 _phantom: PhantomData,
346 }
347 }
348
349 pub fn set_prog_type(&mut self, prog_type: ProgramType) {
351 let rc = unsafe { libbpf_sys::bpf_program__set_type(self.ptr.as_ptr(), prog_type as u32) };
352 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
353 }
354
355 pub fn set_attach_type(&mut self, attach_type: ProgramAttachType) {
357 let rc = unsafe {
358 libbpf_sys::bpf_program__set_expected_attach_type(self.ptr.as_ptr(), attach_type as u32)
359 };
360 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
361 }
362
363 pub fn set_ifindex(&mut self, idx: u32) {
367 unsafe { libbpf_sys::bpf_program__set_ifindex(self.ptr.as_ptr(), idx) }
368 }
369
370 pub fn set_log_level(&mut self, log_level: u32) {
379 let rc = unsafe { libbpf_sys::bpf_program__set_log_level(self.ptr.as_ptr(), log_level) };
380 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
381 }
382
383 pub fn set_autoload(&mut self, autoload: bool) {
386 let rc = unsafe { libbpf_sys::bpf_program__set_autoload(self.ptr.as_ptr(), autoload) };
387 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
388 }
389
390 pub fn set_autoattach(&mut self, autoattach: bool) {
393 unsafe { libbpf_sys::bpf_program__set_autoattach(self.ptr.as_ptr(), autoattach) };
394 }
395
396 #[expect(missing_docs)]
397 pub fn set_attach_target(
398 &mut self,
399 attach_prog_fd: i32,
400 attach_func_name: Option<String>,
401 ) -> Result<()> {
402 let name_c = if let Some(name) = attach_func_name {
403 Some(util::str_to_cstring(&name)?)
404 } else {
405 None
406 };
407 let name_ptr = name_c.as_ref().map_or(ptr::null(), |name| name.as_ptr());
408 let ret = unsafe {
409 libbpf_sys::bpf_program__set_attach_target(self.ptr.as_ptr(), attach_prog_fd, name_ptr)
410 };
411 util::parse_ret(ret)
412 }
413
414 pub fn set_flags(&mut self, flags: u32) {
416 let rc = unsafe { libbpf_sys::bpf_program__set_flags(self.ptr.as_ptr(), flags) };
417 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
418 }
419}
420
421impl<'obj> Deref for OpenProgramMut<'obj> {
422 type Target = OpenProgram<'obj>;
423
424 fn deref(&self) -> &Self::Target {
425 unsafe { transmute::<&OpenProgramMut<'obj>, &OpenProgram<'obj>>(self) }
428 }
429}
430
431impl<T> AsRawLibbpf for OpenProgramImpl<'_, T> {
432 type LibbpfType = libbpf_sys::bpf_program;
433
434 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
436 self.ptr
437 }
438}
439
440#[non_exhaustive]
442#[repr(u32)]
443#[derive(Copy, Clone, PartialEq, Eq, Debug)]
444#[expect(missing_docs)]
446pub enum ProgramType {
447 Unspec = 0,
448 SocketFilter = libbpf_sys::BPF_PROG_TYPE_SOCKET_FILTER,
449 Kprobe = libbpf_sys::BPF_PROG_TYPE_KPROBE,
450 SchedCls = libbpf_sys::BPF_PROG_TYPE_SCHED_CLS,
451 SchedAct = libbpf_sys::BPF_PROG_TYPE_SCHED_ACT,
452 Tracepoint = libbpf_sys::BPF_PROG_TYPE_TRACEPOINT,
453 Xdp = libbpf_sys::BPF_PROG_TYPE_XDP,
454 PerfEvent = libbpf_sys::BPF_PROG_TYPE_PERF_EVENT,
455 CgroupSkb = libbpf_sys::BPF_PROG_TYPE_CGROUP_SKB,
456 CgroupSock = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCK,
457 LwtIn = libbpf_sys::BPF_PROG_TYPE_LWT_IN,
458 LwtOut = libbpf_sys::BPF_PROG_TYPE_LWT_OUT,
459 LwtXmit = libbpf_sys::BPF_PROG_TYPE_LWT_XMIT,
460 SockOps = libbpf_sys::BPF_PROG_TYPE_SOCK_OPS,
461 SkSkb = libbpf_sys::BPF_PROG_TYPE_SK_SKB,
462 CgroupDevice = libbpf_sys::BPF_PROG_TYPE_CGROUP_DEVICE,
463 SkMsg = libbpf_sys::BPF_PROG_TYPE_SK_MSG,
464 RawTracepoint = libbpf_sys::BPF_PROG_TYPE_RAW_TRACEPOINT,
465 CgroupSockAddr = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
466 LwtSeg6local = libbpf_sys::BPF_PROG_TYPE_LWT_SEG6LOCAL,
467 LircMode2 = libbpf_sys::BPF_PROG_TYPE_LIRC_MODE2,
468 SkReuseport = libbpf_sys::BPF_PROG_TYPE_SK_REUSEPORT,
469 FlowDissector = libbpf_sys::BPF_PROG_TYPE_FLOW_DISSECTOR,
470 CgroupSysctl = libbpf_sys::BPF_PROG_TYPE_CGROUP_SYSCTL,
471 RawTracepointWritable = libbpf_sys::BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
472 CgroupSockopt = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCKOPT,
473 Tracing = libbpf_sys::BPF_PROG_TYPE_TRACING,
474 StructOps = libbpf_sys::BPF_PROG_TYPE_STRUCT_OPS,
475 Ext = libbpf_sys::BPF_PROG_TYPE_EXT,
476 Lsm = libbpf_sys::BPF_PROG_TYPE_LSM,
477 SkLookup = libbpf_sys::BPF_PROG_TYPE_SK_LOOKUP,
478 Syscall = libbpf_sys::BPF_PROG_TYPE_SYSCALL,
479 Netfilter = libbpf_sys::BPF_PROG_TYPE_NETFILTER,
480 Unknown = u32::MAX,
482}
483
484impl ProgramType {
485 pub fn is_supported(&self) -> Result<bool> {
490 let ret = unsafe { libbpf_sys::libbpf_probe_bpf_prog_type(*self as u32, ptr::null()) };
491 match ret {
492 0 => Ok(false),
493 1 => Ok(true),
494 _ => Err(Error::from_raw_os_error(-ret)),
495 }
496 }
497
498 pub fn is_helper_supported(&self, helper_id: bpf_func_id) -> Result<bool> {
504 let ret =
505 unsafe { libbpf_sys::libbpf_probe_bpf_helper(*self as u32, helper_id, ptr::null()) };
506 match ret {
507 0 => Ok(false),
508 1 => Ok(true),
509 _ => Err(Error::from_raw_os_error(-ret)),
510 }
511 }
512}
513
514impl From<u32> for ProgramType {
515 fn from(value: u32) -> Self {
516 use ProgramType::*;
517
518 match value {
519 x if x == Unspec as u32 => Unspec,
520 x if x == SocketFilter as u32 => SocketFilter,
521 x if x == Kprobe as u32 => Kprobe,
522 x if x == SchedCls as u32 => SchedCls,
523 x if x == SchedAct as u32 => SchedAct,
524 x if x == Tracepoint as u32 => Tracepoint,
525 x if x == Xdp as u32 => Xdp,
526 x if x == PerfEvent as u32 => PerfEvent,
527 x if x == CgroupSkb as u32 => CgroupSkb,
528 x if x == CgroupSock as u32 => CgroupSock,
529 x if x == LwtIn as u32 => LwtIn,
530 x if x == LwtOut as u32 => LwtOut,
531 x if x == LwtXmit as u32 => LwtXmit,
532 x if x == SockOps as u32 => SockOps,
533 x if x == SkSkb as u32 => SkSkb,
534 x if x == CgroupDevice as u32 => CgroupDevice,
535 x if x == SkMsg as u32 => SkMsg,
536 x if x == RawTracepoint as u32 => RawTracepoint,
537 x if x == CgroupSockAddr as u32 => CgroupSockAddr,
538 x if x == LwtSeg6local as u32 => LwtSeg6local,
539 x if x == LircMode2 as u32 => LircMode2,
540 x if x == SkReuseport as u32 => SkReuseport,
541 x if x == FlowDissector as u32 => FlowDissector,
542 x if x == CgroupSysctl as u32 => CgroupSysctl,
543 x if x == RawTracepointWritable as u32 => RawTracepointWritable,
544 x if x == CgroupSockopt as u32 => CgroupSockopt,
545 x if x == Tracing as u32 => Tracing,
546 x if x == StructOps as u32 => StructOps,
547 x if x == Ext as u32 => Ext,
548 x if x == Lsm as u32 => Lsm,
549 x if x == SkLookup as u32 => SkLookup,
550 x if x == Syscall as u32 => Syscall,
551 x if x == Netfilter as u32 => Netfilter,
552 _ => Unknown,
553 }
554 }
555}
556
557#[non_exhaustive]
559#[repr(u32)]
560#[derive(Clone, Debug)]
561#[expect(missing_docs)]
563pub enum ProgramAttachType {
564 CgroupInetIngress = libbpf_sys::BPF_CGROUP_INET_INGRESS,
565 CgroupInetEgress = libbpf_sys::BPF_CGROUP_INET_EGRESS,
566 CgroupInetSockCreate = libbpf_sys::BPF_CGROUP_INET_SOCK_CREATE,
567 CgroupSockOps = libbpf_sys::BPF_CGROUP_SOCK_OPS,
568 SkSkbStreamParser = libbpf_sys::BPF_SK_SKB_STREAM_PARSER,
569 SkSkbStreamVerdict = libbpf_sys::BPF_SK_SKB_STREAM_VERDICT,
570 CgroupDevice = libbpf_sys::BPF_CGROUP_DEVICE,
571 SkMsgVerdict = libbpf_sys::BPF_SK_MSG_VERDICT,
572 CgroupInet4Bind = libbpf_sys::BPF_CGROUP_INET4_BIND,
573 CgroupInet6Bind = libbpf_sys::BPF_CGROUP_INET6_BIND,
574 CgroupInet4Connect = libbpf_sys::BPF_CGROUP_INET4_CONNECT,
575 CgroupInet6Connect = libbpf_sys::BPF_CGROUP_INET6_CONNECT,
576 CgroupInet4PostBind = libbpf_sys::BPF_CGROUP_INET4_POST_BIND,
577 CgroupInet6PostBind = libbpf_sys::BPF_CGROUP_INET6_POST_BIND,
578 CgroupUdp4Sendmsg = libbpf_sys::BPF_CGROUP_UDP4_SENDMSG,
579 CgroupUdp6Sendmsg = libbpf_sys::BPF_CGROUP_UDP6_SENDMSG,
580 LircMode2 = libbpf_sys::BPF_LIRC_MODE2,
581 FlowDissector = libbpf_sys::BPF_FLOW_DISSECTOR,
582 CgroupSysctl = libbpf_sys::BPF_CGROUP_SYSCTL,
583 CgroupUdp4Recvmsg = libbpf_sys::BPF_CGROUP_UDP4_RECVMSG,
584 CgroupUdp6Recvmsg = libbpf_sys::BPF_CGROUP_UDP6_RECVMSG,
585 CgroupGetsockopt = libbpf_sys::BPF_CGROUP_GETSOCKOPT,
586 CgroupSetsockopt = libbpf_sys::BPF_CGROUP_SETSOCKOPT,
587 TraceRawTp = libbpf_sys::BPF_TRACE_RAW_TP,
588 TraceFentry = libbpf_sys::BPF_TRACE_FENTRY,
589 TraceFexit = libbpf_sys::BPF_TRACE_FEXIT,
590 ModifyReturn = libbpf_sys::BPF_MODIFY_RETURN,
591 LsmMac = libbpf_sys::BPF_LSM_MAC,
592 TraceIter = libbpf_sys::BPF_TRACE_ITER,
593 CgroupInet4Getpeername = libbpf_sys::BPF_CGROUP_INET4_GETPEERNAME,
594 CgroupInet6Getpeername = libbpf_sys::BPF_CGROUP_INET6_GETPEERNAME,
595 CgroupInet4Getsockname = libbpf_sys::BPF_CGROUP_INET4_GETSOCKNAME,
596 CgroupInet6Getsockname = libbpf_sys::BPF_CGROUP_INET6_GETSOCKNAME,
597 XdpDevmap = libbpf_sys::BPF_XDP_DEVMAP,
598 CgroupInetSockRelease = libbpf_sys::BPF_CGROUP_INET_SOCK_RELEASE,
599 XdpCpumap = libbpf_sys::BPF_XDP_CPUMAP,
600 SkLookup = libbpf_sys::BPF_SK_LOOKUP,
601 Xdp = libbpf_sys::BPF_XDP,
602 SkSkbVerdict = libbpf_sys::BPF_SK_SKB_VERDICT,
603 SkReuseportSelect = libbpf_sys::BPF_SK_REUSEPORT_SELECT,
604 SkReuseportSelectOrMigrate = libbpf_sys::BPF_SK_REUSEPORT_SELECT_OR_MIGRATE,
605 PerfEvent = libbpf_sys::BPF_PERF_EVENT,
606 KprobeMulti = libbpf_sys::BPF_TRACE_KPROBE_MULTI,
607 NetkitPeer = libbpf_sys::BPF_NETKIT_PEER,
608 TraceUprobeMulti = libbpf_sys::BPF_TRACE_UPROBE_MULTI,
609 LsmCgroup = libbpf_sys::BPF_LSM_CGROUP,
610 TraceKprobeSession = libbpf_sys::BPF_TRACE_KPROBE_SESSION,
611 TcxIngress = libbpf_sys::BPF_TCX_INGRESS,
612 TcxEgress = libbpf_sys::BPF_TCX_EGRESS,
613 Netfilter = libbpf_sys::BPF_NETFILTER,
614 CgroupUnixGetsockname = libbpf_sys::BPF_CGROUP_UNIX_GETSOCKNAME,
615 CgroupUnixSendmsg = libbpf_sys::BPF_CGROUP_UNIX_SENDMSG,
616 NetkitPrimary = libbpf_sys::BPF_NETKIT_PRIMARY,
617 CgroupUnixRecvmsg = libbpf_sys::BPF_CGROUP_UNIX_RECVMSG,
618 CgroupUnixConnect = libbpf_sys::BPF_CGROUP_UNIX_CONNECT,
619 CgroupUnixGetpeername = libbpf_sys::BPF_CGROUP_UNIX_GETPEERNAME,
620 StructOps = libbpf_sys::BPF_STRUCT_OPS,
621 Unknown = u32::MAX,
623}
624
625impl From<u32> for ProgramAttachType {
626 fn from(value: u32) -> Self {
627 use ProgramAttachType::*;
628
629 match value {
630 x if x == CgroupInetIngress as u32 => CgroupInetIngress,
631 x if x == CgroupInetEgress as u32 => CgroupInetEgress,
632 x if x == CgroupInetSockCreate as u32 => CgroupInetSockCreate,
633 x if x == CgroupSockOps as u32 => CgroupSockOps,
634 x if x == SkSkbStreamParser as u32 => SkSkbStreamParser,
635 x if x == SkSkbStreamVerdict as u32 => SkSkbStreamVerdict,
636 x if x == CgroupDevice as u32 => CgroupDevice,
637 x if x == SkMsgVerdict as u32 => SkMsgVerdict,
638 x if x == CgroupInet4Bind as u32 => CgroupInet4Bind,
639 x if x == CgroupInet6Bind as u32 => CgroupInet6Bind,
640 x if x == CgroupInet4Connect as u32 => CgroupInet4Connect,
641 x if x == CgroupInet6Connect as u32 => CgroupInet6Connect,
642 x if x == CgroupInet4PostBind as u32 => CgroupInet4PostBind,
643 x if x == CgroupInet6PostBind as u32 => CgroupInet6PostBind,
644 x if x == CgroupUdp4Sendmsg as u32 => CgroupUdp4Sendmsg,
645 x if x == CgroupUdp6Sendmsg as u32 => CgroupUdp6Sendmsg,
646 x if x == LircMode2 as u32 => LircMode2,
647 x if x == FlowDissector as u32 => FlowDissector,
648 x if x == CgroupSysctl as u32 => CgroupSysctl,
649 x if x == CgroupUdp4Recvmsg as u32 => CgroupUdp4Recvmsg,
650 x if x == CgroupUdp6Recvmsg as u32 => CgroupUdp6Recvmsg,
651 x if x == CgroupGetsockopt as u32 => CgroupGetsockopt,
652 x if x == CgroupSetsockopt as u32 => CgroupSetsockopt,
653 x if x == TraceRawTp as u32 => TraceRawTp,
654 x if x == TraceFentry as u32 => TraceFentry,
655 x if x == TraceFexit as u32 => TraceFexit,
656 x if x == ModifyReturn as u32 => ModifyReturn,
657 x if x == LsmMac as u32 => LsmMac,
658 x if x == TraceIter as u32 => TraceIter,
659 x if x == CgroupInet4Getpeername as u32 => CgroupInet4Getpeername,
660 x if x == CgroupInet6Getpeername as u32 => CgroupInet6Getpeername,
661 x if x == CgroupInet4Getsockname as u32 => CgroupInet4Getsockname,
662 x if x == CgroupInet6Getsockname as u32 => CgroupInet6Getsockname,
663 x if x == XdpDevmap as u32 => XdpDevmap,
664 x if x == CgroupInetSockRelease as u32 => CgroupInetSockRelease,
665 x if x == XdpCpumap as u32 => XdpCpumap,
666 x if x == SkLookup as u32 => SkLookup,
667 x if x == Xdp as u32 => Xdp,
668 x if x == SkSkbVerdict as u32 => SkSkbVerdict,
669 x if x == SkReuseportSelect as u32 => SkReuseportSelect,
670 x if x == SkReuseportSelectOrMigrate as u32 => SkReuseportSelectOrMigrate,
671 x if x == PerfEvent as u32 => PerfEvent,
672 x if x == KprobeMulti as u32 => KprobeMulti,
673 x if x == NetkitPeer as u32 => NetkitPeer,
674 x if x == TraceUprobeMulti as u32 => TraceUprobeMulti,
675 x if x == LsmCgroup as u32 => LsmCgroup,
676 x if x == TraceKprobeSession as u32 => TraceKprobeSession,
677 x if x == TcxIngress as u32 => TcxIngress,
678 x if x == TcxEgress as u32 => TcxEgress,
679 x if x == Netfilter as u32 => Netfilter,
680 x if x == CgroupUnixGetsockname as u32 => CgroupUnixGetsockname,
681 x if x == CgroupUnixSendmsg as u32 => CgroupUnixSendmsg,
682 x if x == NetkitPrimary as u32 => NetkitPrimary,
683 x if x == CgroupUnixRecvmsg as u32 => CgroupUnixRecvmsg,
684 x if x == CgroupUnixConnect as u32 => CgroupUnixConnect,
685 x if x == CgroupUnixGetpeername as u32 => CgroupUnixGetpeername,
686 x if x == StructOps as u32 => StructOps,
687 _ => Unknown,
688 }
689 }
690}
691
692#[derive(Debug, Default)]
697pub struct Input<'dat> {
698 pub context_in: Option<&'dat mut [u8]>,
702 pub context_out: Option<&'dat mut [u8]>,
704 pub data_in: Option<&'dat [u8]>,
706 pub data_out: Option<&'dat mut [u8]>,
708 pub cpu: u32,
710 pub flags: u32,
712 pub repeat: u32,
715 #[doc(hidden)]
717 pub _non_exhaustive: (),
718}
719
720#[derive(Debug)]
725pub struct Output<'dat> {
726 pub return_value: u32,
728 pub context: Option<&'dat mut [u8]>,
730 pub data: Option<&'dat mut [u8]>,
732 pub duration: Duration,
734 #[doc(hidden)]
736 pub _non_exhaustive: (),
737}
738
739pub type Program<'obj> = ProgramImpl<'obj>;
741pub type ProgramMut<'obj> = ProgramImpl<'obj, Mut>;
743
744#[derive(Debug)]
752#[repr(transparent)]
753pub struct ProgramImpl<'obj, T = ()> {
754 pub(crate) ptr: NonNull<libbpf_sys::bpf_program>,
755 _phantom: PhantomData<&'obj T>,
756}
757
758impl<'obj> Program<'obj> {
759 pub fn new(prog: &'obj libbpf_sys::bpf_program) -> Self {
761 Self {
764 ptr: unsafe { NonNull::new_unchecked(prog as *const _ as *mut _) },
765 _phantom: PhantomData,
766 }
767 }
768
769 pub fn name(&self) -> &'obj OsStr {
771 let name_ptr = unsafe { libbpf_sys::bpf_program__name(self.ptr.as_ptr()) };
772 let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
773 OsStr::from_bytes(name_c_str.to_bytes())
775 }
776
777 pub fn section(&self) -> &'obj OsStr {
779 let p = unsafe { libbpf_sys::bpf_program__section_name(self.ptr.as_ptr()) };
781 let section_c_str = unsafe { CStr::from_ptr(p) };
784 let section = OsStr::from_bytes(section_c_str.to_bytes());
785 section
786 }
787
788 pub fn prog_type(&self) -> ProgramType {
790 ProgramType::from(unsafe { libbpf_sys::bpf_program__type(self.ptr.as_ptr()) })
791 }
792
793 #[deprecated = "renamed to Program::fd_from_id"]
794 #[expect(missing_docs)]
795 #[inline]
796 pub fn get_fd_by_id(id: u32) -> Result<OwnedFd> {
797 Self::fd_from_id(id)
798 }
799
800 pub fn fd_from_id(id: u32) -> Result<OwnedFd> {
802 let ret = unsafe { libbpf_sys::bpf_prog_get_fd_by_id(id) };
803 let fd = util::parse_ret_i32(ret)?;
804 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
808 }
809
810 pub fn id_from_fd(fd: BorrowedFd<'_>) -> Result<u32> {
812 let mut prog_info = libbpf_sys::bpf_prog_info::default();
813 let prog_info_ptr: *mut libbpf_sys::bpf_prog_info = &mut prog_info;
814 let mut len = size_of::<libbpf_sys::bpf_prog_info>() as u32;
815 let ret = unsafe {
816 libbpf_sys::bpf_obj_get_info_by_fd(
817 fd.as_raw_fd(),
818 prog_info_ptr as *mut c_void,
819 &mut len,
820 )
821 };
822 util::parse_ret(ret)?;
823 Ok(prog_info.id)
824 }
825
826 pub fn fd_from_pinned_path<P: AsRef<Path>>(path: P) -> Result<OwnedFd> {
830 let path_c = util::path_to_cstring(&path)?;
831 let path_ptr = path_c.as_ptr();
832
833 let fd = unsafe { libbpf_sys::bpf_obj_get(path_ptr) };
834 let fd = util::parse_ret_i32(fd).with_context(|| {
835 format!(
836 "failed to retrieve BPF object from pinned path `{}`",
837 path.as_ref().display()
838 )
839 })?;
840 let fd = unsafe { OwnedFd::from_raw_fd(fd) };
841
842 let fd_type = util::object_type_from_fd(fd.as_fd())?;
846 match fd_type {
847 BpfObjectType::Program => Ok(fd),
848 other => Err(Error::with_invalid_data(format!(
849 "retrieved BPF fd is not a program fd: {other:#?}"
850 ))),
851 }
852 }
853
854 pub fn flags(&self) -> u32 {
856 unsafe { libbpf_sys::bpf_program__flags(self.ptr.as_ptr()) }
857 }
858
859 pub fn attach_type(&self) -> ProgramAttachType {
861 ProgramAttachType::from(unsafe {
862 libbpf_sys::bpf_program__expected_attach_type(self.ptr.as_ptr())
863 })
864 }
865
866 pub fn autoload(&self) -> bool {
868 unsafe { libbpf_sys::bpf_program__autoload(self.ptr.as_ptr()) }
869 }
870
871 pub fn log_level(&self) -> u32 {
873 unsafe { libbpf_sys::bpf_program__log_level(self.ptr.as_ptr()) }
874 }
875
876 pub fn insn_cnt(&self) -> usize {
880 unsafe { libbpf_sys::bpf_program__insn_cnt(self.ptr.as_ptr()) as usize }
881 }
882
883 pub fn insns(&self) -> &'obj [libbpf_sys::bpf_insn] {
887 let count = self.insn_cnt();
888 let ptr = unsafe { libbpf_sys::bpf_program__insns(self.ptr.as_ptr()) };
889 unsafe { slice::from_raw_parts(ptr, count) }
890 }
891}
892
893impl<'obj> ProgramMut<'obj> {
894 pub fn new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self {
896 Self {
897 ptr: unsafe { NonNull::new_unchecked(prog as *mut _) },
898 _phantom: PhantomData,
899 }
900 }
901
902 pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
905 let path_c = util::path_to_cstring(path)?;
906 let path_ptr = path_c.as_ptr();
907
908 let ret = unsafe { libbpf_sys::bpf_program__pin(self.ptr.as_ptr(), path_ptr) };
909 util::parse_ret(ret)
910 }
911
912 pub fn unpin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
915 let path_c = util::path_to_cstring(path)?;
916 let path_ptr = path_c.as_ptr();
917
918 let ret = unsafe { libbpf_sys::bpf_program__unpin(self.ptr.as_ptr(), path_ptr) };
919 util::parse_ret(ret)
920 }
921
922 pub fn attach(&self) -> Result<Link> {
924 let ptr = unsafe { libbpf_sys::bpf_program__attach(self.ptr.as_ptr()) };
925 let ptr = validate_bpf_ret(ptr).context("failed to attach BPF program")?;
926 let link = unsafe { Link::new(ptr) };
928 Ok(link)
929 }
930
931 pub fn attach_cgroup(&self, cgroup_fd: i32) -> Result<Link> {
934 let ptr = unsafe { libbpf_sys::bpf_program__attach_cgroup(self.ptr.as_ptr(), cgroup_fd) };
935 let ptr = validate_bpf_ret(ptr).context("failed to attach cgroup")?;
936 let link = unsafe { Link::new(ptr) };
938 Ok(link)
939 }
940
941 pub fn attach_perf_event(&self, pfd: i32) -> Result<Link> {
943 let ptr = unsafe { libbpf_sys::bpf_program__attach_perf_event(self.ptr.as_ptr(), pfd) };
944 let ptr = validate_bpf_ret(ptr).context("failed to attach perf event")?;
945 let link = unsafe { Link::new(ptr) };
947 Ok(link)
948 }
949
950 pub fn attach_perf_event_with_opts(&self, pfd: i32, opts: PerfEventOpts) -> Result<Link> {
953 let libbpf_opts = libbpf_sys::bpf_perf_event_opts::from(opts);
954 let ptr = unsafe {
955 libbpf_sys::bpf_program__attach_perf_event_opts(self.ptr.as_ptr(), pfd, &libbpf_opts)
956 };
957 let ptr = validate_bpf_ret(ptr).context("failed to attach perf event")?;
958 let link = unsafe { Link::new(ptr) };
960 Ok(link)
961 }
962
963 pub fn attach_uprobe<T: AsRef<Path>>(
966 &self,
967 retprobe: bool,
968 pid: i32,
969 binary_path: T,
970 func_offset: usize,
971 ) -> Result<Link> {
972 let path = util::path_to_cstring(binary_path)?;
973 let path_ptr = path.as_ptr();
974 let ptr = unsafe {
975 libbpf_sys::bpf_program__attach_uprobe(
976 self.ptr.as_ptr(),
977 retprobe,
978 pid,
979 path_ptr,
980 func_offset as libbpf_sys::size_t,
981 )
982 };
983 let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe")?;
984 let link = unsafe { Link::new(ptr) };
986 Ok(link)
987 }
988
989 pub fn attach_uprobe_with_opts(
993 &self,
994 pid: i32,
995 binary_path: impl AsRef<Path>,
996 func_offset: usize,
997 opts: UprobeOpts,
998 ) -> Result<Link> {
999 let path = util::path_to_cstring(binary_path)?;
1000 let path_ptr = path.as_ptr();
1001 let UprobeOpts {
1002 ref_ctr_offset,
1003 cookie,
1004 retprobe,
1005 func_name,
1006 _non_exhaustive,
1007 } = opts;
1008
1009 let func_name: Option<CString> = if let Some(func_name) = func_name {
1010 Some(util::str_to_cstring(&func_name)?)
1011 } else {
1012 None
1013 };
1014 let ptr = func_name
1015 .as_ref()
1016 .map_or(ptr::null(), |func_name| func_name.as_ptr());
1017 let opts = libbpf_sys::bpf_uprobe_opts {
1018 sz: size_of::<libbpf_sys::bpf_uprobe_opts>() as _,
1019 ref_ctr_offset: ref_ctr_offset as libbpf_sys::size_t,
1020 bpf_cookie: cookie,
1021 retprobe,
1022 func_name: ptr,
1023 ..Default::default()
1024 };
1025
1026 let ptr = unsafe {
1027 libbpf_sys::bpf_program__attach_uprobe_opts(
1028 self.ptr.as_ptr(),
1029 pid,
1030 path_ptr,
1031 func_offset as libbpf_sys::size_t,
1032 &opts as *const _,
1033 )
1034 };
1035 let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe")?;
1036 let link = unsafe { Link::new(ptr) };
1038 Ok(link)
1039 }
1040
1041 pub fn attach_uprobe_multi(
1044 &self,
1045 pid: i32,
1046 binary_path: impl AsRef<Path>,
1047 func_pattern: impl AsRef<str>,
1048 retprobe: bool,
1049 session: bool,
1050 ) -> Result<Link> {
1051 let opts = UprobeMultiOpts {
1052 syms: Vec::new(),
1053 offsets: Vec::new(),
1054 ref_ctr_offsets: Vec::new(),
1055 cookies: Vec::new(),
1056 retprobe,
1057 session,
1058 _non_exhaustive: (),
1059 };
1060
1061 self.attach_uprobe_multi_with_opts(pid, binary_path, func_pattern, opts)
1062 }
1063
1064 pub fn attach_uprobe_multi_with_opts(
1068 &self,
1069 pid: i32,
1070 binary_path: impl AsRef<Path>,
1071 func_pattern: impl AsRef<str>,
1072 opts: UprobeMultiOpts,
1073 ) -> Result<Link> {
1074 let path = util::path_to_cstring(binary_path)?;
1075 let path_ptr = path.as_ptr();
1076
1077 let UprobeMultiOpts {
1078 syms,
1079 offsets,
1080 ref_ctr_offsets,
1081 cookies,
1082 retprobe,
1083 session,
1084 _non_exhaustive,
1085 } = opts;
1086
1087 let pattern = util::str_to_cstring(func_pattern.as_ref())?;
1088 let pattern_ptr = if pattern.is_empty() {
1090 ptr::null()
1091 } else {
1092 pattern.as_ptr()
1093 };
1094
1095 let syms_cstrings = syms
1096 .iter()
1097 .map(|s| util::str_to_cstring(s))
1098 .collect::<Result<Vec<_>>>()?;
1099 let syms_ptrs = syms_cstrings
1100 .iter()
1101 .map(|cs| cs.as_ptr())
1102 .collect::<Vec<_>>();
1103 let syms_ptr = if !syms_ptrs.is_empty() {
1104 syms_ptrs.as_ptr()
1105 } else {
1106 ptr::null()
1107 };
1108 let offsets_ptr = if !offsets.is_empty() {
1109 offsets.as_ptr()
1110 } else {
1111 ptr::null()
1112 };
1113 let ref_ctr_offsets_ptr = if !ref_ctr_offsets.is_empty() {
1114 ref_ctr_offsets.as_ptr()
1115 } else {
1116 ptr::null()
1117 };
1118 let cookies_ptr = if !cookies.is_empty() {
1119 cookies.as_ptr()
1120 } else {
1121 ptr::null()
1122 };
1123 let cnt = if !syms.is_empty() {
1124 syms.len()
1125 } else if !offsets.is_empty() {
1126 offsets.len()
1127 } else {
1128 0
1129 };
1130
1131 let c_opts = libbpf_sys::bpf_uprobe_multi_opts {
1132 sz: size_of::<libbpf_sys::bpf_uprobe_multi_opts>() as _,
1133 syms: syms_ptr.cast_mut(),
1134 offsets: offsets_ptr.cast(),
1135 ref_ctr_offsets: ref_ctr_offsets_ptr.cast(),
1136 cookies: cookies_ptr.cast(),
1137 cnt: cnt as libbpf_sys::size_t,
1138 retprobe,
1139 session,
1140 ..Default::default()
1141 };
1142
1143 let ptr = unsafe {
1144 libbpf_sys::bpf_program__attach_uprobe_multi(
1145 self.ptr.as_ptr(),
1146 pid,
1147 path_ptr,
1148 pattern_ptr,
1149 &c_opts as *const _,
1150 )
1151 };
1152
1153 let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe multi")?;
1154 let link = unsafe { Link::new(ptr) };
1156 Ok(link)
1157 }
1158
1159 pub fn attach_kprobe<T: AsRef<str>>(&self, retprobe: bool, func_name: T) -> Result<Link> {
1162 let func_name = util::str_to_cstring(func_name.as_ref())?;
1163 let func_name_ptr = func_name.as_ptr();
1164 let ptr = unsafe {
1165 libbpf_sys::bpf_program__attach_kprobe(self.ptr.as_ptr(), retprobe, func_name_ptr)
1166 };
1167 let ptr = validate_bpf_ret(ptr).context("failed to attach kprobe")?;
1168 let link = unsafe { Link::new(ptr) };
1170 Ok(link)
1171 }
1172
1173 pub fn attach_kprobe_with_opts<T: AsRef<str>>(
1177 &self,
1178 retprobe: bool,
1179 func_name: T,
1180 opts: KprobeOpts,
1181 ) -> Result<Link> {
1182 let func_name = util::str_to_cstring(func_name.as_ref())?;
1183 let func_name_ptr = func_name.as_ptr();
1184
1185 let mut opts = libbpf_sys::bpf_kprobe_opts::from(opts);
1186 opts.retprobe = retprobe;
1187
1188 let ptr = unsafe {
1189 libbpf_sys::bpf_program__attach_kprobe_opts(
1190 self.ptr.as_ptr(),
1191 func_name_ptr,
1192 &opts as *const _,
1193 )
1194 };
1195 let ptr = validate_bpf_ret(ptr).context("failed to attach kprobe")?;
1196 let link = unsafe { Link::new(ptr) };
1198 Ok(link)
1199 }
1200
1201 fn check_kprobe_multi_args<T: AsRef<str>>(symbols: &[T], cookies: &[u64]) -> Result<usize> {
1202 if symbols.is_empty() {
1203 return Err(Error::with_invalid_input("Symbols list cannot be empty"));
1204 }
1205
1206 if !cookies.is_empty() && symbols.len() != cookies.len() {
1207 return Err(Error::with_invalid_input(
1208 "Symbols and cookies list must have the same size",
1209 ));
1210 }
1211
1212 Ok(symbols.len())
1213 }
1214
1215 fn attach_kprobe_multi_impl(&self, opts: libbpf_sys::bpf_kprobe_multi_opts) -> Result<Link> {
1216 let ptr = unsafe {
1217 libbpf_sys::bpf_program__attach_kprobe_multi_opts(
1218 self.ptr.as_ptr(),
1219 ptr::null(),
1220 &opts as *const _,
1221 )
1222 };
1223 let ptr = validate_bpf_ret(ptr).context("failed to attach kprobe multi")?;
1224 let link = unsafe { Link::new(ptr) };
1226 Ok(link)
1227 }
1228
1229 pub fn attach_kprobe_multi<T: AsRef<str>>(
1233 &self,
1234 retprobe: bool,
1235 symbols: Vec<T>,
1236 ) -> Result<Link> {
1237 let cnt = Self::check_kprobe_multi_args(&symbols, &[])?;
1238
1239 let csyms = symbols
1240 .iter()
1241 .map(|s| util::str_to_cstring(s.as_ref()))
1242 .collect::<Result<Vec<_>>>()?;
1243 let mut syms = csyms.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
1244
1245 let opts = libbpf_sys::bpf_kprobe_multi_opts {
1246 sz: size_of::<libbpf_sys::bpf_kprobe_multi_opts>() as _,
1247 syms: syms.as_mut_ptr() as _,
1248 cnt: cnt as libbpf_sys::size_t,
1249 retprobe,
1250 ..Default::default()
1252 };
1253
1254 self.attach_kprobe_multi_impl(opts)
1255 }
1256
1257 pub fn attach_kprobe_multi_with_opts(&self, opts: KprobeMultiOpts) -> Result<Link> {
1261 let KprobeMultiOpts {
1262 symbols,
1263 mut cookies,
1264 retprobe,
1265 _non_exhaustive,
1266 } = opts;
1267
1268 let cnt = Self::check_kprobe_multi_args(&symbols, &cookies)?;
1269
1270 let csyms = symbols
1271 .iter()
1272 .map(|s| util::str_to_cstring(s.as_ref()))
1273 .collect::<Result<Vec<_>>>()?;
1274 let mut syms = csyms.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
1275
1276 let opts = libbpf_sys::bpf_kprobe_multi_opts {
1277 sz: size_of::<libbpf_sys::bpf_kprobe_multi_opts>() as _,
1278 syms: syms.as_mut_ptr() as _,
1279 cookies: if !cookies.is_empty() {
1280 cookies.as_mut_ptr() as _
1281 } else {
1282 ptr::null()
1283 },
1284 cnt: cnt as libbpf_sys::size_t,
1285 retprobe,
1286 ..Default::default()
1288 };
1289
1290 self.attach_kprobe_multi_impl(opts)
1291 }
1292
1293 pub fn attach_ksyscall<T: AsRef<str>>(&self, retprobe: bool, syscall_name: T) -> Result<Link> {
1295 let opts = libbpf_sys::bpf_ksyscall_opts {
1296 sz: size_of::<libbpf_sys::bpf_ksyscall_opts>() as _,
1297 retprobe,
1298 ..Default::default()
1299 };
1300
1301 let syscall_name = util::str_to_cstring(syscall_name.as_ref())?;
1302 let syscall_name_ptr = syscall_name.as_ptr();
1303 let ptr = unsafe {
1304 libbpf_sys::bpf_program__attach_ksyscall(self.ptr.as_ptr(), syscall_name_ptr, &opts)
1305 };
1306 let ptr = validate_bpf_ret(ptr).context("failed to attach ksyscall")?;
1307 let link = unsafe { Link::new(ptr) };
1309 Ok(link)
1310 }
1311
1312 fn attach_tracepoint_impl(
1313 &self,
1314 tp_category: &str,
1315 tp_name: &str,
1316 tp_opts: Option<TracepointOpts>,
1317 ) -> Result<Link> {
1318 let tp_category = util::str_to_cstring(tp_category)?;
1319 let tp_category_ptr = tp_category.as_ptr();
1320 let tp_name = util::str_to_cstring(tp_name)?;
1321 let tp_name_ptr = tp_name.as_ptr();
1322
1323 let tp_opts = tp_opts.map(libbpf_sys::bpf_tracepoint_opts::from);
1324 let opts = tp_opts.as_ref().map_or(ptr::null(), |opts| opts);
1325 let ptr = unsafe {
1326 libbpf_sys::bpf_program__attach_tracepoint_opts(
1327 self.ptr.as_ptr(),
1328 tp_category_ptr,
1329 tp_name_ptr,
1330 opts as *const _,
1331 )
1332 };
1333
1334 let ptr = validate_bpf_ret(ptr).context("failed to attach tracepoint")?;
1335 let link = unsafe { Link::new(ptr) };
1337 Ok(link)
1338 }
1339
1340 pub fn attach_tracepoint(
1343 &self,
1344 tp_category: TracepointCategory,
1345 tp_name: impl AsRef<str>,
1346 ) -> Result<Link> {
1347 self.attach_tracepoint_impl(tp_category.as_ref(), tp_name.as_ref(), None)
1348 }
1349
1350 pub fn attach_tracepoint_with_opts(
1354 &self,
1355 tp_category: TracepointCategory,
1356 tp_name: impl AsRef<str>,
1357 tp_opts: TracepointOpts,
1358 ) -> Result<Link> {
1359 self.attach_tracepoint_impl(tp_category.as_ref(), tp_name.as_ref(), Some(tp_opts))
1360 }
1361
1362 pub fn attach_raw_tracepoint<T: AsRef<str>>(&self, tp_name: T) -> Result<Link> {
1365 let tp_name = util::str_to_cstring(tp_name.as_ref())?;
1366 let tp_name_ptr = tp_name.as_ptr();
1367 let ptr = unsafe {
1368 libbpf_sys::bpf_program__attach_raw_tracepoint(self.ptr.as_ptr(), tp_name_ptr)
1369 };
1370 let ptr = validate_bpf_ret(ptr).context("failed to attach raw tracepoint")?;
1371 let link = unsafe { Link::new(ptr) };
1373 Ok(link)
1374 }
1375
1376 pub fn attach_raw_tracepoint_with_opts<T: AsRef<str>>(
1380 &self,
1381 tp_name: T,
1382 tp_opts: RawTracepointOpts,
1383 ) -> Result<Link> {
1384 let tp_name = util::str_to_cstring(tp_name.as_ref())?;
1385 let tp_name_ptr = tp_name.as_ptr();
1386 let mut tp_opts = libbpf_sys::bpf_raw_tracepoint_opts::from(tp_opts);
1387 let ptr = unsafe {
1388 libbpf_sys::bpf_program__attach_raw_tracepoint_opts(
1389 self.ptr.as_ptr(),
1390 tp_name_ptr,
1391 &mut tp_opts as *mut _,
1392 )
1393 };
1394 let ptr = validate_bpf_ret(ptr).context("failed to attach raw tracepoint")?;
1395 let link = unsafe { Link::new(ptr) };
1397 Ok(link)
1398 }
1399
1400 pub fn attach_lsm(&self) -> Result<Link> {
1402 let ptr = unsafe { libbpf_sys::bpf_program__attach_lsm(self.ptr.as_ptr()) };
1403 let ptr = validate_bpf_ret(ptr).context("failed to attach LSM")?;
1404 let link = unsafe { Link::new(ptr) };
1406 Ok(link)
1407 }
1408
1409 pub fn attach_trace(&self) -> Result<Link> {
1411 let ptr = unsafe { libbpf_sys::bpf_program__attach_trace(self.ptr.as_ptr()) };
1412 let ptr = validate_bpf_ret(ptr).context("failed to attach fentry/fexit kernel probe")?;
1413 let link = unsafe { Link::new(ptr) };
1415 Ok(link)
1416 }
1417
1418 pub fn attach_sockmap(&self, map_fd: i32) -> Result<()> {
1420 let err = unsafe {
1421 libbpf_sys::bpf_prog_attach(
1422 self.as_fd().as_raw_fd(),
1423 map_fd,
1424 self.attach_type() as u32,
1425 0,
1426 )
1427 };
1428 util::parse_ret(err)
1429 }
1430
1431 pub fn attach_xdp(&self, ifindex: i32) -> Result<Link> {
1433 let ptr = unsafe { libbpf_sys::bpf_program__attach_xdp(self.ptr.as_ptr(), ifindex) };
1434 let ptr = validate_bpf_ret(ptr).context("failed to attach XDP program")?;
1435 let link = unsafe { Link::new(ptr) };
1437 Ok(link)
1438 }
1439
1440 pub fn attach_netns(&self, netns_fd: i32) -> Result<Link> {
1442 let ptr = unsafe { libbpf_sys::bpf_program__attach_netns(self.ptr.as_ptr(), netns_fd) };
1443 let ptr = validate_bpf_ret(ptr).context("failed to attach network namespace program")?;
1444 let link = unsafe { Link::new(ptr) };
1446 Ok(link)
1447 }
1448
1449 pub fn attach_netfilter_with_opts(
1451 &self,
1452 netfilter_opt: netfilter::NetfilterOpts,
1453 ) -> Result<Link> {
1454 let netfilter_opts = libbpf_sys::bpf_netfilter_opts::from(netfilter_opt);
1455
1456 let ptr = unsafe {
1457 libbpf_sys::bpf_program__attach_netfilter(
1458 self.ptr.as_ptr(),
1459 &netfilter_opts as *const _,
1460 )
1461 };
1462
1463 let ptr = validate_bpf_ret(ptr).context("failed to attach netfilter program")?;
1464 let link = unsafe { Link::new(ptr) };
1466 Ok(link)
1467 }
1468
1469 fn attach_usdt_impl(
1470 &self,
1471 pid: i32,
1472 binary_path: &Path,
1473 usdt_provider: &str,
1474 usdt_name: &str,
1475 usdt_opts: Option<UsdtOpts>,
1476 ) -> Result<Link> {
1477 let path = util::path_to_cstring(binary_path)?;
1478 let path_ptr = path.as_ptr();
1479 let usdt_provider = util::str_to_cstring(usdt_provider)?;
1480 let usdt_provider_ptr = usdt_provider.as_ptr();
1481 let usdt_name = util::str_to_cstring(usdt_name)?;
1482 let usdt_name_ptr = usdt_name.as_ptr();
1483 let usdt_opts = usdt_opts.map(libbpf_sys::bpf_usdt_opts::from);
1484 let usdt_opts_ptr = usdt_opts
1485 .as_ref()
1486 .map(|opts| opts as *const _)
1487 .unwrap_or_else(ptr::null);
1488
1489 let ptr = unsafe {
1490 libbpf_sys::bpf_program__attach_usdt(
1491 self.ptr.as_ptr(),
1492 pid,
1493 path_ptr,
1494 usdt_provider_ptr,
1495 usdt_name_ptr,
1496 usdt_opts_ptr,
1497 )
1498 };
1499 let ptr = validate_bpf_ret(ptr).context("failed to attach USDT")?;
1500 let link = unsafe { Link::new(ptr) };
1502 Ok(link)
1503 }
1504
1505 pub fn attach_usdt(
1509 &self,
1510 pid: i32,
1511 binary_path: impl AsRef<Path>,
1512 usdt_provider: impl AsRef<str>,
1513 usdt_name: impl AsRef<str>,
1514 ) -> Result<Link> {
1515 self.attach_usdt_impl(
1516 pid,
1517 binary_path.as_ref(),
1518 usdt_provider.as_ref(),
1519 usdt_name.as_ref(),
1520 None,
1521 )
1522 }
1523
1524 pub fn attach_usdt_with_opts(
1528 &self,
1529 pid: i32,
1530 binary_path: impl AsRef<Path>,
1531 usdt_provider: impl AsRef<str>,
1532 usdt_name: impl AsRef<str>,
1533 usdt_opts: UsdtOpts,
1534 ) -> Result<Link> {
1535 self.attach_usdt_impl(
1536 pid,
1537 binary_path.as_ref(),
1538 usdt_provider.as_ref(),
1539 usdt_name.as_ref(),
1540 Some(usdt_opts),
1541 )
1542 }
1543
1544 pub fn attach_iter(&self, map_fd: BorrowedFd<'_>) -> Result<Link> {
1548 let map_opts = MapIterOpts {
1549 fd: map_fd,
1550 _non_exhaustive: (),
1551 };
1552 self.attach_iter_with_opts(IterOpts::Map(map_opts))
1553 }
1554
1555 pub fn attach_iter_with_opts(&self, opts: IterOpts<'_>) -> Result<Link> {
1561 let mut linkinfo = match opts {
1562 IterOpts::None => None,
1563 IterOpts::Map(map_opts) => {
1564 let MapIterOpts {
1565 fd,
1566 _non_exhaustive: (),
1567 } = map_opts;
1568
1569 let mut linkinfo = libbpf_sys::bpf_iter_link_info::default();
1570 linkinfo.map.map_fd = fd.as_raw_fd() as _;
1571 Some(linkinfo)
1572 }
1573 IterOpts::Cgroup(cgroup_opts) => {
1574 let CgroupIterOpts {
1575 fd,
1576 order,
1577 _non_exhaustive: (),
1578 } = cgroup_opts;
1579
1580 let mut linkinfo = libbpf_sys::bpf_iter_link_info::default();
1581 linkinfo.cgroup.order = order as libbpf_sys::bpf_cgroup_iter_order;
1582 linkinfo.cgroup.cgroup_fd = fd.as_raw_fd() as _;
1583 Some(linkinfo)
1584 }
1585 };
1586 let (linkinfo_ptr, linkinfo_len) = match &mut linkinfo {
1587 Some(info) => (
1588 info as *mut _,
1589 size_of::<libbpf_sys::bpf_iter_link_info>() as _,
1590 ),
1591 None => (ptr::null_mut(), 0),
1592 };
1593
1594 let attach_opt = libbpf_sys::bpf_iter_attach_opts {
1595 link_info: linkinfo_ptr,
1596 link_info_len: linkinfo_len,
1597 sz: size_of::<libbpf_sys::bpf_iter_attach_opts>() as _,
1598 ..Default::default()
1599 };
1600 let ptr = unsafe {
1601 libbpf_sys::bpf_program__attach_iter(
1602 self.ptr.as_ptr(),
1603 &attach_opt as *const libbpf_sys::bpf_iter_attach_opts,
1604 )
1605 };
1606
1607 let ptr = validate_bpf_ret(ptr).context("failed to attach iterator")?;
1608 let link = unsafe { Link::new(ptr) };
1610 Ok(link)
1611 }
1612
1613 pub fn assoc_struct_ops(&self, map: &Map<'_>) -> Result<()> {
1622 let ret = unsafe {
1623 libbpf_sys::bpf_program__assoc_struct_ops(
1624 self.ptr.as_ptr(),
1625 map.as_libbpf_object().as_ptr(),
1626 ptr::null_mut(),
1627 )
1628 };
1629 util::parse_ret(ret).context("failed to associate program with struct_ops map")
1630 }
1631
1632 pub fn test_run<'dat>(&self, input: Input<'dat>) -> Result<Output<'dat>> {
1638 unsafe fn slice_from_array<'t, T>(items: *mut T, num_items: usize) -> Option<&'t mut [T]> {
1639 if items.is_null() {
1640 None
1641 } else {
1642 Some(unsafe { slice::from_raw_parts_mut(items, num_items) })
1643 }
1644 }
1645
1646 let Input {
1647 context_in,
1648 mut context_out,
1649 data_in,
1650 mut data_out,
1651 cpu,
1652 flags,
1653 repeat,
1654 _non_exhaustive: (),
1655 } = input;
1656
1657 let mut opts = unsafe { mem::zeroed::<libbpf_sys::bpf_test_run_opts>() };
1658 opts.sz = size_of_val(&opts) as _;
1659 opts.ctx_in = context_in
1660 .as_ref()
1661 .map(|data| data.as_ptr().cast())
1662 .unwrap_or_else(ptr::null);
1663 opts.ctx_size_in = context_in.map(|data| data.len() as _).unwrap_or(0);
1664 opts.ctx_out = context_out
1665 .as_mut()
1666 .map(|data| data.as_mut_ptr().cast())
1667 .unwrap_or_else(ptr::null_mut);
1668 opts.ctx_size_out = context_out.map(|data| data.len() as _).unwrap_or(0);
1669 opts.data_in = data_in
1670 .map(|data| data.as_ptr().cast())
1671 .unwrap_or_else(ptr::null);
1672 opts.data_size_in = data_in.map(|data| data.len() as _).unwrap_or(0);
1673 opts.data_out = data_out
1674 .as_mut()
1675 .map(|data| data.as_mut_ptr().cast())
1676 .unwrap_or_else(ptr::null_mut);
1677 opts.data_size_out = data_out.map(|data| data.len() as _).unwrap_or(0);
1678 opts.cpu = cpu;
1679 opts.flags = flags;
1680 opts.repeat = repeat as i32;
1683
1684 let rc = unsafe { libbpf_sys::bpf_prog_test_run_opts(self.as_fd().as_raw_fd(), &mut opts) };
1685 let () = util::parse_ret(rc)?;
1686 let output = Output {
1687 return_value: opts.retval,
1688 context: unsafe { slice_from_array(opts.ctx_out.cast(), opts.ctx_size_out as _) },
1689 data: unsafe { slice_from_array(opts.data_out.cast(), opts.data_size_out as _) },
1690 duration: Duration::from_nanos(opts.duration.into()),
1691 _non_exhaustive: (),
1692 };
1693 Ok(output)
1694 }
1695
1696 pub fn stdout(&self) -> impl Read + '_ {
1698 Stream::new(self.as_fd(), Stream::BPF_STDOUT)
1699 }
1700
1701 pub fn stderr(&self) -> impl Read + '_ {
1703 Stream::new(self.as_fd(), Stream::BPF_STDERR)
1704 }
1705}
1706
1707impl<'obj> Deref for ProgramMut<'obj> {
1708 type Target = Program<'obj>;
1709
1710 fn deref(&self) -> &Self::Target {
1711 unsafe { transmute::<&ProgramMut<'obj>, &Program<'obj>>(self) }
1714 }
1715}
1716
1717impl<T> AsFd for ProgramImpl<'_, T> {
1718 fn as_fd(&self) -> BorrowedFd<'_> {
1719 let fd = unsafe { libbpf_sys::bpf_program__fd(self.ptr.as_ptr()) };
1720 unsafe { BorrowedFd::borrow_raw(fd) }
1721 }
1722}
1723
1724impl<T> AsRawLibbpf for ProgramImpl<'_, T> {
1725 type LibbpfType = libbpf_sys::bpf_program;
1726
1727 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
1729 self.ptr
1730 }
1731}
1732
1733#[cfg(test)]
1734mod tests {
1735 use super::*;
1736
1737 use std::mem::discriminant;
1738
1739 #[test]
1740 fn program_type() {
1741 use ProgramType::*;
1742
1743 for t in [
1744 Unspec,
1745 SocketFilter,
1746 Kprobe,
1747 SchedCls,
1748 SchedAct,
1749 Tracepoint,
1750 Xdp,
1751 PerfEvent,
1752 CgroupSkb,
1753 CgroupSock,
1754 LwtIn,
1755 LwtOut,
1756 LwtXmit,
1757 SockOps,
1758 SkSkb,
1759 CgroupDevice,
1760 SkMsg,
1761 RawTracepoint,
1762 CgroupSockAddr,
1763 LwtSeg6local,
1764 LircMode2,
1765 SkReuseport,
1766 FlowDissector,
1767 CgroupSysctl,
1768 RawTracepointWritable,
1769 CgroupSockopt,
1770 Tracing,
1771 StructOps,
1772 Ext,
1773 Lsm,
1774 SkLookup,
1775 Syscall,
1776 Netfilter,
1777 Unknown,
1778 ] {
1779 assert_eq!(discriminant(&t), discriminant(&ProgramType::from(t as u32)));
1781 }
1782 }
1783
1784 #[test]
1785 fn program_attach_type() {
1786 use ProgramAttachType::*;
1787
1788 for t in [
1789 CgroupInetIngress,
1790 CgroupInetEgress,
1791 CgroupInetSockCreate,
1792 CgroupSockOps,
1793 SkSkbStreamParser,
1794 SkSkbStreamVerdict,
1795 CgroupDevice,
1796 SkMsgVerdict,
1797 CgroupInet4Bind,
1798 CgroupInet6Bind,
1799 CgroupInet4Connect,
1800 CgroupInet6Connect,
1801 CgroupInet4PostBind,
1802 CgroupInet6PostBind,
1803 CgroupUdp4Sendmsg,
1804 CgroupUdp6Sendmsg,
1805 LircMode2,
1806 FlowDissector,
1807 CgroupSysctl,
1808 CgroupUdp4Recvmsg,
1809 CgroupUdp6Recvmsg,
1810 CgroupGetsockopt,
1811 CgroupSetsockopt,
1812 TraceRawTp,
1813 TraceFentry,
1814 TraceFexit,
1815 ModifyReturn,
1816 LsmMac,
1817 TraceIter,
1818 CgroupInet4Getpeername,
1819 CgroupInet6Getpeername,
1820 CgroupInet4Getsockname,
1821 CgroupInet6Getsockname,
1822 XdpDevmap,
1823 CgroupInetSockRelease,
1824 XdpCpumap,
1825 SkLookup,
1826 Xdp,
1827 SkSkbVerdict,
1828 SkReuseportSelect,
1829 SkReuseportSelectOrMigrate,
1830 PerfEvent,
1831 Unknown,
1832 ] {
1833 assert_eq!(
1835 discriminant(&t),
1836 discriminant(&ProgramAttachType::from(t as u32))
1837 );
1838 }
1839 }
1840}