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::ffi::OsString;
10use std::fs::remove_file;
11use std::io::Read;
12use std::marker::PhantomData;
13use std::mem;
14use std::mem::size_of;
15use std::mem::size_of_val;
16use std::mem::transmute;
17use std::ops::Deref;
18use std::os::unix::ffi::OsStrExt as _;
19use std::os::unix::io::AsFd;
20use std::os::unix::io::AsRawFd;
21use std::os::unix::io::BorrowedFd;
22use std::os::unix::io::FromRawFd;
23use std::os::unix::io::OwnedFd;
24use std::path::Path;
25use std::ptr;
26use std::ptr::NonNull;
27use std::slice;
28use std::time::Duration;
29
30use libbpf_sys::bpf_func_id;
31
32use crate::netfilter;
33use crate::streams::Stream;
34use crate::util;
35use crate::util::validate_bpf_ret;
36use crate::util::BpfObjectType;
37use crate::AsRawLibbpf;
38use crate::Error;
39use crate::ErrorExt as _;
40use crate::Link;
41use crate::Map;
42use crate::Mut;
43use crate::RawTracepointOpts;
44use crate::Result;
45use crate::TracepointCategory;
46use crate::TracepointOpts;
47
48#[derive(Clone, Debug, Default)]
50#[doc(alias = "bpf_uprobe_opts")]
51pub struct UprobeOpts {
52 pub ref_ctr_offset: usize,
54 pub cookie: u64,
56 pub retprobe: bool,
58 pub func_name: Option<String>,
70 #[doc(hidden)]
71 pub _non_exhaustive: (),
72}
73
74#[derive(Clone, Debug, Default)]
76#[doc(alias = "bpf_uprobe_multi_opts")]
77pub struct UprobeMultiOpts {
78 pub syms: Vec<String>,
80 pub offsets: Vec<usize>,
82 pub ref_ctr_offsets: Vec<usize>,
84 pub cookies: Vec<u64>,
86 pub retprobe: bool,
88 pub session: bool,
90 #[doc(hidden)]
91 pub _non_exhaustive: (),
92}
93
94#[derive(Clone, Debug, Default)]
96#[doc(alias = "bpf_usdt_opts")]
97pub struct UsdtOpts {
98 pub cookie: u64,
100 #[doc(hidden)]
101 pub _non_exhaustive: (),
102}
103
104impl From<UsdtOpts> for libbpf_sys::bpf_usdt_opts {
105 fn from(opts: UsdtOpts) -> Self {
106 let UsdtOpts {
107 cookie,
108 _non_exhaustive,
109 } = opts;
110 #[allow(clippy::needless_update)]
111 Self {
112 sz: size_of::<Self>() as _,
113 usdt_cookie: cookie,
114 ..Default::default()
116 }
117 }
118}
119
120#[derive(Clone, Debug, Default)]
122#[doc(alias = "bpf_kprobe_opts")]
123pub struct KprobeOpts {
124 pub cookie: u64,
126 #[doc(hidden)]
127 pub _non_exhaustive: (),
128}
129
130impl From<KprobeOpts> for libbpf_sys::bpf_kprobe_opts {
131 fn from(opts: KprobeOpts) -> Self {
132 let KprobeOpts {
133 cookie,
134 _non_exhaustive,
135 } = opts;
136
137 #[allow(clippy::needless_update)]
138 Self {
139 sz: size_of::<Self>() as _,
140 bpf_cookie: cookie,
141 ..Default::default()
143 }
144 }
145}
146
147#[derive(Clone, Debug, Default)]
149#[doc(alias = "bpf_kprobe_multi_opts")]
150pub struct KprobeMultiOpts {
151 pub symbols: Vec<String>,
153 pub cookies: Vec<u64>,
155 pub retprobe: bool,
157 #[doc(hidden)]
158 pub _non_exhaustive: (),
159}
160
161#[derive(Clone, Debug, Default)]
163#[doc(alias = "bpf_perf_event_opts")]
164pub struct PerfEventOpts {
165 pub cookie: u64,
167 pub force_ioctl_attach: bool,
169 #[doc(hidden)]
170 pub _non_exhaustive: (),
171}
172
173impl From<PerfEventOpts> for libbpf_sys::bpf_perf_event_opts {
174 fn from(opts: PerfEventOpts) -> Self {
175 let PerfEventOpts {
176 cookie,
177 force_ioctl_attach,
178 _non_exhaustive,
179 } = opts;
180
181 #[allow(clippy::needless_update)]
182 Self {
183 sz: size_of::<Self>() as _,
184 bpf_cookie: cookie,
185 force_ioctl_attach,
186 ..Default::default()
188 }
189 }
190}
191
192
193#[derive(Clone, Debug)]
195pub struct MapIterOpts<'fd> {
196 pub fd: BorrowedFd<'fd>,
198 #[doc(hidden)]
199 pub _non_exhaustive: (),
200}
201
202impl<'fd> MapIterOpts<'fd> {
203 pub fn from_fd(fd: BorrowedFd<'fd>) -> Self {
205 Self {
206 fd,
207 _non_exhaustive: (),
208 }
209 }
210}
211
212
213#[non_exhaustive]
215#[repr(u32)]
216#[derive(Clone, Debug, Default)]
217#[doc(alias = "bpf_cgroup_iter_order")]
218pub enum CgroupIterOrder {
219 #[default]
221 Default = libbpf_sys::BPF_CGROUP_ITER_ORDER_UNSPEC,
222 SelfOnly = libbpf_sys::BPF_CGROUP_ITER_SELF_ONLY,
224 DescendantsPre = libbpf_sys::BPF_CGROUP_ITER_DESCENDANTS_PRE,
226 DescendantsPost = libbpf_sys::BPF_CGROUP_ITER_DESCENDANTS_POST,
228 AncestorsUp = libbpf_sys::BPF_CGROUP_ITER_ANCESTORS_UP,
230}
231
232#[derive(Clone, Debug)]
234pub struct CgroupIterOpts<'fd> {
235 pub fd: BorrowedFd<'fd>,
237 pub order: CgroupIterOrder,
239 #[doc(hidden)]
240 pub _non_exhaustive: (),
241}
242
243impl<'fd> CgroupIterOpts<'fd> {
244 pub fn from_fd(fd: BorrowedFd<'fd>) -> Self {
246 Self {
247 fd,
248 order: CgroupIterOrder::default(),
249 _non_exhaustive: (),
250 }
251 }
252}
253
254
255#[non_exhaustive]
257#[derive(Clone, Debug)]
258#[doc(alias = "bpf_iter_attach_opts")]
259#[doc(alias = "bpf_iter_link_info")]
260pub enum IterOpts<'fd> {
261 None,
263 Map(MapIterOpts<'fd>),
265 Cgroup(CgroupIterOpts<'fd>),
267}
268
269
270pub type OpenProgram<'obj> = OpenProgramImpl<'obj>;
272pub type OpenProgramMut<'obj> = OpenProgramImpl<'obj, Mut>;
274
275
276#[derive(Debug)]
280#[repr(transparent)]
281#[doc(alias = "bpf_program")]
282pub struct OpenProgramImpl<'obj, T = ()> {
283 ptr: NonNull<libbpf_sys::bpf_program>,
284 _phantom: PhantomData<&'obj T>,
285}
286
287impl<'obj> OpenProgram<'obj> {
288 pub fn new(prog: &'obj libbpf_sys::bpf_program) -> Self {
290 Self {
293 ptr: unsafe { NonNull::new_unchecked(prog as *const _ as *mut _) },
294 _phantom: PhantomData,
295 }
296 }
297
298 #[doc(alias = "bpf_program__type")]
300 pub fn prog_type(&self) -> ProgramType {
301 ProgramType::from(unsafe { libbpf_sys::bpf_program__type(self.ptr.as_ptr()) })
302 }
303
304 #[doc(alias = "bpf_program__name")]
306 pub fn name(&self) -> &'obj OsStr {
307 let name_ptr = unsafe { libbpf_sys::bpf_program__name(self.ptr.as_ptr()) };
308 let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
309 OsStr::from_bytes(name_c_str.to_bytes())
311 }
312
313 #[doc(alias = "bpf_program__section_name")]
315 pub fn section(&self) -> &'obj OsStr {
316 let p = unsafe { libbpf_sys::bpf_program__section_name(self.ptr.as_ptr()) };
318 let section_c_str = unsafe { CStr::from_ptr(p) };
321 let section = OsStr::from_bytes(section_c_str.to_bytes());
322 section
323 }
324
325 #[doc(alias = "bpf_program__insn_cnt")]
331 pub fn insn_cnt(&self) -> usize {
332 unsafe { libbpf_sys::bpf_program__insn_cnt(self.ptr.as_ptr()) as usize }
333 }
334
335 #[doc(alias = "bpf_program__insns")]
345 pub fn insns(&self) -> &'obj [libbpf_sys::bpf_insn] {
346 let count = self.insn_cnt();
347 let ptr = unsafe { libbpf_sys::bpf_program__insns(self.ptr.as_ptr()) };
348 unsafe { slice::from_raw_parts(ptr, count) }
349 }
350
351 #[doc(alias = "bpf_program__autoload")]
353 pub fn autoload(&self) -> bool {
354 unsafe { libbpf_sys::bpf_program__autoload(self.ptr.as_ptr()) }
355 }
356}
357
358impl<'obj> OpenProgramMut<'obj> {
359 pub fn new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self {
361 Self {
362 ptr: unsafe { NonNull::new_unchecked(prog as *mut _) },
363 _phantom: PhantomData,
364 }
365 }
366
367 #[doc(alias = "bpf_program__set_type")]
369 pub fn set_prog_type(&mut self, prog_type: ProgramType) {
370 let rc = unsafe { libbpf_sys::bpf_program__set_type(self.ptr.as_ptr(), prog_type as u32) };
371 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
372 }
373
374 #[doc(alias = "bpf_program__set_expected_attach_type")]
376 pub fn set_attach_type(&mut self, attach_type: ProgramAttachType) {
377 let rc = unsafe {
378 libbpf_sys::bpf_program__set_expected_attach_type(self.ptr.as_ptr(), attach_type as u32)
379 };
380 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
381 }
382
383 #[doc(alias = "bpf_program__set_ifindex")]
387 pub fn set_ifindex(&mut self, idx: u32) {
388 unsafe { libbpf_sys::bpf_program__set_ifindex(self.ptr.as_ptr(), idx) }
389 }
390
391 #[doc(alias = "bpf_program__set_log_level")]
400 pub fn set_log_level(&mut self, log_level: u32) {
401 let rc = unsafe { libbpf_sys::bpf_program__set_log_level(self.ptr.as_ptr(), log_level) };
402 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
403 }
404
405 #[doc(alias = "bpf_program__set_autoload")]
408 pub fn set_autoload(&mut self, autoload: bool) {
409 let rc = unsafe { libbpf_sys::bpf_program__set_autoload(self.ptr.as_ptr(), autoload) };
410 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
411 }
412
413 #[doc(alias = "bpf_program__set_autoattach")]
416 pub fn set_autoattach(&mut self, autoattach: bool) {
417 unsafe { libbpf_sys::bpf_program__set_autoattach(self.ptr.as_ptr(), autoattach) };
418 }
419
420 #[expect(missing_docs)]
421 #[doc(alias = "bpf_program__set_attach_target")]
422 pub fn set_attach_target(
423 &mut self,
424 attach_prog_fd: i32,
425 attach_func_name: Option<String>,
426 ) -> Result<()> {
427 let name_c = if let Some(name) = attach_func_name {
428 Some(util::str_to_cstring(&name)?)
429 } else {
430 None
431 };
432 let name_ptr = name_c.as_ref().map_or(ptr::null(), |name| name.as_ptr());
433 let ret = unsafe {
434 libbpf_sys::bpf_program__set_attach_target(self.ptr.as_ptr(), attach_prog_fd, name_ptr)
435 };
436 util::parse_ret(ret)
437 }
438
439 #[doc(alias = "bpf_program__set_flags")]
441 pub fn set_flags(&mut self, flags: u32) {
442 let rc = unsafe { libbpf_sys::bpf_program__set_flags(self.ptr.as_ptr(), flags) };
443 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
444 }
445}
446
447impl<'obj> Deref for OpenProgramMut<'obj> {
448 type Target = OpenProgram<'obj>;
449
450 fn deref(&self) -> &Self::Target {
451 unsafe { transmute::<&OpenProgramMut<'obj>, &OpenProgram<'obj>>(self) }
454 }
455}
456
457impl<T> AsRawLibbpf for OpenProgramImpl<'_, T> {
458 type LibbpfType = libbpf_sys::bpf_program;
459
460 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
462 self.ptr
463 }
464}
465
466#[non_exhaustive]
468#[repr(u32)]
469#[derive(Copy, Clone, PartialEq, Eq, Debug)]
470#[expect(missing_docs)]
472#[doc(alias = "bpf_prog_type")]
473pub enum ProgramType {
474 Unspec = 0,
475 SocketFilter = libbpf_sys::BPF_PROG_TYPE_SOCKET_FILTER,
476 Kprobe = libbpf_sys::BPF_PROG_TYPE_KPROBE,
477 SchedCls = libbpf_sys::BPF_PROG_TYPE_SCHED_CLS,
478 SchedAct = libbpf_sys::BPF_PROG_TYPE_SCHED_ACT,
479 Tracepoint = libbpf_sys::BPF_PROG_TYPE_TRACEPOINT,
480 Xdp = libbpf_sys::BPF_PROG_TYPE_XDP,
481 PerfEvent = libbpf_sys::BPF_PROG_TYPE_PERF_EVENT,
482 CgroupSkb = libbpf_sys::BPF_PROG_TYPE_CGROUP_SKB,
483 CgroupSock = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCK,
484 LwtIn = libbpf_sys::BPF_PROG_TYPE_LWT_IN,
485 LwtOut = libbpf_sys::BPF_PROG_TYPE_LWT_OUT,
486 LwtXmit = libbpf_sys::BPF_PROG_TYPE_LWT_XMIT,
487 SockOps = libbpf_sys::BPF_PROG_TYPE_SOCK_OPS,
488 SkSkb = libbpf_sys::BPF_PROG_TYPE_SK_SKB,
489 CgroupDevice = libbpf_sys::BPF_PROG_TYPE_CGROUP_DEVICE,
490 SkMsg = libbpf_sys::BPF_PROG_TYPE_SK_MSG,
491 RawTracepoint = libbpf_sys::BPF_PROG_TYPE_RAW_TRACEPOINT,
492 CgroupSockAddr = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
493 LwtSeg6local = libbpf_sys::BPF_PROG_TYPE_LWT_SEG6LOCAL,
494 LircMode2 = libbpf_sys::BPF_PROG_TYPE_LIRC_MODE2,
495 SkReuseport = libbpf_sys::BPF_PROG_TYPE_SK_REUSEPORT,
496 FlowDissector = libbpf_sys::BPF_PROG_TYPE_FLOW_DISSECTOR,
497 CgroupSysctl = libbpf_sys::BPF_PROG_TYPE_CGROUP_SYSCTL,
498 RawTracepointWritable = libbpf_sys::BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
499 CgroupSockopt = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCKOPT,
500 Tracing = libbpf_sys::BPF_PROG_TYPE_TRACING,
501 StructOps = libbpf_sys::BPF_PROG_TYPE_STRUCT_OPS,
502 Ext = libbpf_sys::BPF_PROG_TYPE_EXT,
503 Lsm = libbpf_sys::BPF_PROG_TYPE_LSM,
504 SkLookup = libbpf_sys::BPF_PROG_TYPE_SK_LOOKUP,
505 Syscall = libbpf_sys::BPF_PROG_TYPE_SYSCALL,
506 Netfilter = libbpf_sys::BPF_PROG_TYPE_NETFILTER,
507 Unknown = u32::MAX,
509}
510
511impl ProgramType {
512 #[doc(alias = "libbpf_probe_bpf_prog_type")]
517 pub fn is_supported(&self) -> Result<bool> {
518 let ret = unsafe { libbpf_sys::libbpf_probe_bpf_prog_type(*self as u32, ptr::null()) };
519 match ret {
520 0 => Ok(false),
521 1 => Ok(true),
522 _ => Err(Error::from_raw_os_error(-ret)),
523 }
524 }
525
526 #[doc(alias = "libbpf_probe_bpf_helper")]
532 pub fn is_helper_supported(&self, helper_id: bpf_func_id) -> Result<bool> {
533 let ret =
534 unsafe { libbpf_sys::libbpf_probe_bpf_helper(*self as u32, helper_id, ptr::null()) };
535 match ret {
536 0 => Ok(false),
537 1 => Ok(true),
538 _ => Err(Error::from_raw_os_error(-ret)),
539 }
540 }
541}
542
543impl From<u32> for ProgramType {
544 fn from(value: u32) -> Self {
545 use ProgramType::*;
546
547 match value {
548 x if x == Unspec as u32 => Unspec,
549 x if x == SocketFilter as u32 => SocketFilter,
550 x if x == Kprobe as u32 => Kprobe,
551 x if x == SchedCls as u32 => SchedCls,
552 x if x == SchedAct as u32 => SchedAct,
553 x if x == Tracepoint as u32 => Tracepoint,
554 x if x == Xdp as u32 => Xdp,
555 x if x == PerfEvent as u32 => PerfEvent,
556 x if x == CgroupSkb as u32 => CgroupSkb,
557 x if x == CgroupSock as u32 => CgroupSock,
558 x if x == LwtIn as u32 => LwtIn,
559 x if x == LwtOut as u32 => LwtOut,
560 x if x == LwtXmit as u32 => LwtXmit,
561 x if x == SockOps as u32 => SockOps,
562 x if x == SkSkb as u32 => SkSkb,
563 x if x == CgroupDevice as u32 => CgroupDevice,
564 x if x == SkMsg as u32 => SkMsg,
565 x if x == RawTracepoint as u32 => RawTracepoint,
566 x if x == CgroupSockAddr as u32 => CgroupSockAddr,
567 x if x == LwtSeg6local as u32 => LwtSeg6local,
568 x if x == LircMode2 as u32 => LircMode2,
569 x if x == SkReuseport as u32 => SkReuseport,
570 x if x == FlowDissector as u32 => FlowDissector,
571 x if x == CgroupSysctl as u32 => CgroupSysctl,
572 x if x == RawTracepointWritable as u32 => RawTracepointWritable,
573 x if x == CgroupSockopt as u32 => CgroupSockopt,
574 x if x == Tracing as u32 => Tracing,
575 x if x == StructOps as u32 => StructOps,
576 x if x == Ext as u32 => Ext,
577 x if x == Lsm as u32 => Lsm,
578 x if x == SkLookup as u32 => SkLookup,
579 x if x == Syscall as u32 => Syscall,
580 x if x == Netfilter as u32 => Netfilter,
581 _ => Unknown,
582 }
583 }
584}
585
586#[non_exhaustive]
588#[repr(u32)]
589#[derive(Clone, Debug)]
590#[expect(missing_docs)]
592#[doc(alias = "bpf_attach_type")]
593pub enum ProgramAttachType {
594 CgroupInetIngress = libbpf_sys::BPF_CGROUP_INET_INGRESS,
595 CgroupInetEgress = libbpf_sys::BPF_CGROUP_INET_EGRESS,
596 CgroupInetSockCreate = libbpf_sys::BPF_CGROUP_INET_SOCK_CREATE,
597 CgroupSockOps = libbpf_sys::BPF_CGROUP_SOCK_OPS,
598 SkSkbStreamParser = libbpf_sys::BPF_SK_SKB_STREAM_PARSER,
599 SkSkbStreamVerdict = libbpf_sys::BPF_SK_SKB_STREAM_VERDICT,
600 CgroupDevice = libbpf_sys::BPF_CGROUP_DEVICE,
601 SkMsgVerdict = libbpf_sys::BPF_SK_MSG_VERDICT,
602 CgroupInet4Bind = libbpf_sys::BPF_CGROUP_INET4_BIND,
603 CgroupInet6Bind = libbpf_sys::BPF_CGROUP_INET6_BIND,
604 CgroupInet4Connect = libbpf_sys::BPF_CGROUP_INET4_CONNECT,
605 CgroupInet6Connect = libbpf_sys::BPF_CGROUP_INET6_CONNECT,
606 CgroupInet4PostBind = libbpf_sys::BPF_CGROUP_INET4_POST_BIND,
607 CgroupInet6PostBind = libbpf_sys::BPF_CGROUP_INET6_POST_BIND,
608 CgroupUdp4Sendmsg = libbpf_sys::BPF_CGROUP_UDP4_SENDMSG,
609 CgroupUdp6Sendmsg = libbpf_sys::BPF_CGROUP_UDP6_SENDMSG,
610 LircMode2 = libbpf_sys::BPF_LIRC_MODE2,
611 FlowDissector = libbpf_sys::BPF_FLOW_DISSECTOR,
612 CgroupSysctl = libbpf_sys::BPF_CGROUP_SYSCTL,
613 CgroupUdp4Recvmsg = libbpf_sys::BPF_CGROUP_UDP4_RECVMSG,
614 CgroupUdp6Recvmsg = libbpf_sys::BPF_CGROUP_UDP6_RECVMSG,
615 CgroupGetsockopt = libbpf_sys::BPF_CGROUP_GETSOCKOPT,
616 CgroupSetsockopt = libbpf_sys::BPF_CGROUP_SETSOCKOPT,
617 TraceRawTp = libbpf_sys::BPF_TRACE_RAW_TP,
618 TraceFentry = libbpf_sys::BPF_TRACE_FENTRY,
619 TraceFexit = libbpf_sys::BPF_TRACE_FEXIT,
620 ModifyReturn = libbpf_sys::BPF_MODIFY_RETURN,
621 LsmMac = libbpf_sys::BPF_LSM_MAC,
622 TraceIter = libbpf_sys::BPF_TRACE_ITER,
623 CgroupInet4Getpeername = libbpf_sys::BPF_CGROUP_INET4_GETPEERNAME,
624 CgroupInet6Getpeername = libbpf_sys::BPF_CGROUP_INET6_GETPEERNAME,
625 CgroupInet4Getsockname = libbpf_sys::BPF_CGROUP_INET4_GETSOCKNAME,
626 CgroupInet6Getsockname = libbpf_sys::BPF_CGROUP_INET6_GETSOCKNAME,
627 XdpDevmap = libbpf_sys::BPF_XDP_DEVMAP,
628 CgroupInetSockRelease = libbpf_sys::BPF_CGROUP_INET_SOCK_RELEASE,
629 XdpCpumap = libbpf_sys::BPF_XDP_CPUMAP,
630 SkLookup = libbpf_sys::BPF_SK_LOOKUP,
631 Xdp = libbpf_sys::BPF_XDP,
632 SkSkbVerdict = libbpf_sys::BPF_SK_SKB_VERDICT,
633 SkReuseportSelect = libbpf_sys::BPF_SK_REUSEPORT_SELECT,
634 SkReuseportSelectOrMigrate = libbpf_sys::BPF_SK_REUSEPORT_SELECT_OR_MIGRATE,
635 PerfEvent = libbpf_sys::BPF_PERF_EVENT,
636 KprobeMulti = libbpf_sys::BPF_TRACE_KPROBE_MULTI,
637 NetkitPeer = libbpf_sys::BPF_NETKIT_PEER,
638 TraceUprobeMulti = libbpf_sys::BPF_TRACE_UPROBE_MULTI,
639 LsmCgroup = libbpf_sys::BPF_LSM_CGROUP,
640 TraceKprobeSession = libbpf_sys::BPF_TRACE_KPROBE_SESSION,
641 TcxIngress = libbpf_sys::BPF_TCX_INGRESS,
642 TcxEgress = libbpf_sys::BPF_TCX_EGRESS,
643 Netfilter = libbpf_sys::BPF_NETFILTER,
644 CgroupUnixGetsockname = libbpf_sys::BPF_CGROUP_UNIX_GETSOCKNAME,
645 CgroupUnixSendmsg = libbpf_sys::BPF_CGROUP_UNIX_SENDMSG,
646 NetkitPrimary = libbpf_sys::BPF_NETKIT_PRIMARY,
647 CgroupUnixRecvmsg = libbpf_sys::BPF_CGROUP_UNIX_RECVMSG,
648 CgroupUnixConnect = libbpf_sys::BPF_CGROUP_UNIX_CONNECT,
649 CgroupUnixGetpeername = libbpf_sys::BPF_CGROUP_UNIX_GETPEERNAME,
650 StructOps = libbpf_sys::BPF_STRUCT_OPS,
651 Unknown = u32::MAX,
653}
654
655impl From<u32> for ProgramAttachType {
656 fn from(value: u32) -> Self {
657 use ProgramAttachType::*;
658
659 match value {
660 x if x == CgroupInetIngress as u32 => CgroupInetIngress,
661 x if x == CgroupInetEgress as u32 => CgroupInetEgress,
662 x if x == CgroupInetSockCreate as u32 => CgroupInetSockCreate,
663 x if x == CgroupSockOps as u32 => CgroupSockOps,
664 x if x == SkSkbStreamParser as u32 => SkSkbStreamParser,
665 x if x == SkSkbStreamVerdict as u32 => SkSkbStreamVerdict,
666 x if x == CgroupDevice as u32 => CgroupDevice,
667 x if x == SkMsgVerdict as u32 => SkMsgVerdict,
668 x if x == CgroupInet4Bind as u32 => CgroupInet4Bind,
669 x if x == CgroupInet6Bind as u32 => CgroupInet6Bind,
670 x if x == CgroupInet4Connect as u32 => CgroupInet4Connect,
671 x if x == CgroupInet6Connect as u32 => CgroupInet6Connect,
672 x if x == CgroupInet4PostBind as u32 => CgroupInet4PostBind,
673 x if x == CgroupInet6PostBind as u32 => CgroupInet6PostBind,
674 x if x == CgroupUdp4Sendmsg as u32 => CgroupUdp4Sendmsg,
675 x if x == CgroupUdp6Sendmsg as u32 => CgroupUdp6Sendmsg,
676 x if x == LircMode2 as u32 => LircMode2,
677 x if x == FlowDissector as u32 => FlowDissector,
678 x if x == CgroupSysctl as u32 => CgroupSysctl,
679 x if x == CgroupUdp4Recvmsg as u32 => CgroupUdp4Recvmsg,
680 x if x == CgroupUdp6Recvmsg as u32 => CgroupUdp6Recvmsg,
681 x if x == CgroupGetsockopt as u32 => CgroupGetsockopt,
682 x if x == CgroupSetsockopt as u32 => CgroupSetsockopt,
683 x if x == TraceRawTp as u32 => TraceRawTp,
684 x if x == TraceFentry as u32 => TraceFentry,
685 x if x == TraceFexit as u32 => TraceFexit,
686 x if x == ModifyReturn as u32 => ModifyReturn,
687 x if x == LsmMac as u32 => LsmMac,
688 x if x == TraceIter as u32 => TraceIter,
689 x if x == CgroupInet4Getpeername as u32 => CgroupInet4Getpeername,
690 x if x == CgroupInet6Getpeername as u32 => CgroupInet6Getpeername,
691 x if x == CgroupInet4Getsockname as u32 => CgroupInet4Getsockname,
692 x if x == CgroupInet6Getsockname as u32 => CgroupInet6Getsockname,
693 x if x == XdpDevmap as u32 => XdpDevmap,
694 x if x == CgroupInetSockRelease as u32 => CgroupInetSockRelease,
695 x if x == XdpCpumap as u32 => XdpCpumap,
696 x if x == SkLookup as u32 => SkLookup,
697 x if x == Xdp as u32 => Xdp,
698 x if x == SkSkbVerdict as u32 => SkSkbVerdict,
699 x if x == SkReuseportSelect as u32 => SkReuseportSelect,
700 x if x == SkReuseportSelectOrMigrate as u32 => SkReuseportSelectOrMigrate,
701 x if x == PerfEvent as u32 => PerfEvent,
702 x if x == KprobeMulti as u32 => KprobeMulti,
703 x if x == NetkitPeer as u32 => NetkitPeer,
704 x if x == TraceUprobeMulti as u32 => TraceUprobeMulti,
705 x if x == LsmCgroup as u32 => LsmCgroup,
706 x if x == TraceKprobeSession as u32 => TraceKprobeSession,
707 x if x == TcxIngress as u32 => TcxIngress,
708 x if x == TcxEgress as u32 => TcxEgress,
709 x if x == Netfilter as u32 => Netfilter,
710 x if x == CgroupUnixGetsockname as u32 => CgroupUnixGetsockname,
711 x if x == CgroupUnixSendmsg as u32 => CgroupUnixSendmsg,
712 x if x == NetkitPrimary as u32 => NetkitPrimary,
713 x if x == CgroupUnixRecvmsg as u32 => CgroupUnixRecvmsg,
714 x if x == CgroupUnixConnect as u32 => CgroupUnixConnect,
715 x if x == CgroupUnixGetpeername as u32 => CgroupUnixGetpeername,
716 x if x == StructOps as u32 => StructOps,
717 _ => Unknown,
718 }
719 }
720}
721
722#[derive(Debug, Default)]
727#[doc(alias = "bpf_test_run_opts")]
728pub struct Input<'dat> {
729 pub context_in: Option<&'dat mut [u8]>,
733 pub context_out: Option<&'dat mut [u8]>,
735 pub data_in: Option<&'dat [u8]>,
737 pub data_out: Option<&'dat mut [u8]>,
739 pub cpu: u32,
741 pub flags: u32,
743 pub repeat: u32,
746 #[doc(hidden)]
748 pub _non_exhaustive: (),
749}
750
751#[derive(Debug)]
756#[doc(alias = "bpf_test_run_opts")]
757pub struct Output<'dat> {
758 pub return_value: u32,
760 pub context: Option<&'dat mut [u8]>,
762 pub data: Option<&'dat mut [u8]>,
764 pub duration: Duration,
766 #[doc(hidden)]
768 pub _non_exhaustive: (),
769}
770
771pub type Program<'obj> = ProgramImpl<'obj>;
773pub type ProgramMut<'obj> = ProgramImpl<'obj, Mut>;
775
776#[derive(Debug)]
784#[repr(transparent)]
785#[doc(alias = "bpf_program")]
786pub struct ProgramImpl<'obj, T = ()> {
787 pub(crate) ptr: NonNull<libbpf_sys::bpf_program>,
788 _phantom: PhantomData<&'obj T>,
789}
790
791impl<'obj> Program<'obj> {
792 pub fn new(prog: &'obj libbpf_sys::bpf_program) -> Self {
794 Self {
797 ptr: unsafe { NonNull::new_unchecked(prog as *const _ as *mut _) },
798 _phantom: PhantomData,
799 }
800 }
801
802 #[doc(alias = "bpf_program__name")]
804 pub fn name(&self) -> &'obj OsStr {
805 let name_ptr = unsafe { libbpf_sys::bpf_program__name(self.ptr.as_ptr()) };
806 let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
807 OsStr::from_bytes(name_c_str.to_bytes())
809 }
810
811 #[doc(alias = "bpf_program__section_name")]
813 pub fn section(&self) -> &'obj OsStr {
814 let p = unsafe { libbpf_sys::bpf_program__section_name(self.ptr.as_ptr()) };
816 let section_c_str = unsafe { CStr::from_ptr(p) };
819 let section = OsStr::from_bytes(section_c_str.to_bytes());
820 section
821 }
822
823 #[doc(alias = "bpf_program__type")]
825 pub fn prog_type(&self) -> ProgramType {
826 ProgramType::from(unsafe { libbpf_sys::bpf_program__type(self.ptr.as_ptr()) })
827 }
828
829 #[deprecated = "renamed to Program::fd_from_id"]
830 #[expect(missing_docs)]
831 #[inline]
832 pub fn get_fd_by_id(id: u32) -> Result<OwnedFd> {
833 Self::fd_from_id(id)
834 }
835
836 #[doc(alias = "bpf_prog_get_fd_by_id")]
838 pub fn fd_from_id(id: u32) -> Result<OwnedFd> {
839 let ret = unsafe { libbpf_sys::bpf_prog_get_fd_by_id(id) };
840 let fd = util::parse_ret_i32(ret)?;
841 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
845 }
846
847 #[doc(alias = "bpf_obj_get_info_by_fd")]
849 pub fn id_from_fd(fd: BorrowedFd<'_>) -> Result<u32> {
850 let mut prog_info = libbpf_sys::bpf_prog_info::default();
851 let prog_info_ptr: *mut libbpf_sys::bpf_prog_info = &mut prog_info;
852 let mut len = size_of::<libbpf_sys::bpf_prog_info>() as u32;
853 let ret = unsafe {
854 libbpf_sys::bpf_obj_get_info_by_fd(
855 fd.as_raw_fd(),
856 prog_info_ptr.cast::<c_void>(),
857 &mut len,
858 )
859 };
860 util::parse_ret(ret)?;
861 Ok(prog_info.id)
862 }
863
864 #[doc(alias = "bpf_obj_get")]
868 pub fn fd_from_pinned_path<P: AsRef<Path>>(path: P) -> Result<OwnedFd> {
869 let path_c = util::path_to_cstring(&path)?;
870 let path_ptr = path_c.as_ptr();
871
872 let fd = unsafe { libbpf_sys::bpf_obj_get(path_ptr) };
873 let fd = util::parse_ret_i32(fd).with_context(|| {
874 format!(
875 "failed to retrieve BPF object from pinned path `{}`",
876 path.as_ref().display()
877 )
878 })?;
879 let fd = unsafe { OwnedFd::from_raw_fd(fd) };
880
881 let fd_type = util::object_type_from_fd(fd.as_fd())?;
885 match fd_type {
886 BpfObjectType::Program => Ok(fd),
887 other => Err(Error::with_invalid_data(format!(
888 "retrieved BPF fd is not a program fd: {other:#?}"
889 ))),
890 }
891 }
892
893 #[doc(alias = "bpf_program__flags")]
895 pub fn flags(&self) -> u32 {
896 unsafe { libbpf_sys::bpf_program__flags(self.ptr.as_ptr()) }
897 }
898
899 #[doc(alias = "bpf_program__expected_attach_type")]
901 pub fn attach_type(&self) -> ProgramAttachType {
902 ProgramAttachType::from(unsafe {
903 libbpf_sys::bpf_program__expected_attach_type(self.ptr.as_ptr())
904 })
905 }
906
907 #[doc(alias = "bpf_program__autoload")]
909 pub fn autoload(&self) -> bool {
910 unsafe { libbpf_sys::bpf_program__autoload(self.ptr.as_ptr()) }
911 }
912
913 #[doc(alias = "bpf_program__log_level")]
915 pub fn log_level(&self) -> u32 {
916 unsafe { libbpf_sys::bpf_program__log_level(self.ptr.as_ptr()) }
917 }
918
919 #[doc(alias = "bpf_program__insn_cnt")]
923 pub fn insn_cnt(&self) -> usize {
924 unsafe { libbpf_sys::bpf_program__insn_cnt(self.ptr.as_ptr()) as usize }
925 }
926
927 #[doc(alias = "bpf_program__insns")]
931 pub fn insns(&self) -> &'obj [libbpf_sys::bpf_insn] {
932 let count = self.insn_cnt();
933 let ptr = unsafe { libbpf_sys::bpf_program__insns(self.ptr.as_ptr()) };
934 unsafe { slice::from_raw_parts(ptr, count) }
935 }
936}
937
938impl<'obj> ProgramMut<'obj> {
939 pub fn new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self {
941 Self {
942 ptr: unsafe { NonNull::new_unchecked(prog as *mut _) },
943 _phantom: PhantomData,
944 }
945 }
946
947 #[doc(alias = "bpf_program__pin")]
950 pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
951 let path_c = util::path_to_cstring(path)?;
952 let path_ptr = path_c.as_ptr();
953
954 let ret = unsafe { libbpf_sys::bpf_program__pin(self.ptr.as_ptr(), path_ptr) };
955 util::parse_ret(ret)
956 }
957
958 #[doc(alias = "bpf_program__unpin")]
961 pub fn unpin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
962 let path_c = util::path_to_cstring(path)?;
963 let path_ptr = path_c.as_ptr();
964
965 let ret = unsafe { libbpf_sys::bpf_program__unpin(self.ptr.as_ptr(), path_ptr) };
966 util::parse_ret(ret)
967 }
968
969 #[doc(alias = "bpf_program__attach")]
971 pub fn attach(&self) -> Result<Link> {
972 let ptr = unsafe { libbpf_sys::bpf_program__attach(self.ptr.as_ptr()) };
973 let ptr = validate_bpf_ret(ptr).context("failed to attach BPF program")?;
974 let link = unsafe { Link::new(ptr) };
976 Ok(link)
977 }
978
979 #[doc(alias = "bpf_program__attach_cgroup")]
982 pub fn attach_cgroup(&self, cgroup_fd: i32) -> Result<Link> {
983 let ptr = unsafe { libbpf_sys::bpf_program__attach_cgroup(self.ptr.as_ptr(), cgroup_fd) };
984 let ptr = validate_bpf_ret(ptr).context("failed to attach cgroup")?;
985 let link = unsafe { Link::new(ptr) };
987 Ok(link)
988 }
989
990 #[doc(alias = "bpf_program__attach_perf_event")]
992 pub fn attach_perf_event(&self, pfd: i32) -> Result<Link> {
993 let ptr = unsafe { libbpf_sys::bpf_program__attach_perf_event(self.ptr.as_ptr(), pfd) };
994 let ptr = validate_bpf_ret(ptr).context("failed to attach perf event")?;
995 let link = unsafe { Link::new(ptr) };
997 Ok(link)
998 }
999
1000 #[doc(alias = "bpf_program__attach_perf_event_opts")]
1003 pub fn attach_perf_event_with_opts(&self, pfd: i32, opts: PerfEventOpts) -> Result<Link> {
1004 let libbpf_opts = libbpf_sys::bpf_perf_event_opts::from(opts);
1005 let ptr = unsafe {
1006 libbpf_sys::bpf_program__attach_perf_event_opts(self.ptr.as_ptr(), pfd, &libbpf_opts)
1007 };
1008 let ptr = validate_bpf_ret(ptr).context("failed to attach perf event")?;
1009 let link = unsafe { Link::new(ptr) };
1011 Ok(link)
1012 }
1013
1014 #[doc(alias = "bpf_program__attach_uprobe")]
1017 pub fn attach_uprobe<T: AsRef<Path>>(
1018 &self,
1019 retprobe: bool,
1020 pid: i32,
1021 binary_path: T,
1022 func_offset: usize,
1023 ) -> Result<Link> {
1024 let path = util::path_to_cstring(binary_path)?;
1025 let path_ptr = path.as_ptr();
1026 let ptr = unsafe {
1027 libbpf_sys::bpf_program__attach_uprobe(
1028 self.ptr.as_ptr(),
1029 retprobe,
1030 pid,
1031 path_ptr,
1032 func_offset as libbpf_sys::size_t,
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 #[doc(alias = "bpf_program__attach_uprobe_opts")]
1045 pub fn attach_uprobe_with_opts(
1046 &self,
1047 pid: i32,
1048 binary_path: impl AsRef<Path>,
1049 func_offset: usize,
1050 opts: UprobeOpts,
1051 ) -> Result<Link> {
1052 let path = util::path_to_cstring(binary_path)?;
1053 let path_ptr = path.as_ptr();
1054 let UprobeOpts {
1055 ref_ctr_offset,
1056 cookie,
1057 retprobe,
1058 func_name,
1059 _non_exhaustive,
1060 } = opts;
1061
1062 let func_name: Option<CString> = if let Some(func_name) = func_name {
1063 Some(util::str_to_cstring(&func_name)?)
1064 } else {
1065 None
1066 };
1067 let ptr = func_name
1068 .as_ref()
1069 .map_or(ptr::null(), |func_name| func_name.as_ptr());
1070 let opts = libbpf_sys::bpf_uprobe_opts {
1071 sz: size_of::<libbpf_sys::bpf_uprobe_opts>() as _,
1072 ref_ctr_offset: ref_ctr_offset as libbpf_sys::size_t,
1073 bpf_cookie: cookie,
1074 retprobe,
1075 func_name: ptr,
1076 ..Default::default()
1077 };
1078
1079 let ptr = unsafe {
1080 libbpf_sys::bpf_program__attach_uprobe_opts(
1081 self.ptr.as_ptr(),
1082 pid,
1083 path_ptr,
1084 func_offset as libbpf_sys::size_t,
1085 &opts as *const _,
1086 )
1087 };
1088 let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe")?;
1089 let link = unsafe { Link::new(ptr) };
1091 Ok(link)
1092 }
1093
1094 #[doc(alias = "bpf_program__attach_uprobe_multi")]
1097 pub fn attach_uprobe_multi(
1098 &self,
1099 pid: i32,
1100 binary_path: impl AsRef<Path>,
1101 func_pattern: impl AsRef<str>,
1102 retprobe: bool,
1103 session: bool,
1104 ) -> Result<Link> {
1105 let opts = UprobeMultiOpts {
1106 syms: Vec::new(),
1107 offsets: Vec::new(),
1108 ref_ctr_offsets: Vec::new(),
1109 cookies: Vec::new(),
1110 retprobe,
1111 session,
1112 _non_exhaustive: (),
1113 };
1114
1115 self.attach_uprobe_multi_with_opts(pid, binary_path, func_pattern, opts)
1116 }
1117
1118 #[doc(alias = "bpf_program__attach_uprobe_multi")]
1122 pub fn attach_uprobe_multi_with_opts(
1123 &self,
1124 pid: i32,
1125 binary_path: impl AsRef<Path>,
1126 func_pattern: impl AsRef<str>,
1127 opts: UprobeMultiOpts,
1128 ) -> Result<Link> {
1129 let path = util::path_to_cstring(binary_path)?;
1130 let path_ptr = path.as_ptr();
1131
1132 let UprobeMultiOpts {
1133 syms,
1134 offsets,
1135 ref_ctr_offsets,
1136 cookies,
1137 retprobe,
1138 session,
1139 _non_exhaustive,
1140 } = opts;
1141
1142 let pattern = util::str_to_cstring(func_pattern.as_ref())?;
1143 let pattern_ptr = if pattern.is_empty() {
1145 ptr::null()
1146 } else {
1147 pattern.as_ptr()
1148 };
1149
1150 let syms_cstrings = syms
1151 .iter()
1152 .map(|s| util::str_to_cstring(s))
1153 .collect::<Result<Vec<_>>>()?;
1154 let syms_ptrs = syms_cstrings
1155 .iter()
1156 .map(|cs| cs.as_ptr())
1157 .collect::<Vec<_>>();
1158 let syms_ptr = if !syms_ptrs.is_empty() {
1159 syms_ptrs.as_ptr()
1160 } else {
1161 ptr::null()
1162 };
1163 let offsets_ptr = if !offsets.is_empty() {
1164 offsets.as_ptr()
1165 } else {
1166 ptr::null()
1167 };
1168 let ref_ctr_offsets_ptr = if !ref_ctr_offsets.is_empty() {
1169 ref_ctr_offsets.as_ptr()
1170 } else {
1171 ptr::null()
1172 };
1173 let cookies_ptr = if !cookies.is_empty() {
1174 cookies.as_ptr()
1175 } else {
1176 ptr::null()
1177 };
1178 let cnt = if !syms.is_empty() {
1179 syms.len()
1180 } else if !offsets.is_empty() {
1181 offsets.len()
1182 } else {
1183 0
1184 };
1185
1186 let c_opts = libbpf_sys::bpf_uprobe_multi_opts {
1187 sz: size_of::<libbpf_sys::bpf_uprobe_multi_opts>() as _,
1188 syms: syms_ptr.cast_mut(),
1189 offsets: offsets_ptr.cast(),
1190 ref_ctr_offsets: ref_ctr_offsets_ptr.cast(),
1191 cookies: cookies_ptr.cast(),
1192 cnt: cnt as libbpf_sys::size_t,
1193 retprobe,
1194 session,
1195 ..Default::default()
1196 };
1197
1198 let ptr = unsafe {
1199 libbpf_sys::bpf_program__attach_uprobe_multi(
1200 self.ptr.as_ptr(),
1201 pid,
1202 path_ptr,
1203 pattern_ptr,
1204 &c_opts as *const _,
1205 )
1206 };
1207
1208 let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe multi")?;
1209 let link = unsafe { Link::new(ptr) };
1211 Ok(link)
1212 }
1213
1214 #[doc(alias = "bpf_program__attach_kprobe")]
1217 pub fn attach_kprobe<T: AsRef<str>>(&self, retprobe: bool, func_name: T) -> Result<Link> {
1218 let func_name = util::str_to_cstring(func_name.as_ref())?;
1219 let func_name_ptr = func_name.as_ptr();
1220 let ptr = unsafe {
1221 libbpf_sys::bpf_program__attach_kprobe(self.ptr.as_ptr(), retprobe, func_name_ptr)
1222 };
1223 let ptr = validate_bpf_ret(ptr).context("failed to attach kprobe")?;
1224 let link = unsafe { Link::new(ptr) };
1226 Ok(link)
1227 }
1228
1229 #[doc(alias = "bpf_program__attach_kprobe_opts")]
1233 pub fn attach_kprobe_with_opts<T: AsRef<str>>(
1234 &self,
1235 retprobe: bool,
1236 func_name: T,
1237 opts: KprobeOpts,
1238 ) -> Result<Link> {
1239 let func_name = util::str_to_cstring(func_name.as_ref())?;
1240 let func_name_ptr = func_name.as_ptr();
1241
1242 let mut opts = libbpf_sys::bpf_kprobe_opts::from(opts);
1243 opts.retprobe = retprobe;
1244
1245 let ptr = unsafe {
1246 libbpf_sys::bpf_program__attach_kprobe_opts(
1247 self.ptr.as_ptr(),
1248 func_name_ptr,
1249 &opts as *const _,
1250 )
1251 };
1252 let ptr = validate_bpf_ret(ptr).context("failed to attach kprobe")?;
1253 let link = unsafe { Link::new(ptr) };
1255 Ok(link)
1256 }
1257
1258 fn check_kprobe_multi_args<T: AsRef<str>>(symbols: &[T], cookies: &[u64]) -> Result<usize> {
1259 if symbols.is_empty() {
1260 return Err(Error::with_invalid_input("Symbols list cannot be empty"));
1261 }
1262
1263 if !cookies.is_empty() && symbols.len() != cookies.len() {
1264 return Err(Error::with_invalid_input(
1265 "Symbols and cookies list must have the same size",
1266 ));
1267 }
1268
1269 Ok(symbols.len())
1270 }
1271
1272 fn attach_kprobe_multi_impl(&self, opts: libbpf_sys::bpf_kprobe_multi_opts) -> Result<Link> {
1273 let ptr = unsafe {
1274 libbpf_sys::bpf_program__attach_kprobe_multi_opts(
1275 self.ptr.as_ptr(),
1276 ptr::null(),
1277 &opts as *const _,
1278 )
1279 };
1280 let ptr = validate_bpf_ret(ptr).context("failed to attach kprobe multi")?;
1281 let link = unsafe { Link::new(ptr) };
1283 Ok(link)
1284 }
1285
1286 #[doc(alias = "bpf_program__attach_kprobe_multi_opts")]
1290 pub fn attach_kprobe_multi<T: AsRef<str>>(
1291 &self,
1292 retprobe: bool,
1293 symbols: Vec<T>,
1294 ) -> Result<Link> {
1295 let cnt = Self::check_kprobe_multi_args(&symbols, &[])?;
1296
1297 let csyms = symbols
1298 .iter()
1299 .map(|s| util::str_to_cstring(s.as_ref()))
1300 .collect::<Result<Vec<_>>>()?;
1301 let mut syms = csyms.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
1302
1303 let opts = libbpf_sys::bpf_kprobe_multi_opts {
1304 sz: size_of::<libbpf_sys::bpf_kprobe_multi_opts>() as _,
1305 syms: syms.as_mut_ptr().cast(),
1306 cnt: cnt as libbpf_sys::size_t,
1307 retprobe,
1308 ..Default::default()
1310 };
1311
1312 self.attach_kprobe_multi_impl(opts)
1313 }
1314
1315 #[doc(alias = "bpf_program__attach_kprobe_multi_opts")]
1319 pub fn attach_kprobe_multi_with_opts(&self, opts: KprobeMultiOpts) -> Result<Link> {
1320 let KprobeMultiOpts {
1321 symbols,
1322 mut cookies,
1323 retprobe,
1324 _non_exhaustive,
1325 } = opts;
1326
1327 let cnt = Self::check_kprobe_multi_args(&symbols, &cookies)?;
1328
1329 let csyms = symbols
1330 .iter()
1331 .map(|s| util::str_to_cstring(s.as_ref()))
1332 .collect::<Result<Vec<_>>>()?;
1333 let mut syms = csyms.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
1334
1335 let opts = libbpf_sys::bpf_kprobe_multi_opts {
1336 sz: size_of::<libbpf_sys::bpf_kprobe_multi_opts>() as _,
1337 syms: syms.as_mut_ptr().cast(),
1338 cookies: if !cookies.is_empty() {
1339 cookies.as_mut_ptr().cast()
1340 } else {
1341 ptr::null()
1342 },
1343 cnt: cnt as libbpf_sys::size_t,
1344 retprobe,
1345 ..Default::default()
1347 };
1348
1349 self.attach_kprobe_multi_impl(opts)
1350 }
1351
1352 #[doc(alias = "bpf_program__attach_ksyscall")]
1354 pub fn attach_ksyscall<T: AsRef<str>>(&self, retprobe: bool, syscall_name: T) -> Result<Link> {
1355 let opts = libbpf_sys::bpf_ksyscall_opts {
1356 sz: size_of::<libbpf_sys::bpf_ksyscall_opts>() as _,
1357 retprobe,
1358 ..Default::default()
1359 };
1360
1361 let syscall_name = util::str_to_cstring(syscall_name.as_ref())?;
1362 let syscall_name_ptr = syscall_name.as_ptr();
1363 let ptr = unsafe {
1364 libbpf_sys::bpf_program__attach_ksyscall(self.ptr.as_ptr(), syscall_name_ptr, &opts)
1365 };
1366 let ptr = validate_bpf_ret(ptr).context("failed to attach ksyscall")?;
1367 let link = unsafe { Link::new(ptr) };
1369 Ok(link)
1370 }
1371
1372 fn attach_tracepoint_impl(
1373 &self,
1374 tp_category: &str,
1375 tp_name: &str,
1376 tp_opts: Option<TracepointOpts>,
1377 ) -> Result<Link> {
1378 let tp_category = util::str_to_cstring(tp_category)?;
1379 let tp_category_ptr = tp_category.as_ptr();
1380 let tp_name = util::str_to_cstring(tp_name)?;
1381 let tp_name_ptr = tp_name.as_ptr();
1382
1383 let tp_opts = tp_opts.map(libbpf_sys::bpf_tracepoint_opts::from);
1384 let opts = tp_opts.as_ref().map_or(ptr::null(), |opts| opts);
1385 let ptr = unsafe {
1386 libbpf_sys::bpf_program__attach_tracepoint_opts(
1387 self.ptr.as_ptr(),
1388 tp_category_ptr,
1389 tp_name_ptr,
1390 opts.cast(),
1391 )
1392 };
1393
1394 let ptr = validate_bpf_ret(ptr).context("failed to attach tracepoint")?;
1395 let link = unsafe { Link::new(ptr) };
1397 Ok(link)
1398 }
1399
1400 #[doc(alias = "bpf_program__attach_tracepoint")]
1403 pub fn attach_tracepoint(
1404 &self,
1405 tp_category: TracepointCategory,
1406 tp_name: impl AsRef<str>,
1407 ) -> Result<Link> {
1408 self.attach_tracepoint_impl(tp_category.as_ref(), tp_name.as_ref(), None)
1409 }
1410
1411 #[doc(alias = "bpf_program__attach_tracepoint_opts")]
1415 pub fn attach_tracepoint_with_opts(
1416 &self,
1417 tp_category: TracepointCategory,
1418 tp_name: impl AsRef<str>,
1419 tp_opts: TracepointOpts,
1420 ) -> Result<Link> {
1421 self.attach_tracepoint_impl(tp_category.as_ref(), tp_name.as_ref(), Some(tp_opts))
1422 }
1423
1424 #[doc(alias = "bpf_program__attach_raw_tracepoint")]
1427 pub fn attach_raw_tracepoint<T: AsRef<str>>(&self, tp_name: T) -> Result<Link> {
1428 let tp_name = util::str_to_cstring(tp_name.as_ref())?;
1429 let tp_name_ptr = tp_name.as_ptr();
1430 let ptr = unsafe {
1431 libbpf_sys::bpf_program__attach_raw_tracepoint(self.ptr.as_ptr(), tp_name_ptr)
1432 };
1433 let ptr = validate_bpf_ret(ptr).context("failed to attach raw tracepoint")?;
1434 let link = unsafe { Link::new(ptr) };
1436 Ok(link)
1437 }
1438
1439 #[doc(alias = "bpf_program__attach_raw_tracepoint_opts")]
1443 pub fn attach_raw_tracepoint_with_opts<T: AsRef<str>>(
1444 &self,
1445 tp_name: T,
1446 tp_opts: RawTracepointOpts,
1447 ) -> Result<Link> {
1448 let tp_name = util::str_to_cstring(tp_name.as_ref())?;
1449 let tp_name_ptr = tp_name.as_ptr();
1450 let mut tp_opts = libbpf_sys::bpf_raw_tracepoint_opts::from(tp_opts);
1451 let ptr = unsafe {
1452 libbpf_sys::bpf_program__attach_raw_tracepoint_opts(
1453 self.ptr.as_ptr(),
1454 tp_name_ptr,
1455 &mut tp_opts as *mut _,
1456 )
1457 };
1458 let ptr = validate_bpf_ret(ptr).context("failed to attach raw tracepoint")?;
1459 let link = unsafe { Link::new(ptr) };
1461 Ok(link)
1462 }
1463
1464 #[doc(alias = "bpf_program__attach_lsm")]
1466 pub fn attach_lsm(&self) -> Result<Link> {
1467 let ptr = unsafe { libbpf_sys::bpf_program__attach_lsm(self.ptr.as_ptr()) };
1468 let ptr = validate_bpf_ret(ptr).context("failed to attach LSM")?;
1469 let link = unsafe { Link::new(ptr) };
1471 Ok(link)
1472 }
1473
1474 #[doc(alias = "bpf_program__attach_trace")]
1476 pub fn attach_trace(&self) -> Result<Link> {
1477 let ptr = unsafe { libbpf_sys::bpf_program__attach_trace(self.ptr.as_ptr()) };
1478 let ptr = validate_bpf_ret(ptr).context("failed to attach fentry/fexit kernel probe")?;
1479 let link = unsafe { Link::new(ptr) };
1481 Ok(link)
1482 }
1483
1484 #[doc(alias = "bpf_prog_attach")]
1486 pub fn attach_sockmap(&self, map_fd: i32) -> Result<()> {
1487 let err = unsafe {
1488 libbpf_sys::bpf_prog_attach(
1489 self.as_fd().as_raw_fd(),
1490 map_fd,
1491 self.attach_type() as u32,
1492 0,
1493 )
1494 };
1495 util::parse_ret(err)
1496 }
1497
1498 #[doc(alias = "bpf_program__attach_xdp")]
1500 pub fn attach_xdp(&self, ifindex: i32) -> Result<Link> {
1501 let ptr = unsafe { libbpf_sys::bpf_program__attach_xdp(self.ptr.as_ptr(), ifindex) };
1502 let ptr = validate_bpf_ret(ptr).context("failed to attach XDP program")?;
1503 let link = unsafe { Link::new(ptr) };
1505 Ok(link)
1506 }
1507
1508 #[doc(alias = "bpf_program__attach_netns")]
1510 pub fn attach_netns(&self, netns_fd: i32) -> Result<Link> {
1511 let ptr = unsafe { libbpf_sys::bpf_program__attach_netns(self.ptr.as_ptr(), netns_fd) };
1512 let ptr = validate_bpf_ret(ptr).context("failed to attach network namespace program")?;
1513 let link = unsafe { Link::new(ptr) };
1515 Ok(link)
1516 }
1517
1518 #[doc(alias = "bpf_program__attach_netfilter")]
1520 pub fn attach_netfilter_with_opts(
1521 &self,
1522 netfilter_opt: netfilter::NetfilterOpts,
1523 ) -> Result<Link> {
1524 let netfilter_opts = libbpf_sys::bpf_netfilter_opts::from(netfilter_opt);
1525
1526 let ptr = unsafe {
1527 libbpf_sys::bpf_program__attach_netfilter(
1528 self.ptr.as_ptr(),
1529 &netfilter_opts as *const _,
1530 )
1531 };
1532
1533 let ptr = validate_bpf_ret(ptr).context("failed to attach netfilter program")?;
1534 let link = unsafe { Link::new(ptr) };
1536 Ok(link)
1537 }
1538
1539 fn attach_usdt_impl(
1540 &self,
1541 pid: i32,
1542 binary_path: &Path,
1543 usdt_provider: &str,
1544 usdt_name: &str,
1545 usdt_opts: Option<UsdtOpts>,
1546 ) -> Result<Link> {
1547 let path = util::path_to_cstring(binary_path)?;
1548 let path_ptr = path.as_ptr();
1549 let usdt_provider = util::str_to_cstring(usdt_provider)?;
1550 let usdt_provider_ptr = usdt_provider.as_ptr();
1551 let usdt_name = util::str_to_cstring(usdt_name)?;
1552 let usdt_name_ptr = usdt_name.as_ptr();
1553 let usdt_opts = usdt_opts.map(libbpf_sys::bpf_usdt_opts::from);
1554 let usdt_opts_ptr = usdt_opts
1555 .as_ref()
1556 .map(|opts| opts as *const _)
1557 .unwrap_or_else(ptr::null);
1558
1559 let ptr = unsafe {
1560 libbpf_sys::bpf_program__attach_usdt(
1561 self.ptr.as_ptr(),
1562 pid,
1563 path_ptr,
1564 usdt_provider_ptr,
1565 usdt_name_ptr,
1566 usdt_opts_ptr,
1567 )
1568 };
1569 let ptr = validate_bpf_ret(ptr).context("failed to attach USDT")?;
1570 let link = unsafe { Link::new(ptr) };
1572 Ok(link)
1573 }
1574
1575 #[doc(alias = "bpf_program__attach_usdt")]
1579 pub fn attach_usdt(
1580 &self,
1581 pid: i32,
1582 binary_path: impl AsRef<Path>,
1583 usdt_provider: impl AsRef<str>,
1584 usdt_name: impl AsRef<str>,
1585 ) -> Result<Link> {
1586 self.attach_usdt_impl(
1587 pid,
1588 binary_path.as_ref(),
1589 usdt_provider.as_ref(),
1590 usdt_name.as_ref(),
1591 None,
1592 )
1593 }
1594
1595 #[doc(alias = "bpf_program__attach_usdt")]
1599 pub fn attach_usdt_with_opts(
1600 &self,
1601 pid: i32,
1602 binary_path: impl AsRef<Path>,
1603 usdt_provider: impl AsRef<str>,
1604 usdt_name: impl AsRef<str>,
1605 usdt_opts: UsdtOpts,
1606 ) -> Result<Link> {
1607 self.attach_usdt_impl(
1608 pid,
1609 binary_path.as_ref(),
1610 usdt_provider.as_ref(),
1611 usdt_name.as_ref(),
1612 Some(usdt_opts),
1613 )
1614 }
1615
1616 #[doc(alias = "bpf_program__attach_iter")]
1620 pub fn attach_iter(&self, map_fd: BorrowedFd<'_>) -> Result<Link> {
1621 let map_opts = MapIterOpts {
1622 fd: map_fd,
1623 _non_exhaustive: (),
1624 };
1625 self.attach_iter_with_opts(IterOpts::Map(map_opts))
1626 }
1627
1628 #[doc(alias = "bpf_program__attach_iter")]
1634 pub fn attach_iter_with_opts(&self, opts: IterOpts<'_>) -> Result<Link> {
1635 let mut linkinfo = match opts {
1636 IterOpts::None => None,
1637 IterOpts::Map(map_opts) => {
1638 let MapIterOpts {
1639 fd,
1640 _non_exhaustive: (),
1641 } = map_opts;
1642
1643 let mut linkinfo = libbpf_sys::bpf_iter_link_info::default();
1644 linkinfo.map.map_fd = fd.as_raw_fd() as _;
1645 Some(linkinfo)
1646 }
1647 IterOpts::Cgroup(cgroup_opts) => {
1648 let CgroupIterOpts {
1649 fd,
1650 order,
1651 _non_exhaustive: (),
1652 } = cgroup_opts;
1653
1654 let mut linkinfo = libbpf_sys::bpf_iter_link_info::default();
1655 linkinfo.cgroup.order = order as libbpf_sys::bpf_cgroup_iter_order;
1656 linkinfo.cgroup.cgroup_fd = fd.as_raw_fd() as _;
1657 Some(linkinfo)
1658 }
1659 };
1660 let (linkinfo_ptr, linkinfo_len) = match &mut linkinfo {
1661 Some(info) => (
1662 info as *mut _,
1663 size_of::<libbpf_sys::bpf_iter_link_info>() as _,
1664 ),
1665 None => (ptr::null_mut(), 0),
1666 };
1667
1668 let attach_opt = libbpf_sys::bpf_iter_attach_opts {
1669 link_info: linkinfo_ptr,
1670 link_info_len: linkinfo_len,
1671 sz: size_of::<libbpf_sys::bpf_iter_attach_opts>() as _,
1672 ..Default::default()
1673 };
1674 let ptr = unsafe {
1675 libbpf_sys::bpf_program__attach_iter(
1676 self.ptr.as_ptr(),
1677 &attach_opt as *const libbpf_sys::bpf_iter_attach_opts,
1678 )
1679 };
1680
1681 let ptr = validate_bpf_ret(ptr).context("failed to attach iterator")?;
1682 let link = unsafe { Link::new(ptr) };
1684 Ok(link)
1685 }
1686
1687 #[doc(alias = "bpf_program__assoc_struct_ops")]
1696 pub fn assoc_struct_ops(&self, map: &Map<'_>) -> Result<()> {
1697 let ret = unsafe {
1698 libbpf_sys::bpf_program__assoc_struct_ops(
1699 self.ptr.as_ptr(),
1700 map.as_libbpf_object().as_ptr(),
1701 ptr::null_mut(),
1702 )
1703 };
1704 util::parse_ret(ret).context("failed to associate program with struct_ops map")
1705 }
1706
1707 #[doc(alias = "bpf_prog_test_run_opts")]
1713 pub fn test_run<'dat>(&self, input: Input<'dat>) -> Result<Output<'dat>> {
1714 unsafe fn slice_from_array<'t, T>(items: *mut T, num_items: usize) -> Option<&'t mut [T]> {
1715 if items.is_null() {
1716 None
1717 } else {
1718 Some(unsafe { slice::from_raw_parts_mut(items, num_items) })
1719 }
1720 }
1721
1722 let Input {
1723 context_in,
1724 mut context_out,
1725 data_in,
1726 mut data_out,
1727 cpu,
1728 flags,
1729 repeat,
1730 _non_exhaustive: (),
1731 } = input;
1732
1733 let mut opts = unsafe { mem::zeroed::<libbpf_sys::bpf_test_run_opts>() };
1734 opts.sz = size_of_val(&opts) as _;
1735 opts.ctx_in = context_in
1736 .as_ref()
1737 .map(|data| data.as_ptr().cast())
1738 .unwrap_or_else(ptr::null);
1739 opts.ctx_size_in = context_in.map(|data| data.len() as _).unwrap_or(0);
1740 opts.ctx_out = context_out
1741 .as_mut()
1742 .map(|data| data.as_mut_ptr().cast())
1743 .unwrap_or_else(ptr::null_mut);
1744 opts.ctx_size_out = context_out.map(|data| data.len() as _).unwrap_or(0);
1745 opts.data_in = data_in
1746 .map(|data| data.as_ptr().cast())
1747 .unwrap_or_else(ptr::null);
1748 opts.data_size_in = data_in.map(|data| data.len() as _).unwrap_or(0);
1749 opts.data_out = data_out
1750 .as_mut()
1751 .map(|data| data.as_mut_ptr().cast())
1752 .unwrap_or_else(ptr::null_mut);
1753 opts.data_size_out = data_out.map(|data| data.len() as _).unwrap_or(0);
1754 opts.cpu = cpu;
1755 opts.flags = flags;
1756 opts.repeat = repeat as i32;
1759
1760 let rc = unsafe { libbpf_sys::bpf_prog_test_run_opts(self.as_fd().as_raw_fd(), &mut opts) };
1761 let () = util::parse_ret(rc)?;
1762 let output = Output {
1763 return_value: opts.retval,
1764 context: unsafe { slice_from_array(opts.ctx_out.cast(), opts.ctx_size_out as _) },
1765 data: unsafe { slice_from_array(opts.data_out.cast(), opts.data_size_out as _) },
1766 duration: Duration::from_nanos(opts.duration.into()),
1767 _non_exhaustive: (),
1768 };
1769 Ok(output)
1770 }
1771
1772 #[doc(alias = "bpf_prog_stream_read")]
1774 pub fn stdout(&self) -> impl Read + '_ {
1775 Stream::new(self.as_fd(), Stream::BPF_STDOUT)
1776 }
1777
1778 #[doc(alias = "bpf_prog_stream_read")]
1780 pub fn stderr(&self) -> impl Read + '_ {
1781 Stream::new(self.as_fd(), Stream::BPF_STDERR)
1782 }
1783}
1784
1785impl<'obj> Deref for ProgramMut<'obj> {
1786 type Target = Program<'obj>;
1787
1788 fn deref(&self) -> &Self::Target {
1789 unsafe { transmute::<&ProgramMut<'obj>, &Program<'obj>>(self) }
1792 }
1793}
1794
1795impl<T> AsFd for ProgramImpl<'_, T> {
1796 #[doc(alias = "bpf_program__fd")]
1797 fn as_fd(&self) -> BorrowedFd<'_> {
1798 let fd = unsafe { libbpf_sys::bpf_program__fd(self.ptr.as_ptr()) };
1799 unsafe { BorrowedFd::borrow_raw(fd) }
1800 }
1801}
1802
1803impl<T> AsRawLibbpf for ProgramImpl<'_, T> {
1804 type LibbpfType = libbpf_sys::bpf_program;
1805
1806 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
1808 self.ptr
1809 }
1810}
1811
1812#[derive(Debug)]
1817pub struct ProgramHandle {
1818 fd: OwnedFd,
1819 name: OsString,
1820 ty: ProgramType,
1821 tag: [u8; 8],
1822 id: u32,
1823}
1824
1825impl ProgramHandle {
1826 fn from_fd(fd: OwnedFd) -> Result<Self> {
1827 let mut info = libbpf_sys::bpf_prog_info::default();
1828 let mut len = size_of::<libbpf_sys::bpf_prog_info>() as u32;
1829 let ret = unsafe {
1830 libbpf_sys::bpf_obj_get_info_by_fd(
1831 fd.as_raw_fd(),
1832 (&mut info as *mut libbpf_sys::bpf_prog_info).cast::<c_void>(),
1833 &mut len,
1834 )
1835 };
1836 util::parse_ret(ret)?;
1837
1838 let name_cstr = util::c_char_slice_to_cstr(&info.name)
1839 .ok_or_else(|| Error::with_invalid_data("program name not NUL-terminated"))?;
1840 let name = OsStr::from_bytes(name_cstr.to_bytes()).to_os_string();
1841
1842 Ok(Self {
1843 fd,
1844 name,
1845 ty: ProgramType::from(info.type_),
1846 tag: info.tag,
1847 id: info.id,
1848 })
1849 }
1850
1851 pub fn from_prog_id(id: u32) -> Result<Self> {
1853 Self::from_fd(Program::fd_from_id(id)?)
1854 }
1855
1856 #[doc(alias = "bpf_obj_get")]
1858 pub fn from_pinned_path<P: AsRef<Path>>(path: P) -> Result<Self> {
1859 let fd = Program::fd_from_pinned_path(path)?;
1860 Self::from_fd(fd)
1861 }
1862
1863 #[inline]
1865 pub fn name(&self) -> &OsStr {
1866 &self.name
1867 }
1868
1869 #[inline]
1871 pub fn prog_type(&self) -> ProgramType {
1872 self.ty
1873 }
1874
1875 #[inline]
1877 pub fn tag(&self) -> [u8; 8] {
1878 self.tag
1879 }
1880
1881 #[inline]
1883 pub fn id(&self) -> u32 {
1884 self.id
1885 }
1886
1887 #[doc(alias = "bpf_obj_pin")]
1890 pub fn pin<P: AsRef<Path>>(&self, path: P) -> Result<()> {
1891 let path_c = util::path_to_cstring(path)?;
1892 let ret = unsafe { libbpf_sys::bpf_obj_pin(self.fd.as_raw_fd(), path_c.as_ptr()) };
1893 util::parse_ret(ret)
1894 }
1895
1896 pub fn unpin<P: AsRef<Path>>(&self, path: P) -> Result<()> {
1899 remove_file(path).context("failed to remove pinned program")
1900 }
1901}
1902
1903impl AsFd for ProgramHandle {
1904 #[inline]
1905 fn as_fd(&self) -> BorrowedFd<'_> {
1906 self.fd.as_fd()
1907 }
1908}
1909
1910impl<'obj, T> TryFrom<&ProgramImpl<'obj, T>> for ProgramHandle
1911where
1912 ProgramImpl<'obj, T>: Deref<Target = Program<'obj>>,
1913{
1914 type Error = Error;
1915
1916 fn try_from(prog: &ProgramImpl<'obj, T>) -> Result<Self> {
1917 let fd = prog
1918 .as_fd()
1919 .try_clone_to_owned()
1920 .context("failed to duplicate program file descriptor")?;
1921 Ok(Self {
1922 name: prog.name().to_os_string(),
1923 ..Self::from_fd(fd)?
1924 })
1925 }
1926}
1927
1928impl TryFrom<&Self> for ProgramHandle {
1929 type Error = Error;
1930
1931 fn try_from(other: &Self) -> Result<Self> {
1932 Ok(Self {
1933 fd: other
1934 .as_fd()
1935 .try_clone_to_owned()
1936 .context("failed to duplicate program file descriptor")?,
1937 name: other.name.clone(),
1938 ty: other.ty,
1939 tag: other.tag,
1940 id: other.id,
1941 })
1942 }
1943}
1944
1945#[cfg(test)]
1946mod tests {
1947 use super::*;
1948
1949 use std::mem::discriminant;
1950
1951 #[test]
1952 fn program_type() {
1953 use ProgramType::*;
1954
1955 for t in [
1956 Unspec,
1957 SocketFilter,
1958 Kprobe,
1959 SchedCls,
1960 SchedAct,
1961 Tracepoint,
1962 Xdp,
1963 PerfEvent,
1964 CgroupSkb,
1965 CgroupSock,
1966 LwtIn,
1967 LwtOut,
1968 LwtXmit,
1969 SockOps,
1970 SkSkb,
1971 CgroupDevice,
1972 SkMsg,
1973 RawTracepoint,
1974 CgroupSockAddr,
1975 LwtSeg6local,
1976 LircMode2,
1977 SkReuseport,
1978 FlowDissector,
1979 CgroupSysctl,
1980 RawTracepointWritable,
1981 CgroupSockopt,
1982 Tracing,
1983 StructOps,
1984 Ext,
1985 Lsm,
1986 SkLookup,
1987 Syscall,
1988 Netfilter,
1989 Unknown,
1990 ] {
1991 assert_eq!(discriminant(&t), discriminant(&ProgramType::from(t as u32)));
1993 }
1994 }
1995
1996 #[test]
1997 fn program_attach_type() {
1998 use ProgramAttachType::*;
1999
2000 for t in [
2001 CgroupInetIngress,
2002 CgroupInetEgress,
2003 CgroupInetSockCreate,
2004 CgroupSockOps,
2005 SkSkbStreamParser,
2006 SkSkbStreamVerdict,
2007 CgroupDevice,
2008 SkMsgVerdict,
2009 CgroupInet4Bind,
2010 CgroupInet6Bind,
2011 CgroupInet4Connect,
2012 CgroupInet6Connect,
2013 CgroupInet4PostBind,
2014 CgroupInet6PostBind,
2015 CgroupUdp4Sendmsg,
2016 CgroupUdp6Sendmsg,
2017 LircMode2,
2018 FlowDissector,
2019 CgroupSysctl,
2020 CgroupUdp4Recvmsg,
2021 CgroupUdp6Recvmsg,
2022 CgroupGetsockopt,
2023 CgroupSetsockopt,
2024 TraceRawTp,
2025 TraceFentry,
2026 TraceFexit,
2027 ModifyReturn,
2028 LsmMac,
2029 TraceIter,
2030 CgroupInet4Getpeername,
2031 CgroupInet6Getpeername,
2032 CgroupInet4Getsockname,
2033 CgroupInet6Getsockname,
2034 XdpDevmap,
2035 CgroupInetSockRelease,
2036 XdpCpumap,
2037 SkLookup,
2038 Xdp,
2039 SkSkbVerdict,
2040 SkReuseportSelect,
2041 SkReuseportSelectOrMigrate,
2042 PerfEvent,
2043 Unknown,
2044 ] {
2045 assert_eq!(
2047 discriminant(&t),
2048 discriminant(&ProgramAttachType::from(t as u32))
2049 );
2050 }
2051 }
2052}