Browse Source

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 <[email protected]>
astoycos 1 year ago
parent
commit
82039144bd

+ 11 - 0
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;
 }
 

+ 70 - 0
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]

+ 14 - 10
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<u64>; 2] = [null_mut(), null_mut()];
+static mut MULTIMAP_MAPS: [*mut Vec<u64>; 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::<u32>() as u32);
         assert_eq!(map.value_size(), size_of::<u64>() 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);