From ce22ca668f3e7c0f9832d28370457204537d2e50 Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Sun, 26 Jun 2022 22:26:19 +0100 Subject: [PATCH 1/4] aya: Make features a lazy_static Signed-off-by: Dave Tucker --- aya-obj/src/btf/btf.rs | 19 +++++++++++ aya/src/bpf.rs | 74 ++++++++++++++++++++---------------------- 2 files changed, 55 insertions(+), 38 deletions(-) diff --git a/aya-obj/src/btf/btf.rs b/aya-obj/src/btf/btf.rs index f439ee1a..4dd4716c 100644 --- a/aya-obj/src/btf/btf.rs +++ b/aya-obj/src/btf/btf.rs @@ -172,6 +172,25 @@ pub struct BtfFeatures { pub btf_type_tag: bool, } +impl std::fmt::Display for BtfFeatures { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!( + "[FEAT PROBE] BTF func support: {}\n\ + [FEAT PROBE] BTF global func support: {}\n\ + [FEAT PROBE] BTF var and datasec support: {}\n\ + [FEAT PROBE] BTF float support: {}\n\ + [FEAT PROBE] BTF decl_tag support: {}\n\ + [FEAT PROBE] BTF type_tag support: {}", + self.btf_func, + self.btf_func_global, + self.btf_datasec, + self.btf_float, + self.btf_decl_tag, + self.btf_type_tag, + )) + } +} + /// Bpf Type Format metadata. /// /// BTF is a kind of debug metadata that allows eBPF programs compiled against one kernel version diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index d3e8059f..cf593b2a 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -65,6 +65,10 @@ unsafe impl Pod for [T; N] {} pub use aya_obj::maps::{bpf_map_def, PinningType}; +lazy_static! { + pub(crate) static ref FEATURES: Features = Features::new(); +} + // Features implements BPF and BTF feature detection #[derive(Default, Debug)] pub(crate) struct Features { @@ -73,42 +77,40 @@ pub(crate) struct Features { } impl Features { - fn probe_features(&mut self) { - self.bpf_name = is_prog_name_supported(); - debug!("[FEAT PROBE] BPF program name support: {}", self.bpf_name); - - self.btf = if is_btf_supported() { - Some(BtfFeatures::default()) + fn new() -> Self { + let btf = if is_btf_supported() { + Some(BtfFeatures { + btf_func: is_btf_func_supported(), + btf_func_global: is_btf_func_global_supported(), + btf_datasec: is_btf_datasec_supported(), + btf_float: is_btf_float_supported(), + btf_decl_tag: is_btf_decl_tag_supported(), + btf_type_tag: is_btf_type_tag_supported(), + }) } else { None }; - debug!("[FEAT PROBE] BTF support: {}", self.btf.is_some()); - - if let Some(ref mut btf) = self.btf { - btf.btf_func = is_btf_func_supported(); - debug!("[FEAT PROBE] BTF func support: {}", btf.btf_func); - - btf.btf_func_global = is_btf_func_global_supported(); - debug!( - "[FEAT PROBE] BTF global func support: {}", - btf.btf_func_global - ); - - btf.btf_datasec = is_btf_datasec_supported(); - debug!( - "[FEAT PROBE] BTF var and datasec support: {}", - btf.btf_datasec - ); - - btf.btf_float = is_btf_float_supported(); - debug!("[FEAT PROBE] BTF float support: {}", btf.btf_float); - - btf.btf_decl_tag = is_btf_decl_tag_supported(); - debug!("[FEAT PROBE] BTF decl_tag support: {}", btf.btf_decl_tag); + let f = Features { + bpf_name: is_prog_name_supported(), + btf, + }; - btf.btf_type_tag = is_btf_type_tag_supported(); - debug!("[FEAT PROBE] BTF type_tag support: {}", btf.btf_type_tag); + debug!("{}", f); + if let Some(btf) = f.btf.as_ref() { + debug!("{}", btf) } + f + } +} + +impl std::fmt::Display for Features { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!( + "[FEAT PROBE] BPF program name support: {}\n\ + [FEAT PROBE] BTF support: {}", + self.bpf_name, + self.btf.is_some() + )) } } @@ -139,7 +141,6 @@ pub struct BpfLoader<'a> { map_pin_path: Option, globals: HashMap<&'a str, &'a [u8]>, max_entries: HashMap<&'a str, u32>, - features: Features, extensions: HashSet<&'a str>, verifier_log_level: VerifierLogLevel, } @@ -169,14 +170,11 @@ impl Default for VerifierLogLevel { impl<'a> BpfLoader<'a> { /// Creates a new loader instance. pub fn new() -> BpfLoader<'a> { - let mut features = Features::default(); - features.probe_features(); BpfLoader { btf: Btf::from_sys_fs().ok().map(Cow::Owned), map_pin_path: None, globals: HashMap::new(), max_entries: HashMap::new(), - features, extensions: HashSet::new(), verifier_log_level: VerifierLogLevel::default(), } @@ -360,8 +358,8 @@ impl<'a> BpfLoader<'a> { let mut obj = Object::parse(data)?; obj.patch_map_data(self.globals.clone())?; - let btf_fd = if let Some(ref btf) = self.features.btf { - if let Some(btf) = obj.fixup_and_sanitize_btf(btf)? { + let btf_fd = if let Some(ref features) = FEATURES.btf { + if let Some(btf) = obj.fixup_and_sanitize_btf(features)? { // load btf to the kernel Some(load_btf(btf.to_bytes())?) } else { @@ -449,7 +447,7 @@ impl<'a> BpfLoader<'a> { .programs .drain() .map(|(name, obj)| { - let prog_name = if self.features.bpf_name { + let prog_name = if FEATURES.bpf_name { Some(name.clone()) } else { None From 763b92a2e007a17cc2b6a17929dcb6a5c26c9f88 Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Mon, 27 Jun 2022 22:20:10 +0100 Subject: [PATCH 2/4] aya: Add probe for bpf_link_create for perf programs Signed-off-by: Dave Tucker --- aya/src/bpf.rs | 10 +++++++--- aya/src/sys/bpf.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index cf593b2a..2d71d88c 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -35,8 +35,8 @@ use crate::{ sys::{ bpf_load_btf, bpf_map_freeze, bpf_map_update_elem_ptr, is_btf_datasec_supported, is_btf_decl_tag_supported, is_btf_float_supported, is_btf_func_global_supported, - is_btf_func_supported, is_btf_supported, is_btf_type_tag_supported, is_prog_name_supported, - retry_with_verifier_logs, + is_btf_func_supported, is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported, + is_prog_name_supported, retry_with_verifier_logs, }, util::{bytes_of, possible_cpus, VerifierLog, POSSIBLE_CPUS}, }; @@ -73,6 +73,7 @@ lazy_static! { #[derive(Default, Debug)] pub(crate) struct Features { pub bpf_name: bool, + pub bpf_perf_link: bool, pub btf: Option, } @@ -92,6 +93,7 @@ impl Features { }; let f = Features { bpf_name: is_prog_name_supported(), + bpf_perf_link: is_perf_link_supported(), btf, }; @@ -107,8 +109,10 @@ impl std::fmt::Display for Features { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!( "[FEAT PROBE] BPF program name support: {}\n\ + [FEAT PROBE] bpf_link support for kprobe/uprobe/tracepoint: {}\n\ [FEAT PROBE] BTF support: {}", self.bpf_name, + self.bpf_perf_link, self.btf.is_some() )) } @@ -358,7 +362,7 @@ impl<'a> BpfLoader<'a> { let mut obj = Object::parse(data)?; obj.patch_map_data(self.globals.clone())?; - let btf_fd = if let Some(ref features) = FEATURES.btf { + let btf_fd = if let Some(features) = &FEATURES.btf { if let Some(btf) = obj.fixup_and_sanitize_btf(features)? { // load btf to the kernel Some(load_btf(btf.to_bytes())?) diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index ec3890d0..20a88f26 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -599,6 +599,37 @@ pub(crate) fn is_prog_name_supported() -> bool { } } +pub(crate) fn is_perf_link_supported() -> bool { + let mut attr = unsafe { mem::zeroed::() }; + let u = unsafe { &mut attr.__bindgen_anon_3 }; + + let prog: &[u8] = &[ + 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r0 = 0 + 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit + ]; + + let gpl = b"GPL\0"; + u.license = gpl.as_ptr() as u64; + + let insns = copy_instructions(prog).unwrap(); + u.insn_cnt = insns.len() as u32; + u.insns = insns.as_ptr() as u64; + u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32; + + if let Ok(fd) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) { + if let Err((code, _)) = + // Uses an invalid target FD so we get EBADF if supported. + bpf_link_create(fd as i32, -1, bpf_attach_type::BPF_PERF_EVENT, None, 0) + { + // Returns EINVAL if unsupported. EBADF if supported. + let res = code == (-libc::EBADF).into(); + unsafe { libc::close(fd as i32) }; + return res; + } + } + false +} + pub(crate) fn is_btf_supported() -> bool { let mut btf = Btf::new(); let name_offset = btf.add_string("int".to_string()); From d0b3d3b2fac955ed0e1e3d885fcd3ba67941dc8c Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Fri, 10 Feb 2023 23:20:37 +0000 Subject: [PATCH 3/4] aya: Enable bpf_link for perf_attach programs This adds support for bpf_link to PerfEvent, Tracepoint, Kprobe and Uprobe programs. Signed-off-by: Dave Tucker --- aya/src/programs/kprobe.rs | 6 +-- aya/src/programs/perf_attach.rs | 83 +++++++++++++++++++++++---------- aya/src/programs/perf_event.rs | 23 ++++++--- aya/src/programs/probe.rs | 17 ++++--- aya/src/programs/trace_point.rs | 9 ++-- aya/src/programs/uprobe.rs | 6 +-- 6 files changed, 98 insertions(+), 46 deletions(-) diff --git a/aya/src/programs/kprobe.rs b/aya/src/programs/kprobe.rs index 5bd2726e..65a505d2 100644 --- a/aya/src/programs/kprobe.rs +++ b/aya/src/programs/kprobe.rs @@ -6,7 +6,7 @@ use crate::{ generated::bpf_prog_type::BPF_PROG_TYPE_KPROBE, programs::{ define_link_wrapper, load_program, - perf_attach::{PerfLink, PerfLinkId}, + perf_attach::{PerfLinkIdInner, PerfLinkInner}, probe::{attach, ProbeKind}, ProgramData, ProgramError, }, @@ -101,8 +101,8 @@ define_link_wrapper!( KProbeLink, /// The type returned by [KProbe::attach]. Can be passed to [KProbe::detach]. KProbeLinkId, - PerfLink, - PerfLinkId + PerfLinkInner, + PerfLinkIdInner ); /// The type returned when attaching a [`KProbe`] fails. diff --git a/aya/src/programs/perf_attach.rs b/aya/src/programs/perf_attach.rs index 7bd15f23..78609110 100644 --- a/aya/src/programs/perf_attach.rs +++ b/aya/src/programs/perf_attach.rs @@ -3,11 +3,42 @@ use libc::close; use std::os::unix::io::RawFd; use crate::{ - programs::{probe::detach_debug_fs, Link, ProbeKind, ProgramData, ProgramError}, - sys::perf_event_ioctl, - PERF_EVENT_IOC_DISABLE, PERF_EVENT_IOC_ENABLE, PERF_EVENT_IOC_SET_BPF, + generated::bpf_attach_type::BPF_PERF_EVENT, + programs::{probe::detach_debug_fs, FdLink, Link, ProbeKind, ProgramError}, + sys::{bpf_link_create, perf_event_ioctl}, + FEATURES, PERF_EVENT_IOC_DISABLE, PERF_EVENT_IOC_ENABLE, PERF_EVENT_IOC_SET_BPF, }; +#[derive(Debug, Hash, Eq, PartialEq)] +pub(crate) enum PerfLinkIdInner { + FdLinkId(::Id), + PerfLinkId(::Id), +} + +#[derive(Debug)] +pub(crate) enum PerfLinkInner { + FdLink(FdLink), + PerfLink(PerfLink), +} + +impl Link for PerfLinkInner { + type Id = PerfLinkIdInner; + + fn id(&self) -> Self::Id { + match self { + PerfLinkInner::FdLink(link) => PerfLinkIdInner::FdLinkId(link.id()), + PerfLinkInner::PerfLink(link) => PerfLinkIdInner::PerfLinkId(link.id()), + } + } + + fn detach(self) -> Result<(), ProgramError> { + match self { + PerfLinkInner::FdLink(link) => link.detach(), + PerfLinkInner::PerfLink(link) => link.detach(), + } + } +} + /// The identifer of a PerfLink. #[derive(Debug, Hash, Eq, PartialEq)] pub struct PerfLinkId(RawFd); @@ -41,29 +72,36 @@ impl Link for PerfLink { } } -pub(crate) fn perf_attach>( - data: &mut ProgramData, - fd: RawFd, -) -> Result { - perf_attach_either(data, fd, None, None) +pub(crate) fn perf_attach(prog_fd: RawFd, fd: RawFd) -> Result { + if FEATURES.bpf_perf_link { + let link_fd = + bpf_link_create(prog_fd, fd, BPF_PERF_EVENT, None, 0).map_err(|(_, io_error)| { + ProgramError::SyscallError { + call: "bpf_link_create".to_owned(), + io_error, + } + })? as RawFd; + Ok(PerfLinkInner::FdLink(FdLink::new(link_fd))) + } else { + perf_attach_either(prog_fd, fd, None, None) + } } -pub(crate) fn perf_attach_debugfs>( - data: &mut ProgramData, +pub(crate) fn perf_attach_debugfs( + prog_fd: RawFd, fd: RawFd, probe_kind: ProbeKind, event_alias: String, -) -> Result { - perf_attach_either(data, fd, Some(probe_kind), Some(event_alias)) +) -> Result { + perf_attach_either(prog_fd, fd, Some(probe_kind), Some(event_alias)) } -fn perf_attach_either>( - data: &mut ProgramData, +fn perf_attach_either( + prog_fd: RawFd, fd: RawFd, probe_kind: Option, event_alias: Option, -) -> Result { - let prog_fd = data.fd_or_err()?; +) -> Result { perf_event_ioctl(fd, PERF_EVENT_IOC_SET_BPF, prog_fd).map_err(|(_, io_error)| { ProgramError::SyscallError { call: "PERF_EVENT_IOC_SET_BPF".to_owned(), @@ -77,12 +115,9 @@ fn perf_attach_either>( } })?; - data.links.insert( - PerfLink { - perf_fd: fd, - probe_kind, - event_alias, - } - .into(), - ) + Ok(PerfLinkInner::PerfLink(PerfLink { + perf_fd: fd, + probe_kind, + event_alias, + })) } diff --git a/aya/src/programs/perf_event.rs b/aya/src/programs/perf_event.rs index d4185375..177b3544 100644 --- a/aya/src/programs/perf_event.rs +++ b/aya/src/programs/perf_event.rs @@ -13,8 +13,9 @@ use crate::{ }, }, programs::{ + links::define_link_wrapper, load_program, perf_attach, - perf_attach::{PerfLink, PerfLinkId}, + perf_attach::{PerfLinkIdInner, PerfLinkInner}, ProgramData, ProgramError, }, sys::perf_event_open, @@ -119,7 +120,7 @@ pub enum PerfEventScope { #[derive(Debug)] #[doc(alias = "BPF_PROG_TYPE_PERF_EVENT")] pub struct PerfEvent { - pub(crate) data: ProgramData, + pub(crate) data: ProgramData, } impl PerfEvent { @@ -141,7 +142,7 @@ impl PerfEvent { config: u64, scope: PerfEventScope, sample_policy: SamplePolicy, - ) -> Result { + ) -> Result { let (sample_period, sample_frequency) = match sample_policy { SamplePolicy::Period(period) => (period, None), SamplePolicy::Frequency(frequency) => (0, Some(frequency)), @@ -168,13 +169,14 @@ impl PerfEvent { io_error, })? as i32; - perf_attach(&mut self.data, fd) + let link = perf_attach(self.data.fd_or_err()?, fd)?; + self.data.links.insert(PerfEventLink::new(link)) } /// Detaches the program. /// /// See [PerfEvent::attach]. - pub fn detach(&mut self, link_id: PerfLinkId) -> Result<(), ProgramError> { + pub fn detach(&mut self, link_id: PerfEventLinkId) -> Result<(), ProgramError> { self.data.links.remove(link_id) } @@ -182,7 +184,16 @@ impl PerfEvent { /// /// The link will be detached on `Drop` and the caller is now responsible /// for managing its lifetime. - pub fn take_link(&mut self, link_id: PerfLinkId) -> Result { + pub fn take_link(&mut self, link_id: PerfEventLinkId) -> Result { self.data.take_link(link_id) } } + +define_link_wrapper!( + /// The link used by [PerfEvent] programs. + PerfEventLink, + /// The type returned by [PerfEvent::attach]. Can be passed to [PerfEvent::detach]. + PerfEventLinkId, + PerfLinkInner, + PerfLinkIdInner +); diff --git a/aya/src/programs/probe.rs b/aya/src/programs/probe.rs index f595ca53..b1690ecd 100644 --- a/aya/src/programs/probe.rs +++ b/aya/src/programs/probe.rs @@ -8,7 +8,7 @@ use std::{ use crate::{ programs::{ - kprobe::KProbeError, perf_attach, perf_attach::PerfLink, perf_attach_debugfs, + kprobe::KProbeError, perf_attach, perf_attach::PerfLinkInner, perf_attach_debugfs, trace_point::read_sys_fs_trace_point_id, uprobe::UProbeError, utils::find_tracefs_path, Link, ProgramData, ProgramError, }, @@ -37,7 +37,7 @@ impl ProbeKind { } } -pub(crate) fn attach>( +pub(crate) fn attach>( program_data: &mut ProgramData, kind: ProbeKind, fn_name: &str, @@ -49,13 +49,18 @@ pub(crate) fn attach>( let k_ver = kernel_version().unwrap(); if k_ver < (4, 17, 0) { let (fd, event_alias) = create_as_trace_point(kind, fn_name, offset, pid)?; - - return perf_attach_debugfs(program_data, fd, kind, event_alias); + let link = T::from(perf_attach_debugfs( + program_data.fd_or_err()?, + fd, + kind, + event_alias, + )?); + return program_data.links.insert(link); }; let fd = create_as_probe(kind, fn_name, offset, pid)?; - - perf_attach(program_data, fd) + let link = T::from(perf_attach(program_data.fd_or_err()?, fd)?); + program_data.links.insert(link) } pub(crate) fn detach_debug_fs(kind: ProbeKind, event_alias: &str) -> Result<(), ProgramError> { diff --git a/aya/src/programs/trace_point.rs b/aya/src/programs/trace_point.rs index d4bf158d..f43cd77e 100644 --- a/aya/src/programs/trace_point.rs +++ b/aya/src/programs/trace_point.rs @@ -6,7 +6,7 @@ use crate::{ generated::bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT, programs::{ define_link_wrapper, load_program, - perf_attach::{perf_attach, PerfLink, PerfLinkId}, + perf_attach::{perf_attach, PerfLinkIdInner, PerfLinkInner}, utils::find_tracefs_path, ProgramData, ProgramError, }, @@ -87,7 +87,8 @@ impl TracePoint { } })? as i32; - perf_attach(&mut self.data, fd) + let link = perf_attach(self.data.fd_or_err()?, fd)?; + self.data.links.insert(TracePointLink::new(link)) } /// Detaches from a trace point. @@ -111,8 +112,8 @@ define_link_wrapper!( TracePointLink, /// The type returned by [TracePoint::attach]. Can be passed to [TracePoint::detach]. TracePointLinkId, - PerfLink, - PerfLinkId + PerfLinkInner, + PerfLinkIdInner ); pub(crate) fn read_sys_fs_trace_point_id( diff --git a/aya/src/programs/uprobe.rs b/aya/src/programs/uprobe.rs index 55629da0..c8a3446d 100644 --- a/aya/src/programs/uprobe.rs +++ b/aya/src/programs/uprobe.rs @@ -17,7 +17,7 @@ use crate::{ generated::bpf_prog_type::BPF_PROG_TYPE_KPROBE, programs::{ define_link_wrapper, load_program, - perf_attach::{PerfLink, PerfLinkId}, + perf_attach::{PerfLinkIdInner, PerfLinkInner}, probe::{attach, ProbeKind}, ProgramData, ProgramError, }, @@ -154,8 +154,8 @@ define_link_wrapper!( UProbeLink, /// The type returned by [UProbe::attach]. Can be passed to [UProbe::detach]. UProbeLinkId, - PerfLink, - PerfLinkId + PerfLinkInner, + PerfLinkIdInner ); /// The type returned when attaching an [`UProbe`] fails. From 7479c1dd6c1356bddb0401dbeea65618674524c9 Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Fri, 10 Feb 2023 23:30:00 +0000 Subject: [PATCH 4/4] aya: More discrete feature logging Just use the Debug formatter vs. printing a message for each probe. Signed-off-by: Dave Tucker --- aya-obj/src/btf/btf.rs | 19 ------------------- aya/src/bpf.rs | 19 +------------------ 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/aya-obj/src/btf/btf.rs b/aya-obj/src/btf/btf.rs index 4dd4716c..f439ee1a 100644 --- a/aya-obj/src/btf/btf.rs +++ b/aya-obj/src/btf/btf.rs @@ -172,25 +172,6 @@ pub struct BtfFeatures { pub btf_type_tag: bool, } -impl std::fmt::Display for BtfFeatures { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_fmt(format_args!( - "[FEAT PROBE] BTF func support: {}\n\ - [FEAT PROBE] BTF global func support: {}\n\ - [FEAT PROBE] BTF var and datasec support: {}\n\ - [FEAT PROBE] BTF float support: {}\n\ - [FEAT PROBE] BTF decl_tag support: {}\n\ - [FEAT PROBE] BTF type_tag support: {}", - self.btf_func, - self.btf_func_global, - self.btf_datasec, - self.btf_float, - self.btf_decl_tag, - self.btf_type_tag, - )) - } -} - /// Bpf Type Format metadata. /// /// BTF is a kind of debug metadata that allows eBPF programs compiled against one kernel version diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index 2d71d88c..719f1195 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -96,28 +96,11 @@ impl Features { bpf_perf_link: is_perf_link_supported(), btf, }; - - debug!("{}", f); - if let Some(btf) = f.btf.as_ref() { - debug!("{}", btf) - } + debug!("BPF Feature Detection: {:#?}", f); f } } -impl std::fmt::Display for Features { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_fmt(format_args!( - "[FEAT PROBE] BPF program name support: {}\n\ - [FEAT PROBE] bpf_link support for kprobe/uprobe/tracepoint: {}\n\ - [FEAT PROBE] BTF support: {}", - self.bpf_name, - self.bpf_perf_link, - self.btf.is_some() - )) - } -} - /// Builder style API for advanced loading of eBPF programs. /// /// Loading eBPF code involves a few steps, including loading maps and applying