integration-test: compile C probes using build.rs

- Add libbpf as a submodule. This prevents having to plumb its location
  around (which can't be passed to Cargo build scripts) and also
  controls the version against which codegen has run.
- Move bpf written in C to the integration-test crate and define
  constants for each probe.
- Remove magic; each C source file must be directly enumerated in the
  build script and in lib.rs.
pull/644/head
Tamir Duberstein 1 year ago
parent 6ca7d53733
commit 8c61fc9ea6
No known key found for this signature in database

@ -9,11 +9,6 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/checkout@v3
with:
repository: libbpf/libbpf
path: libbpf
- name: libbpf-version - name: libbpf-version
working-directory: libbpf working-directory: libbpf
run: echo "LIBBPF_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV run: echo "LIBBPF_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
@ -32,7 +27,7 @@ jobs:
- name: Run codegen - name: Run codegen
run: | run: |
cargo xtask codegen --libbpf-dir ./libbpf cargo xtask codegen
- name: Check for changes - name: Check for changes
run: | run: |

@ -17,11 +17,9 @@ jobs:
runs-on: macos-latest runs-on: macos-latest
steps: steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
repository: libbpf/libbpf submodules: recursive
path: libbpf
- name: Install Pre-requisites - name: Install Pre-requisites
run: | run: |
@ -40,4 +38,4 @@ jobs:
key: tmp-files-${{ hashFiles('test/run.sh') }} key: tmp-files-${{ hashFiles('test/run.sh') }}
- name: Run integration tests - name: Run integration tests
run: test/run.sh ./libbpf run: test/run.sh

1
.gitignore vendored

@ -1,6 +1,5 @@
Cargo.lock Cargo.lock
target/ target/
libbpf/
.vscode/ .vscode/
!.vscode/settings.json !.vscode/settings.json
site/ site/

3
.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "libbpf"]
path = libbpf
url = https://github.com/libbpf/libbpf

@ -299,7 +299,7 @@ macro_rules! include_bytes_aligned {
pub bytes: Bytes, pub bytes: Bytes,
} }
static ALIGNED: &Aligned<[u8]> = &Aligned { const ALIGNED: &Aligned<[u8]> = &Aligned {
_align: [], _align: [],
bytes: *include_bytes!($path), bytes: *include_bytes!($path),
}; };

@ -0,0 +1 @@
Subproject commit a2258003f21d9d52afd48aa64787b65ef80bd355

@ -30,13 +30,13 @@ From the root of this repository:
### Native ### Native
``` ```
cargo xtask integration-test --libbpf-dir /path/to/libbpf cargo xtask integration-test
``` ```
### Virtualized ### Virtualized
``` ```
./test/run.sh /path/to/libbpf ./test/run.sh
``` ```
### Writing an integration test ### Writing an integration test
@ -45,9 +45,9 @@ Tests should follow these guidelines:
- Rust eBPF code should live in `integration-ebpf/${NAME}.rs` and included in - Rust eBPF code should live in `integration-ebpf/${NAME}.rs` and included in
`integration-ebpf/Cargo.toml`. `integration-ebpf/Cargo.toml`.
- C eBPF code should live in `integration-ebpf/src/bpf/${NAME}.bpf.c`. It's automatically compiled - C eBPF code should live in `integration-test/bpf/${NAME}.bpf.c`. It should be
and made available as `${OUT_DIR}/${NAME}.bpf.o`. added to the list of files in `integration-test/build.rs` and the list of
- Any bytecode should be included in the integration test binary using `include_bytes_aligned!`. constants in `integration-test/src/lib.rs` using `include_bytes_aligned!`.
- Tests should be added to `integration-test/tests`. - Tests should be added to `integration-test/tests`.
- You may add a new module, or use an existing one. - You may add a new module, or use an existing one.
- Test functions should not return `anyhow::Result<()>` since this produces errors without stack - Test functions should not return `anyhow::Result<()>` since this produces errors without stack

