Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions aya-ebpf-macros/src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ impl Map {
let section_name: Cow<'_, _> = "maps".into();
let name = &self.name;
let item = &self.item;

quote! {
#[unsafe(link_section = #section_name)]
#[unsafe(export_name = #name)]
Expand Down Expand Up @@ -72,4 +73,18 @@ mod tests {
);
assert_eq!(expected.to_string(), expanded.to_string());
}

#[test]
fn test_map_unknown_arg() {
let result = Map::parse(
parse_quote!(unknown = "foo"),
parse_quote!(
static BAR: HashMap<&'static str, u32> = HashMap::new();
),
);
let Err(err) = result else {
panic!("expected parse error for unknown argument")
};
assert_eq!(err.to_string(), "invalid argument");
}
}
21 changes: 21 additions & 0 deletions aya-obj/src/btf/btf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,27 @@ pub enum BtfError {
/// unable to get symbol name
#[error("Unable to get symbol name")]
InvalidSymbolName,

/// Inner map definition cannot be pinned.
#[error("BTF map `{name}`: inner map definition cannot be pinned")]
InnerMapCannotBePinned {
/// The name of the map with the invalid definition.
name: String,
},

/// Multi-level map-in-map is not supported.
#[error("BTF map `{name}`: multi-level map-in-map is not supported")]
MultiLevelMapInMapNotSupported {
/// The name of the map with the invalid definition.
name: String,
},

/// The `values` spec must be a zero-sized array.
#[error("BTF map `{name}`: `values` spec is not a zero-sized array")]
InvalidValuesSpec {
/// The name of the map with the invalid definition.
name: String,
},
}

/// Available BTF features
Expand Down
59 changes: 59 additions & 0 deletions aya-obj/src/maps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,61 @@ impl Map {
Self::Btf(m) => Some(m.symbol_index),
}
}

/// Returns the inner map definition, in case of a map of maps.
pub fn inner(&self) -> Option<Self> {
match self {
Self::Legacy(m) => m.inner_def.as_ref().map(|inner_def| {
Self::Legacy(LegacyMap {
def: *inner_def,
inner_def: None,
// The inner map is a synthetic object with no ELF presence
// of its own, so use neutral metadata values.
section_index: 0,
section_kind: EbpfSectionKind::Undefined,
symbol_index: None,
data: Vec::new(),
})
}),
Self::Btf(m) => m.inner_def.as_ref().map(|inner_def| {
Self::Btf(BtfMap {
def: *inner_def,
inner_def: None,
// The inner map is a synthetic object with no ELF presence
// of its own, so use neutral metadata values.
section_index: 0,
symbol_index: 0,
data: Vec::new(),
})
}),
}
}

/// Creates a new map definition from raw parameters.
pub const fn new_from_params(
map_type: u32,
key_size: u32,
value_size: u32,
max_entries: u32,
flags: u32,
) -> Self {
Self::Legacy(LegacyMap {
def: bpf_map_def {
map_type,
key_size,
value_size,
max_entries,
map_flags: flags,
id: 0,
pinning: PinningType::None,
},
inner_def: None,
section_index: 0,
section_kind: EbpfSectionKind::Undefined,
symbol_index: None,
data: Vec::new(),
})
}
}

