integration-test: Add map pinning coverage

Add coverage to the new public api's for
map pinning (pin and unpin) which can be called
on the generic aya::Map type OR explit map types.

Additionally add coverage for the new libbpf
LIBBPF_PIN_BY_NAME behavior.

Signed-off-by: astoycos <astoycos@redhat.com>
reviewable/pr783/r3
astoycos 2 years ago
parent e002b6fa08
commit e1ba78e9df

@ -17,13 +17,24 @@ struct {
__uint(max_entries, 1); __uint(max_entries, 1);
} map_2 SEC(".maps"); } map_2 SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__type(key, __u32);
__type(value, __u64);
__uint(max_entries, 1);
__uint(pinning, LIBBPF_PIN_BY_NAME);
} map_pin_by_name SEC(".maps");
SEC("uprobe") SEC("uprobe")
int bpf_prog(void *ctx) { int bpf_prog(void *ctx) {
__u32 key = 0; __u32 key = 0;
__u64 twenty_four = 24; __u64 twenty_four = 24;
__u64 forty_two = 42; __u64 forty_two = 42;
__u64 forty_four = 44;
bpf_map_update_elem(&map_1, &key, &twenty_four, BPF_ANY); bpf_map_update_elem(&map_1, &key, &twenty_four, BPF_ANY);
bpf_map_update_elem(&map_2, &key, &forty_two, BPF_ANY); bpf_map_update_elem(&map_2, &key, &forty_two, BPF_ANY);
bpf_map_update_elem(&map_pin_by_name, &key, &forty_four, BPF_ANY);
return 0; return 0;
} }

