From 82039144bdf7d46d536b62d94d29268990180294 Mon Sep 17 00:00:00 2001 From: astoycos Date: Fri, 22 Sep 2023 10:37:57 -0400 Subject: [PATCH] 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 --- test/integration-test/bpf/multimap-btf.bpf.c | 11 +++ test/integration-test/src/tests/load.rs | 70 ++++++++++++++++++++ test/integration-test/src/tests/rbpf.rs | 24 ++++--- 3 files changed, 95 insertions(+), 10 deletions(-) diff --git a/test/integration-test/bpf/multimap-btf.bpf.c b/test/integration-test/bpf/multimap-btf.bpf.c index f6d34bcf..9e595165 100644 --- a/test/integration-test/bpf/multimap-btf.bpf.c +++ b/test/integration-test/bpf/multimap-btf.bpf.c @@ -17,13 +17,24 @@ struct { __uint(max_entries, 1); } 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") int bpf_prog(void *ctx) { __u32 key = 0; __u64 twenty_four = 24; __u64 forty_two = 42; + __u64 forty_four = 44; + 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_pin_by_name, &key, &forty_four, BPF_ANY); return 0; } diff --git a/test/integration-test/src/tests/load.rs b/test/integration-test/src/tests/load.rs index 5e193dbf..685867e9 100644 --- a/test/integration-test/src/tests/load.rs +++ b/test/integration-test/src/tests/load.rs @@ -1,5 +1,7 @@ use std::{ convert::TryInto as _, + fs::remove_file, + path::Path, thread, time::{Duration, SystemTime}, }; @@ -40,6 +42,8 @@ fn multiple_btf_maps() { 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_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(); @@ -51,9 +55,75 @@ fn multiple_btf_maps() { 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_pin = Path::new("/sys/fs/bpf/map_pin_by_name"); + assert!(&map_pin.exists()); + + remove_file(map_pin).unwrap(); +} + +#[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_path = Path::new("/sys/fs/bpf/map_pin_by_name"); + + assert!(map_pin_by_name_path.exists()); + remove_file(map_pin_by_name_path).unwrap(); + + // 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 = &Path::new("/sys/fs/bpf/").join(i.to_string()); + + map.pin(map_pin_path).unwrap(); + + assert!(map_pin_path.exists()); + remove_file(map_pin_path).unwrap(); + } + + 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 = Path::new("/sys/fs/bpf/map_1"); + let map_2_pin_path = Path::new("/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()); + + remove_file(map_1_pin_path).unwrap(); + remove_file(map_2_pin_path).unwrap(); + remove_file(map_pin_by_name_path).unwrap(); } #[no_mangle] diff --git a/test/integration-test/src/tests/rbpf.rs b/test/integration-test/src/tests/rbpf.rs index 3d2c0c97..d2aeafd8 100644 --- a/test/integration-test/src/tests/rbpf.rs +++ b/test/integration-test/src/tests/rbpf.rs @@ -34,7 +34,7 @@ fn run_with_rbpf() { assert_eq!(vm.execute_program().unwrap(), XDP_PASS); } -static mut MULTIMAP_MAPS: [*mut Vec; 2] = [null_mut(), null_mut()]; +static mut MULTIMAP_MAPS: [*mut Vec; 3] = [null_mut(); 3]; #[test] fn use_map_with_rbpf() { @@ -47,11 +47,11 @@ fn use_map_with_rbpf() { ); // 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, // so we keeps the pointers to our maps in MULTIMAP_MAPS, to be used in helpers. 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() { assert_eq!(map.key_size(), size_of::() as u32); assert_eq!(map.value_size(), size_of::() as u32); @@ -60,8 +60,14 @@ fn use_map_with_rbpf() { aya_obj::generated::bpf_map_type::BPF_MAP_TYPE_ARRAY as u32 ); - let map_id = if name == "map_1" { 0 } else { 1 }; - let fd = map_id as std::os::fd::RawFd | 0xCAFE00; + let map_id = match name.as_str() { + "map_1" => 0, + "map_2" => 1, + "map_pin_by_name" => 2, + n => panic!("Unexpected map: {n}"), + }; + + let fd = map_id as i32 | 0xCAFE00; maps.insert(name.to_owned(), (fd, map.clone())); unsafe { @@ -102,18 +108,16 @@ fn use_map_with_rbpf() { .expect("Helper failed"); assert_eq!(vm.execute_program().unwrap(), 0); - assert_eq!(map_instances[0][0], 24); - assert_eq!(map_instances[1][0], 42); + assert_eq!(map_instances, [[24], [42], [44]]); unsafe { - MULTIMAP_MAPS[0] = null_mut(); - MULTIMAP_MAPS[1] = null_mut(); + MULTIMAP_MAPS.iter_mut().for_each(|v| *v = null_mut()); } } #[track_caller] 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 value = *unsafe { (value as usize as *const u64).as_ref().unwrap() }; assert_eq!(key, 0);