/// A map declared with legacy BPF map declaration style, most likely from a `maps` section.
Expand All @@ -261,6 +316,8 @@ impl Map {
pub struct LegacyMap {
/// The definition of the map
pub def: bpf_map_def,
/// The definition of the inner map, in case of a map of maps.
pub inner_def: Option<bpf_map_def>,
/// The section index
pub section_index: usize,
/// The section kind
Expand All @@ -280,6 +337,8 @@ pub struct LegacyMap {
pub struct BtfMap {
/// The definition of the map
pub def: BtfMapDef,
/// The definition of the inner map, in case of a map of maps.
pub(crate) inner_def: Option<BtfMapDef>,
pub(crate) section_index: usize,
pub(crate) symbol_index: usize,
pub(crate) data: Vec<u8>,
Expand Down
84 changes: 80 additions & 4 deletions aya-obj/src/obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use object::{
use crate::{
btf::{
Array, Btf, BtfError, BtfExt, BtfFeatures, BtfType, DataSecEntry, FuncSecInfo, LineSecInfo,
Struct,
},
generated::{
BPF_CALL, BPF_F_RDONLY_PROG, BPF_JMP, BPF_K, bpf_func_id, bpf_insn, bpf_map_info,
Expand Down Expand Up @@ -770,7 +771,7 @@ impl Object {
if type_name == section.name {
// each btf_var_secinfo contains a map
for info in &datasec.entries {
let (map_name, def) = parse_btf_map_def(btf, info)?;
let (map_name, def, inner_def) = parse_btf_map_def(btf, info)?;
let symbol_index =
maps.get(&map_name)
.ok_or_else(|| ParseError::SymbolNotFound {
Expand All @@ -780,6 +781,7 @@ impl Object {
map_name,
Map::Btf(BtfMap {
def,
inner_def,
section_index: section.index.0,
symbol_index: *symbol_index,
data: Vec::new(),
Expand Down Expand Up @@ -825,6 +827,7 @@ impl Object {
section_kind: section.kind,
symbol_index: Some(sym.index),
def,
inner_def: None,
data: Vec::new(),
}),
);
Expand Down Expand Up @@ -1240,6 +1243,7 @@ fn parse_data_map_section(section: &Section<'_>) -> Map {
// Data maps don't require symbols to be relocated
symbol_index: None,
def,
inner_def: None,
data,
})
}
Expand All @@ -1263,7 +1267,10 @@ fn parse_map_def(name: &str, data: &[u8]) -> Result<bpf_map_def, ParseError> {
}
}

fn parse_btf_map_def(btf: &Btf, info: &DataSecEntry) -> Result<(String, BtfMapDef), BtfError> {
fn parse_btf_map_def(
btf: &Btf,
info: &DataSecEntry,
) -> Result<(String, BtfMapDef, Option<BtfMapDef>), BtfError> {
let ty = match btf.type_by_id(info.btf_type)? {
BtfType::Var(var) => var,
other => {
Expand All @@ -1273,7 +1280,6 @@ fn parse_btf_map_def(btf: &Btf, info: &DataSecEntry) -> Result<(String, BtfMapDe
}
};
let map_name = btf.string_at(ty.name_offset)?;
let mut map_def = BtfMapDef::default();

let root_type = btf.resolve_type(ty.btf_type)?;
let s = match btf.type_by_id(root_type)? {
Expand All @@ -1285,6 +1291,23 @@ fn parse_btf_map_def(btf: &Btf, info: &DataSecEntry) -> Result<(String, BtfMapDe
}
};

let (map_def, inner_def) = parse_btf_map_struct(btf, s, &map_name, false)?;
Ok((map_name.to_string(), map_def, inner_def))
}

/// Parses BTF struct members into a map definition.
///
/// When `is_inner` is true, rejects `values` and `pinning` fields, matching
/// libbpf behavior for inner map definitions.
fn parse_btf_map_struct(
btf: &Btf,
s: &Struct,
map_name: &str,
is_inner: bool,
) -> Result<(BtfMapDef, Option<BtfMapDef>), BtfError> {
let mut map_def = BtfMapDef::default();
let mut inner_map_def = None;

for m in &s.members {
match btf.string_at(m.name_offset)?.as_ref() {
"type" => {
Expand Down Expand Up @@ -1325,18 +1348,67 @@ fn parse_btf_map_def(btf: &Btf, info: &DataSecEntry) -> Result<(String, BtfMapDe
map_def.map_flags = get_map_field(btf, m.btf_type)?;
}
"pinning" => {
if is_inner {
return Err(BtfError::InnerMapCannotBePinned {
name: map_name.to_owned(),
});
}
let pinning = get_map_field(btf, m.btf_type)?;
map_def.pinning = PinningType::try_from(pinning).unwrap_or_else(|_| {
debug!("{pinning} is not a valid pin type. using PIN_NONE");
PinningType::None
});
}
"values" => {
if is_inner {
return Err(BtfError::MultiLevelMapInMapNotSupported {
name: map_name.to_owned(),
});
}
// The inner map type is encoded as a zero-length array of pointers
// to the inner struct, matching libbpf's parse_btf_map_def().
let arr = match btf.type_by_id(m.btf_type)? {
BtfType::Array(Array { array, .. }) => array,
other => {
return Err(BtfError::UnexpectedBtfType {
type_id: other.btf_type().unwrap_or(0),
});
}
};
if arr.len != 0 {
return Err(BtfError::InvalidValuesSpec {
name: map_name.to_owned(),
});
}
let elem_type_id = btf.resolve_type(arr.element_type)?;
let ptr = match btf.type_by_id(elem_type_id)? {
BtfType::Ptr(ptr) => ptr,
other => {
return Err(BtfError::UnexpectedBtfType {
type_id: other.btf_type().unwrap_or(0),
});
}
};
let inner_struct_id = btf.resolve_type(ptr.btf_type)?;
let inner_s = match btf.type_by_id(inner_struct_id)? {
BtfType::Struct(s) => s,
other => {
return Err(BtfError::UnexpectedBtfType {
type_id: other.btf_type().unwrap_or(0),
});
}
};
let (inner_def, _) = parse_btf_map_struct(btf, inner_s, map_name, true)?;
inner_map_def = Some(inner_def);
// Map-of-maps value is always an fd (u32).
map_def.value_size = size_of::<u32>() as u32;
}
other => {
debug!("skipping unknown map section: {other}");
}
}
}
Ok((map_name.to_string(), map_def))
Ok((map_def, inner_map_def))
}

/// Parses a [`bpf_map_info`] into a [`Map`].
Expand All @@ -1353,6 +1425,7 @@ pub const fn parse_map_info(info: bpf_map_info, pinned: PinningType) -> Map {
btf_key_type_id: info.btf_key_type_id,
btf_value_type_id: info.btf_value_type_id,
},
inner_def: None,
section_index: 0,
symbol_index: 0,
data: Vec::new(),
Expand All @@ -1368,6 +1441,7 @@ pub const fn parse_map_info(info: bpf_map_info, pinned: PinningType) -> Map {
pinning: pinned,
id: info.id,
},
inner_def: None,
section_index: 0,
symbol_index: None,
section_kind: EbpfSectionKind::Undefined,
Expand Down Expand Up @@ -1632,6 +1706,7 @@ mod tests {
pinning: PinningType::None,
},
data,
..
}) if data == map_data && value_size == map_data.len() as u32
)
}
Expand Down Expand Up @@ -2629,6 +2704,7 @@ mod tests {
id: 1,
pinning: PinningType::None,
},
inner_def: None,
section_index: 1,
section_kind: EbpfSectionKind::Rodata,
symbol_index: Some(1),
Expand Down
2 changes: 2 additions & 0 deletions aya-obj/src/relocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ mod test {
fn fake_legacy_map(symbol_index: usize) -> Map {
Map::Legacy(LegacyMap {
def: Default::default(),
inner_def: None,
section_index: 0,
section_kind: EbpfSectionKind::Undefined,
symbol_index: Some(symbol_index),
Expand All @@ -529,6 +530,7 @@ mod test {
fn fake_btf_map(symbol_index: usize) -> Map {
Map::Btf(BtfMap {
def: Default::default(),
inner_def: None,
section_index: 0,
symbol_index,
data: Vec::new(),
Expand Down
Loading