diff --git a/Cargo.toml b/Cargo.toml index 2a41fa9c..a49fa346 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "aya-obj", "aya-tool", "init", + "test/integration-common", "test/integration-test", "xtask", @@ -31,6 +32,7 @@ default-members = [ "aya-obj", "aya-tool", "init", + "test/integration-common", # test/integration-test is omitted; including it in this list causes `cargo test` to run its # tests, and that doesn't work unless they've been built with `cargo xtask`. "xtask", diff --git a/clippy.sh b/clippy.sh index 2c50ca8e..b690f988 100755 --- a/clippy.sh +++ b/clippy.sh @@ -1,12 +1,20 @@ #!/usr/bin/env sh -# `-C panic=abort` because "unwinding panics are not supported without std"; -# integration-ebpf contains `#[no_std]` binaries. -# +set -eux + +# We cannot run clippy over the whole workspace at once due to feature unification. Since both +# integration-test and integration-ebpf depend on integration-common and integration-test activates +# integration-common's aya dependency, we end up trying to compile the panic handler twice: once +# from the bpf program, and again from std via aya. +# +# `-C panic=abort` because "unwinding panics are not supported without std"; integration-ebpf +# contains `#[no_std]` binaries. +# # `-Zpanic_abort_tests` because "building tests with panic=abort is not supported without -# `-Zpanic_abort_tests`"; Cargo does this automatically when panic=abort is set via profile -# but we want to preserve unwinding at runtime - here we are just running clippy so we don't -# care about unwinding behavior. -# +# `-Zpanic_abort_tests`"; Cargo does this automatically when panic=abort is set via profile but we +# want to preserve unwinding at runtime - here we are just running clippy so we don't care about +# unwinding behavior. +# # `+nightly` because "the option `Z` is only accepted on the nightly compiler". -exec cargo +nightly hack clippy "$@" --all-targets --feature-powerset --workspace -- --deny warnings -C panic=abort -Zpanic_abort_tests +cargo +nightly hack clippy "$@" --exclude integration-ebpf --all-targets --feature-powerset --workspace -- --deny warnings +cargo +nightly hack clippy "$@" --package integration-ebpf --all-targets --feature-powerset -- --deny warnings -C panic=abort -Zpanic_abort_tests diff --git a/test/integration-common/Cargo.toml b/test/integration-common/Cargo.toml new file mode 100644 index 00000000..07de4936 --- /dev/null +++ b/test/integration-common/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "integration-common" +version = "0.1.0" +publish = false +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +edition.workspace = true + +[dependencies] +aya = { path = "../../aya", optional = true } + +[features] +user = ["aya"] diff --git a/test/integration-common/src/lib.rs b/test/integration-common/src/lib.rs new file mode 100644 index 00000000..1b789913 --- /dev/null +++ b/test/integration-common/src/lib.rs @@ -0,0 +1,53 @@ +#![no_std] + +pub mod bpf_probe_read { + pub const RESULT_BUF_LEN: usize = 1024; + + #[derive(Copy, Clone)] + #[repr(C)] + pub struct TestResult { + pub buf: [u8; RESULT_BUF_LEN], + pub len: Option>, + } + + #[cfg(feature = "user")] + unsafe impl aya::Pod for TestResult {} +} + +pub mod ring_buf { + // This structure's definition is duplicated in the probe. + #[repr(C)] + #[derive(Clone, Copy, Debug, Eq, PartialEq, Default)] + pub struct Registers { + pub dropped: u64, + pub rejected: u64, + } + + impl core::ops::Add for Registers { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + Self { + dropped: self.dropped + rhs.dropped, + rejected: self.rejected + rhs.rejected, + } + } + } + + impl<'a> core::iter::Sum<&'a Registers> for Registers { + fn sum>(iter: I) -> Self { + iter.fold(Default::default(), |a, b| a + *b) + } + } + + #[cfg(feature = "user")] + unsafe impl aya::Pod for Registers {} +} + +pub mod strncmp { + #[derive(Copy, Clone)] + #[repr(C)] + pub struct TestResult(pub core::cmp::Ordering); + + #[cfg(feature = "user")] + unsafe impl aya::Pod for TestResult {} +} diff --git a/test/integration-ebpf/Cargo.toml b/test/integration-ebpf/Cargo.toml index 6c550dae..a23abb70 100644 --- a/test/integration-ebpf/Cargo.toml +++ b/test/integration-ebpf/Cargo.toml @@ -11,6 +11,7 @@ edition.workspace = true [dependencies] aya-ebpf = { path = "../../ebpf/aya-ebpf" } aya-log-ebpf = { path = "../../ebpf/aya-log-ebpf" } +integration-common = { path = "../integration-common" } network-types = "0.0.7" [build-dependencies] diff --git a/test/integration-ebpf/src/bpf_probe_read.rs b/test/integration-ebpf/src/bpf_probe_read.rs index 87118198..5c01e5ae 100644 --- a/test/integration-ebpf/src/bpf_probe_read.rs +++ b/test/integration-ebpf/src/bpf_probe_read.rs @@ -7,8 +7,7 @@ use aya_ebpf::{ maps::Array, programs::ProbeContext, }; - -const RESULT_BUF_LEN: usize = 1024; +use integration_common::bpf_probe_read::{TestResult, RESULT_BUF_LEN}; fn read_str_bytes( fun: unsafe fn(*const u8, &mut [u8]) -> Result<&[u8], i64>, @@ -30,9 +29,8 @@ fn read_str_bytes( }; *len = None; - // len comes from ctx.arg(1) so it's dynamic and the verifier - // doesn't see any bounds. We do len.min(RESULT_BUF_LEN) here to - // ensure that the verifier can see the upper bound, or you get: + // len comes from ctx.arg(1) so it's dynamic and the verifier doesn't see any bounds. We slice + // here to ensure that the verifier can see the upper bound, or you get: // // 18: (79) r7 = *(u64 *)(r7 +8) ; R7_w=scalar() // [snip] @@ -47,12 +45,6 @@ fn read_str_bytes( *len = Some(unsafe { fun(iptr, buf) }.map(<[_]>::len)); } -#[repr(C)] -struct TestResult { - buf: [u8; RESULT_BUF_LEN], - len: Option>, -} - #[map] static RESULT: Array = Array::with_max_entries(1, 0); diff --git a/test/integration-ebpf/src/ring_buf.rs b/test/integration-ebpf/src/ring_buf.rs index 66af6cef..6674f5e6 100644 --- a/test/integration-ebpf/src/ring_buf.rs +++ b/test/integration-ebpf/src/ring_buf.rs @@ -6,17 +6,11 @@ use aya_ebpf::{ maps::{PerCpuArray, RingBuf}, programs::ProbeContext, }; +use integration_common::ring_buf::Registers; #[map] static RING_BUF: RingBuf = RingBuf::with_byte_size(0, 0); -// This structure's definition is duplicated in userspace. -#[repr(C)] -struct Registers { - dropped: u64, - rejected: u64, -} - // Use a PerCpuArray to store the registers so that we can update the values from multiple CPUs // without needing synchronization. Atomics exist [1], but aren't exposed. // diff --git a/test/integration-ebpf/src/strncmp.rs b/test/integration-ebpf/src/strncmp.rs index 975d9f0c..a19b10d2 100644 --- a/test/integration-ebpf/src/strncmp.rs +++ b/test/integration-ebpf/src/strncmp.rs @@ -1,8 +1,6 @@ #![no_std] #![no_main] -use core::cmp::Ordering; - use aya_ebpf::{ cty::c_long, helpers::{bpf_probe_read_user_str_bytes, bpf_strncmp}, @@ -10,9 +8,7 @@ use aya_ebpf::{ maps::Array, programs::ProbeContext, }; - -#[repr(C)] -struct TestResult(Ordering); +use integration_common::strncmp::TestResult; #[map] static RESULT: Array = Array::with_max_entries(1, 0); diff --git a/test/integration-test/Cargo.toml b/test/integration-test/Cargo.toml index 07cdfafe..3a2d8014 100644 --- a/test/integration-test/Cargo.toml +++ b/test/integration-test/Cargo.toml @@ -14,6 +14,7 @@ assert_matches = { workspace = true } aya = { path = "../../aya", version = "^0.13.1", default-features = false } aya-log = { path = "../../aya-log", version = "^0.2.1", default-features = false } aya-obj = { path = "../../aya-obj", version = "^0.2.1", default-features = false } +integration-common = { path = "../integration-common", features = ["user"] } env_logger = { workspace = true } epoll = { workspace = true } futures = { workspace = true, features = ["std"] } diff --git a/test/integration-test/src/tests/bpf_probe_read.rs b/test/integration-test/src/tests/bpf_probe_read.rs index 6479a2df..9218a5b1 100644 --- a/test/integration-test/src/tests/bpf_probe_read.rs +++ b/test/integration-test/src/tests/bpf_probe_read.rs @@ -1,17 +1,7 @@ use aya::{maps::Array, programs::UProbe, Ebpf}; +use integration_common::bpf_probe_read::{TestResult, RESULT_BUF_LEN}; use test_log::test; -const RESULT_BUF_LEN: usize = 1024; - -#[derive(Copy, Clone)] -#[repr(C)] -struct TestResult { - buf: [u8; RESULT_BUF_LEN], - len: Option>, -} - -unsafe impl aya::Pod for TestResult {} - #[test] fn bpf_probe_read_user_str_bytes() { let bpf = set_user_buffer(b"foo\0", RESULT_BUF_LEN); diff --git a/test/integration-test/src/tests/ring_buf.rs b/test/integration-test/src/tests/ring_buf.rs index 18e38de9..2493bdf6 100644 --- a/test/integration-test/src/tests/ring_buf.rs +++ b/test/integration-test/src/tests/ring_buf.rs @@ -13,9 +13,10 @@ use assert_matches::assert_matches; use aya::{ maps::{array::PerCpuArray, ring_buf::RingBuf, MapData}, programs::UProbe, - Ebpf, EbpfLoader, Pod, + Ebpf, EbpfLoader, }; use aya_obj::generated::BPF_RINGBUF_HDR_SZ; +use integration_common::ring_buf::Registers; use rand::Rng as _; use test_log::test; use tokio::{ @@ -23,32 +24,6 @@ use tokio::{ time::{sleep, Duration}, }; -// This structure's definition is duplicated in the probe. -#[repr(C)] -#[derive(Clone, Copy, Debug, Eq, PartialEq, Default)] -struct Registers { - dropped: u64, - rejected: u64, -} - -impl std::ops::Add for Registers { - type Output = Self; - fn add(self, rhs: Self) -> Self::Output { - Self { - dropped: self.dropped + rhs.dropped, - rejected: self.rejected + rhs.rejected, - } - } -} - -impl<'a> std::iter::Sum<&'a Registers> for Registers { - fn sum>(iter: I) -> Self { - iter.fold(Default::default(), |a, b| a + *b) - } -} - -unsafe impl Pod for Registers {} - struct RingBufTest { _bpf: Ebpf, ring_buf: RingBuf, diff --git a/test/integration-test/src/tests/strncmp.rs b/test/integration-test/src/tests/strncmp.rs index 55254d9c..9ee66152 100644 --- a/test/integration-test/src/tests/strncmp.rs +++ b/test/integration-test/src/tests/strncmp.rs @@ -8,12 +8,7 @@ use aya::{ programs::UProbe, Ebpf, }; - -#[derive(Copy, Clone)] -#[repr(C)] -struct TestResult(Ordering); - -unsafe impl aya::Pod for TestResult {} +use integration_common::strncmp::TestResult; #[test] fn bpf_strncmp() {