Ver Fonte

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 <dave@dtucker.co.uk>
Dave Tucker há 3 anos atrás
pai
commit
657fb44525

+ 5 - 5
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

+ 85 - 0
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<P: AsRef<Path>>(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<P: Clone + AsRef<Path>>(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<String> = 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(())
+}

+ 12 - 0
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() {