Skip to content

Commit 978b651

Browse files
committed
aya: simplify map-of-maps to BTF-only
- Drop legacy map-of-maps support - Replace impl_create_map macro with a CreatableMap trait - Unify PerfEventArray/RingBuf into impl_from_map_data via accessor arm - Add fused lookups (get_value/get_value_ptr_mut) for BTF map-of-maps - Rename tests to btf_map_of_maps
1 parent 97047a4 commit 978b651

File tree

23 files changed

+546
-1036
lines changed

23 files changed

+546
-1036
lines changed

aya-ebpf-macros/src/map.rs

Lines changed: 2 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,33 @@
11
use std::borrow::Cow;
22

33
use proc_macro2::TokenStream;
4-
use quote::{format_ident, quote};
4+
use quote::quote;
55
use syn::{ItemStatic, Result};
66

77
use crate::args::Args;
88
pub(crate) struct Map {
99
item: ItemStatic,
1010
name: String,
11-
inner: Option<String>,
1211
}
1312

1413
impl Map {
1514
pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
1615
let item: ItemStatic = syn::parse2(item)?;
1716
let mut args: Args = syn::parse2(attrs)?;
1817
let name = args.pop_name().unwrap_or_else(|| item.ident.to_string());
19-
let inner = args.pop_string("inner");
2018
args.into_error()?;
21-
Ok(Self { item, name, inner })
19+
Ok(Self { item, name })
2220
}
2321

2422
pub(crate) fn expand(&self) -> TokenStream {
2523
let section_name: Cow<'_, _> = "maps".into();
2624
let name = &self.name;
2725
let item = &self.item;
2826

29-
// Aya-specific mechanism for inner map bindings (legacy, NOT libbpf-compatible).
30-
//
31-
// Unlike libbpf which uses BTF relocations within the `.maps` section
32-
// (see https://patchwork.ozlabs.org/comment/2418417/), this legacy `#[map]` macro
33-
// uses a separate `.maps.inner` section containing null-terminated string pairs.
34-
//
35-
// This approach was chosen because the legacy map system doesn't require BTF.
36-
// However, this mechanism is NOT compatible with libbpf loaders.
37-
//
38-
// For libbpf compatibility, use `#[btf_map]` with `aya_ebpf::btf_maps::{ArrayOfMaps, HashOfMaps}`
39-
// which use BTF relocations that both aya and libbpf can process.
40-
//
41-
// Format: "outer_name\0inner_name\0" pairs, parsed by aya-obj.
42-
let inner_binding = self.inner.as_ref().map(|inner| {
43-
let binding_ident = format_ident!("__inner_map_binding_{}", name);
44-
let binding_value = format!("{name}\0{inner}\0");
45-
let binding_len = binding_value.len();
46-
let binding_bytes = binding_value.as_bytes();
47-
quote! {
48-
#[unsafe(link_section = ".maps.inner")]
49-
#[used]
50-
#[allow(non_upper_case_globals)]
51-
static #binding_ident: [u8; #binding_len] = [#(#binding_bytes),*];
52-
}
53-
});
54-
5527
quote! {
5628
#[unsafe(link_section = #section_name)]
5729
#[unsafe(export_name = #name)]
5830
#item
59-
60-
#inner_binding
6131
}
6232
}
6333
}
@@ -104,54 +74,6 @@ mod tests {
10474
assert_eq!(expected.to_string(), expanded.to_string());
10575
}
10676

