-
Notifications
You must be signed in to change notification settings - Fork 297
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Before this change, Aya supported only legacy BPF map definitions, which are instances of the `bpf_map_def` struct and end up in the `maps` ELF section. This change introduces BTF maps, with custom structs indicating the metadata of the map, which end up in the `.maps` section. Legacy maps are not supported by libbpf anymore and not even by the kernel for newer types of maps like inode/task storage. Add support of BTF maps in aya-ebpf under the `btf-maps` feature flag. Usage of this feature requires emitting debug info for the eBPF crate and passing the `--btf` flag to bpf-linker.
- Loading branch information
1 parent
5a43bed
commit f327ceb
Showing
42 changed files
with
2,269 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
use proc_macro2::TokenStream; | ||
use quote::quote; | ||
use syn::{ItemStatic, Result}; | ||
|
||
use crate::args::name_arg; | ||
|
||
pub(crate) struct BtfMap { | ||
item: ItemStatic, | ||
name: String, | ||
} | ||
|
||
impl BtfMap { | ||
pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<BtfMap> { | ||
let item: ItemStatic = syn::parse2(item)?; | ||
let mut args = syn::parse2(attrs)?; | ||
let name = name_arg(&mut args).unwrap_or_else(|| item.ident.to_string()); | ||
Ok(BtfMap { item, name }) | ||
} | ||
|
||
pub(crate) fn expand(&self) -> TokenStream { | ||
let section_name = ".maps"; | ||
let name = &self.name; | ||
let item = &self.item; | ||
quote! { | ||
#[link_section = #section_name] | ||
#[export_name = #name] | ||
#item | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use syn::parse_quote; | ||
|
||
use super::*; | ||
|
||
#[test] | ||
fn test_map_with_name() { | ||
let map = BtfMap::parse( | ||
parse_quote!(name = "foo"), | ||
parse_quote!( | ||
static BAR: HashMap<&'static str, u32> = HashMap::new(); | ||
), | ||
) | ||
.unwrap(); | ||
let expanded = map.expand(); | ||
let expected = quote!( | ||
#[link_section = ".maps"] | ||
#[export_name = "foo"] | ||
static BAR: HashMap<&'static str, u32> = HashMap::new(); | ||
); | ||
assert_eq!(expected.to_string(), expanded.to_string()); | ||
} | ||
|
||
#[test] | ||
fn test_map_no_name() { | ||
let map = BtfMap::parse( | ||
parse_quote!(), | ||
parse_quote!( | ||
static BAR: HashMap<&'static str, u32> = HashMap::new(); | ||
), | ||
) | ||
.unwrap(); | ||
let expanded = map.expand(); | ||
let expected = quote!( | ||
#[link_section = ".maps"] | ||
#[export_name = "BAR"] | ||
static BAR: HashMap<&'static str, u32> = HashMap::new(); | ||
); | ||
assert_eq!(expected.to_string(), expanded.to_string()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
use core::{cell::UnsafeCell, ptr::NonNull}; | ||
|
||
use crate::{ | ||
bindings::bpf_map_type::BPF_MAP_TYPE_ARRAY, btf_map_def, cty::c_void, | ||
helpers::bpf_map_lookup_elem, | ||
}; | ||
|
||
btf_map_def!(ArrayDef, BPF_MAP_TYPE_ARRAY); | ||
|
||
#[repr(transparent)] | ||
pub struct Array<T, const M: usize, const F: usize = 0>(UnsafeCell<ArrayDef<u32, T, M, F>>); | ||
|
||
unsafe impl<T: Sync, const M: usize, const F: usize> Sync for Array<T, M, F> {} | ||
|
||
impl<T, const M: usize, const F: usize> Array<T, M, F> { | ||
pub const fn new() -> Self { | ||
Array(UnsafeCell::new(ArrayDef::new())) | ||
} | ||
|
||
#[inline(always)] | ||
pub fn get(&self, index: u32) -> Option<&T> { | ||
// FIXME: alignment | ||
unsafe { self.lookup(index).map(|p| p.as_ref()) } | ||
} | ||
|
||
#[inline(always)] | ||
pub fn get_ptr(&self, index: u32) -> Option<*const T> { | ||
unsafe { self.lookup(index).map(|p| p.as_ptr() as *const T) } | ||
} | ||
|
||
#[inline(always)] | ||
pub fn get_ptr_mut(&self, index: u32) -> Option<*mut T> { | ||
unsafe { self.lookup(index).map(|p| p.as_ptr()) } | ||
} | ||
|
||
#[inline(always)] | ||
unsafe fn lookup(&self, index: u32) -> Option<NonNull<T>> { | ||
let ptr = bpf_map_lookup_elem(self.0.get() as *mut _, &index as *const _ as *const c_void); | ||
NonNull::new(ptr as *mut T) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
use core::{cell::UnsafeCell, ptr}; | ||
|
||
use aya_ebpf_bindings::helpers::{bpf_map_peek_elem, bpf_map_push_elem}; | ||
|
||
use crate::{ | ||
bindings::bpf_map_type::BPF_MAP_TYPE_BLOOM_FILTER, btf_maps::AyaBtfMapMarker, cty::c_void, | ||
}; | ||
|
||
#[allow(dead_code)] | ||
pub struct BloomFilterDef<T, const M: usize, const H: usize = 5, const F: usize = 0> { | ||
r#type: *const [i32; BPF_MAP_TYPE_BLOOM_FILTER as usize], | ||
value: *const T, | ||
max_entries: *const [i32; M], | ||
map_extra: *const [i32; H], | ||
map_flags: *const [i32; F], | ||
|
||
// Anonymize the struct. | ||
_anon: AyaBtfMapMarker, | ||
} | ||
|
||
#[repr(transparent)] | ||
pub struct BloomFilter<T, const M: usize, const H: usize = 5, const F: usize = 0>( | ||
UnsafeCell<BloomFilterDef<T, M, H, F>>, | ||
); | ||
|
||
impl<T, const M: usize, const H: usize, const F: usize> BloomFilter<T, M, H, F> { | ||
pub const fn new() -> Self { | ||
BloomFilter(UnsafeCell::new(BloomFilterDef { | ||
r#type: &[0i32; BPF_MAP_TYPE_BLOOM_FILTER as usize] as *const _, | ||
value: ptr::null(), | ||
max_entries: &[0i32; M] as *const _, | ||
map_extra: &[0i32; H] as *const _, | ||
map_flags: &[0i32; F] as *const _, | ||
_anon: AyaBtfMapMarker::new(), | ||
})) | ||
} | ||
|
||
#[inline] | ||
pub fn contains(&mut self, value: &T) -> Result<(), i64> { | ||
let ret = unsafe { | ||
bpf_map_peek_elem( | ||
&mut self.0.get() as *mut _ as *mut _, | ||
value as *const _ as *mut c_void, | ||
) | ||
}; | ||
(ret == 0).then_some(()).ok_or(ret) | ||
} | ||
|
||
#[inline] | ||
pub fn insert(&mut self, value: &T, flags: u64) -> Result<(), i64> { | ||
let ret = unsafe { | ||
bpf_map_push_elem( | ||
&mut self.0.get() as *mut _ as *mut _, | ||
value as *const _ as *const _, | ||
flags, | ||
) | ||
}; | ||
(ret == 0).then_some(()).ok_or(ret) | ||
} | ||
} |
Oops, something went wrong.