mirror of https://github.com/aya-rs/aya
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
7.5 KiB
Rust
239 lines
7.5 KiB
Rust
use std::thread;
|
|
|
|
use aya::{
|
|
Ebpf, EbpfLoader,
|
|
maps::{Array, HashMap, MapData, MapError, PerCpuHashMap},
|
|
programs::UProbe,
|
|
};
|
|
use integration_common::hash_map::GET_INDEX;
|
|
use nix::{
|
|
sched::{CpuSet, sched_setaffinity},
|
|
unistd::Pid,
|
|
};
|
|
|
|
/// Triggers the eBPF program that inserts the given `key` and `value` pair
|
|
/// into the hash map.
|
|
#[unsafe(no_mangle)]
|
|
#[inline(never)]
|
|
extern "C" fn hash_map_insert(key: u32, value: u32) {
|
|
std::hint::black_box((key, value));
|
|
}
|
|
|
|
/// Triggers the eBPF program that retrieves the value associated with the
|
|
/// `key` and inserts it into the array.
|
|
#[unsafe(no_mangle)]
|
|
#[inline(never)]
|
|
extern "C" fn hash_map_get(key: u32) {
|
|
std::hint::black_box(key);
|
|
}
|
|
|
|
/// Loads the uprobe program and attaches it to the given `symbol`.
|
|
fn load_program(ebpf: &mut Ebpf, prog_name: &str, symbol: &str) {
|
|
let prog: &mut UProbe = ebpf.program_mut(prog_name).unwrap().try_into().unwrap();
|
|
prog.load().unwrap();
|
|
prog.attach(symbol, "/proc/self/exe", None, None).unwrap();
|
|
}
|
|
|
|
/// Loads the pair of programs:
|
|
///
|
|
/// * `insert_prog` that inserts key and value pairs into the `hash_map`.
|
|
/// * `get_prog` that retrieves values from the `hash_map` and inserts them
|
|
/// into `result_map`.
|
|
///
|
|
/// Returns the result array and the hash map.
|
|
fn load_programs_with_maps<'a>(
|
|
ebpf: &'a mut Ebpf,
|
|
result_array: &'a str,
|
|
hash_map: &'a str,
|
|
insert_prog: &'a str,
|
|
get_prog: &'a str,
|
|
) -> (Array<&'a MapData, u32>, HashMap<&'a MapData, u32, u32>) {
|
|
load_program(ebpf, insert_prog, "hash_map_insert");
|
|
load_program(ebpf, get_prog, "hash_map_get");
|
|
|
|
let result_array = ebpf.map(result_array).unwrap();
|
|
let result_array = Array::<_, u32>::try_from(result_array).unwrap();
|
|
|
|
let hash_map = ebpf.map(hash_map).unwrap();
|
|
let hash_map = HashMap::<_, u32, u32>::try_from(hash_map).unwrap();
|
|
|
|
(result_array, hash_map)
|
|
}
|
|
|
|
/// Loads the `insert_prog` program that inserts elements into the
|
|
/// `per_cpu_hash_map`. Returns the map.
|
|
fn load_program_with_per_cpu_map<'a>(
|
|
ebpf: &'a mut Ebpf,
|
|
per_cpu_hash_map: &'a str,
|
|
insert_prog: &'a str,
|
|
) -> PerCpuHashMap<&'a MapData, u32, u32> {
|
|
load_program(ebpf, insert_prog, "hash_map_insert");
|
|
|
|
let hash_map = ebpf.map(per_cpu_hash_map).unwrap();
|
|
PerCpuHashMap::<_, u32, u32>::try_from(hash_map).unwrap()
|
|
}
|
|
|
|
#[test_log::test]
|
|
fn test_hash_map() {
|
|
let mut ebpf = EbpfLoader::new().load(crate::HASH_MAP).unwrap();
|
|
for (result_map_name, hash_map_name, insert_prog_name, get_prog_name) in [
|
|
// BTF map definitions.
|
|
("RESULT", "HASH_MAP", "hash_map_insert", "hash_map_get"),
|
|
// Legacy map definitions.
|
|
(
|
|
"RESULT_LEGACY",
|
|
"HASH_MAP_LEGACY",
|
|
"hash_map_insert_legacy",
|
|
"hash_map_get_legacy",
|
|
),
|
|
] {
|
|
let (result_array, hash_map) = load_programs_with_maps(
|
|
&mut ebpf,
|
|
result_map_name,
|
|
hash_map_name,
|
|
insert_prog_name,
|
|
get_prog_name,
|
|
);
|
|
|
|
let seq = 0_u32..9;
|
|
for i in seq.clone() {
|
|
hash_map_insert(i.pow(2), i);
|
|
}
|
|
for i in seq.clone() {
|
|
// Assert the value returned by user-space API.
|
|
let key = i.pow(2);
|
|
let value = hash_map.get(&key, 0).unwrap();
|
|
assert_eq!(value, i);
|
|
// Assert the value returned by eBPF in-kernel API.
|
|
hash_map_get(key);
|
|
let result = result_array.get(&GET_INDEX, 0).unwrap();
|
|
assert_eq!(result, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test_log::test]
|
|
fn test_lru_hash_map() {
|
|
let mut ebpf = EbpfLoader::new().load(crate::HASH_MAP).unwrap();
|
|
for (result_map_name, hash_map_name, insert_prog_name, get_prog_name) in [
|
|
// BTF map definitions.
|
|
(
|
|
"RESULT",
|
|
"LRU_HASH_MAP",
|
|
"lru_hash_map_insert",
|
|
"lru_hash_map_get",
|
|
),
|
|
// Legacy map definitions.
|
|
(
|
|
"RESULT_LEGACY",
|
|
"LRU_HASH_MAP_LEGACY",
|
|
"lru_hash_map_insert_legacy",
|
|
"lru_hash_map_get_legacy",
|
|
),
|
|
] {
|
|
let (result_array, hash_map) = load_programs_with_maps(
|
|
&mut ebpf,
|
|
result_map_name,
|
|
hash_map_name,
|
|
insert_prog_name,
|
|
get_prog_name,
|
|
);
|
|
|
|
// Insert elements over capacity.
|
|
let seq = 0_u32..15;
|
|
for i in seq.clone() {
|
|
hash_map_insert(i.pow(2), i);
|
|
}
|
|
// Check whether elements 0..5 got evicted.
|
|
for i in 0_u32..5 {
|
|
let key = i.pow(2);
|
|
assert!(matches!(hash_map.get(&key, 0), Err(MapError::KeyNotFound)));
|
|
}
|
|
// Check whether the newest 10 elements can be retrieved.
|
|
for i in 5_u32..15 {
|
|
// Assert the value returned by user-space API.
|
|
let key = i.pow(2);
|
|
let value = hash_map.get(&key, 0).unwrap();
|
|
assert_eq!(value, i);
|
|
// Assert the value returned by eBPF in-kernel API.
|
|
hash_map_get(key);
|
|
let result = result_array.get(&GET_INDEX, 0).unwrap();
|
|
assert_eq!(result, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test_log::test]
|
|
fn test_per_cpu_hash_map() {
|
|
let mut ebpf = EbpfLoader::new().load(crate::HASH_MAP).unwrap();
|
|
for (hash_map_name, insert_prog_name) in [
|
|
// BTF map definitions.
|
|
("PER_CPU_HASH_MAP", "per_cpu_hash_map_insert"),
|
|
// Legacy map definitions.
|
|
("PER_CPU_HASH_MAP_LEGACY", "per_cpu_hash_map_insert_legacy"),
|
|
] {
|
|
let hash_map = load_program_with_per_cpu_map(&mut ebpf, hash_map_name, insert_prog_name);
|
|
|
|
let seq = 0_u32..9;
|
|
thread::scope(|s| {
|
|
let seq = seq.clone();
|
|
s.spawn(move || {
|
|
let mut cpu_set = CpuSet::new();
|
|
cpu_set.set(0).unwrap();
|
|
sched_setaffinity(Pid::from_raw(0), &cpu_set).unwrap();
|
|
|
|
for i in seq {
|
|
hash_map_insert(i.pow(2), i);
|
|
}
|
|
});
|
|
});
|
|
for i in seq.clone() {
|
|
let key = i.pow(2);
|
|
let values = hash_map.get(&key, 0).unwrap();
|
|
assert_eq!(values.first().unwrap(), &i);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test_log::test]
|
|
fn test_lru_per_cpu_hash_map() {
|
|
let mut ebpf = EbpfLoader::new().load(crate::HASH_MAP).unwrap();
|
|
for (hash_map_name, insert_prog_name) in [
|
|
// BTF map definitions.
|
|
("LRU_PER_CPU_HASH_MAP", "lru_per_cpu_hash_map_insert"),
|
|
// Legacy map definitions.
|
|
(
|
|
"LRU_PER_CPU_HASH_MAP_LEGACY",
|
|
"lru_per_cpu_hash_map_insert_legacy",
|
|
),
|
|
] {
|
|
let hash_map = load_program_with_per_cpu_map(&mut ebpf, hash_map_name, insert_prog_name);
|
|
|
|
// Insert elements over capacity.
|
|
let seq = 0_u32..15;
|
|
thread::scope(|s| {
|
|
let seq = seq.clone();
|
|
s.spawn(move || {
|
|
let mut cpu_set = CpuSet::new();
|
|
cpu_set.set(0).unwrap();
|
|
sched_setaffinity(Pid::from_raw(0), &cpu_set).unwrap();
|
|
|
|
for i in seq {
|
|
hash_map_insert(i.pow(2), i);
|
|
}
|
|
});
|
|
});
|
|
// Check whether elements 0..5 got evicted.
|
|
for i in 0_u32..5 {
|
|
let key = i.pow(2);
|
|
assert!(matches!(hash_map.get(&key, 0), Err(MapError::KeyNotFound)));
|
|
}
|
|
// Check whether the newest 10 elements can be retrieved.
|
|
for i in 5_u32..15 {
|
|
let key = i.pow(2);
|
|
let values = hash_map.get(&key, 0).unwrap();
|
|
assert_eq!(values.first().unwrap(), &i);
|
|
}
|
|
}
|
|
}
|