107-
#[test]
108-
fn test_map_with_inner() {
109-
let map = Map::parse(
110-
parse_quote!(inner = "INNER_TEMPLATE"),
111-
parse_quote!(
112-
static OUTER: Array<u32> = Array::new();
113-
),
114-
)
115-
.unwrap();
116-
let expanded = map.expand();
117-
let binding_bytes: &[u8] = b"OUTER\0INNER_TEMPLATE\0";
118-
let expected = quote!(
119-
#[unsafe(link_section = "maps")]
120-
#[unsafe(export_name = "OUTER")]
121-
static OUTER: Array<u32> = Array::new();
122-
123-
#[unsafe(link_section = ".maps.inner")]
124-
#[used]
125-
#[allow(non_upper_case_globals)]
126-
static __inner_map_binding_OUTER: [u8; 21usize] = [#(#binding_bytes),*];
127-
);
128-
assert_eq!(expected.to_string(), expanded.to_string());
129-
}
130-
131-
#[test]
132-
fn test_map_with_name_and_inner() {
133-
let map = Map::parse(
134-
parse_quote!(name = "my_map", inner = "my_template"),
135-
parse_quote!(
136-
static OUTER: Array<u32> = Array::new();
137-
),
138-
)
139-
.unwrap();
140-
let expanded = map.expand();
141-
let binding_bytes: &[u8] = b"my_map\0my_template\0";
142-
let expected = quote!(
143-
#[unsafe(link_section = "maps")]
144-
#[unsafe(export_name = "my_map")]
145-
static OUTER: Array<u32> = Array::new();
146-
147-
#[unsafe(link_section = ".maps.inner")]
148-
#[used]
149-
#[allow(non_upper_case_globals)]
150-
static __inner_map_binding_my_map: [u8; 19usize] = [#(#binding_bytes),*];
151-
);
152-
assert_eq!(expected.to_string(), expanded.to_string());
153-
}
154-
15577
#[test]
15678
fn test_map_unknown_arg() {
15779
let result = Map::parse(

aya-obj/src/maps.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,6 @@ impl Map {
282282
}
283283

284284
/// Creates a new legacy map definition programmatically.
285-
///
286-
/// This is useful for creating inner maps dynamically for map-of-maps types.
287285
pub const fn new_legacy(
288286
map_type: u32,
289287
key_size: u32,

aya-obj/src/obj.rs

Lines changed: 0 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,6 @@ pub struct Object {
147147
pub programs: HashMap<String, Program>,
148148
/// Functions
149149
pub functions: BTreeMap<(usize, u64), Function>,
150-
/// Inner map bindings: maps outer map name to inner (template) map name.
151-
pub(crate) inner_map_bindings: HashMap<String, String>,
152150
pub(crate) relocations: HashMap<SectionIndex, HashMap<u64, Relocation>>,
153151
pub(crate) symbol_table: HashMap<usize, Symbol>,
154152
pub(crate) symbols_by_section: HashMap<SectionIndex, Vec<usize>>,
@@ -533,7 +531,6 @@ impl Object {
533531
maps: HashMap::new(),
534532
programs: HashMap::new(),
535533
functions: BTreeMap::new(),
536-
inner_map_bindings: HashMap::new(),
537534
relocations: HashMap::new(),
538535
symbol_table: HashMap::new(),
539536
symbols_by_section: HashMap::new(),
@@ -892,86 +889,12 @@ impl Object {
892889
);
893890
}
894891
}
895-
EbpfSectionKind::MapsInner => self.parse_maps_inner(&section)?,
896892
EbpfSectionKind::Undefined | EbpfSectionKind::License | EbpfSectionKind::Version => {}
897893
}
898894

899895
Ok(())
900896
}
901897

902-
/// Parses the `.maps.inner` section which contains outer->inner map bindings.
903-
///
904-
/// This is an aya-specific mechanism for declaring inner map bindings at compile time,
905-
/// used by the legacy `#[map(inner = "...")]` macro. This mechanism is NOT compatible
906-
/// with libbpf loaders.
907-
///
908-
/// Unlike libbpf which uses BTF relocations within the `.maps` section
909-
/// (see <https://patchwork.ozlabs.org/comment/2418417/>), this legacy system uses a
910-
/// separate section containing null-terminated string pairs.
911-
///
912-
/// For libbpf compatibility, use `#[btf_map]` with `aya_ebpf::btf_maps::{ArrayOfMaps, HashOfMaps}`
913-
/// which use BTF relocations that both aya and libbpf can process.
914-
///
915-
/// Format: `"outer_name\0inner_name\0"` pairs, emitted by the `#[map(inner = "...")]` macro.
916-
fn parse_maps_inner(&mut self, section: &Section<'_>) -> Result<(), ParseError> {
917-
let data = section.data;
918-
let mut offset = 0;
919-
920-
while offset < data.len() {
921-
// Read outer map name (null-terminated).
922-
let Some(outer_len) = data[offset..].iter().position(|&b| b == 0) else {
923-
return Err(ParseError::InvalidMapsInnerSection {
924-
offset,
925-
msg: "unterminated outer map name",
926-
});
927-
};
928-
929-
let outer_name =
930-
core::str::from_utf8(&data[offset..offset + outer_len]).map_err(|_utf8_err| {
931-
ParseError::InvalidMapsInnerSection {
932-
offset,
933-
msg: "invalid UTF-8 in outer map name",
934-
}
935-
})?;
936-
offset += outer_len + 1; // skip null terminator
937-
938-
// Read inner map name (null-terminated).
939-
let Some(inner_len) = data[offset..].iter().position(|&b| b == 0) else {
940-
return Err(ParseError::InvalidMapsInnerSection {
941-
offset,
942-
msg: "unterminated inner map name",
943-
});
944-
};
945-
946-
let inner_name =
947-
core::str::from_utf8(&data[offset..offset + inner_len]).map_err(|_utf8_err| {
948-
ParseError::InvalidMapsInnerSection {
949-
offset,
950-
msg: "invalid UTF-8 in inner map name",
951-
}
952-
})?;
953-
offset += inner_len + 1; // skip null terminator
954-
955-
if outer_name.is_empty() || inner_name.is_empty() {
956-
return Err(ParseError::InvalidMapsInnerSection {
957-
offset,
958-
msg: "empty outer or inner map name",
959-
});
960-
}
961-
962-
self.inner_map_bindings
963-
.insert(outer_name.to_owned(), inner_name.to_owned());
964-
}
965-
966-
Ok(())
967-
}
968-
969-
/// Returns the inner (template) map name bound to the given outer map, if
970-
/// any. These bindings are parsed from the `.maps.inner` ELF section.
971-
pub fn inner_map_binding(&self, outer: &str) -> Option<&str> {
972-
self.inner_map_bindings.get(outer).map(String::as_str)
973-
}
974-
975898
/// Sanitize BPF functions.
976899
pub fn sanitize_functions(&mut self, features: &Features) {
977900
for function in self.functions.values_mut() {
@@ -1089,15 +1012,6 @@ pub enum ParseError {
10891012
/// No BTF parsed for object
10901013
#[error("no BTF parsed for object")]
10911014
NoBTF,
1092-
1093-
/// Invalid `.maps.inner` section data.
1094-
#[error("invalid `.maps.inner` section at offset {offset}: {msg}")]
1095-
InvalidMapsInnerSection {
1096-
/// Byte offset within the section where the error occurred.
1097-
offset: usize,
1098-
/// Description of the error.
1099-
msg: &'static str,
1100-
},
11011015
}
11021016

11031017
/// Invalid bindings to the bpf type from the parsed/received value.
@@ -1115,8 +1029,6 @@ pub enum EbpfSectionKind {
11151029
Maps,
11161030
/// `.maps`
11171031
BtfMaps,
1118-
/// `.maps.inner`
1119-
MapsInner,
11201032
/// A program section
11211033
Program,
11221034
/// `.data`
@@ -1145,10 +1057,6 @@ impl EbpfSectionKind {
11451057
Self::Version
11461058
} else if name.starts_with("maps") {
11471059
Self::Maps
1148-
// NB: `.maps.inner` must be matched before `.maps` to avoid being
1149-
// swallowed by the `.starts_with(".maps")` arm below.
1150-
} else if name == ".maps.inner" {
1151-
Self::MapsInner
11521060
} else if name.starts_with(".maps") {
11531061
Self::BtfMaps
11541062
} else if name.starts_with(".text") {

aya/src/bpf.rs

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -557,25 +557,13 @@ impl<'a> EbpfLoader<'a> {
557557
// The kernel requires an inner map fd when creating a map-of-maps.
558558
let btf_inner_map;
559559
let inner_map_fd = if is_map_of_maps {
560-
if let Some(inner) = map_obj.inner() {
561-
// Try using a BTF definition of the inner map.
562-
btf_inner_map = MapData::create(inner, &format!("{name}.inner"), btf_fd)?;
563-
Some(btf_inner_map.fd().as_fd())
564-
} else {
565-
// No BTF inner definition; fall back to the `.maps.inner` binding.
566-
let inner_name = obj.inner_map_binding(&name).ok_or_else(|| {
567-
EbpfError::MapError(MapError::MissingInnerMapBinding {
568-
outer_name: name.clone(),
569-
})
570-
})?;
571-
let inner_map = maps.get(inner_name).ok_or_else(|| {
572-
EbpfError::MapError(MapError::InnerMapNotFound {
573-
outer_name: name.clone(),
574-
inner_name: inner_name.to_owned(),
575-
})
576-
})?;
577-
Some(inner_map.fd().as_fd())
578-
}
560+
let inner = map_obj.inner().ok_or_else(|| {
561+
EbpfError::MapError(MapError::MissingInnerMapDefinition {
562+
outer_name: name.clone(),
563+
})
564+
})?;
565+
btf_inner_map = MapData::create(inner, &format!("{name}.inner"), btf_fd)?;
566+
Some(btf_inner_map.fd().as_fd())
579567
} else {
580568
None
581569
};

0 commit comments

Comments
 (0)