ghostscope_loader/
kernel_caps.rs1use aya::maps::MapData;
2use aya_obj::{
3 generated::bpf_map_type::{BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_MAP_TYPE_RINGBUF},
4 maps::PinningType,
5 EbpfSectionKind, Map,
6};
7use std::{fmt, sync::OnceLock};
8use tracing::{error, info, warn};
9
10static KERNEL_CAPS: OnceLock<Result<KernelCapabilities, KernelCapabilityError>> = OnceLock::new();
12
13#[derive(Debug, Clone)]
14pub struct KernelCapabilityError {
15 message: String,
16}
17
18impl KernelCapabilityError {
19 fn new(message: impl Into<String>) -> Self {
20 Self {
21 message: message.into(),
22 }
23 }
24}
25
26impl fmt::Display for KernelCapabilityError {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 write!(f, "{}", self.message)
29 }
30}
31
32impl std::error::Error for KernelCapabilityError {}
33
34#[derive(Debug, Clone, Copy)]
36pub struct KernelCapabilities {
37 pub supports_ringbuf: bool,
39 pub supports_perf_event_array: bool,
41}
42
43impl KernelCapabilities {
44 pub fn get() -> Result<&'static Self, KernelCapabilityError> {
47 match KERNEL_CAPS.get_or_init(detect_full_capabilities) {
48 Ok(capabilities) => Ok(capabilities),
49 Err(err) => Err(err.clone()),
50 }
51 }
52
53 pub fn get_perf_only() -> Result<&'static Self, KernelCapabilityError> {
57 match KERNEL_CAPS.get_or_init(detect_perf_only_capabilities) {
58 Ok(capabilities) => Ok(capabilities),
59 Err(err) => Err(err.clone()),
60 }
61 }
62
63 pub fn ringbuf_supported() -> bool {
65 Self::get()
66 .map(|caps| caps.supports_ringbuf)
67 .unwrap_or(false)
68 }
69
70 pub fn perf_event_array_supported() -> bool {
72 Self::get()
73 .map(|caps| caps.supports_perf_event_array)
74 .unwrap_or(false)
75 }
76}
77
78fn detect_full_capabilities() -> Result<KernelCapabilities, KernelCapabilityError> {
79 let supports_ringbuf = detect_ringbuf_support();
80 let supports_perf_event_array = if !supports_ringbuf {
81 detect_perf_event_array_support()
82 } else {
83 true
84 };
85
86 if supports_ringbuf {
87 info!("✓ Kernel supports RingBuf (>= 5.8)");
88 } else if supports_perf_event_array {
89 warn!("⚠️ Kernel does not support RingBuf (< 5.8)");
90 warn!("⚠️ Will use PerfEventArray as fallback");
91 info!("✓ Kernel supports PerfEventArray (>= 4.3)");
92 } else {
93 error!("❌ Kernel supports neither RingBuf nor PerfEventArray");
94 error!("❌ GhostScope requires kernel >= 4.3 for eBPF event output");
95 error!("❌ Current kernel appears to be older or eBPF is disabled");
96 return Err(KernelCapabilityError::new(
97 "Kernel lacks both RingBuf (>=5.8) and PerfEventArray (>=4.3) support. \
98 Please upgrade the kernel or enable eBPF features.",
99 ));
100 }
101
102 Ok(KernelCapabilities {
103 supports_ringbuf,
104 supports_perf_event_array,
105 })
106}
107
108fn detect_perf_only_capabilities() -> Result<KernelCapabilities, KernelCapabilityError> {
109 info!("Testing mode: Only detecting PerfEventArray support");
110 let supports_perf_event_array = detect_perf_event_array_support();
111
112 if !supports_perf_event_array {
113 error!("❌ Kernel does not support PerfEventArray");
114 error!("❌ GhostScope requires kernel >= 4.3 for eBPF event output");
115 return Err(KernelCapabilityError::new(
116 "Kernel lacks PerfEventArray support (>=4.3 required). \
117 Please upgrade the kernel or enable eBPF features.",
118 ));
119 }
120
121 info!("✓ Kernel supports PerfEventArray (>= 4.3)");
122
123 Ok(KernelCapabilities {
124 supports_ringbuf: false,
125 supports_perf_event_array,
126 })
127}
128
129fn detect_ringbuf_support() -> bool {
131 info!("Probing kernel RingBuf support by attempting map creation...");
132
133 let obj_map = Map::Legacy(aya_obj::maps::LegacyMap {
135 section_index: 0,
136 section_kind: EbpfSectionKind::Maps,
137 symbol_index: None,
138 def: aya_obj::maps::bpf_map_def {
139 map_type: BPF_MAP_TYPE_RINGBUF as u32,
140 key_size: 0, value_size: 0, max_entries: 4096, map_flags: 0,
144 id: 0,
145 pinning: PinningType::None,
146 },
147 data: Vec::new(),
148 });
149
150 match MapData::create(obj_map, "probe_ringbuf", None) {
152 Ok(_map) => {
153 info!("RingBuf map creation succeeded - RingBuf is supported");
156 true
157 }
158 Err(e) => {
159 info!(
161 "RingBuf map creation failed (this is normal on kernels < 5.8): {}",
162 e
163 );
164 false
165 }
166 }
167}
168
169fn detect_perf_event_array_support() -> bool {
171 info!("Probing kernel PerfEventArray support by attempting map creation...");
172
173 let obj_map = Map::Legacy(aya_obj::maps::LegacyMap {
175 section_index: 0,
176 section_kind: EbpfSectionKind::Maps,
177 symbol_index: None,
178 def: aya_obj::maps::bpf_map_def {
179 map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32,
180 key_size: 4, value_size: 4, max_entries: 0, map_flags: 0,
184 id: 0,
185 pinning: PinningType::None,
186 },
187 data: Vec::new(),
188 });
189
190 match MapData::create(obj_map, "probe_perf_event_array", None) {
192 Ok(_map) => {
193 info!("PerfEventArray map creation succeeded - PerfEventArray is supported");
196 true
197 }
198 Err(e) => {
199 error!(
201 "PerfEventArray map creation failed (kernel may be older than 4.3): {}",
202 e
203 );
204 false
205 }
206 }
207}