From 657fb4452563d323721c3671e63f4f6d7cf9e334 Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Fri, 21 Jan 2022 18:17:22 +0000 Subject: [PATCH] test: Add compile_c_ebpf to library This allows for C code to be compiled and used in tests! It does require libbpf on the host machine though... Also moved removal of the `user` and `ebpf` dirs created by rust-script into `lib.sh` and parameterized bits of the XDP smoke test for ease of copying Signed-off-by: Dave Tucker --- test/cases/000_smoke/000_xdp/test.sh | 10 ++-- test/cases/_lib/compile-ebpf.ers | 85 ++++++++++++++++++++++++++++ test/cases/_lib/lib.sh | 12 ++++ 3 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 test/cases/_lib/compile-ebpf.ers diff --git a/test/cases/000_smoke/000_xdp/test.sh b/test/cases/000_smoke/000_xdp/test.sh index 974e033c..eba23581 100755 --- a/test/cases/000_smoke/000_xdp/test.sh +++ b/test/cases/000_smoke/000_xdp/test.sh @@ -11,8 +11,8 @@ set -e NAME=pass clean_up() { - rm -rf ebpf user ${NAME}.o ${NAME} - exec_vm rm -f pass pass.o + rm -rf ${NAME}.o ${NAME} + exec_vm rm -f ${NAME} ${NAME}.o } trap clean_up EXIT @@ -21,9 +21,9 @@ trap clean_up EXIT compile_ebpf "$(pwd)/${NAME}.ebpf.rs" compile_user "$(pwd)/${NAME}.rs" -scp_vm pass.o -scp_vm pass +scp_vm ${NAME}.o +scp_vm ${NAME} -exec_vm sudo ./pass +exec_vm sudo ./${NAME} exit 0 \ No newline at end of file diff --git a/test/cases/_lib/compile-ebpf.ers b/test/cases/_lib/compile-ebpf.ers new file mode 100644 index 00000000..66993d20 --- /dev/null +++ b/test/cases/_lib/compile-ebpf.ers @@ -0,0 +1,85 @@ +//! ```cargo +//! [dependencies] +//! libbpf-sys = { version = "0.6.1-1" } +//! anyhow = "1" +//! ``` + +use std::{ + env, + fs::{self, OpenOptions}, + io::Write, + path::Path, + process::Command, + string::String, +}; +use anyhow::{bail, Context, Result}; +static CLANG_DEFAULT: &str = "/usr/bin/clang"; + +/// Extract vendored libbpf headers from libbpf-sys. +fn extract_libbpf_headers>(include_path: P) -> Result<()> { + let dir = include_path.as_ref().join("bpf"); + fs::create_dir_all(&dir)?; + for (filename, contents) in libbpf_sys::API_HEADERS.iter() { + let path = dir.as_path().join(filename); + let mut file = OpenOptions::new().write(true).create(true).open(path)?; + file.write_all(contents.as_bytes())?; + } + + Ok(()) +} + +/// Build eBPF programs with clang and libbpf headers. +fn build_ebpf>(in_file: P, out_file: P, include_path: P) -> Result<()> { + extract_libbpf_headers(include_path.clone())?; + let clang = match env::var("CLANG") { + Ok(val) => val, + Err(_) => String::from(CLANG_DEFAULT), + }; + let arch = match std::env::consts::ARCH { + "x86_64" => "x86", + "aarch64" => "arm64", + _ => std::env::consts::ARCH, + }; + let mut cmd = Command::new(clang); + cmd.arg(format!("-I{}", include_path.as_ref().to_string_lossy())) + .arg("-g") + .arg("-O2") + .arg("-target") + .arg("bpf") + .arg("-c") + .arg(format!("-D__TARGET_ARCH_{}", arch)) + .arg(in_file.as_ref().as_os_str()) + .arg("-o") + .arg(out_file.as_ref().as_os_str()); + + let output = cmd.output().context("Failed to execute clang")?; + if !output.status.success() { + bail!( + "Failed to compile eBPF programs\n \ + stdout=\n \ + {}\n \ + stderr=\n \ + {}\n", + String::from_utf8(output.stdout).unwrap(), + String::from_utf8(output.stderr).unwrap() + ); + } + + Ok(()) +} + +fn main() -> Result<()> { + let args: Vec = env::args().collect(); + if args.len() != 3 { + bail!("requires 2 arguments. src and dst") + } + let path = env::current_dir()?; + let src = Path::new(&args[1]); + let dst = Path::new(&args[2]); + + let include_path = path.join("include"); + fs::create_dir_all(include_path.clone())?; + build_ebpf(src, dst, &include_path)?; + + Ok(()) +} \ No newline at end of file diff --git a/test/cases/_lib/lib.sh b/test/cases/_lib/lib.sh index f6a7e7e1..384aea6d 100644 --- a/test/cases/_lib/lib.sh +++ b/test/cases/_lib/lib.sh @@ -54,6 +54,17 @@ EOF cargo build -q --manifest-path "${dir}/ebpf/Cargo.toml" mv "${dir}/ebpf/target/bpfel-unknown-none/debug/${artifact}" "${dir}/${base}.o" rm -rf "${dir}/.cargo" + rm -rf "${dir}/ebpf" +} + +# compile a C BPF file +compile_c_ebpf() { + file=$(basename "$1") + dir=$(dirname "$1") + base=$(echo "${file}" | cut -f1 -d '.') + + rust-script "${RT_PROJECT_ROOT}/_lib/compile-ebpf.ers" "${1}" "${dir}/${base}.o" + rm -rf "${dir}/include" } # compiles the userspace program by using rust-script to create a temporary @@ -75,6 +86,7 @@ members = [] EOF cargo build -q --release --manifest-path "${dir}/user/Cargo.toml" --target=x86_64-unknown-linux-musl mv "${dir}/user/target/x86_64-unknown-linux-musl/release/${artifact}" "${dir}/${base}" + rm -rf "${dir}/user" } download_images() {