aya: fix map_pin_path logic

If a user specifies map_pin_path then the maps should ALWAYS be
pinned by name at that path, or consumed from existing pins.

Add an integration test to verify this logic is functioning as
expected.

Signed-off-by: astoycos <astoycos@redhat.com>
fix-verifier-blixt
astoycos 11 months ago
parent a381022fca
commit 5dc007caf5

@ -490,7 +490,19 @@ impl<'a> BpfLoader<'a> {
}
let btf_fd = btf_fd.as_deref().map(|fd| fd.as_fd());
let mut map = match obj.pinning() {
PinningType::None => MapData::create(obj, &name, btf_fd)?,
PinningType::None => {
// If map_pin_path is provided be sure to create the maps if they don't exist
// and pin by name at the provided path.
if let BpfSectionKind::Bss | BpfSectionKind::Rodata | BpfSectionKind::Data =
obj.section_kind()
{
MapData::create(obj, &name, btf_fd)?
} else if let Some(path) = map_pin_path {
MapData::create_pinned_by_name(path, obj, &name, btf_fd)?
} else {
MapData::create(obj, &name, btf_fd)?
}
}
PinningType::ByName => {
// pin maps in /sys/fs/bpf by default to align with libbpf
// behavior https://github.com/libbpf/libbpf/blob/v1.2.2/src/libbpf.c#L2161.

@ -7,21 +7,21 @@ struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__type(key, __u32);
__type(value, __u64);
__uint(max_entries, 1);
__uint(max_entries, 2);
} map_1 SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__type(key, __u32);
__type(value, __u64);
__uint(max_entries, 1);
__uint(max_entries, 2);
} map_2 SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__type(key, __u32);
__type(value, __u64);
__uint(max_entries, 1);
__uint(max_entries, 2);
__uint(pinning, LIBBPF_PIN_BY_NAME);
} map_pin_by_name SEC(".maps");
@ -38,4 +38,17 @@ int bpf_prog(void *ctx) {
return 0;
}
SEC("uprobe")
int bpf_prog1(void *ctx) {
__u32 key = 1;
__u64 twenty_four = 35;
__u64 forty_two = 53;
__u64 forty_four = 55;
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;
}
char _license[] SEC("license") = "GPL";

@ -1,6 +1,6 @@
use std::{
convert::TryInto as _,
fs::remove_file,
fs::{create_dir, remove_dir_all, remove_file},
path::Path,
thread,
time::{Duration, SystemTime},
@ -13,7 +13,7 @@ use aya::{
loaded_links, loaded_programs, KProbe, TracePoint, UProbe, Xdp, XdpFlags,
},
util::KernelVersion,
Bpf,
Bpf, BpfLoader,
};
use aya_obj::programs::XdpAttachType;
use test_log::test;
@ -79,7 +79,7 @@ fn pin_lifecycle_multiple_btf_maps() {
// 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.
// Don't pin system maps.
if name.contains(".rodata") || name.contains(".bss") {
continue;
}
@ -127,6 +127,83 @@ fn pin_lifecycle_multiple_btf_maps() {
remove_file(map_pin_by_name_path).unwrap();
}
#[test]
fn pin_lifecycle_sharing_btf_maps() {
let map_pin_path = Path::new("/sys/fs/bpf/map-sharing-test");
if map_pin_path.exists() {
remove_dir_all(map_pin_path).unwrap();
}
create_dir(map_pin_path).unwrap();
let mut loader = BpfLoader::new();
let mut bpf = loader.load(crate::MULTIMAP_BTF).unwrap();
// "map_pin_by_name" should already be pinned at the default bpffs.
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();
for (_, (name, map)) in bpf.maps_mut().enumerate() {
// Don't pin system maps.
if name.contains(".rodata") || name.contains(".bss") {
continue;
}
// Pin the map by it's name.
map.pin(map_pin_path.join(name)).unwrap();
assert!(map_pin_path.exists());
}
// Load the same program using the existing maps at map_pin_path.
let mut bpf1 = loader
.map_pin_path(map_pin_path)
.load(crate::MULTIMAP_BTF)
.unwrap();
// Get the maps from the first program.
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();
// Attach both programs so they can be triggered.
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();
let prog1: &mut UProbe = bpf1.program_mut("bpf_prog1").unwrap().try_into().unwrap();
prog1.load().unwrap();
prog1
.attach(Some("trigger_bpf_program"), 0, "/proc/self/exe", None)
.unwrap();
trigger_bpf_program();
// Ensure both program's updated the same 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 key = 1;
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, 35);
assert_eq!(val_2, 53);
assert_eq!(val_3, 55);
remove_dir_all(map_pin_path).unwrap()
}
#[no_mangle]
#[inline(never)]
pub extern "C" fn trigger_bpf_program() {

Loading…
Cancel
Save