1#![allow(rustdoc::private_intra_doc_links)]
4
5use std::ffi::c_void;
6use std::ffi::CStr;
7use std::ffi::OsStr;
8use std::marker::PhantomData;
9use std::mem;
10use std::mem::size_of;
11use std::mem::size_of_val;
12use std::mem::transmute;
13use std::ops::Deref;
14use std::os::unix::ffi::OsStrExt as _;
15use std::os::unix::io::AsFd;
16use std::os::unix::io::AsRawFd;
17use std::os::unix::io::BorrowedFd;
18use std::os::unix::io::FromRawFd;
19use std::os::unix::io::OwnedFd;
20use std::path::Path;
21use std::ptr;
22use std::ptr::NonNull;
23use std::slice;
24
25use libbpf_sys::bpf_func_id;
26
27use crate::netfilter;
28use crate::util;
29use crate::util::validate_bpf_ret;
30use crate::util::BpfObjectType;
31use crate::AsRawLibbpf;
32use crate::Error;
33use crate::ErrorExt as _;
34use crate::Link;
35use crate::Mut;
36use crate::Result;
37
38#[derive(Clone, Debug, Default)]
40pub struct UprobeOpts {
41 pub ref_ctr_offset: usize,
43 pub cookie: u64,
45 pub retprobe: bool,
47 pub func_name: String,
56 #[doc(hidden)]
57 pub _non_exhaustive: (),
58}
59
60#[derive(Clone, Debug, Default)]
62pub struct UsdtOpts {
63 pub cookie: u64,
65 #[doc(hidden)]
66 pub _non_exhaustive: (),
67}
68
69impl From<UsdtOpts> for libbpf_sys::bpf_usdt_opts {
70 fn from(opts: UsdtOpts) -> Self {
71 let UsdtOpts {
72 cookie,
73 _non_exhaustive,
74 } = opts;
75 #[allow(clippy::needless_update)]
76 libbpf_sys::bpf_usdt_opts {
77 sz: size_of::<Self>() as _,
78 usdt_cookie: cookie,
79 ..Default::default()
81 }
82 }
83}
84
85#[derive(Clone, Debug, Default)]
87pub struct TracepointOpts {
88 pub cookie: u64,
90 #[doc(hidden)]
91 pub _non_exhaustive: (),
92}
93
94impl From<TracepointOpts> for libbpf_sys::bpf_tracepoint_opts {
95 fn from(opts: TracepointOpts) -> Self {
96 let TracepointOpts {
97 cookie,
98 _non_exhaustive,
99 } = opts;
100
101 #[allow(clippy::needless_update)]
102 libbpf_sys::bpf_tracepoint_opts {
103 sz: size_of::<Self>() as _,
104 bpf_cookie: cookie,
105 ..Default::default()
107 }
108 }
109}
110
111
112pub type OpenProgram<'obj> = OpenProgramImpl<'obj>;
114pub type OpenProgramMut<'obj> = OpenProgramImpl<'obj, Mut>;
116
117#[derive(Debug)]
121#[repr(transparent)]
122pub struct OpenProgramImpl<'obj, T = ()> {
123 ptr: NonNull<libbpf_sys::bpf_program>,
124 _phantom: PhantomData<&'obj T>,
125}
126
127impl<'obj> OpenProgram<'obj> {
128 pub fn new(prog: &'obj libbpf_sys::bpf_program) -> Self {
130 Self {
133 ptr: unsafe { NonNull::new_unchecked(prog as *const _ as *mut _) },
134 _phantom: PhantomData,
135 }
136 }
137
138 pub fn prog_type(&self) -> ProgramType {
140 ProgramType::from(unsafe { libbpf_sys::bpf_program__type(self.ptr.as_ptr()) })
141 }
142
143 pub fn name(&self) -> &OsStr {
145 let name_ptr = unsafe { libbpf_sys::bpf_program__name(self.ptr.as_ptr()) };
146 let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
147 OsStr::from_bytes(name_c_str.to_bytes())
149 }
150
151 pub fn section(&self) -> &OsStr {
153 let p = unsafe { libbpf_sys::bpf_program__section_name(self.ptr.as_ptr()) };
155 let section_c_str = unsafe { CStr::from_ptr(p) };
158 let section = OsStr::from_bytes(section_c_str.to_bytes());
159 section
160 }
161
162 pub fn insn_cnt(&self) -> usize {
168 unsafe { libbpf_sys::bpf_program__insn_cnt(self.ptr.as_ptr()) as usize }
169 }
170
171 pub fn insns(&self) -> &[libbpf_sys::bpf_insn] {
181 let count = self.insn_cnt();
182 let ptr = unsafe { libbpf_sys::bpf_program__insns(self.ptr.as_ptr()) };
183 unsafe { slice::from_raw_parts(ptr, count) }
184 }
185}
186
187impl<'obj> OpenProgramMut<'obj> {
188 pub fn new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self {
190 Self {
191 ptr: unsafe { NonNull::new_unchecked(prog as *mut _) },
192 _phantom: PhantomData,
193 }
194 }
195
196 pub fn set_prog_type(&mut self, prog_type: ProgramType) {
198 let rc = unsafe { libbpf_sys::bpf_program__set_type(self.ptr.as_ptr(), prog_type as u32) };
199 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
200 }
201
202 pub fn set_attach_type(&mut self, attach_type: ProgramAttachType) {
204 let rc = unsafe {
205 libbpf_sys::bpf_program__set_expected_attach_type(self.ptr.as_ptr(), attach_type as u32)
206 };
207 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
208 }
209
210 pub fn set_ifindex(&mut self, idx: u32) {
214 unsafe { libbpf_sys::bpf_program__set_ifindex(self.ptr.as_ptr(), idx) }
215 }
216
217 pub fn set_log_level(&mut self, log_level: u32) {
226 let rc = unsafe { libbpf_sys::bpf_program__set_log_level(self.ptr.as_ptr(), log_level) };
227 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
228 }
229
230 pub fn set_autoload(&mut self, autoload: bool) {
233 let rc = unsafe { libbpf_sys::bpf_program__set_autoload(self.ptr.as_ptr(), autoload) };
234 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
235 }
236
237 #[allow(missing_docs)]
238 pub fn set_attach_target(
239 &mut self,
240 attach_prog_fd: i32,
241 attach_func_name: Option<String>,
242 ) -> Result<()> {
243 let ret = if let Some(name) = attach_func_name {
244 let name_c = util::str_to_cstring(&name)?;
246 unsafe {
247 libbpf_sys::bpf_program__set_attach_target(
248 self.ptr.as_ptr(),
249 attach_prog_fd,
250 name_c.as_ptr(),
251 )
252 }
253 } else {
254 unsafe {
255 libbpf_sys::bpf_program__set_attach_target(
256 self.ptr.as_ptr(),
257 attach_prog_fd,
258 ptr::null(),
259 )
260 }
261 };
262 util::parse_ret(ret)
263 }
264
265 pub fn set_flags(&mut self, flags: u32) {
267 let rc = unsafe { libbpf_sys::bpf_program__set_flags(self.ptr.as_ptr(), flags) };
268 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}");
269 }
270}
271
272impl<'obj> Deref for OpenProgramMut<'obj> {
273 type Target = OpenProgram<'obj>;
274
275 fn deref(&self) -> &Self::Target {
276 unsafe { transmute::<&OpenProgramMut<'obj>, &OpenProgram<'obj>>(self) }
279 }
280}
281
282impl<T> AsRawLibbpf for OpenProgramImpl<'_, T> {
283 type LibbpfType = libbpf_sys::bpf_program;
284
285 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
287 self.ptr
288 }
289}
290
291#[non_exhaustive]
293#[repr(u32)]
294#[derive(Copy, Clone, Debug)]
295#[allow(missing_docs)]
297pub enum ProgramType {
298 Unspec = 0,
299 SocketFilter = libbpf_sys::BPF_PROG_TYPE_SOCKET_FILTER,
300 Kprobe = libbpf_sys::BPF_PROG_TYPE_KPROBE,
301 SchedCls = libbpf_sys::BPF_PROG_TYPE_SCHED_CLS,
302 SchedAct = libbpf_sys::BPF_PROG_TYPE_SCHED_ACT,
303 Tracepoint = libbpf_sys::BPF_PROG_TYPE_TRACEPOINT,
304 Xdp = libbpf_sys::BPF_PROG_TYPE_XDP,
305 PerfEvent = libbpf_sys::BPF_PROG_TYPE_PERF_EVENT,
306 CgroupSkb = libbpf_sys::BPF_PROG_TYPE_CGROUP_SKB,
307 CgroupSock = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCK,
308 LwtIn = libbpf_sys::BPF_PROG_TYPE_LWT_IN,
309 LwtOut = libbpf_sys::BPF_PROG_TYPE_LWT_OUT,
310 LwtXmit = libbpf_sys::BPF_PROG_TYPE_LWT_XMIT,
311 SockOps = libbpf_sys::BPF_PROG_TYPE_SOCK_OPS,
312 SkSkb = libbpf_sys::BPF_PROG_TYPE_SK_SKB,
313 CgroupDevice = libbpf_sys::BPF_PROG_TYPE_CGROUP_DEVICE,
314 SkMsg = libbpf_sys::BPF_PROG_TYPE_SK_MSG,
315 RawTracepoint = libbpf_sys::BPF_PROG_TYPE_RAW_TRACEPOINT,
316 CgroupSockAddr = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
317 LwtSeg6local = libbpf_sys::BPF_PROG_TYPE_LWT_SEG6LOCAL,
318 LircMode2 = libbpf_sys::BPF_PROG_TYPE_LIRC_MODE2,
319 SkReuseport = libbpf_sys::BPF_PROG_TYPE_SK_REUSEPORT,
320 FlowDissector = libbpf_sys::BPF_PROG_TYPE_FLOW_DISSECTOR,
321 CgroupSysctl = libbpf_sys::BPF_PROG_TYPE_CGROUP_SYSCTL,
322 RawTracepointWritable = libbpf_sys::BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
323 CgroupSockopt = libbpf_sys::BPF_PROG_TYPE_CGROUP_SOCKOPT,
324 Tracing = libbpf_sys::BPF_PROG_TYPE_TRACING,
325 StructOps = libbpf_sys::BPF_PROG_TYPE_STRUCT_OPS,
326 Ext = libbpf_sys::BPF_PROG_TYPE_EXT,
327 Lsm = libbpf_sys::BPF_PROG_TYPE_LSM,
328 SkLookup = libbpf_sys::BPF_PROG_TYPE_SK_LOOKUP,
329 Syscall = libbpf_sys::BPF_PROG_TYPE_SYSCALL,
330 Unknown = u32::MAX,
332}
333
334impl ProgramType {
335 pub fn is_supported(&self) -> Result<bool> {
340 let ret = unsafe { libbpf_sys::libbpf_probe_bpf_prog_type(*self as u32, ptr::null()) };
341 match ret {
342 0 => Ok(false),
343 1 => Ok(true),
344 _ => Err(Error::from_raw_os_error(-ret)),
345 }
346 }
347
348 pub fn is_helper_supported(&self, helper_id: bpf_func_id) -> Result<bool> {
354 let ret =
355 unsafe { libbpf_sys::libbpf_probe_bpf_helper(*self as u32, helper_id, ptr::null()) };
356 match ret {
357 0 => Ok(false),
358 1 => Ok(true),
359 _ => Err(Error::from_raw_os_error(-ret)),
360 }
361 }
362}
363
364impl From<u32> for ProgramType {
365 fn from(value: u32) -> Self {
366 use ProgramType::*;
367
368 match value {
369 x if x == Unspec as u32 => Unspec,
370 x if x == SocketFilter as u32 => SocketFilter,
371 x if x == Kprobe as u32 => Kprobe,
372 x if x == SchedCls as u32 => SchedCls,
373 x if x == SchedAct as u32 => SchedAct,
374 x if x == Tracepoint as u32 => Tracepoint,
375 x if x == Xdp as u32 => Xdp,
376 x if x == PerfEvent as u32 => PerfEvent,
377 x if x == CgroupSkb as u32 => CgroupSkb,
378 x if x == CgroupSock as u32 => CgroupSock,
379 x if x == LwtIn as u32 => LwtIn,
380 x if x == LwtOut as u32 => LwtOut,
381 x if x == LwtXmit as u32 => LwtXmit,
382 x if x == SockOps as u32 => SockOps,
383 x if x == SkSkb as u32 => SkSkb,
384 x if x == CgroupDevice as u32 => CgroupDevice,
385 x if x == SkMsg as u32 => SkMsg,
386 x if x == RawTracepoint as u32 => RawTracepoint,
387 x if x == CgroupSockAddr as u32 => CgroupSockAddr,
388 x if x == LwtSeg6local as u32 => LwtSeg6local,
389 x if x == LircMode2 as u32 => LircMode2,
390 x if x == SkReuseport as u32 => SkReuseport,
391 x if x == FlowDissector as u32 => FlowDissector,
392 x if x == CgroupSysctl as u32 => CgroupSysctl,
393 x if x == RawTracepointWritable as u32 => RawTracepointWritable,
394 x if x == CgroupSockopt as u32 => CgroupSockopt,
395 x if x == Tracing as u32 => Tracing,
396 x if x == StructOps as u32 => StructOps,
397 x if x == Ext as u32 => Ext,
398 x if x == Lsm as u32 => Lsm,
399 x if x == SkLookup as u32 => SkLookup,
400 x if x == Syscall as u32 => Syscall,
401 _ => Unknown,
402 }
403 }
404}
405
406#[non_exhaustive]
408#[repr(u32)]
409#[derive(Clone, Debug)]
410#[allow(missing_docs)]
412pub enum ProgramAttachType {
413 CgroupInetIngress = libbpf_sys::BPF_CGROUP_INET_INGRESS,
414 CgroupInetEgress = libbpf_sys::BPF_CGROUP_INET_EGRESS,
415 CgroupInetSockCreate = libbpf_sys::BPF_CGROUP_INET_SOCK_CREATE,
416 CgroupSockOps = libbpf_sys::BPF_CGROUP_SOCK_OPS,
417 SkSkbStreamParser = libbpf_sys::BPF_SK_SKB_STREAM_PARSER,
418 SkSkbStreamVerdict = libbpf_sys::BPF_SK_SKB_STREAM_VERDICT,
419 CgroupDevice = libbpf_sys::BPF_CGROUP_DEVICE,
420 SkMsgVerdict = libbpf_sys::BPF_SK_MSG_VERDICT,
421 CgroupInet4Bind = libbpf_sys::BPF_CGROUP_INET4_BIND,
422 CgroupInet6Bind = libbpf_sys::BPF_CGROUP_INET6_BIND,
423 CgroupInet4Connect = libbpf_sys::BPF_CGROUP_INET4_CONNECT,
424 CgroupInet6Connect = libbpf_sys::BPF_CGROUP_INET6_CONNECT,
425 CgroupInet4PostBind = libbpf_sys::BPF_CGROUP_INET4_POST_BIND,
426 CgroupInet6PostBind = libbpf_sys::BPF_CGROUP_INET6_POST_BIND,
427 CgroupUdp4Sendmsg = libbpf_sys::BPF_CGROUP_UDP4_SENDMSG,
428 CgroupUdp6Sendmsg = libbpf_sys::BPF_CGROUP_UDP6_SENDMSG,
429 LircMode2 = libbpf_sys::BPF_LIRC_MODE2,
430 FlowDissector = libbpf_sys::BPF_FLOW_DISSECTOR,
431 CgroupSysctl = libbpf_sys::BPF_CGROUP_SYSCTL,
432 CgroupUdp4Recvmsg = libbpf_sys::BPF_CGROUP_UDP4_RECVMSG,
433 CgroupUdp6Recvmsg = libbpf_sys::BPF_CGROUP_UDP6_RECVMSG,
434 CgroupGetsockopt = libbpf_sys::BPF_CGROUP_GETSOCKOPT,
435 CgroupSetsockopt = libbpf_sys::BPF_CGROUP_SETSOCKOPT,
436 TraceRawTp = libbpf_sys::BPF_TRACE_RAW_TP,
437 TraceFentry = libbpf_sys::BPF_TRACE_FENTRY,
438 TraceFexit = libbpf_sys::BPF_TRACE_FEXIT,
439 ModifyReturn = libbpf_sys::BPF_MODIFY_RETURN,
440 LsmMac = libbpf_sys::BPF_LSM_MAC,
441 TraceIter = libbpf_sys::BPF_TRACE_ITER,
442 CgroupInet4Getpeername = libbpf_sys::BPF_CGROUP_INET4_GETPEERNAME,
443 CgroupInet6Getpeername = libbpf_sys::BPF_CGROUP_INET6_GETPEERNAME,
444 CgroupInet4Getsockname = libbpf_sys::BPF_CGROUP_INET4_GETSOCKNAME,
445 CgroupInet6Getsockname = libbpf_sys::BPF_CGROUP_INET6_GETSOCKNAME,
446 XdpDevmap = libbpf_sys::BPF_XDP_DEVMAP,
447 CgroupInetSockRelease = libbpf_sys::BPF_CGROUP_INET_SOCK_RELEASE,
448 XdpCpumap = libbpf_sys::BPF_XDP_CPUMAP,
449 SkLookup = libbpf_sys::BPF_SK_LOOKUP,
450 Xdp = libbpf_sys::BPF_XDP,
451 SkSkbVerdict = libbpf_sys::BPF_SK_SKB_VERDICT,
452 SkReuseportSelect = libbpf_sys::BPF_SK_REUSEPORT_SELECT,
453 SkReuseportSelectOrMigrate = libbpf_sys::BPF_SK_REUSEPORT_SELECT_OR_MIGRATE,
454 PerfEvent = libbpf_sys::BPF_PERF_EVENT,
455 Unknown = u32::MAX,
457}
458
459impl From<u32> for ProgramAttachType {
460 fn from(value: u32) -> Self {
461 use ProgramAttachType::*;
462
463 match value {
464 x if x == CgroupInetIngress as u32 => CgroupInetIngress,
465 x if x == CgroupInetEgress as u32 => CgroupInetEgress,
466 x if x == CgroupInetSockCreate as u32 => CgroupInetSockCreate,
467 x if x == CgroupSockOps as u32 => CgroupSockOps,
468 x if x == SkSkbStreamParser as u32 => SkSkbStreamParser,
469 x if x == SkSkbStreamVerdict as u32 => SkSkbStreamVerdict,
470 x if x == CgroupDevice as u32 => CgroupDevice,
471 x if x == SkMsgVerdict as u32 => SkMsgVerdict,
472 x if x == CgroupInet4Bind as u32 => CgroupInet4Bind,
473 x if x == CgroupInet6Bind as u32 => CgroupInet6Bind,
474 x if x == CgroupInet4Connect as u32 => CgroupInet4Connect,
475 x if x == CgroupInet6Connect as u32 => CgroupInet6Connect,
476 x if x == CgroupInet4PostBind as u32 => CgroupInet4PostBind,
477 x if x == CgroupInet6PostBind as u32 => CgroupInet6PostBind,
478 x if x == CgroupUdp4Sendmsg as u32 => CgroupUdp4Sendmsg,
479 x if x == CgroupUdp6Sendmsg as u32 => CgroupUdp6Sendmsg,
480 x if x == LircMode2 as u32 => LircMode2,
481 x if x == FlowDissector as u32 => FlowDissector,
482 x if x == CgroupSysctl as u32 => CgroupSysctl,
483 x if x == CgroupUdp4Recvmsg as u32 => CgroupUdp4Recvmsg,
484 x if x == CgroupUdp6Recvmsg as u32 => CgroupUdp6Recvmsg,
485 x if x == CgroupGetsockopt as u32 => CgroupGetsockopt,
486 x if x == CgroupSetsockopt as u32 => CgroupSetsockopt,
487 x if x == TraceRawTp as u32 => TraceRawTp,
488 x if x == TraceFentry as u32 => TraceFentry,
489 x if x == TraceFexit as u32 => TraceFexit,
490 x if x == ModifyReturn as u32 => ModifyReturn,
491 x if x == LsmMac as u32 => LsmMac,
492 x if x == TraceIter as u32 => TraceIter,
493 x if x == CgroupInet4Getpeername as u32 => CgroupInet4Getpeername,
494 x if x == CgroupInet6Getpeername as u32 => CgroupInet6Getpeername,
495 x if x == CgroupInet4Getsockname as u32 => CgroupInet4Getsockname,
496 x if x == CgroupInet6Getsockname as u32 => CgroupInet6Getsockname,
497 x if x == XdpDevmap as u32 => XdpDevmap,
498 x if x == CgroupInetSockRelease as u32 => CgroupInetSockRelease,
499 x if x == XdpCpumap as u32 => XdpCpumap,
500 x if x == SkLookup as u32 => SkLookup,
501 x if x == Xdp as u32 => Xdp,
502 x if x == SkSkbVerdict as u32 => SkSkbVerdict,
503 x if x == SkReuseportSelect as u32 => SkReuseportSelect,
504 x if x == SkReuseportSelectOrMigrate as u32 => SkReuseportSelectOrMigrate,
505 x if x == PerfEvent as u32 => PerfEvent,
506 _ => Unknown,
507 }
508 }
509}
510
511#[derive(Debug, Default)]
516pub struct Input<'dat> {
517 pub context_in: Option<&'dat mut [u8]>,
521 pub context_out: Option<&'dat mut [u8]>,
523 pub data_in: Option<&'dat [u8]>,
525 pub data_out: Option<&'dat mut [u8]>,
527 pub cpu: u32,
529 pub flags: u32,
531 #[doc(hidden)]
533 pub _non_exhaustive: (),
534}
535
536#[derive(Debug)]
541pub struct Output<'dat> {
542 pub return_value: u32,
544 pub context: Option<&'dat mut [u8]>,
546 pub data: Option<&'dat mut [u8]>,
548 #[doc(hidden)]
550 pub _non_exhaustive: (),
551}
552
553pub type Program<'obj> = ProgramImpl<'obj>;
555pub type ProgramMut<'obj> = ProgramImpl<'obj, Mut>;
557
558
559#[derive(Debug)]
567#[repr(transparent)]
568pub struct ProgramImpl<'obj, T = ()> {
569 pub(crate) ptr: NonNull<libbpf_sys::bpf_program>,
570 _phantom: PhantomData<&'obj T>,
571}
572
573impl<'obj> Program<'obj> {
574 pub fn new(prog: &'obj libbpf_sys::bpf_program) -> Self {
576 Self {
579 ptr: unsafe { NonNull::new_unchecked(prog as *const _ as *mut _) },
580 _phantom: PhantomData,
581 }
582 }
583
584 pub fn name(&self) -> &OsStr {
586 let name_ptr = unsafe { libbpf_sys::bpf_program__name(self.ptr.as_ptr()) };
587 let name_c_str = unsafe { CStr::from_ptr(name_ptr) };
588 OsStr::from_bytes(name_c_str.to_bytes())
590 }
591
592 pub fn section(&self) -> &OsStr {
594 let p = unsafe { libbpf_sys::bpf_program__section_name(self.ptr.as_ptr()) };
596 let section_c_str = unsafe { CStr::from_ptr(p) };
599 let section = OsStr::from_bytes(section_c_str.to_bytes());
600 section
601 }
602
603 pub fn prog_type(&self) -> ProgramType {
605 ProgramType::from(unsafe { libbpf_sys::bpf_program__type(self.ptr.as_ptr()) })
606 }
607
608 #[deprecated = "renamed to Program::fd_from_id"]
609 #[allow(missing_docs)]
610 #[inline]
611 pub fn get_fd_by_id(id: u32) -> Result<OwnedFd> {
612 Self::fd_from_id(id)
613 }
614
615 pub fn fd_from_id(id: u32) -> Result<OwnedFd> {
617 let ret = unsafe { libbpf_sys::bpf_prog_get_fd_by_id(id) };
618 let fd = util::parse_ret_i32(ret)?;
619 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
623 }
624
625 #[deprecated = "renamed to Program::id_from_fd"]
627 #[allow(missing_docs)]
628 #[inline]
629 pub fn get_id_by_fd(fd: BorrowedFd<'_>) -> Result<u32> {
630 Self::id_from_fd(fd)
631 }
632
633 pub fn id_from_fd(fd: BorrowedFd<'_>) -> Result<u32> {
635 let mut prog_info = libbpf_sys::bpf_prog_info::default();
636 let prog_info_ptr: *mut libbpf_sys::bpf_prog_info = &mut prog_info;
637 let mut len = size_of::<libbpf_sys::bpf_prog_info>() as u32;
638 let ret = unsafe {
639 libbpf_sys::bpf_obj_get_info_by_fd(
640 fd.as_raw_fd(),
641 prog_info_ptr as *mut c_void,
642 &mut len,
643 )
644 };
645 util::parse_ret(ret)?;
646 Ok(prog_info.id)
647 }
648
649 pub fn fd_from_pinned_path<P: AsRef<Path>>(path: P) -> Result<OwnedFd> {
653 let path_c = util::path_to_cstring(&path)?;
654 let path_ptr = path_c.as_ptr();
655
656 let fd = unsafe { libbpf_sys::bpf_obj_get(path_ptr) };
657 let fd = util::parse_ret_i32(fd).with_context(|| {
658 format!(
659 "failed to retrieve BPF object from pinned path `{}`",
660 path.as_ref().display()
661 )
662 })?;
663 let fd = unsafe { OwnedFd::from_raw_fd(fd) };
664
665 let fd_type = util::object_type_from_fd(fd.as_fd())?;
669 match fd_type {
670 BpfObjectType::Program => Ok(fd),
671 other => Err(Error::with_invalid_data(format!(
672 "retrieved BPF fd is not a program fd: {:#?}",
673 other
674 ))),
675 }
676 }
677
678 pub fn flags(&self) -> u32 {
680 unsafe { libbpf_sys::bpf_program__flags(self.ptr.as_ptr()) }
681 }
682
683 pub fn attach_type(&self) -> ProgramAttachType {
685 ProgramAttachType::from(unsafe {
686 libbpf_sys::bpf_program__expected_attach_type(self.ptr.as_ptr())
687 })
688 }
689
690 pub fn autoload(&self) -> bool {
692 unsafe { libbpf_sys::bpf_program__autoload(self.ptr.as_ptr()) }
693 }
694
695 pub fn log_level(&self) -> u32 {
697 unsafe { libbpf_sys::bpf_program__log_level(self.ptr.as_ptr()) }
698 }
699
700 pub fn insn_cnt(&self) -> usize {
704 unsafe { libbpf_sys::bpf_program__insn_cnt(self.ptr.as_ptr()) as usize }
705 }
706
707 pub fn insns(&self) -> &[libbpf_sys::bpf_insn] {
711 let count = self.insn_cnt();
712 let ptr = unsafe { libbpf_sys::bpf_program__insns(self.ptr.as_ptr()) };
713 unsafe { slice::from_raw_parts(ptr, count) }
714 }
715}
716
717impl<'obj> ProgramMut<'obj> {
718 pub fn new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self {
720 Self {
721 ptr: unsafe { NonNull::new_unchecked(prog as *mut _) },
722 _phantom: PhantomData,
723 }
724 }
725
726 pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
729 let path_c = util::path_to_cstring(path)?;
730 let path_ptr = path_c.as_ptr();
731
732 let ret = unsafe { libbpf_sys::bpf_program__pin(self.ptr.as_ptr(), path_ptr) };
733 util::parse_ret(ret)
734 }
735
736 pub fn unpin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
739 let path_c = util::path_to_cstring(path)?;
740 let path_ptr = path_c.as_ptr();
741
742 let ret = unsafe { libbpf_sys::bpf_program__unpin(self.ptr.as_ptr(), path_ptr) };
743 util::parse_ret(ret)
744 }
745
746 pub fn attach(&self) -> Result<Link> {
748 let ptr = unsafe { libbpf_sys::bpf_program__attach(self.ptr.as_ptr()) };
749 let ptr = validate_bpf_ret(ptr).context("failed to attach BPF program")?;
750 let link = unsafe { Link::new(ptr) };
752 Ok(link)
753 }
754
755 pub fn attach_cgroup(&self, cgroup_fd: i32) -> Result<Link> {
758 let ptr = unsafe { libbpf_sys::bpf_program__attach_cgroup(self.ptr.as_ptr(), cgroup_fd) };
759 let ptr = validate_bpf_ret(ptr).context("failed to attach cgroup")?;
760 let link = unsafe { Link::new(ptr) };
762 Ok(link)
763 }
764
765 pub fn attach_perf_event(&self, pfd: i32) -> Result<Link> {
767 let ptr = unsafe { libbpf_sys::bpf_program__attach_perf_event(self.ptr.as_ptr(), pfd) };
768 let ptr = validate_bpf_ret(ptr).context("failed to attach perf event")?;
769 let link = unsafe { Link::new(ptr) };
771 Ok(link)
772 }
773
774 pub fn attach_uprobe<T: AsRef<Path>>(
777 &self,
778 retprobe: bool,
779 pid: i32,
780 binary_path: T,
781 func_offset: usize,
782 ) -> Result<Link> {
783 let path = util::path_to_cstring(binary_path)?;
784 let path_ptr = path.as_ptr();
785 let ptr = unsafe {
786 libbpf_sys::bpf_program__attach_uprobe(
787 self.ptr.as_ptr(),
788 retprobe,
789 pid,
790 path_ptr,
791 func_offset as libbpf_sys::size_t,
792 )
793 };
794 let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe")?;
795 let link = unsafe { Link::new(ptr) };
797 Ok(link)
798 }
799
800 pub fn attach_uprobe_with_opts(
804 &self,
805 pid: i32,
806 binary_path: impl AsRef<Path>,
807 func_offset: usize,
808 opts: UprobeOpts,
809 ) -> Result<Link> {
810 let path = util::path_to_cstring(binary_path)?;
811 let path_ptr = path.as_ptr();
812 let UprobeOpts {
813 ref_ctr_offset,
814 cookie,
815 retprobe,
816 func_name,
817 _non_exhaustive,
818 } = opts;
819
820 let func_name = util::str_to_cstring(&func_name)?;
821 let opts = libbpf_sys::bpf_uprobe_opts {
822 sz: size_of::<libbpf_sys::bpf_uprobe_opts>() as _,
823 ref_ctr_offset: ref_ctr_offset as libbpf_sys::size_t,
824 bpf_cookie: cookie,
825 retprobe,
826 func_name: func_name.as_ptr(),
827 ..Default::default()
828 };
829
830 let ptr = unsafe {
831 libbpf_sys::bpf_program__attach_uprobe_opts(
832 self.ptr.as_ptr(),
833 pid,
834 path_ptr,
835 func_offset as libbpf_sys::size_t,
836 &opts as *const _,
837 )
838 };
839 let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe")?;
840 let link = unsafe { Link::new(ptr) };
842 Ok(link)
843 }
844
845 pub fn attach_kprobe<T: AsRef<str>>(&self, retprobe: bool, func_name: T) -> Result<Link> {
848 let func_name = util::str_to_cstring(func_name.as_ref())?;
849 let func_name_ptr = func_name.as_ptr();
850 let ptr = unsafe {
851 libbpf_sys::bpf_program__attach_kprobe(self.ptr.as_ptr(), retprobe, func_name_ptr)
852 };
853 let ptr = validate_bpf_ret(ptr).context("failed to attach kprobe")?;
854 let link = unsafe { Link::new(ptr) };
856 Ok(link)
857 }
858
859 pub fn attach_ksyscall<T: AsRef<str>>(&self, retprobe: bool, syscall_name: T) -> Result<Link> {
861 let opts = libbpf_sys::bpf_ksyscall_opts {
862 sz: size_of::<libbpf_sys::bpf_ksyscall_opts>() as _,
863 retprobe,
864 ..Default::default()
865 };
866
867 let syscall_name = util::str_to_cstring(syscall_name.as_ref())?;
868 let syscall_name_ptr = syscall_name.as_ptr();
869 let ptr = unsafe {
870 libbpf_sys::bpf_program__attach_ksyscall(self.ptr.as_ptr(), syscall_name_ptr, &opts)
871 };
872 let ptr = validate_bpf_ret(ptr).context("failed to attach ksyscall")?;
873 let link = unsafe { Link::new(ptr) };
875 Ok(link)
876 }
877
878 fn attach_tracepoint_impl(
879 &self,
880 tp_category: &str,
881 tp_name: &str,
882 tp_opts: Option<TracepointOpts>,
883 ) -> Result<Link> {
884 let tp_category = util::str_to_cstring(tp_category)?;
885 let tp_category_ptr = tp_category.as_ptr();
886 let tp_name = util::str_to_cstring(tp_name)?;
887 let tp_name_ptr = tp_name.as_ptr();
888
889 let ptr = if let Some(tp_opts) = tp_opts {
890 let tp_opts = libbpf_sys::bpf_tracepoint_opts::from(tp_opts);
891 unsafe {
892 libbpf_sys::bpf_program__attach_tracepoint_opts(
893 self.ptr.as_ptr(),
894 tp_category_ptr,
895 tp_name_ptr,
896 &tp_opts as *const _,
897 )
898 }
899 } else {
900 unsafe {
901 libbpf_sys::bpf_program__attach_tracepoint(
902 self.ptr.as_ptr(),
903 tp_category_ptr,
904 tp_name_ptr,
905 )
906 }
907 };
908
909 let ptr = validate_bpf_ret(ptr).context("failed to attach tracepoint")?;
910 let link = unsafe { Link::new(ptr) };
912 Ok(link)
913 }
914
915 pub fn attach_tracepoint(
918 &self,
919 tp_category: impl AsRef<str>,
920 tp_name: impl AsRef<str>,
921 ) -> Result<Link> {
922 self.attach_tracepoint_impl(tp_category.as_ref(), tp_name.as_ref(), None)
923 }
924
925 pub fn attach_tracepoint_with_opts(
929 &self,
930 tp_category: impl AsRef<str>,
931 tp_name: impl AsRef<str>,
932 tp_opts: TracepointOpts,
933 ) -> Result<Link> {
934 self.attach_tracepoint_impl(tp_category.as_ref(), tp_name.as_ref(), Some(tp_opts))
935 }
936
937 pub fn attach_raw_tracepoint<T: AsRef<str>>(&self, tp_name: T) -> Result<Link> {
940 let tp_name = util::str_to_cstring(tp_name.as_ref())?;
941 let tp_name_ptr = tp_name.as_ptr();
942 let ptr = unsafe {
943 libbpf_sys::bpf_program__attach_raw_tracepoint(self.ptr.as_ptr(), tp_name_ptr)
944 };
945 let ptr = validate_bpf_ret(ptr).context("failed to attach raw tracepoint")?;
946 let link = unsafe { Link::new(ptr) };
948 Ok(link)
949 }
950
951 pub fn attach_lsm(&self) -> Result<Link> {
953 let ptr = unsafe { libbpf_sys::bpf_program__attach_lsm(self.ptr.as_ptr()) };
954 let ptr = validate_bpf_ret(ptr).context("failed to attach LSM")?;
955 let link = unsafe { Link::new(ptr) };
957 Ok(link)
958 }
959
960 pub fn attach_trace(&self) -> Result<Link> {
962 let ptr = unsafe { libbpf_sys::bpf_program__attach_trace(self.ptr.as_ptr()) };
963 let ptr = validate_bpf_ret(ptr).context("failed to attach fentry/fexit kernel probe")?;
964 let link = unsafe { Link::new(ptr) };
966 Ok(link)
967 }
968
969 pub fn attach_sockmap(&self, map_fd: i32) -> Result<()> {
971 let err = unsafe {
972 libbpf_sys::bpf_prog_attach(
973 self.as_fd().as_raw_fd(),
974 map_fd,
975 self.attach_type() as u32,
976 0,
977 )
978 };
979 util::parse_ret(err)
980 }
981
982 pub fn attach_xdp(&self, ifindex: i32) -> Result<Link> {
984 let ptr = unsafe { libbpf_sys::bpf_program__attach_xdp(self.ptr.as_ptr(), ifindex) };
985 let ptr = validate_bpf_ret(ptr).context("failed to attach XDP program")?;
986 let link = unsafe { Link::new(ptr) };
988 Ok(link)
989 }
990
991 pub fn attach_netns(&self, netns_fd: i32) -> Result<Link> {
993 let ptr = unsafe { libbpf_sys::bpf_program__attach_netns(self.ptr.as_ptr(), netns_fd) };
994 let ptr = validate_bpf_ret(ptr).context("failed to attach network namespace program")?;
995 let link = unsafe { Link::new(ptr) };
997 Ok(link)
998 }
999
1000 pub fn attach_netfilter_with_opts(
1002 &self,
1003 netfilter_opt: netfilter::NetfilterOpts,
1004 ) -> Result<Link> {
1005 let netfilter_opts = libbpf_sys::bpf_netfilter_opts::from(netfilter_opt);
1006
1007 let ptr = unsafe {
1008 libbpf_sys::bpf_program__attach_netfilter(
1009 self.ptr.as_ptr(),
1010 &netfilter_opts as *const _,
1011 )
1012 };
1013
1014 let ptr = validate_bpf_ret(ptr).context("failed to attach netfilter program")?;
1015 let link = unsafe { Link::new(ptr) };
1017 Ok(link)
1018 }
1019
1020 fn attach_usdt_impl(
1021 &self,
1022 pid: i32,
1023 binary_path: &Path,
1024 usdt_provider: &str,
1025 usdt_name: &str,
1026 usdt_opts: Option<UsdtOpts>,
1027 ) -> Result<Link> {
1028 let path = util::path_to_cstring(binary_path)?;
1029 let path_ptr = path.as_ptr();
1030 let usdt_provider = util::str_to_cstring(usdt_provider)?;
1031 let usdt_provider_ptr = usdt_provider.as_ptr();
1032 let usdt_name = util::str_to_cstring(usdt_name)?;
1033 let usdt_name_ptr = usdt_name.as_ptr();
1034 let usdt_opts = usdt_opts.map(libbpf_sys::bpf_usdt_opts::from);
1035 let usdt_opts_ptr = usdt_opts
1036 .as_ref()
1037 .map(|opts| opts as *const _)
1038 .unwrap_or_else(ptr::null);
1039
1040 let ptr = unsafe {
1041 libbpf_sys::bpf_program__attach_usdt(
1042 self.ptr.as_ptr(),
1043 pid,
1044 path_ptr,
1045 usdt_provider_ptr,
1046 usdt_name_ptr,
1047 usdt_opts_ptr,
1048 )
1049 };
1050 let ptr = validate_bpf_ret(ptr).context("failed to attach USDT")?;
1051 let link = unsafe { Link::new(ptr) };
1053 Ok(link)
1054 }
1055
1056 pub fn attach_usdt(
1060 &self,
1061 pid: i32,
1062 binary_path: impl AsRef<Path>,
1063 usdt_provider: impl AsRef<str>,
1064 usdt_name: impl AsRef<str>,
1065 ) -> Result<Link> {
1066 self.attach_usdt_impl(
1067 pid,
1068 binary_path.as_ref(),
1069 usdt_provider.as_ref(),
1070 usdt_name.as_ref(),
1071 None,
1072 )
1073 }
1074
1075 pub fn attach_usdt_with_opts(
1079 &self,
1080 pid: i32,
1081 binary_path: impl AsRef<Path>,
1082 usdt_provider: impl AsRef<str>,
1083 usdt_name: impl AsRef<str>,
1084 usdt_opts: UsdtOpts,
1085 ) -> Result<Link> {
1086 self.attach_usdt_impl(
1087 pid,
1088 binary_path.as_ref(),
1089 usdt_provider.as_ref(),
1090 usdt_name.as_ref(),
1091 Some(usdt_opts),
1092 )
1093 }
1094
1095 pub fn attach_iter(&self, map_fd: BorrowedFd<'_>) -> Result<Link> {
1099 let mut linkinfo = libbpf_sys::bpf_iter_link_info::default();
1100 linkinfo.map.map_fd = map_fd.as_raw_fd() as _;
1101 let attach_opt = libbpf_sys::bpf_iter_attach_opts {
1102 link_info: &mut linkinfo as *mut libbpf_sys::bpf_iter_link_info,
1103 link_info_len: size_of::<libbpf_sys::bpf_iter_link_info>() as _,
1104 sz: size_of::<libbpf_sys::bpf_iter_attach_opts>() as _,
1105 ..Default::default()
1106 };
1107 let ptr = unsafe {
1108 libbpf_sys::bpf_program__attach_iter(
1109 self.ptr.as_ptr(),
1110 &attach_opt as *const libbpf_sys::bpf_iter_attach_opts,
1111 )
1112 };
1113
1114 let ptr = validate_bpf_ret(ptr).context("failed to attach iterator")?;
1115 let link = unsafe { Link::new(ptr) };
1117 Ok(link)
1118 }
1119
1120 pub fn test_run<'dat>(&self, input: Input<'dat>) -> Result<Output<'dat>> {
1126 unsafe fn slice_from_array<'t, T>(items: *mut T, num_items: usize) -> Option<&'t mut [T]> {
1127 if items.is_null() {
1128 None
1129 } else {
1130 Some(unsafe { slice::from_raw_parts_mut(items, num_items) })
1131 }
1132 }
1133
1134 let Input {
1135 context_in,
1136 mut context_out,
1137 data_in,
1138 mut data_out,
1139 cpu,
1140 flags,
1141 _non_exhaustive: (),
1142 } = input;
1143
1144 let mut opts = unsafe { mem::zeroed::<libbpf_sys::bpf_test_run_opts>() };
1145 opts.sz = size_of_val(&opts) as _;
1146 opts.ctx_in = context_in
1147 .as_ref()
1148 .map(|data| data.as_ptr().cast())
1149 .unwrap_or_else(ptr::null);
1150 opts.ctx_size_in = context_in.map(|data| data.len() as _).unwrap_or(0);
1151 opts.ctx_out = context_out
1152 .as_mut()
1153 .map(|data| data.as_mut_ptr().cast())
1154 .unwrap_or_else(ptr::null_mut);
1155 opts.ctx_size_out = context_out.map(|data| data.len() as _).unwrap_or(0);
1156 opts.data_in = data_in
1157 .map(|data| data.as_ptr().cast())
1158 .unwrap_or_else(ptr::null);
1159 opts.data_size_in = data_in.map(|data| data.len() as _).unwrap_or(0);
1160 opts.data_out = data_out
1161 .as_mut()
1162 .map(|data| data.as_mut_ptr().cast())
1163 .unwrap_or_else(ptr::null_mut);
1164 opts.data_size_out = data_out.map(|data| data.len() as _).unwrap_or(0);
1165 opts.cpu = cpu;
1166 opts.flags = flags;
1167
1168 let rc = unsafe { libbpf_sys::bpf_prog_test_run_opts(self.as_fd().as_raw_fd(), &mut opts) };
1169 let () = util::parse_ret(rc)?;
1170 let output = Output {
1171 return_value: opts.retval,
1172 context: unsafe { slice_from_array(opts.ctx_out.cast(), opts.ctx_size_out as _) },
1173 data: unsafe { slice_from_array(opts.data_out.cast(), opts.data_size_out as _) },
1174 _non_exhaustive: (),
1175 };
1176 Ok(output)
1177 }
1178}
1179
1180impl<'obj> Deref for ProgramMut<'obj> {
1181 type Target = Program<'obj>;
1182
1183 fn deref(&self) -> &Self::Target {
1184 unsafe { transmute::<&ProgramMut<'obj>, &Program<'obj>>(self) }
1187 }
1188}
1189
1190impl<T> AsFd for ProgramImpl<'_, T> {
1191 fn as_fd(&self) -> BorrowedFd<'_> {
1192 let fd = unsafe { libbpf_sys::bpf_program__fd(self.ptr.as_ptr()) };
1193 unsafe { BorrowedFd::borrow_raw(fd) }
1194 }
1195}
1196
1197impl<T> AsRawLibbpf for ProgramImpl<'_, T> {
1198 type LibbpfType = libbpf_sys::bpf_program;
1199
1200 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> {
1202 self.ptr
1203 }
1204}
1205
1206#[cfg(test)]
1207mod tests {
1208 use super::*;
1209
1210 use std::mem::discriminant;
1211
1212 #[test]
1213 fn program_type() {
1214 use ProgramType::*;
1215
1216 for t in [
1217 Unspec,
1218 SocketFilter,
1219 Kprobe,
1220 SchedCls,
1221 SchedAct,
1222 Tracepoint,
1223 Xdp,
1224 PerfEvent,
1225 CgroupSkb,
1226 CgroupSock,
1227 LwtIn,
1228 LwtOut,
1229 LwtXmit,
1230 SockOps,
1231 SkSkb,
1232 CgroupDevice,
1233 SkMsg,
1234 RawTracepoint,
1235 CgroupSockAddr,
1236 LwtSeg6local,
1237 LircMode2,
1238 SkReuseport,
1239 FlowDissector,
1240 CgroupSysctl,
1241 RawTracepointWritable,
1242 CgroupSockopt,
1243 Tracing,
1244 StructOps,
1245 Ext,
1246 Lsm,
1247 SkLookup,
1248 Syscall,
1249 Unknown,
1250 ] {
1251 assert_eq!(discriminant(&t), discriminant(&ProgramType::from(t as u32)));
1253 }
1254 }
1255
1256 #[test]
1257 fn program_attach_type() {
1258 use ProgramAttachType::*;
1259
1260 for t in [
1261 CgroupInetIngress,
1262 CgroupInetEgress,
1263 CgroupInetSockCreate,
1264 CgroupSockOps,
1265 SkSkbStreamParser,
1266 SkSkbStreamVerdict,
1267 CgroupDevice,
1268 SkMsgVerdict,
1269 CgroupInet4Bind,
1270 CgroupInet6Bind,
1271 CgroupInet4Connect,
1272 CgroupInet6Connect,
1273 CgroupInet4PostBind,
1274 CgroupInet6PostBind,
1275 CgroupUdp4Sendmsg,
1276 CgroupUdp6Sendmsg,
1277 LircMode2,
1278 FlowDissector,
1279 CgroupSysctl,
1280 CgroupUdp4Recvmsg,
1281 CgroupUdp6Recvmsg,
1282 CgroupGetsockopt,
1283 CgroupSetsockopt,
1284 TraceRawTp,
1285 TraceFentry,
1286 TraceFexit,
1287 ModifyReturn,
1288 LsmMac,
1289 TraceIter,
1290 CgroupInet4Getpeername,
1291 CgroupInet6Getpeername,
1292 CgroupInet4Getsockname,
1293 CgroupInet6Getsockname,
1294 XdpDevmap,
1295 CgroupInetSockRelease,
1296 XdpCpumap,
1297 SkLookup,
1298 Xdp,
1299 SkSkbVerdict,
1300 SkReuseportSelect,
1301 SkReuseportSelectOrMigrate,
1302 PerfEvent,
1303 Unknown,
1304 ] {
1305 assert_eq!(
1307 discriminant(&t),
1308 discriminant(&ProgramAttachType::from(t as u32))
1309 );
1310 }
1311 }
1312}