@ -1,7 +1,9 @@
//! Test feature probing against kernel version.
//! Test feature probing against kernel version.
use assert_matches ::assert_matches ;
use assert_matches ::assert_matches ;
use aya ::{ programs ::ProgramType , sys ::feature_probe ::* , util ::KernelVersion } ;
use aya ::{ maps ::MapType , programs ::ProgramType , sys ::feature_probe ::* , util ::KernelVersion } ;
use super ::load ::{ MAX_RETRIES , RETRY_DURATION } ;
// TODO: Enable certain CONFIG_* options when compiling the image for VM tests.
// TODO: Enable certain CONFIG_* options when compiling the image for VM tests.
#[ test ]
#[ test ]
@ -193,14 +195,211 @@ fn probe_supported_programs() {
}
}
}
}
#[ test ]
fn probe_supported_maps ( ) {
let current = KernelVersion ::current ( ) . unwrap ( ) ;
let hash = is_map_supported ( MapType ::Hash ) ;
let array = is_map_supported ( MapType ::Array ) ;
if current > = KernelVersion ::new ( 3 , 19 , 0 ) {
assert_matches ! ( hash , Ok ( true ) ) ;
assert_matches ! ( array , Ok ( true ) ) ;
} else {
assert_matches ! ( hash , Ok ( false ) ) ;
assert_matches ! ( array , Ok ( false ) ) ;
}
let prog_array = retry ( 3 , | | is_map_supported ( MapType ::ProgramArray ) ) ;
if current > = KernelVersion ::new ( 4 , 2 , 0 ) {
assert_matches ! ( prog_array , Ok ( true ) ) ;
} else {
assert_matches ! ( prog_array , Ok ( false ) ) ;
}
let perf_event_array = retry ( 3 , | | is_map_supported ( MapType ::PerfEventArray ) ) ;
if current > = KernelVersion ::new ( 4 , 3 , 0 ) {
assert_matches ! ( perf_event_array , Ok ( true ) ) ;
} else {
assert_matches ! ( perf_event_array , Ok ( false ) ) ;
}
let per_cpu_hash = retry ( 3 , | | is_map_supported ( MapType ::PerCpuHash ) ) ;
let per_cpu_array = retry ( 3 , | | is_map_supported ( MapType ::PerCpuArray ) ) ;
let stack_trace = retry ( 3 , | | is_map_supported ( MapType ::StackTrace ) ) ;
if current > = KernelVersion ::new ( 4 , 6 , 0 ) {
assert_matches ! ( per_cpu_hash , Ok ( true ) ) ;
assert_matches ! ( per_cpu_array , Ok ( true ) ) ;
assert_matches ! ( stack_trace , Ok ( true ) ) ;
} else {
assert_matches ! ( per_cpu_hash , Ok ( false ) ) ;
assert_matches ! ( per_cpu_array , Ok ( false ) ) ;
assert_matches ! ( stack_trace , Ok ( false ) ) ;
}
let cgroup_array = is_map_supported ( MapType ::CgroupArray ) ;
if current > = KernelVersion ::new ( 4 , 8 , 0 ) {
assert_matches ! ( cgroup_array , Ok ( true ) ) ;
} else {
assert_matches ! ( cgroup_array , Ok ( false ) ) ;
}
let lru_hash = retry ( 3 , | | is_map_supported ( MapType ::LruHash ) ) ;
let lru_per_cpu_hash = retry ( 3 , | | is_map_supported ( MapType ::LruPerCpuHash ) ) ;
if current > = KernelVersion ::new ( 4 , 10 , 0 ) {
assert_matches ! ( lru_hash , Ok ( true ) ) ;
assert_matches ! ( lru_per_cpu_hash , Ok ( true ) ) ;
} else {
assert_matches ! ( lru_hash , Ok ( false ) ) ;
assert_matches ! ( lru_per_cpu_hash , Ok ( false ) ) ;
}
let lpm_trie = retry ( 3 , | | is_map_supported ( MapType ::LpmTrie ) ) ;
if current > = KernelVersion ::new ( 4 , 11 , 0 ) {
assert_matches ! ( lpm_trie , Ok ( true ) ) ;
} else {
assert_matches ! ( lpm_trie , Ok ( false ) ) ;
}
let array_of_maps = retry ( 3 , | | is_map_supported ( MapType ::ArrayOfMaps ) ) ;
let hash_of_maps = retry ( 3 , | | is_map_supported ( MapType ::HashOfMaps ) ) ;
if current > = KernelVersion ::new ( 4 , 12 , 0 ) {
assert_matches ! ( array_of_maps , Ok ( true ) ) ;
assert_matches ! ( hash_of_maps , Ok ( true ) ) ;
} else {
assert_matches ! ( array_of_maps , Ok ( false ) ) ;
assert_matches ! ( hash_of_maps , Ok ( false ) ) ;
}
let dev_map = retry ( MAX_RETRIES , | | is_map_supported ( MapType ::DevMap ) ) ;
let sock_map = retry ( 3 , | | is_map_supported ( MapType ::SockMap ) ) ;
if current > = KernelVersion ::new ( 4 , 14 , 0 ) {
assert_matches ! ( dev_map , Ok ( true ) ) ;
assert_matches ! ( sock_map , Ok ( true ) ) ;
} else {
assert_matches ! ( dev_map , Ok ( false ) ) ;
assert_matches ! ( sock_map , Ok ( false ) ) ;
}
let cpu_map = retry ( 3 , | | is_map_supported ( MapType ::CpuMap ) ) ;
if current > = KernelVersion ::new ( 4 , 15 , 0 ) {
assert_matches ! ( cpu_map , Ok ( true ) ) ;
} else {
assert_matches ! ( cpu_map , Ok ( false ) ) ;
}
let xsk_map = retry ( 3 , | | is_map_supported ( MapType ::XskMap ) ) ;
let sock_hash = retry ( 3 , | | is_map_supported ( MapType ::SockHash ) ) ;
if current > = KernelVersion ::new ( 4 , 18 , 0 ) {
assert_matches ! ( xsk_map , Ok ( true ) ) ;
assert_matches ! ( sock_hash , Ok ( true ) ) ;
} else {
assert_matches ! ( xsk_map , Ok ( false ) ) ;
assert_matches ! ( sock_hash , Ok ( false ) ) ;
}
let cgroup_storage = retry ( 3 , | | is_map_supported ( MapType ::CgroupStorage ) ) ;
let reuseport_sock_array = retry ( 3 , | | is_map_supported ( MapType ::ReuseportSockArray ) ) ;
if current > = KernelVersion ::new ( 4 , 19 , 0 ) {
assert_matches ! ( cgroup_storage , Ok ( true ) ) ;
assert_matches ! ( reuseport_sock_array , Ok ( true ) ) ;
} else {
assert_matches ! ( cgroup_storage , Ok ( false ) ) ;
assert_matches ! ( reuseport_sock_array , Ok ( false ) ) ;
}
let per_cpu_cgroup_storage = retry ( 3 , | | is_map_supported ( MapType ::PerCpuCgroupStorage ) ) ;
let queue = retry ( 3 , | | is_map_supported ( MapType ::Queue ) ) ;
let stack = retry ( 3 , | | is_map_supported ( MapType ::Stack ) ) ;
if current > = KernelVersion ::new ( 4 , 20 , 0 ) {
assert_matches ! ( per_cpu_cgroup_storage , Ok ( true ) ) ;
assert_matches ! ( queue , Ok ( true ) ) ;
assert_matches ! ( stack , Ok ( true ) ) ;
} else {
assert_matches ! ( per_cpu_cgroup_storage , Ok ( false ) ) ;
assert_matches ! ( queue , Ok ( false ) ) ;
assert_matches ! ( stack , Ok ( false ) ) ;
}
let sk_storage = retry ( 3 , | | is_map_supported ( MapType ::SkStorage ) ) ;
if current > = KernelVersion ::new ( 5 , 2 , 0 ) {
assert_matches ! ( sk_storage , Ok ( true ) ) ;
} else {
assert_matches ! ( sk_storage , Ok ( false ) ) ;
}
let devmap_hash = retry ( MAX_RETRIES , | | is_map_supported ( MapType ::DevMapHash ) ) ;
if current > = KernelVersion ::new ( 5 , 4 , 0 ) {
assert_matches ! ( devmap_hash , Ok ( true ) ) ;
} else {
assert_matches ! ( devmap_hash , Ok ( false ) ) ;
}
let struct_ops = retry ( 3 , | | is_map_supported ( MapType ::StructOps ) ) ;
if current > = KernelVersion ::new ( 5 , 6 , 0 ) {
assert_matches ! ( struct_ops , Ok ( true ) ) ;
} else {
assert_matches ! ( struct_ops , Ok ( false ) ) ;
}
let ring_buf = retry ( MAX_RETRIES , | | is_map_supported ( MapType ::RingBuf ) ) ;
if current > = KernelVersion ::new ( 5 , 8 , 0 ) {
assert_matches ! ( ring_buf , Ok ( true ) ) ;
} else {
assert_matches ! ( ring_buf , Ok ( false ) ) ;
}
// Requires `CONFIG_BPF_LSM=y`
// let inode_storage = retry(3, || is_map_supported(MapType::InodeStorage));
// if current >= KernelVersion::new(5, 10, 0) {
// assert_matches!(inode_storage, Ok(true));
// } else {
// assert_matches!(inode_storage, Ok(false));
// }
let task_storage = retry ( 3 , | | is_map_supported ( MapType ::TaskStorage ) ) ;
if current > = KernelVersion ::new ( 5 , 11 , 0 ) {
assert_matches ! ( task_storage , Ok ( true ) ) ;
} else {
assert_matches ! ( task_storage , Ok ( false ) ) ;
}
let bloom_filter = retry ( 3 , | | is_map_supported ( MapType ::BloomFilter ) ) ;
if current > = KernelVersion ::new ( 5 , 16 , 0 ) {
assert_matches ! ( bloom_filter , Ok ( true ) ) ;
} else {
assert_matches ! ( bloom_filter , Ok ( false ) ) ;
}
let user_ring_buf = retry ( 3 , | | is_map_supported ( MapType ::UserRingBuf ) ) ;
if current > = KernelVersion ::new ( 6 , 1 , 0 ) {
assert_matches ! ( user_ring_buf , Ok ( true ) ) ;
} else {
assert_matches ! ( user_ring_buf , Ok ( false ) ) ;
}
let cgrp_storage = retry ( 3 , | | is_map_supported ( MapType ::CgrpStorage ) ) ;
if current > = KernelVersion ::new ( 6 , 2 , 0 ) {
assert_matches ! ( cgrp_storage , Ok ( true ) ) ;
} else {
assert_matches ! ( cgrp_storage , Ok ( false ) ) ;
}
let arena = retry ( 3 , | | is_map_supported ( MapType ::Arena ) ) ;
if current > = KernelVersion ::new ( 6 , 9 , 0 ) {
assert_matches ! ( arena , Ok ( true ) ) ;
} else {
assert_matches ! ( arena , Ok ( false ) ) ;
}
}
// Back-to-back calls can be flaky and return `EPERM`.
// Back-to-back calls can be flaky and return `EPERM`.
fn retry < T , E > ( max_retries : u64 , try_func : impl Fn ( ) -> Result < T , E > ) -> Result < T , E > {
fn retry < T , E > ( max_retries : u size , try_func : impl Fn ( ) -> Result < T , E > ) -> Result < T , E > {
let mut res = try_func ( ) ;
let mut res = try_func ( ) ;
for i in 1 .. max_retries {
for i in 1 .. ( max_retries as u32 ) {
if res . is_ok ( ) {
if res . is_ok ( ) {
return res ;
return res ;
}
}
std ::thread ::sleep ( std ::time ::Duration ::from_millis ( i * 10 ) ) ;
std ::thread ::sleep ( RETRY_DURATION * i ) ;
res = try_func ( ) ;
res = try_func ( ) ;
}
}
res
res