@ -0,0 +1,88 @@
use std::{env, ffi::OsString, path::PathBuf, process::Command};
fn main() {
let manifest_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap();
let manifest_dir = PathBuf::from(manifest_dir);
let out_dir = env::var_os("OUT_DIR").unwrap();
let out_dir = PathBuf::from(out_dir);
let libbpf_dir = manifest_dir
.parent()
.unwrap()
.parent()
.unwrap()
.join("libbpf");
let libbpf_headers_dir = out_dir.join("libbpf_headers");
let mut includedir = OsString::new();
includedir.push("INCLUDEDIR=");
includedir.push(&libbpf_headers_dir);
let mut cmd = Command::new("make");
cmd.arg("-C")
.arg(libbpf_dir.join("src"))
.arg(includedir)
.arg("install_headers");
let status = cmd
.status()
.unwrap_or_else(|err| panic!("failed to run {cmd:?}: {err}"));
match status.code() {
Some(code) => match code {
0 => {}
code => panic!("{cmd:?} exited with code {code}"),
},
None => panic!("{cmd:?} terminated by signal"),
}
let bpf_dir = manifest_dir.join("bpf");
let endian = env::var_os("CARGO_CFG_TARGET_ENDIAN").unwrap();
let target = if endian == "big" {
"bpfeb"
} else if endian == "little" {
"bpfel"
} else {
panic!("unsupported endian={:?}", endian)
};
let mut target_arch = OsString::new();
target_arch.push("-D__TARGET_ARCH_");
let arch = env::var_os("CARGO_CFG_TARGET_ARCH").unwrap();
if arch == "x86_64" {
target_arch.push("x86");
} else if arch == "aarch64" {
target_arch.push("arm64");
} else {
target_arch.push(arch);
};
for (src, dst) in [
("ext.bpf.c", "ext.bpf.o"),
("main.bpf.c", "main.bpf.o"),
("multimap-btf.bpf.c", "multimap-btf.bpf.o"),
("text_64_64_reloc.c", "text_64_64_reloc.o"),
] {
let src = bpf_dir.join(src);
let out = out_dir.join(dst);
let mut cmd = Command::new("clang");
cmd.arg("-I")
.arg(&libbpf_headers_dir)
.args(["-g", "-O2", "-target", target, "-c"])
.arg(&target_arch)
.arg(src)
.arg("-o")
.arg(out);
let status = cmd
.status()
.unwrap_or_else(|err| panic!("failed to run {cmd:?}: {err}"));
match status.code() {
Some(code) => match code {
0 => {}
code => panic!("{cmd:?} exited with code {code}"),
},
None => panic!("{cmd:?} terminated by signal"),
}
}
}

@ -1 +1,8 @@
use aya::include_bytes_aligned;
pub const EXT: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/ext.bpf.o"));
pub const MAIN: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/main.bpf.o"));
pub const MULTIMAP_BTF: &[u8] =
include_bytes_aligned!(concat!(env!("OUT_DIR"), "/multimap-btf.bpf.o"));
pub const TEXT_64_64_RELOC: &[u8] =
include_bytes_aligned!(concat!(env!("OUT_DIR"), "/text_64_64_reloc.o"));

