add support for older (and newer) map definitions

pull/14/head
Rafael Ortiz 4 years ago
parent 5f0ff1698a
commit 1404d12a7e

@ -50,13 +50,41 @@ unsafe_impl_pod!(i8, u8, i16, u16, i32, u32, i64, u64);
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub(crate) struct bpf_map_def { pub(crate) struct bpf_map_def {
// minimum features required by old BPF programs
pub(crate) map_type: u32, pub(crate) map_type: u32,
pub(crate) key_size: u32, pub(crate) key_size: u32,
pub(crate) value_size: u32, pub(crate) value_size: u32,
pub(crate) max_entries: u32, pub(crate) max_entries: u32,
pub(crate) map_flags: u32, pub(crate) map_flags: u32,
pub(crate) id: u32, // optional features
pub(crate) pinning: u32, pub(crate) inner_map_fd: u32, // id
pub(crate) numa_node: u32, // pinning
pub(crate) map_name: [u8; BPF_OBJ_NAME_LEN],
pub(crate) map_ifindex: u32,
pub(crate) btf_id: u32,
pub(crate) btf_key_type_id: u32,
pub(crate) btf_value_type_id: u32,
pub(crate) btf_vmlinux_value_type_id: u32,
}
impl Default for bpf_map_def {
fn default() -> Self {
Self {
map_type: 0,
key_size: 0,
value_size: 0,
max_entries: 0,
map_flags: 0,
inner_map_fd: 0,
numa_node: 0,
map_name: [0u8; BPF_OBJ_NAME_LEN],
map_ifindex: 0,
btf_id: 0,
btf_key_type_id: 0,
btf_value_type_id: 0,
btf_vmlinux_value_type_id: 0
}
}
} }
/// The main entry point into the library, used to work with eBPF programs and maps. /// The main entry point into the library, used to work with eBPF programs and maps.

@ -162,9 +162,7 @@ mod tests {
key_size: 4, key_size: 4,
value_size: 4, value_size: 4,
max_entries: 1024, max_entries: 1024,
map_flags: 0, ..Default::default()
id: 0,
pinning: 0,
}, },
section_index: 0, section_index: 0,
data: Vec::new(), data: Vec::new(),
@ -215,9 +213,7 @@ mod tests {
key_size: 4, key_size: 4,
value_size: 4, value_size: 4,
max_entries: 1024, max_entries: 1024,
map_flags: 0, ..Default::default()
id: 0,
pinning: 0,
}, },
section_index: 0, section_index: 0,
data: Vec::new(), data: Vec::new(),
@ -273,9 +269,7 @@ mod tests {
key_size: 4, key_size: 4,
value_size: 4, value_size: 4,
max_entries: 1024, max_entries: 1024,
map_flags: 0, ..Default::default()
id: 0,
pinning: 0,
}, },
section_index: 0, section_index: 0,
data: Vec::new(), data: Vec::new(),

@ -426,9 +426,7 @@ mod tests {
key_size: 4, key_size: 4,
value_size: 4, value_size: 4,
max_entries: 1024, max_entries: 1024,
map_flags: 0, ..Default::default()
id: 0,
pinning: 0,
}, },
section_index: 0, section_index: 0,
data: Vec::new(), data: Vec::new(),

