xref: /DragonOS/kernel/src/bpf/helper/mod.rs (revision 55e6f0b65f91b32638fd56581f711a816eccdcd1)
1 mod consts;
2 mod print;
3 
4 use crate::bpf::helper::print::trace_printf;
5 use crate::bpf::map::{BpfCallBackFn, BpfMap};
6 use crate::include::bindings::linux_bpf::BPF_F_CURRENT_CPU;
7 use crate::libs::lazy_init::Lazy;
8 use crate::smp::core::smp_get_processor_id;
9 use alloc::{collections::BTreeMap, sync::Arc};
10 use core::ffi::c_void;
11 use system_error::SystemError;
12 
13 type RawBPFHelperFn = fn(u64, u64, u64, u64, u64) -> u64;
14 type Result<T> = core::result::Result<T, SystemError>;
15 macro_rules! define_func {
16     ($name:ident) => {
17         core::mem::transmute::<usize, RawBPFHelperFn>($name as usize)
18     };
19 }
20 
21 /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_map_lookup_elem/
22 unsafe fn raw_map_lookup_elem(map: *mut c_void, key: *const c_void) -> *const c_void {
23     let map = Arc::from_raw(map as *const BpfMap);
24     let key_size = map.key_size();
25     let key = core::slice::from_raw_parts(key as *const u8, key_size);
26     let value = map_lookup_elem(&map, key);
27     // log::info!("<raw_map_lookup_elem>: {:x?}", value);
28     // warning: We need to keep the map alive, so we don't drop it here.
29     let _ = Arc::into_raw(map);
30     match value {
31         Ok(Some(value)) => value as *const c_void,
32         _ => core::ptr::null_mut(),
33     }
34 }
35 
36 pub fn map_lookup_elem(map: &Arc<BpfMap>, key: &[u8]) -> Result<Option<*const u8>> {
37     let mut binding = map.inner_map().lock();
38     let value = binding.lookup_elem(key);
39     match value {
40         Ok(Some(value)) => Ok(Some(value.as_ptr())),
41         _ => Ok(None),
42     }
43 }
44 
45 /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_perf_event_output/
46 ///
47 /// See https://man7.org/linux/man-pages/man7/bpf-helpers.7.html
48 unsafe fn raw_perf_event_output(
49     ctx: *mut c_void,
50     map: *mut c_void,
51     flags: u64,
52     data: *mut c_void,
53     size: u64,
54 ) -> i64 {
55     // log::info!("<raw_perf_event_output>: {:x?}", data);
56     let map = Arc::from_raw(map as *const BpfMap);
57     let data = core::slice::from_raw_parts(data as *const u8, size as usize);
58     let res = perf_event_output(ctx, &map, flags, data);
59     // warning: We need to keep the map alive, so we don't drop it here.
60     let _ = Arc::into_raw(map);
61     match res {
62         Ok(_) => 0,
63         Err(e) => e as i64,
64     }
65 }
66 
67 pub fn perf_event_output(
68     ctx: *mut c_void,
69     map: &Arc<BpfMap>,
70     flags: u64,
71     data: &[u8],
72 ) -> Result<()> {
73     let mut binding = map.inner_map().lock();
74     let index = flags as u32;
75     let flags = (flags >> 32) as u32;
76     let key = if index == BPF_F_CURRENT_CPU as u32 {
77         smp_get_processor_id().data()
78     } else {
79         index
80     };
81     let fd = binding
82         .lookup_elem(&key.to_ne_bytes())?
83         .ok_or(SystemError::ENOENT)?;
84     let fd = u32::from_ne_bytes(fd.try_into().map_err(|_| SystemError::EINVAL)?);
85     crate::perf::perf_event_output(ctx, fd as usize, flags, data)?;
86     Ok(())
87 }
88 
89 /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_probe_read/
90 fn raw_bpf_probe_read(dst: *mut c_void, size: u32, unsafe_ptr: *const c_void) -> i64 {
91     log::info!(
92         "raw_bpf_probe_read, dst:{:x}, size:{}, unsafe_ptr: {:x}",
93         dst as usize,
94         size,
95         unsafe_ptr as usize
96     );
97     let (dst, src) = unsafe {
98         let dst = core::slice::from_raw_parts_mut(dst as *mut u8, size as usize);
99         let src = core::slice::from_raw_parts(unsafe_ptr as *const u8, size as usize);
100         (dst, src)
101     };
102     let res = bpf_probe_read(dst, src);
103     match res {
104         Ok(_) => 0,
105         Err(e) => e as i64,
106     }
107 }
108 
109 /// For tracing programs, safely attempt to read size
110 /// bytes from kernel space address unsafe_ptr and
111 /// store the data in dst.
112 pub fn bpf_probe_read(dst: &mut [u8], src: &[u8]) -> Result<()> {
113     log::info!("bpf_probe_read: len: {}", dst.len());
114     dst.copy_from_slice(src);
115     Ok(())
116 }
117 
118 unsafe fn raw_map_update_elem(
119     map: *mut c_void,
120     key: *const c_void,
121     value: *const c_void,
122     flags: u64,
123 ) -> i64 {
124     let map = Arc::from_raw(map as *const BpfMap);
125     let key_size = map.key_size();
126     let value_size = map.value_size();
127     // log::info!("<raw_map_update_elem>: flags: {:x?}", flags);
128     let key = core::slice::from_raw_parts(key as *const u8, key_size);
129     let value = core::slice::from_raw_parts(value as *const u8, value_size);
130     let res = map_update_elem(&map, key, value, flags);
131     let _ = Arc::into_raw(map);
132     match res {
133         Ok(_) => 0,
134         Err(e) => e as _,
135     }
136 }
137 
138 pub fn map_update_elem(map: &Arc<BpfMap>, key: &[u8], value: &[u8], flags: u64) -> Result<()> {
139     let mut binding = map.inner_map().lock();
140     let value = binding.update_elem(key, value, flags);
141     value
142 }
143 
144 /// Delete entry with key from map.
145 ///
146 /// The delete map element helper call is used to delete values from maps.
147 unsafe fn raw_map_delete_elem(map: *mut c_void, key: *const c_void) -> i64 {
148     let map = Arc::from_raw(map as *const BpfMap);
149     let key_size = map.key_size();
150     let key = core::slice::from_raw_parts(key as *const u8, key_size);
151     let res = map_delete_elem(&map, key);
152     let _ = Arc::into_raw(map);
153     match res {
154         Ok(_) => 0,
155         Err(e) => e as i64,
156     }
157 }
158 
159 pub fn map_delete_elem(map: &Arc<BpfMap>, key: &[u8]) -> Result<()> {
160     let mut binding = map.inner_map().lock();
161     let value = binding.delete_elem(key);
162     value
163 }
164 
165 /// For each element in map, call callback_fn function with map, callback_ctx and other map-specific
166 /// parameters. The callback_fn should be a static function and the callback_ctx should be a pointer
167 /// to the stack. The flags is used to control certain aspects of the helper.  Currently, the flags must
168 /// be 0.
169 ///
170 /// The following are a list of supported map types and their respective expected callback signatures:
171 /// - BPF_MAP_TYPE_HASH
172 /// - BPF_MAP_TYPE_PERCPU_HASH
173 /// - BPF_MAP_TYPE_LRU_HASH
174 /// - BPF_MAP_TYPE_LRU_PERCPU_HASH
175 /// - BPF_MAP_TYPE_ARRAY
176 /// - BPF_MAP_TYPE_PERCPU_ARRAY
177 ///
178 /// `long (*callback_fn)(struct bpf_map *map, const void key, void *value, void *ctx);`
179 ///
180 /// For per_cpu maps, the map_value is the value on the cpu where the bpf_prog is running.
181 unsafe fn raw_map_for_each_elem(
182     map: *mut c_void,
183     cb: *const c_void,
184     ctx: *const c_void,
185     flags: u64,
186 ) -> i64 {
187     let map = Arc::from_raw(map as *const BpfMap);
188     let cb = *core::mem::transmute::<*const c_void, *const BpfCallBackFn>(cb);
189     let res = map_for_each_elem(&map, cb, ctx as _, flags);
190     let _ = Arc::into_raw(map);
191     match res {
192         Ok(v) => v as i64,
193         Err(e) => e as i64,
194     }
195 }
196 
197 pub fn map_for_each_elem(
198     map: &Arc<BpfMap>,
199     cb: BpfCallBackFn,
200     ctx: *const u8,
201     flags: u64,
202 ) -> Result<u32> {
203     let mut binding = map.inner_map().lock();
204     let value = binding.for_each_elem(cb, ctx, flags);
205     value
206 }
207 
208 /// Perform a lookup in percpu map for an entry associated to key on cpu.
209 ///
210 /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_map_lookup_percpu_elem/
211 unsafe fn raw_map_lookup_percpu_elem(
212     map: *mut c_void,
213     key: *const c_void,
214     cpu: u32,
215 ) -> *const c_void {
216     let map = Arc::from_raw(map as *const BpfMap);
217     let key_size = map.key_size();
218     let key = core::slice::from_raw_parts(key as *const u8, key_size);
219     let value = map_lookup_percpu_elem(&map, key, cpu);
220     // warning: We need to keep the map alive, so we don't drop it here.
221     let _ = Arc::into_raw(map);
222     match value {
223         Ok(Some(value)) => value as *const c_void,
224         _ => core::ptr::null_mut(),
225     }
226 }
227 
228 pub fn map_lookup_percpu_elem(
229     map: &Arc<BpfMap>,
230     key: &[u8],
231     cpu: u32,
232 ) -> Result<Option<*const u8>> {
233     let mut binding = map.inner_map().lock();
234     let value = binding.lookup_percpu_elem(key, cpu);
235     match value {
236         Ok(Some(value)) => Ok(Some(value.as_ptr())),
237         _ => Ok(None),
238     }
239 }
240 /// Push an element value in map.
241 ///
242 /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_map_push_elem/
243 unsafe fn raw_map_push_elem(map: *mut c_void, value: *const c_void, flags: u64) -> i64 {
244     let map = Arc::from_raw(map as *const BpfMap);
245     let value_size = map.value_size();
246     let value = core::slice::from_raw_parts(value as *const u8, value_size);
247     let res = map_push_elem(&map, value, flags);
248     let _ = Arc::into_raw(map);
249     match res {
250         Ok(_) => 0,
251         Err(e) => e as i64,
252     }
253 }
254 
255 pub fn map_push_elem(map: &Arc<BpfMap>, value: &[u8], flags: u64) -> Result<()> {
256     let mut binding = map.inner_map().lock();
257     let value = binding.push_elem(value, flags);
258     value
259 }
260 
261 /// Pop an element from map.
262 ///
263 /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_map_pop_elem/
264 unsafe fn raw_map_pop_elem(map: *mut c_void, value: *mut c_void) -> i64 {
265     let map = Arc::from_raw(map as *const BpfMap);
266     let value_size = map.value_size();
267     let value = core::slice::from_raw_parts_mut(value as *mut u8, value_size);
268     let res = map_pop_elem(&map, value);
269     let _ = Arc::into_raw(map);
270     match res {
271         Ok(_) => 0,
272         Err(e) => e as i64,
273     }
274 }
275 
276 pub fn map_pop_elem(map: &Arc<BpfMap>, value: &mut [u8]) -> Result<()> {
277     let mut binding = map.inner_map().lock();
278     let value = binding.pop_elem(value);
279     value
280 }
281 
282 /// Get an element from map without removing it.
283 ///
284 /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_map_peek_elem/
285 unsafe fn raw_map_peek_elem(map: *mut c_void, value: *mut c_void) -> i64 {
286     let map = Arc::from_raw(map as *const BpfMap);
287     let value_size = map.value_size();
288     let value = core::slice::from_raw_parts_mut(value as *mut u8, value_size);
289     let res = map_peek_elem(&map, value);
290     let _ = Arc::into_raw(map);
291     match res {
292         Ok(_) => 0,
293         Err(e) => e as i64,
294     }
295 }
296 
297 pub fn map_peek_elem(map: &Arc<BpfMap>, value: &mut [u8]) -> Result<()> {
298     let binding = map.inner_map().lock();
299     let value = binding.peek_elem(value);
300     value
301 }
302 
303 pub static BPF_HELPER_FUN_SET: Lazy<BTreeMap<u32, RawBPFHelperFn>> = Lazy::new();
304 
305 /// Initialize the helper functions.
306 pub fn init_helper_functions() {
307     use consts::*;
308     let mut map = BTreeMap::new();
309     unsafe {
310         // Map helpers::Generic map helpers
311         map.insert(HELPER_MAP_LOOKUP_ELEM, define_func!(raw_map_lookup_elem));
312         map.insert(HELPER_MAP_UPDATE_ELEM, define_func!(raw_map_update_elem));
313         map.insert(HELPER_MAP_DELETE_ELEM, define_func!(raw_map_delete_elem));
314         map.insert(
315             HELPER_MAP_FOR_EACH_ELEM,
316             define_func!(raw_map_for_each_elem),
317         );
318         map.insert(
319             HELPER_MAP_LOOKUP_PERCPU_ELEM,
320             define_func!(raw_map_lookup_percpu_elem),
321         );
322         // map.insert(93,define_func!(raw_bpf_spin_lock);
323         // map.insert(94,define_func!(raw_bpf_spin_unlock);
324         // Map helpers::Perf event array helpers
325         map.insert(
326             HELPER_PERF_EVENT_OUTPUT,
327             define_func!(raw_perf_event_output),
328         );
329         // Probe and trace helpers::Memory helpers
330         map.insert(HELPER_BPF_PROBE_READ, define_func!(raw_bpf_probe_read));
331         // Print helpers
332         map.insert(HELPER_TRACE_PRINTF, define_func!(trace_printf));
333 
334         // Map helpers::Queue and stack helpers
335         map.insert(HELPER_MAP_PUSH_ELEM, define_func!(raw_map_push_elem));
336         map.insert(HELPER_MAP_POP_ELEM, define_func!(raw_map_pop_elem));
337         map.insert(HELPER_MAP_PEEK_ELEM, define_func!(raw_map_peek_elem));
338     }
339     BPF_HELPER_FUN_SET.init(map);
340 }
341