1 // `rustdoc` is buggy, claiming that we have some links to private items 2 // when they are actually public. 3 #![allow(rustdoc::private_intra_doc_links)] 4 5 use std::ffi::c_void; 6 use std::ffi::CStr; 7 use std::ffi::OsStr; 8 use std::marker::PhantomData; 9 use std::mem; 10 use std::mem::size_of; 11 use std::mem::size_of_val; 12 use std::mem::transmute; 13 use std::ops::Deref; 14 use std::os::unix::ffi::OsStrExt as _; 15 use std::os::unix::io::AsFd; 16 use std::os::unix::io::AsRawFd; 17 use std::os::unix::io::BorrowedFd; 18 use std::os::unix::io::FromRawFd; 19 use std::os::unix::io::OwnedFd; 20 use std::path::Path; 21 use std::ptr; 22 use std::ptr::NonNull; 23 use std::slice; 24 25 use libbpf_sys::bpf_func_id; 26 27 use crate::util; 28 use crate::util::validate_bpf_ret; 29 use crate::AsRawLibbpf; 30 use crate::Error; 31 use crate::ErrorExt as _; 32 use crate::Link; 33 use crate::Mut; 34 use crate::Result; 35 36 /// Options to optionally be provided when attaching to a uprobe. 37 #[derive(Clone, Debug, Default)] 38 pub struct UprobeOpts { 39 /// Offset of kernel reference counted USDT semaphore. 40 pub ref_ctr_offset: usize, 41 /// Custom user-provided value accessible through `bpf_get_attach_cookie`. 42 pub cookie: u64, 43 /// uprobe is return probe, invoked at function return time. 44 pub retprobe: bool, 45 /// Function name to attach to. 46 /// 47 /// Could be an unqualified ("abc") or library-qualified "abc@LIBXYZ" name. 48 /// To specify function entry, `func_name` should be set while `func_offset` 49 /// argument to should be 0. To trace an offset within a function, specify 50 /// `func_name` and use `func_offset` argument to specify offset within the 51 /// function. Shared library functions must specify the shared library 52 /// binary_path. 53 pub func_name: String, 54 #[doc(hidden)] 55 pub _non_exhaustive: (), 56 } 57 58 /// Options to optionally be provided when attaching to a USDT. 59 #[derive(Clone, Debug, Default)] 60 pub struct UsdtOpts { 61 /// Custom user-provided value accessible through `bpf_usdt_cookie`. 62 pub cookie: u64, 63 #[doc(hidden)] 64 pub _non_exhaustive: (), 65 } 66 67 impl From<UsdtOpts> for libbpf_sys::bpf_usdt_opts { from(opts: UsdtOpts) -> Self68 fn from(opts: UsdtOpts) -> Self { 69 let UsdtOpts { 70 cookie, 71 _non_exhaustive, 72 } = opts; 73 #[allow(clippy::needless_update)] 74 libbpf_sys::bpf_usdt_opts { 75 sz: size_of::<Self>() as _, 76 usdt_cookie: cookie, 77 // bpf_usdt_opts might have padding fields on some platform 78 ..Default::default() 79 } 80 } 81 } 82 83 /// Options to optionally be provided when attaching to a tracepoint. 84 #[derive(Clone, Debug, Default)] 85 pub struct TracepointOpts { 86 /// Custom user-provided value accessible through `bpf_get_attach_cookie`. 87 pub cookie: u64, 88 #[doc(hidden)] 89 pub _non_exhaustive: (), 90 } 91 92 impl From<TracepointOpts> for libbpf_sys::bpf_tracepoint_opts { from(opts: TracepointOpts) -> Self93 fn from(opts: TracepointOpts) -> Self { 94 let TracepointOpts { 95 cookie, 96 _non_exhaustive, 97 } = opts; 98 99 #[allow(clippy::needless_update)] 100 libbpf_sys::bpf_tracepoint_opts { 101 sz: size_of::<Self>() as _, 102 bpf_cookie: cookie, 103 // bpf_tracepoint_opts might have padding fields on some platform 104 ..Default::default() 105 } 106 } 107 } 108 109 110 /// An immutable parsed but not yet loaded BPF program. 111 pub type OpenProgram<'obj> = OpenProgramImpl<'obj>; 112 /// A mutable parsed but not yet loaded BPF program. 113 pub type OpenProgramMut<'obj> = OpenProgramImpl<'obj, Mut>; 114 115 /// Represents a parsed but not yet loaded BPF program. 116 /// 117 /// This object exposes operations that need to happen before the program is loaded. 118 #[derive(Debug)] 119 #[repr(transparent)] 120 pub struct OpenProgramImpl<'obj, T = ()> { 121 ptr: NonNull<libbpf_sys::bpf_program>, 122 _phantom: PhantomData<&'obj T>, 123 } 124 125 // TODO: Document variants. 126 #[allow(missing_docs)] 127 impl<'obj> OpenProgram<'obj> { 128 /// Create a new [`OpenProgram`] from a ptr to a `libbpf_sys::bpf_program`. new(prog: &'obj libbpf_sys::bpf_program) -> Self129 pub fn new(prog: &'obj libbpf_sys::bpf_program) -> Self { 130 // SAFETY: We inferred the address from a reference, which is always 131 // valid. 132 Self { 133 ptr: unsafe { NonNull::new_unchecked(prog as *const _ as *mut _) }, 134 _phantom: PhantomData, 135 } 136 } 137 138 // The `ProgramType` of this `OpenProgram`. prog_type(&self) -> ProgramType139 pub fn prog_type(&self) -> ProgramType { 140 ProgramType::from(unsafe { libbpf_sys::bpf_program__type(self.ptr.as_ptr()) }) 141 } 142 143 /// Retrieve the name of this `OpenProgram`. name(&self) -> &OsStr144 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 // SAFETY: `bpf_program__name` always returns a non-NULL pointer. 148 OsStr::from_bytes(name_c_str.to_bytes()) 149 } 150 151 /// Retrieve the name of the section this `OpenProgram` belongs to. section(&self) -> &OsStr152 pub fn section(&self) -> &OsStr { 153 // SAFETY: The program is always valid. 154 let p = unsafe { libbpf_sys::bpf_program__section_name(self.ptr.as_ptr()) }; 155 // SAFETY: `bpf_program__section_name` will always return a non-NULL 156 // pointer. 157 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 /// Returns the number of instructions that form the program. 163 /// 164 /// Note: Keep in mind, libbpf can modify the program's instructions 165 /// and consequently its instruction count, as it processes the BPF object file. 166 /// So [`OpenProgram::insn_cnt`] and [`Program::insn_cnt`] may return different values. insn_cnt(&self) -> usize167 pub fn insn_cnt(&self) -> usize { 168 unsafe { libbpf_sys::bpf_program__insn_cnt(self.ptr.as_ptr()) as usize } 169 } 170 171 /// Gives read-only access to BPF program's underlying BPF instructions. 172 /// 173 /// Keep in mind, libbpf can modify and append/delete BPF program's 174 /// instructions as it processes BPF object file and prepares everything for 175 /// uploading into the kernel. So [`OpenProgram::insns`] and [`Program::insns`] may return 176 /// different sets of instructions. As an example, during BPF object load phase BPF program 177 /// instructions will be CO-RE-relocated, BPF subprograms instructions will be appended, ldimm64 178 /// instructions will have FDs embedded, etc. So instructions returned before load and after it 179 /// might be quite different. insns(&self) -> &[libbpf_sys::bpf_insn]180 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 187 impl<'obj> OpenProgramMut<'obj> { 188 /// Create a new [`OpenProgram`] from a ptr to a `libbpf_sys::bpf_program`. new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self189 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 set_prog_type(&mut self, prog_type: ProgramType)196 pub fn set_prog_type(&mut self, prog_type: ProgramType) { 197 let rc = unsafe { libbpf_sys::bpf_program__set_type(self.ptr.as_ptr(), prog_type as u32) }; 198 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}"); 199 } 200 set_attach_type(&mut self, attach_type: ProgramAttachType)201 pub fn set_attach_type(&mut self, attach_type: ProgramAttachType) { 202 let rc = unsafe { 203 libbpf_sys::bpf_program__set_expected_attach_type(self.ptr.as_ptr(), attach_type as u32) 204 }; 205 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}"); 206 } 207 set_ifindex(&mut self, idx: u32)208 pub fn set_ifindex(&mut self, idx: u32) { 209 unsafe { libbpf_sys::bpf_program__set_ifindex(self.ptr.as_ptr(), idx) } 210 } 211 212 /// Set the log level for the bpf program. 213 /// 214 /// The log level is interpreted by bpf kernel code and interpretation may 215 /// change with newer kernel versions. Refer to the kernel source code for 216 /// details. 217 /// 218 /// In general, a value of `0` disables logging while values `> 0` enables 219 /// it. set_log_level(&mut self, log_level: u32)220 pub fn set_log_level(&mut self, log_level: u32) { 221 let rc = unsafe { libbpf_sys::bpf_program__set_log_level(self.ptr.as_ptr(), log_level) }; 222 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}"); 223 } 224 225 /// Set whether a bpf program should be automatically loaded by default 226 /// when the bpf object is loaded. set_autoload(&mut self, autoload: bool)227 pub fn set_autoload(&mut self, autoload: bool) { 228 let rc = unsafe { libbpf_sys::bpf_program__set_autoload(self.ptr.as_ptr(), autoload) }; 229 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}"); 230 } 231 set_attach_target( &mut self, attach_prog_fd: i32, attach_func_name: Option<String>, ) -> Result<()>232 pub fn set_attach_target( 233 &mut self, 234 attach_prog_fd: i32, 235 attach_func_name: Option<String>, 236 ) -> Result<()> { 237 let ret = if let Some(name) = attach_func_name { 238 // NB: we must hold onto a CString otherwise our pointer dangles 239 let name_c = util::str_to_cstring(&name)?; 240 unsafe { 241 libbpf_sys::bpf_program__set_attach_target( 242 self.ptr.as_ptr(), 243 attach_prog_fd, 244 name_c.as_ptr(), 245 ) 246 } 247 } else { 248 unsafe { 249 libbpf_sys::bpf_program__set_attach_target( 250 self.ptr.as_ptr(), 251 attach_prog_fd, 252 ptr::null(), 253 ) 254 } 255 }; 256 util::parse_ret(ret) 257 } 258 set_flags(&mut self, flags: u32)259 pub fn set_flags(&mut self, flags: u32) { 260 let rc = unsafe { libbpf_sys::bpf_program__set_flags(self.ptr.as_ptr(), flags) }; 261 debug_assert!(util::parse_ret(rc).is_ok(), "{rc}"); 262 } 263 } 264 265 impl<'obj> Deref for OpenProgramMut<'obj> { 266 type Target = OpenProgram<'obj>; 267 deref(&self) -> &Self::Target268 fn deref(&self) -> &Self::Target { 269 // SAFETY: `OpenProgramImpl` is `repr(transparent)` and so 270 // in-memory representation of both types is the same. 271 unsafe { transmute::<&OpenProgramMut<'obj>, &OpenProgram<'obj>>(self) } 272 } 273 } 274 275 impl<T> AsRawLibbpf for OpenProgramImpl<'_, T> { 276 type LibbpfType = libbpf_sys::bpf_program; 277 278 /// Retrieve the underlying [`libbpf_sys::bpf_program`]. as_libbpf_object(&self) -> NonNull<Self::LibbpfType>279 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> { 280 self.ptr 281 } 282 } 283 284 /// Type of a [`Program`]. Maps to `enum bpf_prog_type` in kernel uapi. 285 #[non_exhaustive] 286 #[repr(u32)] 287 #[derive(Copy, Clone, Debug)] 288 // TODO: Document variants. 289 #[allow(missing_docs)] 290 pub enum ProgramType { 291 Unspec = 0, 292 SocketFilter, 293 Kprobe, 294 SchedCls, 295 SchedAct, 296 Tracepoint, 297 Xdp, 298 PerfEvent, 299 CgroupSkb, 300 CgroupSock, 301 LwtIn, 302 LwtOut, 303 LwtXmit, 304 SockOps, 305 SkSkb, 306 CgroupDevice, 307 SkMsg, 308 RawTracepoint, 309 CgroupSockAddr, 310 LwtSeg6local, 311 LircMode2, 312 SkReuseport, 313 FlowDissector, 314 CgroupSysctl, 315 RawTracepointWritable, 316 CgroupSockopt, 317 Tracing, 318 StructOps, 319 Ext, 320 Lsm, 321 SkLookup, 322 Syscall, 323 /// See [`MapType::Unknown`][crate::MapType::Unknown] 324 Unknown = u32::MAX, 325 } 326 327 impl ProgramType { 328 /// Detects if host kernel supports this BPF program type 329 /// 330 /// Make sure the process has required set of CAP_* permissions (or runs as 331 /// root) when performing feature checking. is_supported(&self) -> Result<bool>332 pub fn is_supported(&self) -> Result<bool> { 333 let ret = unsafe { libbpf_sys::libbpf_probe_bpf_prog_type(*self as u32, ptr::null()) }; 334 match ret { 335 0 => Ok(false), 336 1 => Ok(true), 337 _ => Err(Error::from_raw_os_error(-ret)), 338 } 339 } 340 341 /// Detects if host kernel supports the use of a given BPF helper from this BPF program type. 342 /// * `helper_id` - BPF helper ID (enum bpf_func_id) to check support for 343 /// 344 /// Make sure the process has required set of CAP_* permissions (or runs as 345 /// root) when performing feature checking. is_helper_supported(&self, helper_id: bpf_func_id) -> Result<bool>346 pub fn is_helper_supported(&self, helper_id: bpf_func_id) -> Result<bool> { 347 let ret = 348 unsafe { libbpf_sys::libbpf_probe_bpf_helper(*self as u32, helper_id, ptr::null()) }; 349 match ret { 350 0 => Ok(false), 351 1 => Ok(true), 352 _ => Err(Error::from_raw_os_error(-ret)), 353 } 354 } 355 } 356 357 impl From<u32> for ProgramType { from(value: u32) -> Self358 fn from(value: u32) -> Self { 359 use ProgramType::*; 360 361 match value { 362 x if x == Unspec as u32 => Unspec, 363 x if x == SocketFilter as u32 => SocketFilter, 364 x if x == Kprobe as u32 => Kprobe, 365 x if x == SchedCls as u32 => SchedCls, 366 x if x == SchedAct as u32 => SchedAct, 367 x if x == Tracepoint as u32 => Tracepoint, 368 x if x == Xdp as u32 => Xdp, 369 x if x == PerfEvent as u32 => PerfEvent, 370 x if x == CgroupSkb as u32 => CgroupSkb, 371 x if x == CgroupSock as u32 => CgroupSock, 372 x if x == LwtIn as u32 => LwtIn, 373 x if x == LwtOut as u32 => LwtOut, 374 x if x == LwtXmit as u32 => LwtXmit, 375 x if x == SockOps as u32 => SockOps, 376 x if x == SkSkb as u32 => SkSkb, 377 x if x == CgroupDevice as u32 => CgroupDevice, 378 x if x == SkMsg as u32 => SkMsg, 379 x if x == RawTracepoint as u32 => RawTracepoint, 380 x if x == CgroupSockAddr as u32 => CgroupSockAddr, 381 x if x == LwtSeg6local as u32 => LwtSeg6local, 382 x if x == LircMode2 as u32 => LircMode2, 383 x if x == SkReuseport as u32 => SkReuseport, 384 x if x == FlowDissector as u32 => FlowDissector, 385 x if x == CgroupSysctl as u32 => CgroupSysctl, 386 x if x == RawTracepointWritable as u32 => RawTracepointWritable, 387 x if x == CgroupSockopt as u32 => CgroupSockopt, 388 x if x == Tracing as u32 => Tracing, 389 x if x == StructOps as u32 => StructOps, 390 x if x == Ext as u32 => Ext, 391 x if x == Lsm as u32 => Lsm, 392 x if x == SkLookup as u32 => SkLookup, 393 x if x == Syscall as u32 => Syscall, 394 _ => Unknown, 395 } 396 } 397 } 398 399 /// Attach type of a [`Program`]. Maps to `enum bpf_attach_type` in kernel uapi. 400 #[non_exhaustive] 401 #[repr(u32)] 402 #[derive(Clone, Debug)] 403 // TODO: Document variants. 404 #[allow(missing_docs)] 405 pub enum ProgramAttachType { 406 CgroupInetIngress, 407 CgroupInetEgress, 408 CgroupInetSockCreate, 409 CgroupSockOps, 410 SkSkbStreamParser, 411 SkSkbStreamVerdict, 412 CgroupDevice, 413 SkMsgVerdict, 414 CgroupInet4Bind, 415 CgroupInet6Bind, 416 CgroupInet4Connect, 417 CgroupInet6Connect, 418 CgroupInet4PostBind, 419 CgroupInet6PostBind, 420 CgroupUdp4Sendmsg, 421 CgroupUdp6Sendmsg, 422 LircMode2, 423 FlowDissector, 424 CgroupSysctl, 425 CgroupUdp4Recvmsg, 426 CgroupUdp6Recvmsg, 427 CgroupGetsockopt, 428 CgroupSetsockopt, 429 TraceRawTp, 430 TraceFentry, 431 TraceFexit, 432 ModifyReturn, 433 LsmMac, 434 TraceIter, 435 CgroupInet4Getpeername, 436 CgroupInet6Getpeername, 437 CgroupInet4Getsockname, 438 CgroupInet6Getsockname, 439 XdpDevmap, 440 CgroupInetSockRelease, 441 XdpCpumap, 442 SkLookup, 443 Xdp, 444 SkSkbVerdict, 445 SkReuseportSelect, 446 SkReuseportSelectOrMigrate, 447 PerfEvent, 448 /// See [`MapType::Unknown`][crate::MapType::Unknown] 449 Unknown = u32::MAX, 450 } 451 452 impl From<u32> for ProgramAttachType { from(value: u32) -> Self453 fn from(value: u32) -> Self { 454 use ProgramAttachType::*; 455 456 match value { 457 x if x == CgroupInetIngress as u32 => CgroupInetIngress, 458 x if x == CgroupInetEgress as u32 => CgroupInetEgress, 459 x if x == CgroupInetSockCreate as u32 => CgroupInetSockCreate, 460 x if x == CgroupSockOps as u32 => CgroupSockOps, 461 x if x == SkSkbStreamParser as u32 => SkSkbStreamParser, 462 x if x == SkSkbStreamVerdict as u32 => SkSkbStreamVerdict, 463 x if x == CgroupDevice as u32 => CgroupDevice, 464 x if x == SkMsgVerdict as u32 => SkMsgVerdict, 465 x if x == CgroupInet4Bind as u32 => CgroupInet4Bind, 466 x if x == CgroupInet6Bind as u32 => CgroupInet6Bind, 467 x if x == CgroupInet4Connect as u32 => CgroupInet4Connect, 468 x if x == CgroupInet6Connect as u32 => CgroupInet6Connect, 469 x if x == CgroupInet4PostBind as u32 => CgroupInet4PostBind, 470 x if x == CgroupInet6PostBind as u32 => CgroupInet6PostBind, 471 x if x == CgroupUdp4Sendmsg as u32 => CgroupUdp4Sendmsg, 472 x if x == CgroupUdp6Sendmsg as u32 => CgroupUdp6Sendmsg, 473 x if x == LircMode2 as u32 => LircMode2, 474 x if x == FlowDissector as u32 => FlowDissector, 475 x if x == CgroupSysctl as u32 => CgroupSysctl, 476 x if x == CgroupUdp4Recvmsg as u32 => CgroupUdp4Recvmsg, 477 x if x == CgroupUdp6Recvmsg as u32 => CgroupUdp6Recvmsg, 478 x if x == CgroupGetsockopt as u32 => CgroupGetsockopt, 479 x if x == CgroupSetsockopt as u32 => CgroupSetsockopt, 480 x if x == TraceRawTp as u32 => TraceRawTp, 481 x if x == TraceFentry as u32 => TraceFentry, 482 x if x == TraceFexit as u32 => TraceFexit, 483 x if x == ModifyReturn as u32 => ModifyReturn, 484 x if x == LsmMac as u32 => LsmMac, 485 x if x == TraceIter as u32 => TraceIter, 486 x if x == CgroupInet4Getpeername as u32 => CgroupInet4Getpeername, 487 x if x == CgroupInet6Getpeername as u32 => CgroupInet6Getpeername, 488 x if x == CgroupInet4Getsockname as u32 => CgroupInet4Getsockname, 489 x if x == CgroupInet6Getsockname as u32 => CgroupInet6Getsockname, 490 x if x == XdpDevmap as u32 => XdpDevmap, 491 x if x == CgroupInetSockRelease as u32 => CgroupInetSockRelease, 492 x if x == XdpCpumap as u32 => XdpCpumap, 493 x if x == SkLookup as u32 => SkLookup, 494 x if x == Xdp as u32 => Xdp, 495 x if x == SkSkbVerdict as u32 => SkSkbVerdict, 496 x if x == SkReuseportSelect as u32 => SkReuseportSelect, 497 x if x == SkReuseportSelectOrMigrate as u32 => SkReuseportSelectOrMigrate, 498 x if x == PerfEvent as u32 => PerfEvent, 499 _ => Unknown, 500 } 501 } 502 } 503 504 /// The input a program accepts. 505 /// 506 /// This type is mostly used in conjunction with the [`Program::test_run`] 507 /// facility. 508 #[derive(Debug, Default)] 509 pub struct Input<'dat> { 510 /// The input context to provide. 511 /// 512 /// The input is mutable because the kernel may modify it. 513 pub context_in: Option<&'dat mut [u8]>, 514 /// The output context buffer provided to the program. 515 pub context_out: Option<&'dat mut [u8]>, 516 /// Additional data to provide to the program. 517 pub data_in: Option<&'dat [u8]>, 518 /// The output data buffer provided to the program. 519 pub data_out: Option<&'dat mut [u8]>, 520 /// The 'cpu' value passed to the kernel. 521 pub cpu: u32, 522 /// The 'flags' value passed to the kernel. 523 pub flags: u32, 524 /// The struct is non-exhaustive and open to extension. 525 #[doc(hidden)] 526 pub _non_exhaustive: (), 527 } 528 529 /// The output a program produces. 530 /// 531 /// This type is mostly used in conjunction with the [`Program::test_run`] 532 /// facility. 533 #[derive(Debug)] 534 pub struct Output<'dat> { 535 /// The value returned by the program. 536 pub return_value: u32, 537 /// The output context filled by the program/kernel. 538 pub context: Option<&'dat mut [u8]>, 539 /// Output data filled by the program. 540 pub data: Option<&'dat mut [u8]>, 541 /// The struct is non-exhaustive and open to extension. 542 #[doc(hidden)] 543 pub _non_exhaustive: (), 544 } 545 546 /// An immutable loaded BPF program. 547 pub type Program<'obj> = ProgramImpl<'obj>; 548 /// A mutable loaded BPF program. 549 pub type ProgramMut<'obj> = ProgramImpl<'obj, Mut>; 550 551 552 /// Represents a loaded [`Program`]. 553 /// 554 /// This struct is not safe to clone because the underlying libbpf resource cannot currently 555 /// be protected from data races. 556 /// 557 /// If you attempt to attach a `Program` with the wrong attach method, the `attach_*` 558 /// method will fail with the appropriate error. 559 #[derive(Debug)] 560 #[repr(transparent)] 561 pub struct ProgramImpl<'obj, T = ()> { 562 pub(crate) ptr: NonNull<libbpf_sys::bpf_program>, 563 _phantom: PhantomData<&'obj T>, 564 } 565 566 impl<'obj> Program<'obj> { 567 /// Create a [`Program`] from a [`libbpf_sys::bpf_program`] new(prog: &'obj libbpf_sys::bpf_program) -> Self568 pub fn new(prog: &'obj libbpf_sys::bpf_program) -> Self { 569 // SAFETY: We inferred the address from a reference, which is always 570 // valid. 571 Self { 572 ptr: unsafe { NonNull::new_unchecked(prog as *const _ as *mut _) }, 573 _phantom: PhantomData, 574 } 575 } 576 577 /// Retrieve the name of this `Program`. name(&self) -> &OsStr578 pub fn name(&self) -> &OsStr { 579 let name_ptr = unsafe { libbpf_sys::bpf_program__name(self.ptr.as_ptr()) }; 580 let name_c_str = unsafe { CStr::from_ptr(name_ptr) }; 581 // SAFETY: `bpf_program__name` always returns a non-NULL pointer. 582 OsStr::from_bytes(name_c_str.to_bytes()) 583 } 584 585 /// Retrieve the name of the section this `Program` belongs to. section(&self) -> &OsStr586 pub fn section(&self) -> &OsStr { 587 // SAFETY: The program is always valid. 588 let p = unsafe { libbpf_sys::bpf_program__section_name(self.ptr.as_ptr()) }; 589 // SAFETY: `bpf_program__section_name` will always return a non-NULL 590 // pointer. 591 let section_c_str = unsafe { CStr::from_ptr(p) }; 592 let section = OsStr::from_bytes(section_c_str.to_bytes()); 593 section 594 } 595 596 /// Retrieve the type of the program. prog_type(&self) -> ProgramType597 pub fn prog_type(&self) -> ProgramType { 598 ProgramType::from(unsafe { libbpf_sys::bpf_program__type(self.ptr.as_ptr()) }) 599 } 600 601 /// Returns program fd by id get_fd_by_id(id: u32) -> Result<OwnedFd>602 pub fn get_fd_by_id(id: u32) -> Result<OwnedFd> { 603 let ret = unsafe { libbpf_sys::bpf_prog_get_fd_by_id(id) }; 604 let fd = util::parse_ret_i32(ret)?; 605 // SAFETY 606 // A file descriptor coming from the bpf_prog_get_fd_by_id function is always suitable for 607 // ownership and can be cleaned up with close. 608 Ok(unsafe { OwnedFd::from_raw_fd(fd) }) 609 } 610 611 /// Returns program id by fd get_id_by_fd(fd: BorrowedFd<'_>) -> Result<u32>612 pub fn get_id_by_fd(fd: BorrowedFd<'_>) -> Result<u32> { 613 let mut prog_info = libbpf_sys::bpf_prog_info::default(); 614 let prog_info_ptr: *mut libbpf_sys::bpf_prog_info = &mut prog_info; 615 let mut len = size_of::<libbpf_sys::bpf_prog_info>() as u32; 616 let ret = unsafe { 617 libbpf_sys::bpf_obj_get_info_by_fd( 618 fd.as_raw_fd(), 619 prog_info_ptr as *mut c_void, 620 &mut len, 621 ) 622 }; 623 util::parse_ret(ret)?; 624 Ok(prog_info.id) 625 } 626 627 /// Returns flags that have been set for the program. flags(&self) -> u32628 pub fn flags(&self) -> u32 { 629 unsafe { libbpf_sys::bpf_program__flags(self.ptr.as_ptr()) } 630 } 631 632 /// Retrieve the attach type of the program. attach_type(&self) -> ProgramAttachType633 pub fn attach_type(&self) -> ProgramAttachType { 634 ProgramAttachType::from(unsafe { 635 libbpf_sys::bpf_program__expected_attach_type(self.ptr.as_ptr()) 636 }) 637 } 638 639 /// Return `true` if the bpf program is set to autoload, `false` otherwise. autoload(&self) -> bool640 pub fn autoload(&self) -> bool { 641 unsafe { libbpf_sys::bpf_program__autoload(self.ptr.as_ptr()) } 642 } 643 644 /// Return the bpf program's log level. log_level(&self) -> u32645 pub fn log_level(&self) -> u32 { 646 unsafe { libbpf_sys::bpf_program__log_level(self.ptr.as_ptr()) } 647 } 648 649 /// Returns the number of instructions that form the program. 650 /// 651 /// Please see note in [`OpenProgram::insn_cnt`]. insn_cnt(&self) -> usize652 pub fn insn_cnt(&self) -> usize { 653 unsafe { libbpf_sys::bpf_program__insn_cnt(self.ptr.as_ptr()) as usize } 654 } 655 656 /// Gives read-only access to BPF program's underlying BPF instructions. 657 /// 658 /// Please see note in [`OpenProgram::insns`]. insns(&self) -> &[libbpf_sys::bpf_insn]659 pub fn insns(&self) -> &[libbpf_sys::bpf_insn] { 660 let count = self.insn_cnt(); 661 let ptr = unsafe { libbpf_sys::bpf_program__insns(self.ptr.as_ptr()) }; 662 unsafe { slice::from_raw_parts(ptr, count) } 663 } 664 } 665 666 impl<'obj> ProgramMut<'obj> { 667 /// Create a [`Program`] from a [`libbpf_sys::bpf_program`] new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self668 pub fn new_mut(prog: &'obj mut libbpf_sys::bpf_program) -> Self { 669 Self { 670 ptr: unsafe { NonNull::new_unchecked(prog as *mut _) }, 671 _phantom: PhantomData, 672 } 673 } 674 675 /// [Pin](https://facebookmicrosites.github.io/bpf/blog/2018/08/31/object-lifetime.html#bpffs) 676 /// this program to bpffs. pin<P: AsRef<Path>>(&mut self, path: P) -> Result<()>677 pub fn pin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> { 678 let path_c = util::path_to_cstring(path)?; 679 let path_ptr = path_c.as_ptr(); 680 681 let ret = unsafe { libbpf_sys::bpf_program__pin(self.ptr.as_ptr(), path_ptr) }; 682 util::parse_ret(ret) 683 } 684 685 /// [Unpin](https://facebookmicrosites.github.io/bpf/blog/2018/08/31/object-lifetime.html#bpffs) 686 /// this program from bpffs unpin<P: AsRef<Path>>(&mut self, path: P) -> Result<()>687 pub fn unpin<P: AsRef<Path>>(&mut self, path: P) -> Result<()> { 688 let path_c = util::path_to_cstring(path)?; 689 let path_ptr = path_c.as_ptr(); 690 691 let ret = unsafe { libbpf_sys::bpf_program__unpin(self.ptr.as_ptr(), path_ptr) }; 692 util::parse_ret(ret) 693 } 694 695 /// Auto-attach based on prog section attach(&mut self) -> Result<Link>696 pub fn attach(&mut self) -> Result<Link> { 697 let ptr = unsafe { libbpf_sys::bpf_program__attach(self.ptr.as_ptr()) }; 698 let ptr = validate_bpf_ret(ptr).context("failed to attach BPF program")?; 699 // SAFETY: the pointer came from libbpf and has been checked for errors. 700 let link = unsafe { Link::new(ptr) }; 701 Ok(link) 702 } 703 704 /// Attach this program to a 705 /// [cgroup](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html). attach_cgroup(&mut self, cgroup_fd: i32) -> Result<Link>706 pub fn attach_cgroup(&mut self, cgroup_fd: i32) -> Result<Link> { 707 let ptr = unsafe { libbpf_sys::bpf_program__attach_cgroup(self.ptr.as_ptr(), cgroup_fd) }; 708 let ptr = validate_bpf_ret(ptr).context("failed to attach cgroup")?; 709 // SAFETY: the pointer came from libbpf and has been checked for errors. 710 let link = unsafe { Link::new(ptr) }; 711 Ok(link) 712 } 713 714 /// Attach this program to a [perf event](https://linux.die.net/man/2/perf_event_open). attach_perf_event(&mut self, pfd: i32) -> Result<Link>715 pub fn attach_perf_event(&mut self, pfd: i32) -> Result<Link> { 716 let ptr = unsafe { libbpf_sys::bpf_program__attach_perf_event(self.ptr.as_ptr(), pfd) }; 717 let ptr = validate_bpf_ret(ptr).context("failed to attach perf event")?; 718 // SAFETY: the pointer came from libbpf and has been checked for errors. 719 let link = unsafe { Link::new(ptr) }; 720 Ok(link) 721 } 722 723 /// Attach this program to a [userspace 724 /// probe](https://www.kernel.org/doc/html/latest/trace/uprobetracer.html). attach_uprobe<T: AsRef<Path>>( &mut self, retprobe: bool, pid: i32, binary_path: T, func_offset: usize, ) -> Result<Link>725 pub fn attach_uprobe<T: AsRef<Path>>( 726 &mut self, 727 retprobe: bool, 728 pid: i32, 729 binary_path: T, 730 func_offset: usize, 731 ) -> Result<Link> { 732 let path = util::path_to_cstring(binary_path)?; 733 let path_ptr = path.as_ptr(); 734 let ptr = unsafe { 735 libbpf_sys::bpf_program__attach_uprobe( 736 self.ptr.as_ptr(), 737 retprobe, 738 pid, 739 path_ptr, 740 func_offset as libbpf_sys::size_t, 741 ) 742 }; 743 let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe")?; 744 // SAFETY: the pointer came from libbpf and has been checked for errors. 745 let link = unsafe { Link::new(ptr) }; 746 Ok(link) 747 } 748 749 /// Attach this program to a [userspace 750 /// probe](https://www.kernel.org/doc/html/latest/trace/uprobetracer.html), 751 /// providing additional options. attach_uprobe_with_opts( &mut self, pid: i32, binary_path: impl AsRef<Path>, func_offset: usize, opts: UprobeOpts, ) -> Result<Link>752 pub fn attach_uprobe_with_opts( 753 &mut self, 754 pid: i32, 755 binary_path: impl AsRef<Path>, 756 func_offset: usize, 757 opts: UprobeOpts, 758 ) -> Result<Link> { 759 let path = util::path_to_cstring(binary_path)?; 760 let path_ptr = path.as_ptr(); 761 let UprobeOpts { 762 ref_ctr_offset, 763 cookie, 764 retprobe, 765 func_name, 766 _non_exhaustive, 767 } = opts; 768 769 let func_name = util::str_to_cstring(&func_name)?; 770 let opts = libbpf_sys::bpf_uprobe_opts { 771 sz: size_of::<libbpf_sys::bpf_uprobe_opts>() as _, 772 ref_ctr_offset: ref_ctr_offset as libbpf_sys::size_t, 773 bpf_cookie: cookie, 774 retprobe, 775 func_name: func_name.as_ptr(), 776 ..Default::default() 777 }; 778 779 let ptr = unsafe { 780 libbpf_sys::bpf_program__attach_uprobe_opts( 781 self.ptr.as_ptr(), 782 pid, 783 path_ptr, 784 func_offset as libbpf_sys::size_t, 785 &opts as *const _, 786 ) 787 }; 788 let ptr = validate_bpf_ret(ptr).context("failed to attach uprobe")?; 789 // SAFETY: the pointer came from libbpf and has been checked for errors. 790 let link = unsafe { Link::new(ptr) }; 791 Ok(link) 792 } 793 794 /// Attach this program to a [kernel 795 /// probe](https://www.kernel.org/doc/html/latest/trace/kprobetrace.html). attach_kprobe<T: AsRef<str>>(&mut self, retprobe: bool, func_name: T) -> Result<Link>796 pub fn attach_kprobe<T: AsRef<str>>(&mut self, retprobe: bool, func_name: T) -> Result<Link> { 797 let func_name = util::str_to_cstring(func_name.as_ref())?; 798 let func_name_ptr = func_name.as_ptr(); 799 let ptr = unsafe { 800 libbpf_sys::bpf_program__attach_kprobe(self.ptr.as_ptr(), retprobe, func_name_ptr) 801 }; 802 let ptr = validate_bpf_ret(ptr).context("failed to attach kprobe")?; 803 // SAFETY: the pointer came from libbpf and has been checked for errors. 804 let link = unsafe { Link::new(ptr) }; 805 Ok(link) 806 } 807 808 /// Attach this program to the specified syscall attach_ksyscall<T: AsRef<str>>( &mut self, retprobe: bool, syscall_name: T, ) -> Result<Link>809 pub fn attach_ksyscall<T: AsRef<str>>( 810 &mut self, 811 retprobe: bool, 812 syscall_name: T, 813 ) -> Result<Link> { 814 let opts = libbpf_sys::bpf_ksyscall_opts { 815 sz: size_of::<libbpf_sys::bpf_ksyscall_opts>() as _, 816 retprobe, 817 ..Default::default() 818 }; 819 820 let syscall_name = util::str_to_cstring(syscall_name.as_ref())?; 821 let syscall_name_ptr = syscall_name.as_ptr(); 822 let ptr = unsafe { 823 libbpf_sys::bpf_program__attach_ksyscall(self.ptr.as_ptr(), syscall_name_ptr, &opts) 824 }; 825 let ptr = validate_bpf_ret(ptr).context("failed to attach ksyscall")?; 826 // SAFETY: the pointer came from libbpf and has been checked for errors. 827 let link = unsafe { Link::new(ptr) }; 828 Ok(link) 829 } 830 attach_tracepoint_impl( &mut self, tp_category: &str, tp_name: &str, tp_opts: Option<TracepointOpts>, ) -> Result<Link>831 fn attach_tracepoint_impl( 832 &mut self, 833 tp_category: &str, 834 tp_name: &str, 835 tp_opts: Option<TracepointOpts>, 836 ) -> Result<Link> { 837 let tp_category = util::str_to_cstring(tp_category)?; 838 let tp_category_ptr = tp_category.as_ptr(); 839 let tp_name = util::str_to_cstring(tp_name)?; 840 let tp_name_ptr = tp_name.as_ptr(); 841 842 let ptr = if let Some(tp_opts) = tp_opts { 843 let tp_opts = libbpf_sys::bpf_tracepoint_opts::from(tp_opts); 844 unsafe { 845 libbpf_sys::bpf_program__attach_tracepoint_opts( 846 self.ptr.as_ptr(), 847 tp_category_ptr, 848 tp_name_ptr, 849 &tp_opts as *const _, 850 ) 851 } 852 } else { 853 unsafe { 854 libbpf_sys::bpf_program__attach_tracepoint( 855 self.ptr.as_ptr(), 856 tp_category_ptr, 857 tp_name_ptr, 858 ) 859 } 860 }; 861 862 let ptr = validate_bpf_ret(ptr).context("failed to attach tracepoint")?; 863 // SAFETY: the pointer came from libbpf and has been checked for errors. 864 let link = unsafe { Link::new(ptr) }; 865 Ok(link) 866 } 867 868 /// Attach this program to a [kernel 869 /// tracepoint](https://www.kernel.org/doc/html/latest/trace/tracepoints.html). attach_tracepoint( &mut self, tp_category: impl AsRef<str>, tp_name: impl AsRef<str>, ) -> Result<Link>870 pub fn attach_tracepoint( 871 &mut self, 872 tp_category: impl AsRef<str>, 873 tp_name: impl AsRef<str>, 874 ) -> Result<Link> { 875 self.attach_tracepoint_impl(tp_category.as_ref(), tp_name.as_ref(), None) 876 } 877 878 /// Attach this program to a [kernel 879 /// tracepoint](https://www.kernel.org/doc/html/latest/trace/tracepoints.html), 880 /// providing additional options. attach_tracepoint_with_opts( &mut self, tp_category: impl AsRef<str>, tp_name: impl AsRef<str>, tp_opts: TracepointOpts, ) -> Result<Link>881 pub fn attach_tracepoint_with_opts( 882 &mut self, 883 tp_category: impl AsRef<str>, 884 tp_name: impl AsRef<str>, 885 tp_opts: TracepointOpts, 886 ) -> Result<Link> { 887 self.attach_tracepoint_impl(tp_category.as_ref(), tp_name.as_ref(), Some(tp_opts)) 888 } 889 890 /// Attach this program to a [raw kernel 891 /// tracepoint](https://lwn.net/Articles/748352/). attach_raw_tracepoint<T: AsRef<str>>(&mut self, tp_name: T) -> Result<Link>892 pub fn attach_raw_tracepoint<T: AsRef<str>>(&mut self, tp_name: T) -> Result<Link> { 893 let tp_name = util::str_to_cstring(tp_name.as_ref())?; 894 let tp_name_ptr = tp_name.as_ptr(); 895 let ptr = unsafe { 896 libbpf_sys::bpf_program__attach_raw_tracepoint(self.ptr.as_ptr(), tp_name_ptr) 897 }; 898 let ptr = validate_bpf_ret(ptr).context("failed to attach raw tracepoint")?; 899 // SAFETY: the pointer came from libbpf and has been checked for errors. 900 let link = unsafe { Link::new(ptr) }; 901 Ok(link) 902 } 903 904 /// Attach to an [LSM](https://en.wikipedia.org/wiki/Linux_Security_Modules) hook attach_lsm(&mut self) -> Result<Link>905 pub fn attach_lsm(&mut self) -> Result<Link> { 906 let ptr = unsafe { libbpf_sys::bpf_program__attach_lsm(self.ptr.as_ptr()) }; 907 let ptr = validate_bpf_ret(ptr).context("failed to attach LSM")?; 908 // SAFETY: the pointer came from libbpf and has been checked for errors. 909 let link = unsafe { Link::new(ptr) }; 910 Ok(link) 911 } 912 913 /// Attach to a [fentry/fexit kernel probe](https://lwn.net/Articles/801479/) attach_trace(&mut self) -> Result<Link>914 pub fn attach_trace(&mut self) -> Result<Link> { 915 let ptr = unsafe { libbpf_sys::bpf_program__attach_trace(self.ptr.as_ptr()) }; 916 let ptr = validate_bpf_ret(ptr).context("failed to attach fentry/fexit kernel probe")?; 917 // SAFETY: the pointer came from libbpf and has been checked for errors. 918 let link = unsafe { Link::new(ptr) }; 919 Ok(link) 920 } 921 922 /// Attach a verdict/parser to a [sockmap/sockhash](https://lwn.net/Articles/731133/) attach_sockmap(&self, map_fd: i32) -> Result<()>923 pub fn attach_sockmap(&self, map_fd: i32) -> Result<()> { 924 let err = unsafe { 925 libbpf_sys::bpf_prog_attach( 926 self.as_fd().as_raw_fd(), 927 map_fd, 928 self.attach_type() as u32, 929 0, 930 ) 931 }; 932 util::parse_ret(err) 933 } 934 935 /// Attach this program to [XDP](https://lwn.net/Articles/825998/) attach_xdp(&mut self, ifindex: i32) -> Result<Link>936 pub fn attach_xdp(&mut self, ifindex: i32) -> Result<Link> { 937 let ptr = unsafe { libbpf_sys::bpf_program__attach_xdp(self.ptr.as_ptr(), ifindex) }; 938 let ptr = validate_bpf_ret(ptr).context("failed to attach XDP program")?; 939 // SAFETY: the pointer came from libbpf and has been checked for errors. 940 let link = unsafe { Link::new(ptr) }; 941 Ok(link) 942 } 943 944 /// Attach this program to [netns-based programs](https://lwn.net/Articles/819618/) attach_netns(&mut self, netns_fd: i32) -> Result<Link>945 pub fn attach_netns(&mut self, netns_fd: i32) -> Result<Link> { 946 let ptr = unsafe { libbpf_sys::bpf_program__attach_netns(self.ptr.as_ptr(), netns_fd) }; 947 let ptr = validate_bpf_ret(ptr).context("failed to attach network namespace program")?; 948 // SAFETY: the pointer came from libbpf and has been checked for errors. 949 let link = unsafe { Link::new(ptr) }; 950 Ok(link) 951 } 952 attach_usdt_impl( &mut self, pid: i32, binary_path: &Path, usdt_provider: &str, usdt_name: &str, usdt_opts: Option<UsdtOpts>, ) -> Result<Link>953 fn attach_usdt_impl( 954 &mut self, 955 pid: i32, 956 binary_path: &Path, 957 usdt_provider: &str, 958 usdt_name: &str, 959 usdt_opts: Option<UsdtOpts>, 960 ) -> Result<Link> { 961 let path = util::path_to_cstring(binary_path)?; 962 let path_ptr = path.as_ptr(); 963 let usdt_provider = util::str_to_cstring(usdt_provider)?; 964 let usdt_provider_ptr = usdt_provider.as_ptr(); 965 let usdt_name = util::str_to_cstring(usdt_name)?; 966 let usdt_name_ptr = usdt_name.as_ptr(); 967 let usdt_opts = usdt_opts.map(libbpf_sys::bpf_usdt_opts::from); 968 let usdt_opts_ptr = usdt_opts 969 .as_ref() 970 .map(|opts| opts as *const _) 971 .unwrap_or_else(ptr::null); 972 973 let ptr = unsafe { 974 libbpf_sys::bpf_program__attach_usdt( 975 self.ptr.as_ptr(), 976 pid, 977 path_ptr, 978 usdt_provider_ptr, 979 usdt_name_ptr, 980 usdt_opts_ptr, 981 ) 982 }; 983 let ptr = validate_bpf_ret(ptr).context("failed to attach USDT")?; 984 // SAFETY: the pointer came from libbpf and has been checked for errors. 985 let link = unsafe { Link::new(ptr) }; 986 Ok(link) 987 } 988 989 /// Attach this program to a [USDT](https://lwn.net/Articles/753601/) probe 990 /// point. The entry point of the program must be defined with 991 /// `SEC("usdt")`. attach_usdt( &mut self, pid: i32, binary_path: impl AsRef<Path>, usdt_provider: impl AsRef<str>, usdt_name: impl AsRef<str>, ) -> Result<Link>992 pub fn attach_usdt( 993 &mut self, 994 pid: i32, 995 binary_path: impl AsRef<Path>, 996 usdt_provider: impl AsRef<str>, 997 usdt_name: impl AsRef<str>, 998 ) -> Result<Link> { 999 self.attach_usdt_impl( 1000 pid, 1001 binary_path.as_ref(), 1002 usdt_provider.as_ref(), 1003 usdt_name.as_ref(), 1004 None, 1005 ) 1006 } 1007 1008 /// Attach this program to a [USDT](https://lwn.net/Articles/753601/) probe 1009 /// point, providing additional options. The entry point of the program must 1010 /// be defined with `SEC("usdt")`. attach_usdt_with_opts( &mut self, pid: i32, binary_path: impl AsRef<Path>, usdt_provider: impl AsRef<str>, usdt_name: impl AsRef<str>, usdt_opts: UsdtOpts, ) -> Result<Link>1011 pub fn attach_usdt_with_opts( 1012 &mut self, 1013 pid: i32, 1014 binary_path: impl AsRef<Path>, 1015 usdt_provider: impl AsRef<str>, 1016 usdt_name: impl AsRef<str>, 1017 usdt_opts: UsdtOpts, 1018 ) -> Result<Link> { 1019 self.attach_usdt_impl( 1020 pid, 1021 binary_path.as_ref(), 1022 usdt_provider.as_ref(), 1023 usdt_name.as_ref(), 1024 Some(usdt_opts), 1025 ) 1026 } 1027 1028 /// Attach this program to a 1029 /// [BPF Iterator](https://www.kernel.org/doc/html/latest/bpf/bpf_iterators.html). 1030 /// The entry point of the program must be defined with `SEC("iter")` or `SEC("iter.s")`. attach_iter(&mut self, map_fd: BorrowedFd<'_>) -> Result<Link>1031 pub fn attach_iter(&mut self, map_fd: BorrowedFd<'_>) -> Result<Link> { 1032 let mut linkinfo = libbpf_sys::bpf_iter_link_info::default(); 1033 linkinfo.map.map_fd = map_fd.as_raw_fd() as _; 1034 let attach_opt = libbpf_sys::bpf_iter_attach_opts { 1035 link_info: &mut linkinfo as *mut libbpf_sys::bpf_iter_link_info, 1036 link_info_len: size_of::<libbpf_sys::bpf_iter_link_info>() as _, 1037 sz: size_of::<libbpf_sys::bpf_iter_attach_opts>() as _, 1038 ..Default::default() 1039 }; 1040 let ptr = unsafe { 1041 libbpf_sys::bpf_program__attach_iter( 1042 self.ptr.as_ptr(), 1043 &attach_opt as *const libbpf_sys::bpf_iter_attach_opts, 1044 ) 1045 }; 1046 1047 let ptr = validate_bpf_ret(ptr).context("failed to attach iterator")?; 1048 // SAFETY: the pointer came from libbpf and has been checked for errors. 1049 let link = unsafe { Link::new(ptr) }; 1050 Ok(link) 1051 } 1052 1053 /// Test run the program with the given input data. 1054 /// 1055 /// This function uses the 1056 /// [BPF_PROG_RUN](https://www.kernel.org/doc/html/latest/bpf/bpf_prog_run.html) 1057 /// facility. test_run<'dat>(&mut self, input: Input<'dat>) -> Result<Output<'dat>>1058 pub fn test_run<'dat>(&mut self, input: Input<'dat>) -> Result<Output<'dat>> { 1059 unsafe fn slice_from_array<'t, T>(items: *mut T, num_items: usize) -> Option<&'t mut [T]> { 1060 if items.is_null() { 1061 None 1062 } else { 1063 Some(unsafe { slice::from_raw_parts_mut(items, num_items) }) 1064 } 1065 } 1066 1067 let Input { 1068 context_in, 1069 mut context_out, 1070 data_in, 1071 mut data_out, 1072 cpu, 1073 flags, 1074 _non_exhaustive: (), 1075 } = input; 1076 1077 let mut opts = unsafe { mem::zeroed::<libbpf_sys::bpf_test_run_opts>() }; 1078 opts.sz = size_of_val(&opts) as _; 1079 opts.ctx_in = context_in 1080 .as_ref() 1081 .map(|data| data.as_ptr().cast()) 1082 .unwrap_or_else(ptr::null); 1083 opts.ctx_size_in = context_in.map(|data| data.len() as _).unwrap_or(0); 1084 opts.ctx_out = context_out 1085 .as_mut() 1086 .map(|data| data.as_mut_ptr().cast()) 1087 .unwrap_or_else(ptr::null_mut); 1088 opts.ctx_size_out = context_out.map(|data| data.len() as _).unwrap_or(0); 1089 opts.data_in = data_in 1090 .map(|data| data.as_ptr().cast()) 1091 .unwrap_or_else(ptr::null); 1092 opts.data_size_in = data_in.map(|data| data.len() as _).unwrap_or(0); 1093 opts.data_out = data_out 1094 .as_mut() 1095 .map(|data| data.as_mut_ptr().cast()) 1096 .unwrap_or_else(ptr::null_mut); 1097 opts.data_size_out = data_out.map(|data| data.len() as _).unwrap_or(0); 1098 opts.cpu = cpu; 1099 opts.flags = flags; 1100 1101 let rc = unsafe { libbpf_sys::bpf_prog_test_run_opts(self.as_fd().as_raw_fd(), &mut opts) }; 1102 let () = util::parse_ret(rc)?; 1103 let output = Output { 1104 return_value: opts.retval, 1105 context: unsafe { slice_from_array(opts.ctx_out.cast(), opts.ctx_size_out as _) }, 1106 data: unsafe { slice_from_array(opts.data_out.cast(), opts.data_size_out as _) }, 1107 _non_exhaustive: (), 1108 }; 1109 Ok(output) 1110 } 1111 } 1112 1113 impl<'obj> Deref for ProgramMut<'obj> { 1114 type Target = Program<'obj>; 1115 deref(&self) -> &Self::Target1116 fn deref(&self) -> &Self::Target { 1117 // SAFETY: `ProgramImpl` is `repr(transparent)` and so in-memory 1118 // representation of both types is the same. 1119 unsafe { transmute::<&ProgramMut<'obj>, &Program<'obj>>(self) } 1120 } 1121 } 1122 1123 impl<T> AsFd for ProgramImpl<'_, T> { as_fd(&self) -> BorrowedFd<'_>1124 fn as_fd(&self) -> BorrowedFd<'_> { 1125 let fd = unsafe { libbpf_sys::bpf_program__fd(self.ptr.as_ptr()) }; 1126 unsafe { BorrowedFd::borrow_raw(fd) } 1127 } 1128 } 1129 1130 impl<T> AsRawLibbpf for ProgramImpl<'_, T> { 1131 type LibbpfType = libbpf_sys::bpf_program; 1132 1133 /// Retrieve the underlying [`libbpf_sys::bpf_program`]. as_libbpf_object(&self) -> NonNull<Self::LibbpfType>1134 fn as_libbpf_object(&self) -> NonNull<Self::LibbpfType> { 1135 self.ptr 1136 } 1137 } 1138 1139 #[cfg(test)] 1140 mod tests { 1141 use super::*; 1142 1143 use std::mem::discriminant; 1144 1145 #[test] program_type()1146 fn program_type() { 1147 use ProgramType::*; 1148 1149 for t in [ 1150 Unspec, 1151 SocketFilter, 1152 Kprobe, 1153 SchedCls, 1154 SchedAct, 1155 Tracepoint, 1156 Xdp, 1157 PerfEvent, 1158 CgroupSkb, 1159 CgroupSock, 1160 LwtIn, 1161 LwtOut, 1162 LwtXmit, 1163 SockOps, 1164 SkSkb, 1165 CgroupDevice, 1166 SkMsg, 1167 RawTracepoint, 1168 CgroupSockAddr, 1169 LwtSeg6local, 1170 LircMode2, 1171 SkReuseport, 1172 FlowDissector, 1173 CgroupSysctl, 1174 RawTracepointWritable, 1175 CgroupSockopt, 1176 Tracing, 1177 StructOps, 1178 Ext, 1179 Lsm, 1180 SkLookup, 1181 Syscall, 1182 Unknown, 1183 ] { 1184 // check if discriminants match after a roundtrip conversion 1185 assert_eq!(discriminant(&t), discriminant(&ProgramType::from(t as u32))); 1186 } 1187 } 1188 1189 #[test] program_attach_type()1190 fn program_attach_type() { 1191 use ProgramAttachType::*; 1192 1193 for t in [ 1194 CgroupInetIngress, 1195 CgroupInetEgress, 1196 CgroupInetSockCreate, 1197 CgroupSockOps, 1198 SkSkbStreamParser, 1199 SkSkbStreamVerdict, 1200 CgroupDevice, 1201 SkMsgVerdict, 1202 CgroupInet4Bind, 1203 CgroupInet6Bind, 1204 CgroupInet4Connect, 1205 CgroupInet6Connect, 1206 CgroupInet4PostBind, 1207 CgroupInet6PostBind, 1208 CgroupUdp4Sendmsg, 1209 CgroupUdp6Sendmsg, 1210 LircMode2, 1211 FlowDissector, 1212 CgroupSysctl, 1213 CgroupUdp4Recvmsg, 1214 CgroupUdp6Recvmsg, 1215 CgroupGetsockopt, 1216 CgroupSetsockopt, 1217 TraceRawTp, 1218 TraceFentry, 1219 TraceFexit, 1220 ModifyReturn, 1221 LsmMac, 1222 TraceIter, 1223 CgroupInet4Getpeername, 1224 CgroupInet6Getpeername, 1225 CgroupInet4Getsockname, 1226 CgroupInet6Getsockname, 1227 XdpDevmap, 1228 CgroupInetSockRelease, 1229 XdpCpumap, 1230 SkLookup, 1231 Xdp, 1232 SkSkbVerdict, 1233 SkReuseportSelect, 1234 SkReuseportSelectOrMigrate, 1235 PerfEvent, 1236 Unknown, 1237 ] { 1238 // check if discriminants match after a roundtrip conversion 1239 assert_eq!( 1240 discriminant(&t), 1241 discriminant(&ProgramAttachType::from(t as u32)) 1242 ); 1243 } 1244 } 1245 } 1246