@ -33,9 +33,7 @@ fn long_name() {
#[test] #[test]
fn multiple_btf_maps() { fn multiple_btf_maps() {
let bytes = let mut bpf = Bpf::load(integration_test::MULTIMAP_BTF).unwrap();
include_bytes_aligned!("../../../target/bpfel-unknown-none/release/multimap-btf.bpf.o");
let mut bpf = Bpf::load(bytes).unwrap();
let map_1: Array<_, u64> = bpf.take_map("map_1").unwrap().try_into().unwrap(); let map_1: Array<_, u64> = bpf.take_map("map_1").unwrap().try_into().unwrap();
let map_2: Array<_, u64> = bpf.take_map("map_2").unwrap().try_into().unwrap(); let map_2: Array<_, u64> = bpf.take_map("map_2").unwrap().try_into().unwrap();

@ -34,9 +34,7 @@ static mut MULTIMAP_MAPS: [*mut Vec<u64>; 2] = [null_mut(), null_mut()];
#[test] #[test]
fn use_map_with_rbpf() { fn use_map_with_rbpf() {
let bytes = let mut object = Object::parse(integration_test::MULTIMAP_BTF).unwrap();
include_bytes_aligned!("../../../target/bpfel-unknown-none/release/multimap-btf.bpf.o");
let mut object = Object::parse(bytes).unwrap();
assert_eq!(object.programs.len(), 1); assert_eq!(object.programs.len(), 1);
matches::assert_matches!( matches::assert_matches!(

@ -20,10 +20,7 @@ fn relocations() {
#[test] #[test]
fn text_64_64_reloc() { fn text_64_64_reloc() {
let mut bpf = load_and_attach( let mut bpf = load_and_attach("test_text_64_64_reloc", integration_test::TEXT_64_64_RELOC);
"test_text_64_64_reloc",
include_bytes_aligned!("../../../target/bpfel-unknown-none/release/text_64_64_reloc.o"),
);
let mut m = aya::maps::Array::<_, u64>::try_from(bpf.map_mut("RESULTS").unwrap()).unwrap(); let mut m = aya::maps::Array::<_, u64>::try_from(bpf.map_mut("RESULTS").unwrap()).unwrap();
m.set(0, 1, 0).unwrap(); m.set(0, 1, 0).unwrap();

@ -27,15 +27,15 @@ fn extension() {
eprintln!("skipping test on kernel {kernel_version:?}, XDP uses netlink"); eprintln!("skipping test on kernel {kernel_version:?}, XDP uses netlink");
return; return;
} }
let main_bytes = let mut bpf = Bpf::load(integration_test::MAIN).unwrap();
include_bytes_aligned!("../../../target/bpfel-unknown-none/release/main.bpf.o");
let mut bpf = Bpf::load(main_bytes).unwrap();
let pass: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap(); let pass: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap();
pass.load().unwrap(); pass.load().unwrap();
pass.attach("lo", XdpFlags::default()).unwrap(); pass.attach("lo", XdpFlags::default()).unwrap();
let ext_bytes = include_bytes_aligned!("../../../target/bpfel-unknown-none/release/ext.bpf.o"); let mut bpf = BpfLoader::new()
let mut bpf = BpfLoader::new().extension("drop").load(ext_bytes).unwrap(); .extension("drop")
.load(integration_test::EXT)
.unwrap();
let drop_: &mut Extension = bpf.program_mut("drop").unwrap().try_into().unwrap(); let drop_: &mut Extension = bpf.program_mut("drop").unwrap().try_into().unwrap();
drop_.load(pass.fd().unwrap(), "xdp_pass").unwrap(); drop_.load(pass.fd().unwrap(), "xdp_pass").unwrap();
} }

@ -7,7 +7,6 @@ if [ "$(uname -s)" = "Darwin" ]; then
fi fi
AYA_SOURCE_DIR="$(realpath $(dirname $0)/..)" AYA_SOURCE_DIR="$(realpath $(dirname $0)/..)"
LIBBPF_DIR=$1
# Temporary directory for tests to use. # Temporary directory for tests to use.
AYA_TMPDIR="${AYA_SOURCE_DIR}/.tmp" AYA_TMPDIR="${AYA_SOURCE_DIR}/.tmp"
@ -236,25 +235,19 @@ cleanup_vm() {
fi fi
} }
if [ -z "$LIBBPF_DIR" ]; then
echo "path to libbpf required"
exit 1
fi
start_vm start_vm
trap cleanup_vm EXIT trap cleanup_vm EXIT
# make sure we always use fresh aya and libbpf (also see comment at the end) # make sure we always use fresh sources (also see comment at the end)
exec_vm "rm -rf aya/* libbpf" exec_vm "rm -rf aya/*"
rsync_vm "--exclude=target --exclude=.tmp $AYA_SOURCE_DIR" rsync_vm "--exclude=target --exclude=.tmp $AYA_SOURCE_DIR"
rsync_vm "$LIBBPF_DIR"
# need to build or linting will fail trying to include object files; don't run the tests though. # need to build or linting will fail trying to include object files; don't run the tests though.
exec_vm "cd aya; cargo xtask integration-test --libbpf-dir ~/libbpf -- filter-that-matches-nothing" exec_vm "cd aya; cargo xtask integration-test -- filter-that-matches-nothing"
exec_vm "cd aya; cargo clippy --all-targets -p integration-test -- --deny warnings" exec_vm "cd aya; cargo clippy --all-targets -p integration-test -- --deny warnings"
exec_vm "cd aya; cargo xtask integration-test --libbpf-dir ~/libbpf" exec_vm "cd aya; cargo xtask integration-test"
# we rm and sync but it doesn't seem to work reliably - I guess we could sleep a # we rm and sync but it doesn't seem to work reliably - I guess we could sleep a
# few seconds after but ain't nobody got time for that. Instead we also rm # few seconds after but ain't nobody got time for that. Instead we also rm
# before rsyncing. # before rsyncing.
exec_vm "rm -rf aya/* libbpf; sync" exec_vm "rm -rf aya/*; sync"

@ -1,11 +1,4 @@
use std::{ use std::{path::PathBuf, process::Command};
borrow::Cow,
env,
ffi::{OsStr, OsString},
fs,
path::{Path, PathBuf},
process::Command,
};
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
@ -44,21 +37,10 @@ pub struct BuildEbpfOptions {
/// Set the endianness of the BPF target /// Set the endianness of the BPF target
#[clap(default_value = "bpfel-unknown-none", long)] #[clap(default_value = "bpfel-unknown-none", long)]
pub target: Architecture, pub target: Architecture,
/// Libbpf dir, required for compiling C code
#[clap(long, action)]
pub libbpf_dir: PathBuf,
} }
pub fn build_ebpf(opts: BuildEbpfOptions) -> Result<()> { pub fn build_ebpf(opts: BuildEbpfOptions) -> Result<()> {
build_rust_ebpf(&opts)?; let BuildEbpfOptions { target } = opts;
build_c_ebpf(&opts)
}
fn build_rust_ebpf(opts: &BuildEbpfOptions) -> Result<()> {
let BuildEbpfOptions {
target,
libbpf_dir: _,
} = opts;
let mut dir = PathBuf::from(workspace_root()); let mut dir = PathBuf::from(workspace_root());
dir.push("test/integration-ebpf"); dir.push("test/integration-ebpf");
@ -72,67 +54,3 @@ fn build_rust_ebpf(opts: &BuildEbpfOptions) -> Result<()> {
.current_dir(&dir), .current_dir(&dir),
) )
} }
fn get_libbpf_headers(libbpf_dir: &Path, include_path: &Path) -> Result<()> {
fs::create_dir_all(include_path)?;
let mut includedir = OsString::new();
includedir.push("INCLUDEDIR=");
includedir.push(include_path);
exec(
Command::new("make")
.current_dir(libbpf_dir.join("src"))
.arg(includedir)
.arg("install_headers"),
)
}
fn build_c_ebpf(opts: &BuildEbpfOptions) -> Result<()> {
let BuildEbpfOptions { target, libbpf_dir } = opts;
let mut src = PathBuf::from(workspace_root());
src.push("test/integration-ebpf/src/bpf");
let mut out_path = PathBuf::from(workspace_root());
out_path.push("target");
out_path.push(target.to_string());
out_path.push("release");
let include_path = out_path.join("include");
get_libbpf_headers(libbpf_dir, &include_path)?;
let files = fs::read_dir(&src).unwrap();
for file in files {
let p = file.unwrap().path();
if let Some(ext) = p.extension() {
if ext == "c" {
let mut out = PathBuf::from(&out_path);
out.push(p.file_name().unwrap());
out.set_extension("o");
compile_with_clang(&p, &out, &include_path)?;
}
}
}
Ok(())
}
/// Build eBPF programs with clang and libbpf headers.
fn compile_with_clang(src: &Path, out: &Path, include_path: &Path) -> Result<()> {
let clang: Cow<'_, _> = match env::var_os("CLANG") {
Some(val) => val.into(),
None => OsStr::new("/usr/bin/clang").into(),
};
let arch = match env::consts::ARCH {
"x86_64" => "x86",
"aarch64" => "arm64",
arch => arch,
};
exec(
Command::new(clang)
.arg("-I")
.arg(include_path)
.args(["-g", "-O2", "-target", "bpf", "-c"])
.arg(format!("-D__TARGET_ARCH_{arch}"))
.arg(src)
.arg("-o")
.arg(out),
)
}

@ -3,20 +3,22 @@ use std::path::PathBuf;
use aya_tool::{bindgen, write_to_file}; use aya_tool::{bindgen, write_to_file};
use crate::codegen::{Architecture, Options}; use crate::codegen::{Architecture, SysrootOptions};
pub fn codegen(opts: &Options) -> Result<(), anyhow::Error> { pub fn codegen(opts: &SysrootOptions) -> Result<(), anyhow::Error> {
codegen_internal_btf_bindings(opts)?; codegen_internal_btf_bindings()?;
codegen_bindings(opts) codegen_bindings(opts)
} }
fn codegen_internal_btf_bindings(opts: &Options) -> Result<(), anyhow::Error> { fn codegen_internal_btf_bindings() -> Result<(), anyhow::Error> {
let dir = PathBuf::from("aya-obj"); let dir = PathBuf::from("aya-obj");
let generated = dir.join("src/generated"); let generated = dir.join("src/generated");
let libbpf_dir = PathBuf::from("libbpf");
let mut bindgen = bindgen::user_builder() let mut bindgen = bindgen::user_builder()
.clang_arg(format!( .clang_arg(format!(
"-I{}", "-I{}",
opts.libbpf_dir libbpf_dir
.join("include/uapi") .join("include/uapi")
.canonicalize() .canonicalize()
.unwrap() .unwrap()
@ -24,17 +26,13 @@ fn codegen_internal_btf_bindings(opts: &Options) -> Result<(), anyhow::Error> {
)) ))
.clang_arg(format!( .clang_arg(format!(
"-I{}", "-I{}",
opts.libbpf_dir libbpf_dir
.join("include") .join("include")
.canonicalize() .canonicalize()
.unwrap() .unwrap()
.to_string_lossy() .to_string_lossy()
)) ))
.header( .header(libbpf_dir.join("src/libbpf_internal.h").to_string_lossy())
opts.libbpf_dir
.join("src/libbpf_internal.h")
.to_string_lossy(),
)
.constified_enum_module("bpf_core_relo_kind"); .constified_enum_module("bpf_core_relo_kind");
let types = ["bpf_core_relo", "btf_ext_header"]; let types = ["bpf_core_relo", "btf_ext_header"];
@ -54,7 +52,13 @@ fn codegen_internal_btf_bindings(opts: &Options) -> Result<(), anyhow::Error> {
Ok(()) Ok(())
} }
fn codegen_bindings(opts: &Options) -> Result<(), anyhow::Error> { fn codegen_bindings(opts: &SysrootOptions) -> Result<(), anyhow::Error> {
let SysrootOptions {
x86_64_sysroot,
aarch64_sysroot,
armv7_sysroot,
riscv64_sysroot,
} = opts;
let types = [ let types = [
// BPF // BPF
"BPF_TYPES", "BPF_TYPES",
@ -158,15 +162,13 @@ fn codegen_bindings(opts: &Options) -> Result<(), anyhow::Error> {
let dir = PathBuf::from("aya-obj"); let dir = PathBuf::from("aya-obj");
let generated = dir.join("src/generated"); let generated = dir.join("src/generated");
let libbpf_dir = PathBuf::from("libbpf");
let builder = || { let builder = || {
bindgen::user_builder() bindgen::user_builder()
.header(dir.join("include/linux_wrapper.h").to_string_lossy()) .header(dir.join("include/linux_wrapper.h").to_string_lossy())
.clang_args(&[ .clang_args(&["-I", &*libbpf_dir.join("include/uapi").to_string_lossy()])
"-I", .clang_args(&["-I", &*libbpf_dir.join("include").to_string_lossy()])
&*opts.libbpf_dir.join("include/uapi").to_string_lossy(),
])
.clang_args(&["-I", &*opts.libbpf_dir.join("include").to_string_lossy()])
}; };
for arch in Architecture::supported() { for arch in Architecture::supported() {
@ -185,10 +187,10 @@ fn codegen_bindings(opts: &Options) -> Result<(), anyhow::Error> {
// Set the sysroot. This is needed to ensure that the correct arch // Set the sysroot. This is needed to ensure that the correct arch
// specific headers are imported. // specific headers are imported.
let sysroot = match arch { let sysroot = match arch {
Architecture::X86_64 => &opts.x86_64_sysroot, Architecture::X86_64 => x86_64_sysroot,
Architecture::ARMv7 => &opts.armv7_sysroot, Architecture::ARMv7 => armv7_sysroot,
Architecture::AArch64 => &opts.aarch64_sysroot, Architecture::AArch64 => aarch64_sysroot,
Architecture::RISCV64 => &opts.riscv64_sysroot, Architecture::RISCV64 => riscv64_sysroot,
}; };
bindgen = bindgen.clang_args(&["-I", &*sysroot.to_string_lossy()]); bindgen = bindgen.clang_args(&["-I", &*sysroot.to_string_lossy()]);

@ -8,11 +8,19 @@ use syn::{parse_str, Item};
use crate::codegen::{ use crate::codegen::{
helpers::{expand_helpers, extract_helpers}, helpers::{expand_helpers, extract_helpers},
Architecture, Options, Architecture, SysrootOptions,
}; };
pub fn codegen(opts: &Options) -> Result<(), anyhow::Error> { pub fn codegen(opts: &SysrootOptions) -> Result<(), anyhow::Error> {
let SysrootOptions {
x86_64_sysroot,
aarch64_sysroot,
armv7_sysroot,
riscv64_sysroot,
} = opts;
let dir = PathBuf::from("bpf/aya-bpf-bindings"); let dir = PathBuf::from("bpf/aya-bpf-bindings");
let libbpf_dir = PathBuf::from("libbpf");
let builder = || { let builder = || {
let mut bindgen = bindgen::bpf_builder() let mut bindgen = bindgen::bpf_builder()
@ -20,12 +28,9 @@ pub fn codegen(opts: &Options) -> Result<(), anyhow::Error> {
// aya-tool uses aya_bpf::cty. We can't use that here since aya-bpf // aya-tool uses aya_bpf::cty. We can't use that here since aya-bpf
// depends on aya-bpf-bindings so it would create a circular dep. // depends on aya-bpf-bindings so it would create a circular dep.
.ctypes_prefix("::aya_bpf_cty") .ctypes_prefix("::aya_bpf_cty")
.clang_args(&[ .clang_args(&["-I", &*libbpf_dir.join("include/uapi").to_string_lossy()])
"-I", .clang_args(&["-I", &*libbpf_dir.join("include").to_string_lossy()])
&*opts.libbpf_dir.join("include/uapi").to_string_lossy(), .clang_args(&["-I", &*libbpf_dir.join("src").to_string_lossy()])
])
.clang_args(&["-I", &*opts.libbpf_dir.join("include").to_string_lossy()])
.clang_args(&["-I", &*opts.libbpf_dir.join("src").to_string_lossy()])
// open aya-bpf-bindings/.../bindings.rs and look for mod // open aya-bpf-bindings/.../bindings.rs and look for mod
// _bindgen, those are anonymous enums // _bindgen, those are anonymous enums
.constified_enum("BPF_F_.*") .constified_enum("BPF_F_.*")
@ -82,10 +87,10 @@ pub fn codegen(opts: &Options) -> Result<(), anyhow::Error> {
// Set the sysroot. This is needed to ensure that the correct arch // Set the sysroot. This is needed to ensure that the correct arch
// specific headers are imported. // specific headers are imported.
let sysroot = match arch { let sysroot = match arch {
Architecture::X86_64 => &opts.x86_64_sysroot, Architecture::X86_64 => x86_64_sysroot,
Architecture::ARMv7 => &opts.armv7_sysroot, Architecture::ARMv7 => armv7_sysroot,
Architecture::AArch64 => &opts.aarch64_sysroot, Architecture::AArch64 => aarch64_sysroot,
Architecture::RISCV64 => &opts.riscv64_sysroot, Architecture::RISCV64 => riscv64_sysroot,
}; };
bindgen = bindgen.clang_args(&["-I", &*sysroot.to_string_lossy()]); bindgen = bindgen.clang_args(&["-I", &*sysroot.to_string_lossy()]);

@ -52,13 +52,10 @@ impl std::fmt::Display for Architecture {
} }
} }
#[derive(Parser)]
pub struct Options {
#[arg(long, action)]
libbpf_dir: PathBuf,
// sysroot options. Default to ubuntu headers installed by the // sysroot options. Default to ubuntu headers installed by the
// libc6-dev-{arm64,armel}-cross packages. // libc6-dev-{arm64,armel}-cross packages.
#[derive(Parser)]
pub struct SysrootOptions {
#[arg(long, default_value = "/usr/include/x86_64-linux-gnu", action)] #[arg(long, default_value = "/usr/include/x86_64-linux-gnu", action)]
x86_64_sysroot: PathBuf, x86_64_sysroot: PathBuf,
@ -70,6 +67,12 @@ pub struct Options {
#[arg(long, default_value = "/usr/riscv64-linux-gnu/include", action)] #[arg(long, default_value = "/usr/riscv64-linux-gnu/include", action)]
riscv64_sysroot: PathBuf, riscv64_sysroot: PathBuf,
}
#[derive(Parser)]
pub struct Options {
#[command(flatten)]
sysroot_options: SysrootOptions,
#[command(subcommand)] #[command(subcommand)]
command: Option<Command>, command: Option<Command>,
@ -84,13 +87,18 @@ enum Command {
} }
pub fn codegen(opts: Options) -> Result<(), anyhow::Error> { pub fn codegen(opts: Options) -> Result<(), anyhow::Error> {
use Command::*; let Options {
match opts.command { sysroot_options,
Some(Aya) => aya::codegen(&opts), command,
Some(AyaBpfBindings) => aya_bpf_bindings::codegen(&opts), } = opts;
match command {
Some(command) => match command {
Command::Aya => aya::codegen(&sysroot_options),
Command::AyaBpfBindings => aya_bpf_bindings::codegen(&sysroot_options),
},
None => { None => {
aya::codegen(&opts)?; aya::codegen(&sysroot_options)?;
aya_bpf_bindings::codegen(&opts) aya_bpf_bindings::codegen(&sysroot_options)
} }
} }
} }

@ -22,9 +22,6 @@ pub struct Options {
/// The command used to wrap your application /// The command used to wrap your application
#[clap(short, long, default_value = "sudo -E")] #[clap(short, long, default_value = "sudo -E")]
pub runner: String, pub runner: String,
/// libbpf directory
#[clap(long, action)]
pub libbpf_dir: PathBuf,
/// Arguments to pass to your application /// Arguments to pass to your application
#[clap(name = "args", last = true)] #[clap(name = "args", last = true)]
pub run_args: Vec<String>, pub run_args: Vec<String>,
@ -90,16 +87,11 @@ pub fn run(opts: Options) -> Result<()> {
bpf_target, bpf_target,
release, release,
runner, runner,
libbpf_dir,
run_args, run_args,
} = opts; } = opts;
// build our ebpf program followed by our application // build our ebpf program followed by our application
build_ebpf(BuildOptions { build_ebpf(BuildOptions { target: bpf_target }).context("error while building eBPF program")?;
target: bpf_target,
libbpf_dir,
})
.context("error while building eBPF program")?;
let binaries = build(release).context("error while building userspace application")?; let binaries = build(release).context("error while building userspace application")?;
let mut args = runner.trim().split_terminator(' '); let mut args = runner.trim().split_terminator(' ');

Loading…
Cancel
Save