@ -493,8 +493,7 @@ fn parse_map(section: &Section, name: &str) -> Result<Map, ParseError> {
value_size: section.data.len() as u32, value_size: section.data.len() as u32,
max_entries: 1, max_entries: 1,
map_flags: 0, /* FIXME: set rodata readonly */ map_flags: 0, /* FIXME: set rodata readonly */
id: 0, ..Default::default()
pinning: 0,
}; };
(def, section.data.to_vec()) (def, section.data.to_vec())
} else { } else {
@ -510,13 +509,31 @@ fn parse_map(section: &Section, name: &str) -> Result<Map, ParseError> {
} }
fn parse_map_def(name: &str, data: &[u8]) -> Result<bpf_map_def, ParseError> { fn parse_map_def(name: &str, data: &[u8]) -> Result<bpf_map_def, ParseError> {
if mem::size_of::<bpf_map_def>() > data.len() { if mem::size_of::<bpf_map_def>() < data.len() {
return Err(ParseError::InvalidMapDefinition { return Err(ParseError::InvalidMapDefinition {
name: name.to_owned(), name: name.to_owned(),
}); });
} }
Ok(unsafe { ptr::read_unaligned(data.as_ptr() as *const bpf_map_def) }) let mut map_def = bpf_map_def{
..Default::default()
};
unsafe {
// std::ptr::copy is const, we can't use it because data.len() isn't known at
// compile time
let mut p = data.as_ptr();
let mut q = &mut map_def as *mut bpf_map_def as *mut u8;
for _ in 0..=data.len() {
*q = *p;
q = q.add(1);
p = p.add(1);
}
}
Ok(map_def)
//Ok(unsafe { ptr::read_unaligned(data.as_ptr() as *const bpf_map_def) })
} }
fn copy_instructions(data: &[u8]) -> Result<Vec<bpf_insn>, ParseError> { fn copy_instructions(data: &[u8]) -> Result<Vec<bpf_insn>, ParseError> {
@ -657,45 +674,54 @@ mod tests {
#[test] #[test]
fn test_parse_map_def() { fn test_parse_map_def() {
#![allow(unused_variables)] // map_def is used by the assertion
assert!(matches!( assert!(matches!(
parse_map_def("foo", &[]), parse_map_def("foo", &[0u8; std::mem::size_of::<bpf_map_def>() + 10]),
Err(ParseError::InvalidMapDefinition { .. }) Err(ParseError::InvalidMapDefinition { .. })
)); ));
assert!(matches!( let map_def = bpf_map_def {
parse_map_def(
"foo",
bytes_of(&bpf_map_def {
map_type: 1, map_type: 1,
key_size: 2, key_size: 2,
value_size: 3, value_size: 3,
max_entries: 4, max_entries: 4,
map_flags: 5, map_flags: 5,
id: 0, ..Default::default()
pinning: 0 };
}) assert!(matches!(
), parse_map_def(
Ok(bpf_map_def { "foo",
bytes_of(&bpf_map_def {
map_type: 1, map_type: 1,
key_size: 2, key_size: 2,
value_size: 3, value_size: 3,
max_entries: 4, max_entries: 4,
map_flags: 5, map_flags: 5,
id: 0, ..Default::default()
pinning: 0
}) })
),
Ok(map_def)
)); ));
} }
#[test] #[test]
fn test_parse_map_error() { fn test_parse_map_error() {
assert!(matches!( assert!(matches!(
parse_map(&fake_section("maps/foo", &[]), "foo"), parse_map(&fake_section("maps/foo", &[0u8; std::mem::size_of::<bpf_map_def>() + 10]), "foo"),
Err(ParseError::InvalidMapDefinition { .. }) Err(ParseError::InvalidMapDefinition { .. })
)) ))
} }
#[test] #[test]
fn test_parse_map() { fn test_parse_map() {
#![allow(unused_variables)] // def is used by the assertion
let def = bpf_map_def {
map_type: 1,
key_size: 2,
value_size: 3,
max_entries: 4,
map_flags: 5,
..Default::default()
};
assert!(matches!( assert!(matches!(
parse_map( parse_map(
&fake_section( &fake_section(
@ -706,8 +732,7 @@ mod tests {
value_size: 3, value_size: 3,
max_entries: 4, max_entries: 4,
map_flags: 5, map_flags: 5,
id: 0, ..Default::default()
pinning: 0
}) })
), ),
"foo" "foo"
@ -715,15 +740,7 @@ mod tests {
Ok(Map { Ok(Map {
section_index: 0, section_index: 0,
name, name,
def: bpf_map_def { def,
map_type: 1,
key_size: 2,
value_size: 3,
max_entries: 4,
map_flags: 5,
id: 0,
pinning: 0
},
data data
}) if name == "foo" && data.is_empty() }) if name == "foo" && data.is_empty()
)) ))
@ -731,7 +748,18 @@ mod tests {
#[test] #[test]
fn test_parse_map_data() { fn test_parse_map_data() {
#![allow(unused_variables)] // def is used by the assertion
let map_data = b"map data"; let map_data = b"map data";
let _map_type = BPF_MAP_TYPE_ARRAY;
let value_size = map_data.len() as u32;
let def = bpf_map_def {
map_type: _map_type as u32,
key_size: 4,
value_size,
max_entries: 1,
map_flags: 0,
..Default::default()
};
assert!(matches!( assert!(matches!(
parse_map( parse_map(
&fake_section( &fake_section(
@ -743,15 +771,7 @@ mod tests {
Ok(Map { Ok(Map {
section_index: 0, section_index: 0,
name, name,
def: bpf_map_def { def,
map_type: _map_type,
key_size: 4,
value_size,
max_entries: 1,
map_flags: 0,
id: 0,
pinning: 0
},
data data
}) if name == ".bss" && data == map_data && value_size == map_data.len() as u32 }) if name == ".bss" && data == map_data && value_size == map_data.len() as u32
)) ))
@ -809,8 +829,7 @@ mod tests {
value_size: 3, value_size: 3,
max_entries: 4, max_entries: 4,
map_flags: 5, map_flags: 5,
id: 0, ..Default::default()
pinning: 0
}) })
),), ),),
Ok(()) Ok(())

Loading…
Cancel
Save