Add tests that validate `bpftool prog list` functions, that we can associate pids with them, and that we can show a prog by id. $ BPFTOOL_PATH=../bpftool CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="sudo -E" cargo test -- --nocapture Finished test [unoptimized + debuginfo] target(s) in 0.05s Running unittests src/main.rs (target/debug/deps/bpftool_tests-afa5a7eef3cdeafb) running 6 tests Running command "../bpftool" "version" test bpftool_tests::run_bpftool ... ok Running command "../bpftool" "map" "list" "--json" Running command "../bpftool" "prog" "list" "--json" Running command "../bpftool" "prog" "list" "--json" Running command "../bpftool" "map" "list" "--json" Running command "../bpftool" "prog" "show" "id" "3160417" "--json" test bpftool_tests::run_bpftool_prog_show_id ... ok test bpftool_tests::run_bpftool_map_pids ... ok test bpftool_tests::run_bpftool_map_list ... ok test bpftool_tests::run_bpftool_prog_pids ... ok test bpftool_tests::run_bpftool_prog_list ... ok test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.20s Signed-off-by: Manu Bretelle <chantr4@xxxxxxxxx> --- .../bpftool_tests/src/bpf/bpftool_tests.bpf.c | 2 +- .../bpf/bpftool_tests/src/bpftool_tests.rs | 79 ++++++++++++++++++- 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/bpftool_tests/src/bpf/bpftool_tests.bpf.c b/tools/testing/selftests/bpf/bpftool_tests/src/bpf/bpftool_tests.bpf.c index dbd4e2aad277..e2b18dd36207 100644 --- a/tools/testing/selftests/bpf/bpftool_tests/src/bpf/bpftool_tests.bpf.c +++ b/tools/testing/selftests/bpf/bpftool_tests/src/bpf/bpftool_tests.bpf.c @@ -14,7 +14,7 @@ struct { int my_pid = 0; SEC("tp/syscalls/sys_enter_write") -int handle_tp(void *ctx) +int handle_tp_sys_enter_write(void *ctx) { int pid = bpf_get_current_pid_tgid() >> 32; diff --git a/tools/testing/selftests/bpf/bpftool_tests/src/bpftool_tests.rs b/tools/testing/selftests/bpf/bpftool_tests/src/bpftool_tests.rs index a832b255e988..695a1cbc5be8 100644 --- a/tools/testing/selftests/bpf/bpftool_tests/src/bpftool_tests.rs +++ b/tools/testing/selftests/bpf/bpftool_tests/src/bpftool_tests.rs @@ -8,9 +8,10 @@ mod bpftool_tests_skel { use bpftool_tests_skel::BpftoolTestsSkelBuilder; use libbpf_rs::skel::OpenSkel; use libbpf_rs::skel::SkelBuilder; +use libbpf_rs::Program; use serde::Deserialize; use serde::Serialize; - +use std::os::fd::AsFd; use std::process::Command; const BPFTOOL_PATH_ENV: &str = "BPFTOOL_PATH"; @@ -23,6 +24,17 @@ struct Pid { pid: u64, } +/// A struct representing a prog entry from `bpftool prog list -j` +#[derive(Serialize, Deserialize, Debug)] +struct Prog { + name: Option<String>, + id: u32, + r#type: String, + tag: String, + #[serde(default)] + pids: Vec<Pid>, +} + /// A struct representing a map entry from `bpftool map list -j` #[derive(Serialize, Deserialize, Debug)] struct Map { @@ -101,3 +113,68 @@ fn run_bpftool_map_pids() { map.pids ); } + +/// A test to validate that we can list programs using bpftool +#[test] +fn run_bpftool_prog_list() { + let _skel = setup().expect("Failed to set up BPF program"); + let output = run_bpftool_command(&["prog", "list", "--json"]); + + let progs = serde_json::from_slice::<Vec<Prog>>(&output.stdout).expect("Failed to parse JSON"); + + assert!(output.status.success()); + assert!(!progs.is_empty(), "No programs were listed"); +} + +/// A test to validate that we can find PIDs associated with a program +#[test] +fn run_bpftool_prog_pids() { + let hook_name = "handle_tp_sys_enter_write"; + + let _skel = setup().expect("Failed to set up BPF program"); + let output = run_bpftool_command(&["prog", "list", "--json"]); + + let progs = serde_json::from_slice::<Vec<Prog>>(&output.stdout).expect("Failed to parse JSON"); + assert!(output.status.success(), "bpftool returned an error."); + + // `handle_tp_sys_enter_write` is a hook our bpftool_tests.bpf.c attaches + // to (tp/syscalls/sys_enter_write). + // It should have at least one entry for our current process. + let prog = progs + .iter() + .find(|m| m.name.is_some() && m.name.as_ref().unwrap() == hook_name) + .unwrap_or_else(|| panic!("Did not find {} prog", hook_name)); + + let mypid = std::process::id() as u64; + assert!( + prog.pids.iter().any(|p| p.pid == mypid), + "Did not find test runner pid ({}) in pids list associated with prog *{}*: {:?}", + mypid, + hook_name, + prog.pids + ); +} + +/// A test to validate that we can run `bpftool prog show <id>` +/// an extract the expected information. +#[test] +fn run_bpftool_prog_show_id() { + let skel = setup().expect("Failed to set up BPF program"); + let binding = skel.progs(); + let handle_tp_sys_enter_write = binding.handle_tp_sys_enter_write(); + let prog_id = + Program::get_id_by_fd(handle_tp_sys_enter_write.as_fd()).expect("Failed to get prog ID"); + + let output = run_bpftool_command(&["prog", "show", "id", &prog_id.to_string(), "--json"]); + assert!(output.status.success(), "bpftool returned an error."); + + let prog = serde_json::from_slice::<Prog>(&output.stdout).expect("Failed to parse JSON"); + + assert_eq!(prog_id, prog.id); + assert_eq!( + handle_tp_sys_enter_write.name(), + prog.name + .expect("Program handle_tp_sys_enter_write has no name") + ); + assert_eq!("tracepoint", prog.r#type); +} -- 2.39.3