@ -1,4 +1,4 @@
use std::{convert::TryInto as _, thread, time}; use std::{convert::TryInto as _, path::PathBuf, thread, time};
use aya::{ use aya::{
maps::Array, maps::Array,
@ -35,6 +35,8 @@ fn multiple_btf_maps() {
let map_1: Array<_, u64> = bpf.take_map("map_1").unwrap().try_into().unwrap(); let map_1: Array<_, u64> = bpf.take_map("map_1").unwrap().try_into().unwrap();
let map_2: Array<_, u64> = bpf.take_map("map_2").unwrap().try_into().unwrap(); let map_2: Array<_, u64> = bpf.take_map("map_2").unwrap().try_into().unwrap();
let mut map_pin_by_name: Array<_, u64> =
bpf.take_map("map_pin_by_name").unwrap().try_into().unwrap();
let prog: &mut UProbe = bpf.program_mut("bpf_prog").unwrap().try_into().unwrap(); let prog: &mut UProbe = bpf.program_mut("bpf_prog").unwrap().try_into().unwrap();
prog.load().unwrap(); prog.load().unwrap();
@ -46,9 +48,81 @@ fn multiple_btf_maps() {
let key = 0; let key = 0;
let val_1 = map_1.get(&key, 0).unwrap(); let val_1 = map_1.get(&key, 0).unwrap();
let val_2 = map_2.get(&key, 0).unwrap(); let val_2 = map_2.get(&key, 0).unwrap();
let val_3 = map_pin_by_name.get(&key, 0).unwrap();
assert_eq!(val_1, 24); assert_eq!(val_1, 24);
assert_eq!(val_2, 42); assert_eq!(val_2, 42);
assert_eq!(val_3, 44);
let map_pin = PathBuf::from("/sys/fs/bpf/map_pin_by_name");
assert!(&map_pin.exists());
map_pin_by_name.unpin(map_pin.clone()).unwrap();
assert!(!map_pin.exists());
}
#[test]
fn pin_lifecycle_multiple_btf_maps() {
let mut bpf = Bpf::load(crate::MULTIMAP_BTF).unwrap();
// "map_pin_by_name" should already be pinned, unpin and pin again later
let map_pin_by_name = bpf.map_mut("map_pin_by_name").unwrap();
let map_pin_by_name_path = &PathBuf::from("/sys/fs/bpf/map_pin_by_name");
assert!(map_pin_by_name_path.exists());
map_pin_by_name.unpin(map_pin_by_name_path).unwrap();
assert!(!map_pin_by_name_path.exists());
// pin and unpin all maps before casting to explicit types
for (i, (name, map)) in bpf.maps_mut().enumerate() {
// Don't pin system maps or the map that's already pinned by name.
if name.contains(".rodata") || name.contains(".bss") {
continue;
}
let map_pin_path = &PathBuf::from("/sys/fs/bpf/").join(i.to_string());
map.pin(map_pin_path).unwrap();
assert!(map_pin_path.exists());
map.unpin(map_pin_path).unwrap();
assert!(!map_pin_path.exists());
}
let mut map_1: Array<_, u64> = bpf.take_map("map_1").unwrap().try_into().unwrap();
let mut map_2: Array<_, u64> = bpf.take_map("map_2").unwrap().try_into().unwrap();
let mut map_pin_by_name: Array<_, u64> =
bpf.take_map("map_pin_by_name").unwrap().try_into().unwrap();
let prog: &mut UProbe = bpf.program_mut("bpf_prog").unwrap().try_into().unwrap();
prog.load().unwrap();
prog.attach(Some("trigger_bpf_program"), 0, "/proc/self/exe", None)
.unwrap();
trigger_bpf_program();
let key = 0;
let val_1 = map_1.get(&key, 0).unwrap();
let val_2 = map_2.get(&key, 0).unwrap();
let val_3 = map_pin_by_name.get(&key, 0).unwrap();
assert_eq!(val_1, 24);
assert_eq!(val_2, 42);
assert_eq!(val_3, 44);
let map_1_pin_path = &PathBuf::from("/sys/fs/bpf/map_1");
let map_2_pin_path = &PathBuf::from("/sys/fs/bpf/map_2");
map_1.pin(map_1_pin_path).unwrap();
map_2.pin(map_2_pin_path).unwrap();
map_pin_by_name.pin(map_pin_by_name_path).unwrap();
assert!(map_1_pin_path.exists());
assert!(map_2_pin_path.exists());
assert!(map_pin_by_name_path.exists());
map_1.unpin(map_1_pin_path).unwrap();
map_2.unpin(map_2_pin_path).unwrap();
map_pin_by_name.unpin(map_pin_by_name_path).unwrap();
assert!(!map_1_pin_path.exists());
assert!(!map_2_pin_path.exists());
assert!(!map_pin_by_name_path.exists());
} }
#[no_mangle] #[no_mangle]

@ -31,7 +31,7 @@ fn run_with_rbpf() {
assert_eq!(vm.execute_program().unwrap(), XDP_PASS); assert_eq!(vm.execute_program().unwrap(), XDP_PASS);
} }
static mut MULTIMAP_MAPS: [*mut Vec<u64>; 2] = [null_mut(), null_mut()]; static mut MULTIMAP_MAPS: [*mut Vec<u64>; 3] = [null_mut(), null_mut(), null_mut()];
#[test] #[test]
fn use_map_with_rbpf() { fn use_map_with_rbpf() {
@ -44,11 +44,11 @@ fn use_map_with_rbpf() {
); );
// Initialize maps: // Initialize maps:
// - fd: 0xCAFE00 or 0xCAFE01 (the 0xCAFE00 part is used to distinguish fds from indices), // - fd: Bitwise OR of the map_id with 0xCAFE00 (used to distinguish fds from indices),
// - Note that rbpf does not convert fds into real pointers, // - Note that rbpf does not convert fds into real pointers,
// so we keeps the pointers to our maps in MULTIMAP_MAPS, to be used in helpers. // so we keeps the pointers to our maps in MULTIMAP_MAPS, to be used in helpers.
let mut maps = HashMap::new(); let mut maps = HashMap::new();
let mut map_instances = vec![vec![0u64], vec![0u64]]; let mut map_instances = vec![vec![0u64], vec![0u64], vec![0u64]];
for (name, map) in object.maps.iter() { for (name, map) in object.maps.iter() {
assert_eq!(map.key_size(), size_of::<u32>() as u32); assert_eq!(map.key_size(), size_of::<u32>() as u32);
assert_eq!(map.value_size(), size_of::<u64>() as u32); assert_eq!(map.value_size(), size_of::<u64>() as u32);
@ -57,8 +57,14 @@ fn use_map_with_rbpf() {
aya_obj::generated::bpf_map_type::BPF_MAP_TYPE_ARRAY as u32 aya_obj::generated::bpf_map_type::BPF_MAP_TYPE_ARRAY as u32
); );
let map_id = if name == "map_1" { 0 } else { 1 }; let map_id = if name == "map_1" {
let fd = map_id as std::os::fd::RawFd | 0xCAFE00; 0
} else if name == "map_2" {
1
} else {
2
};
let fd = map_id as i32 | 0xCAFE00;
maps.insert(name.to_owned(), (fd, map.clone())); maps.insert(name.to_owned(), (fd, map.clone()));
unsafe { unsafe {
@ -99,18 +105,16 @@ fn use_map_with_rbpf() {
.expect("Helper failed"); .expect("Helper failed");
assert_eq!(vm.execute_program().unwrap(), 0); assert_eq!(vm.execute_program().unwrap(), 0);
assert_eq!(map_instances[0][0], 24); assert_eq!(map_instances, [[24], [42], [44],]);
assert_eq!(map_instances[1][0], 42);
unsafe { unsafe {
MULTIMAP_MAPS[0] = null_mut(); MULTIMAP_MAPS.iter_mut().for_each(|v| *v = null_mut());
MULTIMAP_MAPS[1] = null_mut();
} }
} }
#[track_caller] #[track_caller]
fn bpf_map_update_elem_multimap(map: u64, key: u64, value: u64, _: u64, _: u64) -> u64 { fn bpf_map_update_elem_multimap(map: u64, key: u64, value: u64, _: u64, _: u64) -> u64 {
assert_matches!(map, 0xCAFE00 | 0xCAFE01); assert_matches!(map, 0xCAFE00 | 0xCAFE01 | 0xCAFE02);
let key = *unsafe { (key as usize as *const u32).as_ref().unwrap() }; let key = *unsafe { (key as usize as *const u32).as_ref().unwrap() };
let value = *unsafe { (value as usize as *const u64).as_ref().unwrap() }; let value = *unsafe { (value as usize as *const u64).as_ref().unwrap() };
assert_eq!(key, 0); assert_eq!(key, 0);

Loading…
Cancel
Save