diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e2ab4cee..fdb8b994 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,9 @@ jobs: with: tool: cargo-hack,taplo-cli + - name: Check C formatting + run: git ls-files -- '*.c' '*.h' | xargs clang-format --dry-run --Werror + - run: taplo fmt --check - name: Check formatting @@ -139,8 +142,14 @@ jobs: --target ${{ matrix.target }} \ -Z build-std=core - build-integration-test: - runs-on: ubuntu-22.04 + run-integration-test: + strategy: + fail-fast: false + matrix: + runner: + - macos-12 + - ubuntu-22.04 + runs-on: ${{ matrix.runner }} steps: - uses: actions/checkout@v3 with: @@ -150,13 +159,12 @@ jobs: with: toolchain: nightly components: rust-src + targets: aarch64-unknown-linux-musl,x86_64-unknown-linux-musl - uses: Swatinem/rust-cache@v2 - - name: bpf-linker - run: cargo install bpf-linker --git https://github.com/aya-rs/bpf-linker.git - - - name: Install dependencies + - name: Install prerequisites + if: runner.os == 'Linux' # ubuntu-22.04 comes with clang 14[0] which doesn't include support for signed and 64bit # enum values which was added in clang 15[1]. # @@ -171,63 +179,82 @@ jobs: set -euxo pipefail wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc echo deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy main | sudo tee /etc/apt/sources.list.d/llvm.list - sudo apt-get update - sudo apt-get -y install clang gcc-multilib llvm + sudo apt update + sudo apt -y install clang gcc-multilib llvm locate qemu-system-{arm,x86} - - name: Build + - name: bpf-linker + if: runner.os == 'Linux' + run: cargo install bpf-linker --git https://github.com/aya-rs/bpf-linker.git + + - name: Install prerequisites + if: runner.os == 'macOS' + # The xargs shipped on macOS always exits 0 with -P0, so we need GNU findutils. + # + # The tar shipped on macOS doesn't support --wildcards, so we need GNU tar. + # + # The clang shipped on macOS doesn't support BPF, so we need LLVM from brew. + # + # We also need LLVM for bpf-linker, see comment below. run: | set -euxo pipefail - mkdir -p integration-test-binaries - # See https://doc.rust-lang.org/cargo/reference/profiles.html for the - # names of the builtin profiles. Note that dev builds "debug" targets. - cargo xtask build-integration-test --cargo-arg=--profile=dev | xargs -I % cp % integration-test-binaries/dev - cargo xtask build-integration-test --cargo-arg=--profile=release | xargs -I % cp % integration-test-binaries/release - - - uses: actions/upload-artifact@v3 - with: - name: integration-test-binaries - path: integration-test-binaries + brew update + brew install dpkg findutils gnu-tar llvm pkg-config + # Workaround for https://github.com/Homebrew/homebrew-core/pull/139492. + brew reinstall qemu + echo /usr/local/opt/findutils/libexec/gnubin >> $GITHUB_PATH + echo /usr/local/opt/gnu-tar/libexec/gnubin >> $GITHUB_PATH + echo /usr/local/opt/llvm/bin >> $GITHUB_PATH - run-integration-test: - runs-on: macos-latest - needs: ["build-integration-test"] - steps: - - uses: actions/checkout@v3 - with: - sparse-checkout: | - test/run.sh - test/cloud-localds + - name: bpf-linker + if: runner.os == 'macOS' + # NB: rustc doesn't ship libLLVM.so on macOS, so disable proxying (default feature). + run: cargo install bpf-linker --git https://github.com/aya-rs/bpf-linker.git --no-default-features - - name: Install Pre-requisites + - name: Download debian kernels + if: runner.arch == 'ARM64' run: | - brew install qemu gnu-getopt coreutils cdrtools - - - name: Cache tmp files - uses: actions/cache@v3 - with: - path: | - .tmp/*.qcow2 - .tmp/test_rsa - .tmp/test_rsa.pub - key: tmp-files-${{ hashFiles('test/run.sh') }} - - - uses: actions/download-artifact@v3 - with: - name: integration-test-binaries - path: integration-test-binaries - - - name: Run integration tests + set -euxo pipefail + mkdir -p test/.tmp/debian-kernels/arm64 + # NB: a 4.19 kernel image for arm64 was not available. + # TODO: enable tests on kernels before 6.0. + # linux-image-5.10.0-23-cloud-arm64-unsigned_5.10.179-3_arm64.deb \ + printf '%s\0' \ + linux-image-6.1.0-10-cloud-arm64-unsigned_6.1.38-2_arm64.deb \ + linux-image-6.4.0-2-cloud-arm64-unsigned_6.4.4-3_arm64.deb \ + | xargs -0 -t -P0 -I {} wget -nd -nv -P test/.tmp/debian-kernels/arm64 ftp://ftp.us.debian.org/debian/pool/main/l/linux/{} + + - name: Download debian kernels + if: runner.arch == 'X64' run: | set -euxo pipefail - find integration-test-binaries -type f -exec chmod +x {} \; - test/run.sh integration-test-binaries + mkdir -p test/.tmp/debian-kernels/amd64 + # TODO: enable tests on kernels before 6.0. + # linux-image-4.19.0-21-cloud-amd64-unsigned_4.19.249-2_amd64.deb \ + # linux-image-5.10.0-23-cloud-amd64-unsigned_5.10.179-3_amd64.deb \ + printf '%s\0' \ + linux-image-6.1.0-10-cloud-amd64-unsigned_6.1.38-2_amd64.deb \ + linux-image-6.4.0-2-cloud-amd64-unsigned_6.4.4-3_amd64.deb \ + | xargs -0 -t -P0 -I {} wget -nd -nv -P test/.tmp/debian-kernels/amd64 ftp://ftp.us.debian.org/debian/pool/main/l/linux/{} + + - name: Extract debian kernels + run: | + set -euxo pipefail + find test/.tmp -name '*.deb' -print0 | xargs -t -0 -I {} \ + sh -c "dpkg --fsys-tarfile {} | tar -C test/.tmp --wildcards --extract '*vmlinuz*' --file -" + + - name: Run integration tests + run: find test/.tmp -name 'vmlinuz-*' | xargs -t cargo xtask integration-test vm # Provides a single status check for the entire build workflow. # This is used for merge automation, like Mergify, since GH actions # has no concept of "when all status checks pass". # https://docs.mergify.com/conditions/#validating-all-status-checks build-workflow-complete: - needs: ["lint", "build-test-aya", "build-test-aya-bpf", "run-integration-test"] + needs: + - lint + - build-test-aya + - build-test-aya-bpf + - run-integration-test runs-on: ubuntu-latest steps: - name: Build Complete diff --git a/Cargo.toml b/Cargo.toml index 0a95461b..f4d1df95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "aya-log-parser", "aya-obj", "aya-tool", + "init", "test/integration-test", "xtask", @@ -29,6 +30,7 @@ default-members = [ "aya-log-parser", "aya-obj", "aya-tool", + "init", # 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", @@ -72,8 +74,9 @@ lazy_static = { version = "1", default-features = false } libc = { version = "0.2.105", default-features = false } log = { version = "0.4", default-features = false } netns-rs = { version = "0.1", default-features = false } -num_enum = { version = "0.6", default-features = false } -object = { version = "0.31", default-features = false } +nix = { version = "0.26.2", default-features = false } +num_enum = { version = "0.7", default-features = false } +object = { version = "0.32", default-features = false } parking_lot = { version = "0.12.0", default-features = false } proc-macro-error = { version = "1.0", default-features = false } proc-macro2 = { version = "1", default-features = false } diff --git a/aya-log-common/src/lib.rs b/aya-log-common/src/lib.rs index 0d789e3b..472090ee 100644 --- a/aya-log-common/src/lib.rs +++ b/aya-log-common/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -use core::{mem, num, ptr}; +use core::num::{NonZeroUsize, TryFromIntError}; use num_enum::IntoPrimitive; @@ -86,7 +86,7 @@ pub trait UpperMacFormatter {} impl UpperMacFormatter for [u8; 6] {} #[repr(u8)] -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, IntoPrimitive)] pub enum RecordField { Target = 1, Level, @@ -99,7 +99,7 @@ pub enum RecordField { /// Types which are supported by aya-log and can be safely sent from eBPF /// programs to userspace. #[repr(u8)] -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, IntoPrimitive)] pub enum Argument { DisplayHint, @@ -147,65 +147,42 @@ pub enum DisplayHint { UpperMac, } -struct TagLenValue { - pub tag: T, - pub value: V, -} - -impl TagLenValue -where - V: IntoIterator, - ::IntoIter: ExactSizeIterator, -{ - pub(crate) fn write(self, mut buf: &mut [u8]) -> Result { - // Break the abstraction to please the verifier. - if buf.len() > LOG_BUF_CAPACITY { - buf = &mut buf[..LOG_BUF_CAPACITY]; - } - let Self { tag, value } = self; - let value = value.into_iter(); - let len = value.len(); - let wire_len: LogValueLength = value - .len() - .try_into() - .map_err(|num::TryFromIntError { .. }| ())?; - let size = mem::size_of_val(&tag) + mem::size_of_val(&wire_len) + len; - if size > buf.len() { - return Err(()); - } - - let tag_size = mem::size_of_val(&tag); - unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, tag) }; - buf = &mut buf[tag_size..]; - - unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, wire_len) }; - buf = &mut buf[mem::size_of_val(&wire_len)..]; - - buf.iter_mut().zip(value).for_each(|(dst, src)| { - *dst = src; - }); - - Ok(size) - } -} - -impl TagLenValue { - #[inline(always)] - pub(crate) fn new(tag: T, value: V) -> TagLenValue { - TagLenValue { tag, value } +// Must be inlined, else the BPF backend emits: +// +// llvm: :0:0: in function _ZN14aya_log_common5write17hc9ed05433e23a663E { i64, i64 } (i8, ptr, i64, ptr, i64): only integer returns supported +#[inline(always)] +pub(crate) fn write(tag: u8, value: &[u8], buf: &mut [u8]) -> Option { + let wire_len: LogValueLength = match value.len().try_into() { + Ok(wire_len) => Some(wire_len), + Err(TryFromIntError { .. }) => None, + }?; + let mut size = 0; + macro_rules! copy_from_slice { + ($value:expr) => {{ + let buf = buf.get_mut(size..)?; + let buf = buf.get_mut(..$value.len())?; + buf.copy_from_slice($value); + size += $value.len(); + }}; } + copy_from_slice!(&[tag]); + copy_from_slice!(&wire_len.to_ne_bytes()); + copy_from_slice!(value); + NonZeroUsize::new(size) } pub trait WriteToBuf { - #[allow(clippy::result_unit_err)] - fn write(self, buf: &mut [u8]) -> Result; + fn write(self, buf: &mut [u8]) -> Option; } macro_rules! impl_write_to_buf { ($type:ident, $arg_type:expr) => { impl WriteToBuf for $type { - fn write(self, buf: &mut [u8]) -> Result { - TagLenValue::new($arg_type, self.to_ne_bytes()).write(buf) + // This need not be inlined because the return value is Option where N is + // mem::size_of<$type>, which is a compile-time constant. + #[inline(never)] + fn write(self, buf: &mut [u8]) -> Option { + write($arg_type.into(), &self.to_ne_bytes(), buf) } } }; @@ -227,46 +204,65 @@ impl_write_to_buf!(f32, Argument::F32); impl_write_to_buf!(f64, Argument::F64); impl WriteToBuf for [u8; 16] { - fn write(self, buf: &mut [u8]) -> Result { - TagLenValue::new(Argument::ArrU8Len16, self).write(buf) + // This need not be inlined because the return value is Option where N is 16, which is a + // compile-time constant. + #[inline(never)] + fn write(self, buf: &mut [u8]) -> Option { + write(Argument::ArrU8Len16.into(), &self, buf) } } impl WriteToBuf for [u16; 8] { - fn write(self, buf: &mut [u8]) -> Result { + // This need not be inlined because the return value is Option where N is 16, which is a + // compile-time constant. + #[inline(never)] + fn write(self, buf: &mut [u8]) -> Option { let bytes = unsafe { core::mem::transmute::<_, [u8; 16]>(self) }; - TagLenValue::new(Argument::ArrU16Len8, bytes).write(buf) + write(Argument::ArrU16Len8.into(), &bytes, buf) } } impl WriteToBuf for [u8; 6] { - fn write(self, buf: &mut [u8]) -> Result { - TagLenValue::new(Argument::ArrU8Len6, self).write(buf) + // This need not be inlined because the return value is Option where N is 6, which is a + // compile-time constant. + #[inline(never)] + fn write(self, buf: &mut [u8]) -> Option { + write(Argument::ArrU8Len6.into(), &self, buf) } } impl WriteToBuf for &[u8] { - fn write(self, buf: &mut [u8]) -> Result { - TagLenValue::new(Argument::Bytes, self.iter().copied()).write(buf) + // Must be inlined, else the BPF backend emits: + // + // llvm: :0:0: in function _ZN63_$LT$$RF$$u5b$u8$u5d$$u20$as$u20$aya_log_common..WriteToBuf$GT$5write17h08f30a45f7b9f09dE { i64, i64 } (ptr, i64, ptr, i64): only integer returns supported + #[inline(always)] + fn write(self, buf: &mut [u8]) -> Option { + write(Argument::Bytes.into(), self, buf) } } impl WriteToBuf for &str { - fn write(self, buf: &mut [u8]) -> Result { - TagLenValue::new(Argument::Str, self.as_bytes().iter().copied()).write(buf) + // Must be inlined, else the BPF backend emits: + // + // llvm: :0:0: in function _ZN54_$LT$$RF$str$u20$as$u20$aya_log_common..WriteToBuf$GT$5write17h7e2d1ccaa758e2b5E { i64, i64 } (ptr, i64, ptr, i64): only integer returns supported + #[inline(always)] + fn write(self, buf: &mut [u8]) -> Option { + write(Argument::Str.into(), self.as_bytes(), buf) } } impl WriteToBuf for DisplayHint { - fn write(self, buf: &mut [u8]) -> Result { + // This need not be inlined because the return value is Option where N is 1, which is a + // compile-time constant. + #[inline(never)] + fn write(self, buf: &mut [u8]) -> Option { let v: u8 = self.into(); - TagLenValue::new(Argument::DisplayHint, v.to_ne_bytes()).write(buf) + write(Argument::DisplayHint.into(), &v.to_ne_bytes(), buf) } } -#[allow(clippy::result_unit_err)] #[doc(hidden)] -#[inline(always)] +#[inline(always)] // This function takes too many arguments to not be inlined. pub fn write_record_header( buf: &mut [u8], target: &str, @@ -275,20 +271,23 @@ pub fn write_record_header( file: &str, line: u32, num_args: usize, -) -> Result { +) -> Option { let level: u8 = level.into(); let mut size = 0; - size += TagLenValue::new(RecordField::Target, target.as_bytes().iter().copied()) - .write(&mut buf[size..])?; - size += TagLenValue::new(RecordField::Level, level.to_ne_bytes()).write(&mut buf[size..])?; - size += TagLenValue::new(RecordField::Module, module.as_bytes().iter().copied()) - .write(&mut buf[size..])?; - size += TagLenValue::new(RecordField::File, file.as_bytes().iter().copied()) - .write(&mut buf[size..])?; - size += TagLenValue::new(RecordField::Line, line.to_ne_bytes()).write(&mut buf[size..])?; - size += - TagLenValue::new(RecordField::NumArgs, num_args.to_ne_bytes()).write(&mut buf[size..])?; - Ok(size) + macro_rules! write { + ($tag:expr, $value:expr) => {{ + let buf = buf.get_mut(size..)?; + let len = write($tag.into(), $value, buf)?; + size += len.get(); + }}; + } + write!(RecordField::Target, target.as_bytes()); + write!(RecordField::Level, &level.to_ne_bytes()); + write!(RecordField::Module, module.as_bytes()); + write!(RecordField::File, file.as_bytes()); + write!(RecordField::Line, &line.to_ne_bytes()); + write!(RecordField::NumArgs, &num_args.to_ne_bytes()); + NonZeroUsize::new(size) } #[cfg(test)] diff --git a/aya-log-ebpf-macros/src/expand.rs b/aya-log-ebpf-macros/src/expand.rs index 78c92b47..ffbe3dbe 100644 --- a/aya-log-ebpf-macros/src/expand.rs +++ b/aya-log-ebpf-macros/src/expand.rs @@ -147,8 +147,8 @@ pub(crate) fn log(args: LogArgs, level: Option) -> Result {}, Some(::aya_log_ebpf::LogBuf { buf }) => { - let _: Result<(), ()> = (|| { - let mut len = ::aya_log_ebpf::write_record_header( + let _: Option<()> = (|| { + let size = ::aya_log_ebpf::write_record_header( buf, #target, #lvl, @@ -157,13 +157,15 @@ pub(crate) fn log(args: LogArgs, level: Option) -> Result Result { - BpfLogger::init_with_logger(bpf, DefaultLogger {}) + BpfLogger::init_with_logger(bpf, log::logger()) } /// Starts reading log records created with `aya-log-ebpf` and logs them @@ -356,23 +356,6 @@ macro_rules! impl_format_float { impl_format_float!(f32); impl_format_float!(f64); -#[derive(Copy, Clone, Debug)] -struct DefaultLogger; - -impl Log for DefaultLogger { - fn enabled(&self, metadata: &log::Metadata) -> bool { - log::logger().enabled(metadata) - } - - fn log(&self, record: &Record) { - log::logger().log(record) - } - - fn flush(&self) { - log::logger().flush() - } -} - #[derive(Error, Debug)] pub enum Error { #[error("log event array {} doesn't exist", MAP_NAME)] @@ -584,7 +567,7 @@ mod test { use aya_log_common::{write_record_header, WriteToBuf}; use log::{logger, Level}; - fn new_log(args: usize) -> Result<(usize, Vec), ()> { + fn new_log(args: usize) -> Option<(usize, Vec)> { let mut buf = vec![0; 8192]; let len = write_record_header( &mut buf, @@ -595,7 +578,7 @@ mod test { 123, args, )?; - Ok((len, buf)) + Some((len.get(), buf)) } #[test] @@ -603,7 +586,7 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(1).unwrap(); - len += "test".write(&mut input[len..]).unwrap(); + len += "test".write(&mut input[len..]).unwrap().get(); _ = len; @@ -621,8 +604,8 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(2).unwrap(); - len += "hello ".write(&mut input[len..]).unwrap(); - len += "test".write(&mut input[len..]).unwrap(); + len += "hello ".write(&mut input[len..]).unwrap().get(); + len += "test".write(&mut input[len..]).unwrap().get(); _ = len; @@ -640,8 +623,11 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(2).unwrap(); - len += DisplayHint::LowerHex.write(&mut input[len..]).unwrap(); - len += [0xde, 0xad].write(&mut input[len..]).unwrap(); + len += DisplayHint::LowerHex + .write(&mut input[len..]) + .unwrap() + .get(); + len += [0xde, 0xad].write(&mut input[len..]).unwrap().get(); _ = len; @@ -659,13 +645,19 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(5).unwrap(); - len += DisplayHint::LowerHex.write(&mut input[len..]).unwrap(); - len += [0xde, 0xad].write(&mut input[len..]).unwrap(); + len += DisplayHint::LowerHex + .write(&mut input[len..]) + .unwrap() + .get(); + len += [0xde, 0xad].write(&mut input[len..]).unwrap().get(); - len += " ".write(&mut input[len..]).unwrap(); + len += " ".write(&mut input[len..]).unwrap().get(); - len += DisplayHint::UpperHex.write(&mut input[len..]).unwrap(); - len += [0xbe, 0xef].write(&mut input[len..]).unwrap(); + len += DisplayHint::UpperHex + .write(&mut input[len..]) + .unwrap() + .get(); + len += [0xbe, 0xef].write(&mut input[len..]).unwrap().get(); _ = len; @@ -683,9 +675,9 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(3).unwrap(); - len += "default hint: ".write(&mut input[len..]).unwrap(); - len += DisplayHint::Default.write(&mut input[len..]).unwrap(); - len += 14.write(&mut input[len..]).unwrap(); + len += "default hint: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::Default.write(&mut input[len..]).unwrap().get(); + len += 14.write(&mut input[len..]).unwrap().get(); _ = len; @@ -703,9 +695,12 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(3).unwrap(); - len += "lower hex: ".write(&mut input[len..]).unwrap(); - len += DisplayHint::LowerHex.write(&mut input[len..]).unwrap(); - len += 200.write(&mut input[len..]).unwrap(); + len += "lower hex: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::LowerHex + .write(&mut input[len..]) + .unwrap() + .get(); + len += 200.write(&mut input[len..]).unwrap().get(); _ = len; @@ -723,9 +718,12 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(3).unwrap(); - len += "upper hex: ".write(&mut input[len..]).unwrap(); - len += DisplayHint::UpperHex.write(&mut input[len..]).unwrap(); - len += 200.write(&mut input[len..]).unwrap(); + len += "upper hex: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::UpperHex + .write(&mut input[len..]) + .unwrap() + .get(); + len += 200.write(&mut input[len..]).unwrap().get(); _ = len; @@ -743,10 +741,10 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(3).unwrap(); - len += "ipv4: ".write(&mut input[len..]).unwrap(); - len += DisplayHint::Ip.write(&mut input[len..]).unwrap(); + len += "ipv4: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get(); // 10.0.0.1 as u32 - len += 167772161u32.write(&mut input[len..]).unwrap(); + len += 167772161u32.write(&mut input[len..]).unwrap().get(); _ = len; @@ -764,14 +762,14 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(3).unwrap(); - len += "ipv6: ".write(&mut input[len..]).unwrap(); - len += DisplayHint::Ip.write(&mut input[len..]).unwrap(); + len += "ipv6: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get(); // 2001:db8::1:1 as byte array let ipv6_arr: [u8; 16] = [ 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, ]; - len += ipv6_arr.write(&mut input[len..]).unwrap(); + len += ipv6_arr.write(&mut input[len..]).unwrap().get(); _ = len; @@ -789,13 +787,13 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(3).unwrap(); - len += "ipv6: ".write(&mut input[len..]).unwrap(); - len += DisplayHint::Ip.write(&mut input[len..]).unwrap(); + len += "ipv6: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get(); // 2001:db8::1:1 as u16 array let ipv6_arr: [u16; 8] = [ 0x2001, 0x0db8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, ]; - len += ipv6_arr.write(&mut input[len..]).unwrap(); + len += ipv6_arr.write(&mut input[len..]).unwrap().get(); _ = len; @@ -813,11 +811,14 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(3).unwrap(); - len += "mac: ".write(&mut input[len..]).unwrap(); - len += DisplayHint::LowerMac.write(&mut input[len..]).unwrap(); + len += "mac: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::LowerMac + .write(&mut input[len..]) + .unwrap() + .get(); // 00:00:5e:00:53:af as byte array let mac_arr: [u8; 6] = [0x00, 0x00, 0x5e, 0x00, 0x53, 0xaf]; - len += mac_arr.write(&mut input[len..]).unwrap(); + len += mac_arr.write(&mut input[len..]).unwrap().get(); _ = len; @@ -835,11 +836,14 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(3).unwrap(); - len += "mac: ".write(&mut input[len..]).unwrap(); - len += DisplayHint::UpperMac.write(&mut input[len..]).unwrap(); + len += "mac: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::UpperMac + .write(&mut input[len..]) + .unwrap() + .get(); // 00:00:5E:00:53:AF as byte array let mac_arr: [u8; 6] = [0x00, 0x00, 0x5e, 0x00, 0x53, 0xaf]; - len += mac_arr.write(&mut input[len..]).unwrap(); + len += mac_arr.write(&mut input[len..]).unwrap().get(); _ = len; diff --git a/aya-obj/include/linux_wrapper.h b/aya-obj/include/linux_wrapper.h index 58ffa680..8be2459a 100644 --- a/aya-obj/include/linux_wrapper.h +++ b/aya-obj/include/linux_wrapper.h @@ -1,11 +1,11 @@ +#include #include #include -#include #include -#include -#include -#include +#include #include +#include +#include /* workaround the fact that bindgen can't parse the IOC macros */ int AYA_PERF_EVENT_IOC_ENABLE = PERF_EVENT_IOC_ENABLE; diff --git a/aya-obj/src/btf/btf.rs b/aya-obj/src/btf/btf.rs index 88d43e82..02976569 100644 --- a/aya-obj/src/btf/btf.rs +++ b/aya-obj/src/btf/btf.rs @@ -17,7 +17,7 @@ use crate::{ info::{FuncSecInfo, LineSecInfo}, relocation::Relocation, Array, BtfEnum, BtfKind, BtfMember, BtfType, Const, Enum, FuncInfo, FuncLinkage, Int, - IntEncoding, LineInfo, Struct, Typedef, VarLinkage, + IntEncoding, LineInfo, Struct, Typedef, Union, VarLinkage, }, generated::{btf_ext_header, btf_header}, util::{bytes_of, HashMap}, @@ -171,6 +171,7 @@ pub struct BtfFeatures { btf_float: bool, btf_decl_tag: bool, btf_type_tag: bool, + btf_enum64: bool, } impl BtfFeatures { @@ -182,6 +183,7 @@ impl BtfFeatures { btf_float: bool, btf_decl_tag: bool, btf_type_tag: bool, + btf_enum64: bool, ) -> Self { BtfFeatures { btf_func, @@ -190,6 +192,7 @@ impl BtfFeatures { btf_float, btf_decl_tag, btf_type_tag, + btf_enum64, } } @@ -227,6 +230,11 @@ impl BtfFeatures { pub fn btf_kind_func_proto(&self) -> bool { self.btf_func && self.btf_decl_tag } + + /// Returns true if the BTF_KIND_ENUM64 is supported. + pub fn btf_enum64(&self) -> bool { + self.btf_enum64 + } } /// Bpf Type Format metadata. @@ -467,83 +475,106 @@ impl Btf { buf } + // This follows the same logic as libbpf's bpf_object__sanitize_btf() function. + // https://github.com/libbpf/libbpf/blob/05f94ddbb837f5f4b3161e341eed21be307eaa04/src/libbpf.c#L2701 + // + // Fixup: The loader needs to adjust values in the BTF before it's loaded into the kernel. + // Sanitize: Replace an unsupported BTF type with a placeholder type. + // + // In addition to the libbpf logic, it performs some fixups to the BTF generated by bpf-linker + // for Aya programs. These fixups are gradually moving into bpf-linker itself. pub(crate) fn fixup_and_sanitize( &mut self, section_infos: &HashMap, symbol_offsets: &HashMap, features: &BtfFeatures, ) -> Result<(), BtfError> { + // ENUM64 placeholder type needs to be added before we take ownership of + // self.types to ensure that the offsets in the BtfHeader are correct. + let placeholder_name = self.add_string("enum64_placeholder"); + let enum64_placeholder_id = (!features.btf_enum64 + && self.types().any(|t| t.kind() == BtfKind::Enum64)) + .then(|| { + self.add_type(BtfType::Int(Int::new( + placeholder_name, + 1, + IntEncoding::None, + 0, + ))) + }); let mut types = mem::take(&mut self.types); for i in 0..types.types.len() { - let t = &types.types[i]; + let t = &mut types.types[i]; let kind = t.kind(); match t { - // Fixup PTR for Rust - // LLVM emits names for Rust pointer types, which the kernel doesn't like + // Fixup PTR for Rust. + // + // LLVM emits names for Rust pointer types, which the kernel doesn't like. // While I figure out if this needs fixing in the Kernel or LLVM, we'll - // do a fixup here + // do a fixup here. BtfType::Ptr(ptr) => { - let mut fixed_ty = ptr.clone(); - fixed_ty.name_offset = 0; - types.types[i] = BtfType::Ptr(fixed_ty) + ptr.name_offset = 0; } - // Sanitize VAR if they are not supported + // Sanitize VAR if they are not supported. BtfType::Var(v) if !features.btf_datasec => { - types.types[i] = BtfType::Int(Int::new(v.name_offset, 1, IntEncoding::None, 0)); + *t = BtfType::Int(Int::new(v.name_offset, 1, IntEncoding::None, 0)); } - // Sanitize DATASEC if they are not supported + // Sanitize DATASEC if they are not supported. BtfType::DataSec(d) if !features.btf_datasec => { debug!("{}: not supported. replacing with STRUCT", kind); // STRUCT aren't allowed to have "." in their name, fixup this if needed. - let mut name_offset = t.name_offset(); + let mut name_offset = d.name_offset; let name = self.string_at(name_offset)?; - // Handle any "." characters in struct names + // Handle any "." characters in struct names. // Example: ".maps" let fixed_name = name.replace('.', "_"); if fixed_name != name { name_offset = self.add_string(&fixed_name); } - let mut members = vec![]; - for member in d.entries.iter() { - let mt = types.type_by_id(member.btf_type).unwrap(); - members.push(BtfMember { - name_offset: mt.name_offset(), - btf_type: member.btf_type, - offset: member.offset * 8, + let entries = std::mem::take(&mut d.entries); + + let members = entries + .iter() + .map(|e| { + let mt = types.type_by_id(e.btf_type).unwrap(); + BtfMember { + name_offset: mt.name_offset(), + btf_type: e.btf_type, + offset: e.offset * 8, + } }) - } + .collect(); - types.types[i] = - BtfType::Struct(Struct::new(name_offset, members, d.entries.len() as u32)); + // Must reborrow here because we borrow `types` immutably above. + let t = &mut types.types[i]; + *t = BtfType::Struct(Struct::new(name_offset, members, entries.len() as u32)); } - // Fixup DATASEC - // DATASEC sizes aren't always set by LLVM - // we need to fix them here before loading the btf to the kernel + // Fixup DATASEC. + // + // DATASEC sizes aren't always set by LLVM so we need to fix them + // here before loading the btf to the kernel. BtfType::DataSec(d) if features.btf_datasec => { // Start DataSec Fixups let name = self.string_at(d.name_offset)?; let name = name.into_owned(); - let mut fixed_ty = d.clone(); - - // Handle any "/" characters in section names + // Handle any "/" characters in section names. // Example: "maps/hashmap" let fixed_name = name.replace('/', "."); if fixed_name != name { - fixed_ty.name_offset = self.add_string(&fixed_name); + d.name_offset = self.add_string(&fixed_name); } - // There are some cases when the compiler does indeed populate the - // size - if t.size().unwrap() > 0 { + // There are some cases when the compiler does indeed populate the size. + if d.size > 0 { debug!("{} {}: size fixup not required", kind, name); } else { - // We need to get the size of the section from the ELF file + // We need to get the size of the section from the ELF file. // Fortunately, we cached these when parsing it initially - // and we can this up by name in section_infos + // and we can this up by name in section_infos. let size = match section_infos.get(&name) { Some((_, size)) => size, None => { @@ -551,22 +582,23 @@ impl Btf { } }; debug!("{} {}: fixup size to {}", kind, name, size); - fixed_ty.size = *size as u32; + d.size = *size as u32; // The Vec contains BTF_KIND_VAR sections // that need to have their offsets adjusted. To do this, // we need to get the offset from the ELF file. // This was also cached during initial parsing and - // we can query by name in symbol_offsets - for d in &mut fixed_ty.entries.iter_mut() { - let var_type = types.type_by_id(d.btf_type)?; - let var_kind = var_type.kind(); - if let BtfType::Var(var) = var_type { + // we can query by name in symbol_offsets. + let mut entries = mem::take(&mut d.entries); + let mut fixed_section = d.clone(); + + for e in entries.iter_mut() { + if let BtfType::Var(var) = types.type_by_id(e.btf_type)? { let var_name = self.string_at(var.name_offset)?; if var.linkage == VarLinkage::Static { debug!( - "{} {}: {} {}: fixup not required", - kind, name, var_kind, var_name + "{} {}: VAR {}: fixup not required", + kind, name, var_name ); continue; } @@ -579,29 +611,31 @@ impl Btf { }); } }; - d.offset = *offset as u32; + e.offset = *offset as u32; debug!( - "{} {}: {} {}: fixup offset {}", - kind, name, var_kind, var_name, offset + "{} {}: VAR {}: fixup offset {}", + kind, name, var_name, offset ); } else { return Err(BtfError::InvalidDatasec); } } + fixed_section.entries = entries; + + // Must reborrow here because we borrow `types` immutably above. + let t = &mut types.types[i]; + *t = BtfType::DataSec(fixed_section); } - types.types[i] = BtfType::DataSec(fixed_ty); } - // Fixup FUNC_PROTO + // Fixup FUNC_PROTO. BtfType::FuncProto(ty) if features.btf_func => { - let mut ty = ty.clone(); for (i, param) in ty.params.iter_mut().enumerate() { if param.name_offset == 0 && param.btf_type != 0 { param.name_offset = self.add_string(&format!("param{i}")); } } - types.types[i] = BtfType::FuncProto(ty); } - // Sanitize FUNC_PROTO + // Sanitize FUNC_PROTO. BtfType::FuncProto(ty) if !features.btf_func => { debug!("{}: not supported. replacing with ENUM", kind); let members: Vec = ty @@ -612,18 +646,16 @@ impl Btf { value: p.btf_type, }) .collect(); - let enum_type = BtfType::Enum(Enum::new(ty.name_offset, members)); - types.types[i] = enum_type; + let enum_type = BtfType::Enum(Enum::new(ty.name_offset, false, members)); + *t = enum_type; } - // Sanitize FUNC + // Sanitize FUNC. BtfType::Func(ty) => { let name = self.string_at(ty.name_offset)?; - // Sanitize FUNC + // Sanitize FUNC. if !features.btf_func { debug!("{}: not supported. replacing with TYPEDEF", kind); - let typedef_type = - BtfType::Typedef(Typedef::new(ty.name_offset, ty.btf_type)); - types.types[i] = typedef_type; + *t = BtfType::Typedef(Typedef::new(ty.name_offset, ty.btf_type)); } else if !features.btf_func_global || name == "memset" || name == "memcpy" @@ -635,7 +667,6 @@ impl Btf { // and verified separately from their callers, while instead we // want tracking info (eg bound checks) to be propagated to the // memory builtins. - let mut fixed_ty = ty.clone(); if ty.linkage() == FuncLinkage::Global { if !features.btf_func_global { debug!( @@ -645,30 +676,47 @@ impl Btf { } else { debug!("changing FUNC {name} linkage to BTF_FUNC_STATIC"); } - fixed_ty.set_linkage(FuncLinkage::Static); + ty.set_linkage(FuncLinkage::Static); } - types.types[i] = BtfType::Func(fixed_ty); } } - // Sanitize FLOAT + // Sanitize FLOAT. BtfType::Float(ty) if !features.btf_float => { debug!("{}: not supported. replacing with STRUCT", kind); - let struct_ty = BtfType::Struct(Struct::new(0, vec![], ty.size)); - types.types[i] = struct_ty; + *t = BtfType::Struct(Struct::new(0, vec![], ty.size)); } - // Sanitize DECL_TAG + // Sanitize DECL_TAG. BtfType::DeclTag(ty) if !features.btf_decl_tag => { debug!("{}: not supported. replacing with INT", kind); - let int_type = BtfType::Int(Int::new(ty.name_offset, 1, IntEncoding::None, 0)); - types.types[i] = int_type; + *t = BtfType::Int(Int::new(ty.name_offset, 1, IntEncoding::None, 0)); } - // Sanitize TYPE_TAG + // Sanitize TYPE_TAG. BtfType::TypeTag(ty) if !features.btf_type_tag => { debug!("{}: not supported. replacing with CONST", kind); - let const_type = BtfType::Const(Const::new(ty.btf_type)); - types.types[i] = const_type; + *t = BtfType::Const(Const::new(ty.btf_type)); + } + // Sanitize Signed ENUMs. + BtfType::Enum(ty) if !features.btf_enum64 && ty.is_signed() => { + debug!("{}: signed ENUMs not supported. Marking as unsigned", kind); + ty.set_signed(false); } - // The type does not need fixing up or sanitization + // Sanitize ENUM64. + BtfType::Enum64(ty) if !features.btf_enum64 => { + debug!("{}: not supported. replacing with UNION", kind); + let placeholder_id = + enum64_placeholder_id.expect("enum64_placeholder_id must be set"); + let members: Vec = ty + .variants + .iter() + .map(|v| BtfMember { + name_offset: v.name_offset, + btf_type: placeholder_id, + offset: 0, + }) + .collect(); + *t = BtfType::Union(Union::new(ty.name_offset, members.len() as u32, members)); + } + // The type does not need fixing up or sanitization. _ => {} } } @@ -1056,7 +1104,8 @@ pub(crate) struct SecInfo<'a> { mod tests { use super::*; use crate::btf::{ - BtfParam, DataSec, DataSecEntry, DeclTag, Float, Func, FuncProto, Ptr, TypeTag, Var, + BtfEnum64, BtfParam, DataSec, DataSecEntry, DeclTag, Enum64, Float, Func, FuncProto, Ptr, + TypeTag, Var, }; use assert_matches::assert_matches; @@ -1244,9 +1293,9 @@ mod tests { 0, ))); - let name_offset = btf.add_string("foo"); + let var_name_offset = btf.add_string("foo"); let var_type_id = btf.add_type(BtfType::Var(Var::new( - name_offset, + var_name_offset, int_type_id, VarLinkage::Static, ))); @@ -1271,11 +1320,14 @@ mod tests { assert_eq!(fixed.name_offset , name_offset); assert_matches!(*fixed.members, [ BtfMember { - name_offset: _, + name_offset: name_offset1, btf_type, offset: 0, }, - ] => assert_eq!(btf_type, var_type_id)); + ] => { + assert_eq!(name_offset1, var_name_offset); + assert_eq!(btf_type, var_type_id); + }) }); // Ensure we can convert to bytes and back again let raw = btf.to_bytes(); @@ -1675,4 +1727,96 @@ mod tests { let u32_ty = btf.type_by_id(u32_base).unwrap(); assert_eq!(u32_ty.kind(), BtfKind::Int); } + + #[test] + fn test_sanitize_signed_enum() { + let mut btf = Btf::new(); + let name_offset = btf.add_string("signed_enum"); + let name_a = btf.add_string("A"); + let name_b = btf.add_string("B"); + let name_c = btf.add_string("C"); + let enum64_type = Enum::new( + name_offset, + true, + vec![ + BtfEnum::new(name_a, -1i32 as u32), + BtfEnum::new(name_b, -2i32 as u32), + BtfEnum::new(name_c, -3i32 as u32), + ], + ); + let enum_type_id = btf.add_type(BtfType::Enum(enum64_type)); + + let features = BtfFeatures { + btf_enum64: false, + ..Default::default() + }; + + btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features) + .unwrap(); + + assert_matches!(btf.type_by_id(enum_type_id).unwrap(), BtfType::Enum(fixed) => { + assert!(!fixed.is_signed()); + assert_matches!(fixed.variants[..], [ + BtfEnum { name_offset: name1, value: 0xFFFF_FFFF }, + BtfEnum { name_offset: name2, value: 0xFFFF_FFFE }, + BtfEnum { name_offset: name3, value: 0xFFFF_FFFD }, + ] => { + assert_eq!(name1, name_a); + assert_eq!(name2, name_b); + assert_eq!(name3, name_c); + }); + }); + + // Ensure we can convert to bytes and back again. + let raw = btf.to_bytes(); + Btf::parse(&raw, Endianness::default()).unwrap(); + } + + #[test] + fn test_sanitize_enum64() { + let mut btf = Btf::new(); + let name_offset = btf.add_string("enum64"); + let name_a = btf.add_string("A"); + let name_b = btf.add_string("B"); + let name_c = btf.add_string("C"); + let enum64_type = Enum64::new( + name_offset, + false, + vec![ + BtfEnum64::new(name_a, 1), + BtfEnum64::new(name_b, 2), + BtfEnum64::new(name_c, 3), + ], + ); + let enum_type_id = btf.add_type(BtfType::Enum64(enum64_type)); + + let features = BtfFeatures { + btf_enum64: false, + ..Default::default() + }; + + btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features) + .unwrap(); + + assert_matches!(btf.type_by_id(enum_type_id).unwrap(), BtfType::Union(fixed) => { + let placeholder = btf.id_by_type_name_kind("enum64_placeholder", BtfKind::Int) + .expect("enum64_placeholder type not found"); + assert_matches!(fixed.members[..], [ + BtfMember { name_offset: name_offset1, btf_type: btf_type1, offset: 0 }, + BtfMember { name_offset: name_offset2, btf_type: btf_type2, offset: 0 }, + BtfMember { name_offset: name_offset3, btf_type: btf_type3, offset: 0 }, + ] => { + assert_eq!(name_offset1, name_a); + assert_eq!(btf_type1, placeholder); + assert_eq!(name_offset2, name_b); + assert_eq!(btf_type2, placeholder); + assert_eq!(name_offset3, name_c); + assert_eq!(btf_type3, placeholder); + }); + }); + + // Ensure we can convert to bytes and back again. + let raw = btf.to_bytes(); + Btf::parse(&raw, Endianness::default()).unwrap(); + } } diff --git a/aya-obj/src/btf/types.rs b/aya-obj/src/btf/types.rs index a910b126..895484df 100644 --- a/aya-obj/src/btf/types.rs +++ b/aya-obj/src/btf/types.rs @@ -400,6 +400,12 @@ pub struct BtfEnum { pub value: u32, } +impl BtfEnum { + pub fn new(name_offset: u32, value: u32) -> Self { + Self { name_offset, value } + } +} + #[repr(C)] #[derive(Clone, Debug)] pub struct Enum { @@ -439,9 +445,12 @@ impl Enum { mem::size_of::() + mem::size_of::() * self.variants.len() } - pub fn new(name_offset: u32, variants: Vec) -> Self { + pub fn new(name_offset: u32, signed: bool, variants: Vec) -> Self { let mut info = (BtfKind::Enum as u32) << 24; info |= (variants.len() as u32) & 0xFFFF; + if signed { + info |= 1 << 31; + } Self { name_offset, info, @@ -453,6 +462,14 @@ impl Enum { pub(crate) fn is_signed(&self) -> bool { self.info >> 31 == 1 } + + pub(crate) fn set_signed(&mut self, signed: bool) { + if signed { + self.info |= 1 << 31; + } else { + self.info &= !(1 << 31); + } + } } #[repr(C)] @@ -463,6 +480,16 @@ pub struct BtfEnum64 { pub(crate) value_high: u32, } +impl BtfEnum64 { + pub fn new(name_offset: u32, value: u64) -> Self { + Self { + name_offset, + value_low: value as u32, + value_high: (value >> 32) as u32, + } + } +} + #[repr(C)] #[derive(Clone, Debug)] pub struct Enum64 { @@ -515,6 +542,26 @@ impl Enum64 { pub(crate) fn is_signed(&self) -> bool { self.info >> 31 == 1 } + + pub fn new(name_offset: u32, signed: bool, variants: Vec) -> Self { + let mut info = (BtfKind::Enum64 as u32) << 24; + if signed { + info |= 1 << 31 + }; + info |= (variants.len() as u32) & 0xFFFF; + Enum64 { + name_offset, + info, + // According to the documentation: + // + // https://www.kernel.org/doc/html/next/bpf/btf.html + // + // The size may be 1/2/4/8. Since BtfEnum64::new() takes a u64, we + // can assume that the size is 8. + size: 8, + variants, + } + } } #[repr(C)] @@ -614,6 +661,16 @@ pub struct Union { } impl Union { + pub(crate) fn new(name_offset: u32, size: u32, members: Vec) -> Self { + let info = (BtfKind::Union as u32) << 24; + Self { + name_offset, + info, + size, + members, + } + } + pub(crate) fn to_bytes(&self) -> Vec { let Self { name_offset, @@ -1794,4 +1851,21 @@ mod tests { assert!(types_are_compatible(&btf, u32t, &btf, u64t).unwrap()); assert!(types_are_compatible(&btf, array_type, &btf, array_type).unwrap()); } + + #[test] + pub fn test_read_btf_type_enum64() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 0x00, 0x00, 0x00, 0x00, // name offset + 0x01, 0x00, 0x00, 0x13, // info: vlen, type_kind + 0x08, 0x00, 0x00, 0x00, // size + 0xd7, 0x06, 0x00, 0x00, // enum variant name offset + 0xbb, 0xbb, 0xbb, 0xbb, // enum variant low + 0xaa, 0xaa, 0xaa, 0xaa, // enum variant high + ]; + + assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Enum64(got) => { + assert_eq!(got.to_bytes(), data); + }); + } } diff --git a/aya-obj/src/relocation.rs b/aya-obj/src/relocation.rs index fc02a79f..8269f6ca 100644 --- a/aya-obj/src/relocation.rs +++ b/aya-obj/src/relocation.rs @@ -73,15 +73,6 @@ pub enum RelocationError { address: u64, }, - /// Referenced map not created yet - #[error("the map `{name}` at section `{section_index}` has not been created")] - MapNotCreated { - /// The section index - section_index: usize, - /// The map name - name: String, - }, - /// Invalid relocation offset #[error("invalid offset `{offset}` applying relocation #{relocation_number}")] InvalidRelocationOffset { @@ -114,7 +105,7 @@ pub(crate) struct Symbol { impl Object { /// Relocates the map references - pub fn relocate_maps<'a, I: Iterator, &'a Map)>>( + pub fn relocate_maps<'a, I: Iterator>( &mut self, maps: I, text_sections: &HashSet, @@ -187,8 +178,8 @@ impl Object { fn relocate_maps<'a, I: Iterator>( fun: &mut Function, relocations: I, - maps_by_section: &HashMap, &Map)>, - maps_by_symbol: &HashMap, &Map)>, + maps_by_section: &HashMap, + maps_by_symbol: &HashMap, symbol_table: &HashMap, text_sections: &HashSet, ) -> Result<(), RelocationError> { @@ -230,7 +221,7 @@ fn relocate_maps<'a, I: Iterator>( continue; } - let (name, fd, map) = if let Some(m) = maps_by_symbol.get(&rel.symbol_index) { + let (_name, fd, map) = if let Some(m) = maps_by_symbol.get(&rel.symbol_index) { let map = &m.2; debug!( "relocating map by symbol index {:?}, kind {:?} at insn {ins_index} in section {}", @@ -266,18 +257,13 @@ fn relocate_maps<'a, I: Iterator>( }; debug_assert_eq!(map.section_index(), section_index); - let map_fd = fd.ok_or_else(|| RelocationError::MapNotCreated { - name: (*name).into(), - section_index, - })?; - if !map.data().is_empty() { instructions[ins_index].set_src_reg(BPF_PSEUDO_MAP_VALUE as u8); instructions[ins_index + 1].imm = instructions[ins_index].imm + sym.address as i32; } else { instructions[ins_index].set_src_reg(BPF_PSEUDO_MAP_FD as u8); } - instructions[ins_index].imm = map_fd; + instructions[ins_index].imm = *fd; } Ok(()) @@ -588,7 +574,7 @@ mod test { let maps_by_section = HashMap::new(); let map = fake_legacy_map(1); - let maps_by_symbol = HashMap::from([(1, ("test_map", Some(1), &map))]); + let maps_by_symbol = HashMap::from([(1, ("test_map", 1, &map))]); relocate_maps( &mut fun, @@ -642,8 +628,8 @@ mod test { let map_1 = fake_legacy_map(1); let map_2 = fake_legacy_map(2); let maps_by_symbol = HashMap::from([ - (1, ("test_map_1", Some(1), &map_1)), - (2, ("test_map_2", Some(2), &map_2)), + (1, ("test_map_1", 1, &map_1)), + (2, ("test_map_2", 2, &map_2)), ]); relocate_maps( @@ -683,7 +669,7 @@ mod test { let maps_by_section = HashMap::new(); let map = fake_btf_map(1); - let maps_by_symbol = HashMap::from([(1, ("test_map", Some(1), &map))]); + let maps_by_symbol = HashMap::from([(1, ("test_map", 1, &map))]); relocate_maps( &mut fun, @@ -737,8 +723,8 @@ mod test { let map_1 = fake_btf_map(1); let map_2 = fake_btf_map(2); let maps_by_symbol = HashMap::from([ - (1, ("test_map_1", Some(1), &map_1)), - (2, ("test_map_2", Some(2), &map_2)), + (1, ("test_map_1", 1, &map_1)), + (2, ("test_map_2", 2, &map_2)), ]); relocate_maps( diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index d768770c..f5841f3f 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -4,7 +4,7 @@ use std::{ ffi::CString, fs, io, os::{ - fd::{OwnedFd, RawFd}, + fd::{AsFd as _, OwnedFd}, raw::c_int, }, path::{Path, PathBuf}, @@ -39,8 +39,8 @@ use crate::{ sys::{ bpf_load_btf, bpf_map_freeze, bpf_map_update_elem_ptr, is_bpf_cookie_supported, is_bpf_global_data_supported, is_btf_datasec_supported, is_btf_decl_tag_supported, - is_btf_float_supported, is_btf_func_global_supported, is_btf_func_supported, - is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported, + is_btf_enum64_supported, is_btf_float_supported, is_btf_func_global_supported, + is_btf_func_supported, is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported, is_probe_read_kernel_supported, is_prog_name_supported, retry_with_verifier_logs, SyscallError, }, @@ -84,6 +84,7 @@ fn detect_features() -> Features { is_btf_float_supported(), is_btf_decl_tag_supported(), is_btf_type_tag_supported(), + is_btf_enum64_supported(), )) } else { None @@ -474,36 +475,15 @@ impl<'a> BpfLoader<'a> { } } } - let mut map = MapData { - obj, - fd: None, - pinned: false, - btf_fd: btf_fd.as_ref().map(Arc::clone), - }; - let fd = match map.obj.pinning() { + let btf_fd = btf_fd.as_deref().map(|fd| fd.as_fd()); + let mut map = match obj.pinning() { + PinningType::None => MapData::create(obj, &name, btf_fd)?, PinningType::ByName => { - let path = match &map_pin_path { - Some(p) => p, - None => return Err(BpfError::NoPinPath), - }; - // try to open map in case it's already pinned - match map.open_pinned(&name, path) { - Ok(fd) => { - map.pinned = true; - fd as RawFd - } - Err(_) => { - let fd = map.create(&name)?; - map.pin(&name, path).map_err(|error| MapError::PinError { - name: Some(name.to_string()), - error, - })?; - fd - } - } + let path = map_pin_path.as_ref().ok_or(BpfError::NoPinPath)?; + MapData::create_pinned(path, obj, &name, btf_fd)? } - PinningType::None => map.create(&name)?, }; + let fd = map.fd; if !map.obj.data().is_empty() && map.obj.section_kind() != BpfSectionKind::Bss { bpf_map_update_elem_ptr(fd, &0 as *const _, map.obj.data_mut().as_mut_ptr(), 0) .map_err(|(_, io_error)| SyscallError { diff --git a/aya/src/maps/array/array.rs b/aya/src/maps/array/array.rs index 7f242ccc..97bb46d6 100644 --- a/aya/src/maps/array/array.rs +++ b/aya/src/maps/array/array.rs @@ -39,8 +39,6 @@ impl, V: Pod> Array { let data = map.borrow(); check_kv_size::(data)?; - let _fd = data.fd_or_err()?; - Ok(Array { inner: map, _v: PhantomData, @@ -63,7 +61,7 @@ impl, V: Pod> Array { pub fn get(&self, index: &u32, flags: u64) -> Result { let data = self.inner.borrow(); check_bounds(data, *index)?; - let fd = data.fd_or_err()?; + let fd = data.fd; let value = bpf_map_lookup_elem(fd, index, flags).map_err(|(_, io_error)| SyscallError { @@ -90,7 +88,7 @@ impl, V: Pod> Array { pub fn set(&mut self, index: u32, value: impl Borrow, flags: u64) -> Result<(), MapError> { let data = self.inner.borrow_mut(); check_bounds(data, index)?; - let fd = data.fd_or_err()?; + let fd = data.fd; bpf_map_update_elem(fd, Some(&index), value.borrow(), flags).map_err(|(_, io_error)| { SyscallError { call: "bpf_map_update_elem", diff --git a/aya/src/maps/array/per_cpu_array.rs b/aya/src/maps/array/per_cpu_array.rs index 7cf1116a..6405af4a 100644 --- a/aya/src/maps/array/per_cpu_array.rs +++ b/aya/src/maps/array/per_cpu_array.rs @@ -58,8 +58,6 @@ impl, V: Pod> PerCpuArray { let data = map.borrow(); check_kv_size::(data)?; - let _fd = data.fd_or_err()?; - Ok(PerCpuArray { inner: map, _v: PhantomData, @@ -82,7 +80,7 @@ impl, V: Pod> PerCpuArray { pub fn get(&self, index: &u32, flags: u64) -> Result, MapError> { let data = self.inner.borrow(); check_bounds(data, *index)?; - let fd = data.fd_or_err()?; + let fd = data.fd; let value = bpf_map_lookup_elem_per_cpu(fd, index, flags).map_err(|(_, io_error)| { SyscallError { @@ -110,7 +108,7 @@ impl, V: Pod> PerCpuArray { pub fn set(&mut self, index: u32, values: PerCpuValues, flags: u64) -> Result<(), MapError> { let data = self.inner.borrow_mut(); check_bounds(data, index)?; - let fd = data.fd_or_err()?; + let fd = data.fd; bpf_map_update_elem_per_cpu(fd, &index, &values, flags).map_err(|(_, io_error)| { SyscallError { diff --git a/aya/src/maps/array/program_array.rs b/aya/src/maps/array/program_array.rs index b7ec75cf..e2152b56 100644 --- a/aya/src/maps/array/program_array.rs +++ b/aya/src/maps/array/program_array.rs @@ -2,7 +2,7 @@ use std::{ borrow::{Borrow, BorrowMut}, - os::fd::{AsRawFd, RawFd}, + os::fd::{AsFd as _, AsRawFd as _, RawFd}, }; use crate::{ @@ -37,13 +37,13 @@ use crate::{ /// let flags = 0; /// /// // bpf_tail_call(ctx, JUMP_TABLE, 0) will jump to prog_0 -/// prog_array.set(0, prog_0_fd, flags); +/// prog_array.set(0, &prog_0_fd, flags); /// /// // bpf_tail_call(ctx, JUMP_TABLE, 1) will jump to prog_1 -/// prog_array.set(1, prog_1_fd, flags); +/// prog_array.set(1, &prog_1_fd, flags); /// /// // bpf_tail_call(ctx, JUMP_TABLE, 2) will jump to prog_2 -/// prog_array.set(2, prog_2_fd, flags); +/// prog_array.set(2, &prog_2_fd, flags); /// # Ok::<(), aya::BpfError>(()) /// ``` #[doc(alias = "BPF_MAP_TYPE_PROG_ARRAY")] @@ -56,8 +56,6 @@ impl> ProgramArray { let data = map.borrow(); check_kv_size::(data)?; - let _fd = data.fd_or_err()?; - Ok(ProgramArray { inner: map }) } @@ -73,11 +71,12 @@ impl> ProgramArray { /// /// When an eBPF program calls `bpf_tail_call(ctx, prog_array, index)`, control /// flow will jump to `program`. - pub fn set(&mut self, index: u32, program: ProgramFd, flags: u64) -> Result<(), MapError> { + pub fn set(&mut self, index: u32, program: &ProgramFd, flags: u64) -> Result<(), MapError> { let data = self.inner.borrow_mut(); check_bounds(data, index)?; - let fd = data.fd_or_err()?; - let prog_fd = program.as_raw_fd(); + let fd = data.fd; + let prog_fd = program.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); bpf_map_update_elem(fd, Some(&index), &prog_fd, flags).map_err(|(_, io_error)| { SyscallError { @@ -95,7 +94,7 @@ impl> ProgramArray { pub fn clear_index(&mut self, index: &u32) -> Result<(), MapError> { let data = self.inner.borrow_mut(); check_bounds(data, *index)?; - let fd = self.inner.borrow_mut().fd_or_err()?; + let fd = self.inner.borrow_mut().fd; bpf_map_delete_elem(fd, index) .map(|_| ()) diff --git a/aya/src/maps/bloom_filter.rs b/aya/src/maps/bloom_filter.rs index b38bccf4..84bff986 100644 --- a/aya/src/maps/bloom_filter.rs +++ b/aya/src/maps/bloom_filter.rs @@ -1,5 +1,8 @@ //! A Bloom Filter. -use std::{borrow::Borrow, marker::PhantomData}; +use std::{ + borrow::{Borrow, BorrowMut}, + marker::PhantomData, +}; use crate::{ maps::{check_v_size, MapData, MapError}, @@ -41,8 +44,6 @@ impl, V: Pod> BloomFilter { let data = map.borrow(); check_v_size::(data)?; - let _ = data.fd_or_err()?; - Ok(BloomFilter { inner: map, _v: PhantomData, @@ -51,7 +52,7 @@ impl, V: Pod> BloomFilter { /// Query the existence of the element. pub fn contains(&self, mut value: &V, flags: u64) -> Result<(), MapError> { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; bpf_map_lookup_elem_ptr::(fd, None, &mut value, flags) .map_err(|(_, io_error)| SyscallError { @@ -61,10 +62,12 @@ impl, V: Pod> BloomFilter { .ok_or(MapError::ElementNotFound)?; Ok(()) } +} +impl, V: Pod> BloomFilter { /// Inserts a value into the map. - pub fn insert(&self, value: impl Borrow, flags: u64) -> Result<(), MapError> { - let fd = self.inner.borrow().fd_or_err()?; + pub fn insert(&mut self, value: impl Borrow, flags: u64) -> Result<(), MapError> { + let fd = self.inner.borrow_mut().fd; bpf_map_push_elem(fd, value.borrow(), flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_push_elem", io_error, @@ -106,18 +109,24 @@ mod tests { }) } + fn new_map(obj: obj::Map) -> MapData { + override_syscall(|call| match call { + Syscall::Bpf { + cmd: bpf_cmd::BPF_MAP_CREATE, + .. + } => Ok(1337), + call => panic!("unexpected syscall {:?}", call), + }); + MapData::create(obj, "foo", None).unwrap() + } + fn sys_error(value: i32) -> SysResult { Err((-1, io::Error::from_raw_os_error(value))) } #[test] fn test_wrong_value_size() { - let map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - btf_fd: None, - }; + let map = new_map(new_obj_map()); assert_matches!( BloomFilter::<_, u16>::new(&map), Err(MapError::InvalidValueSize { @@ -129,26 +138,21 @@ mod tests { #[test] fn test_try_from_wrong_map() { - let map_data = MapData { - obj: obj::Map::Legacy(LegacyMap { - def: bpf_map_def { - map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32, - key_size: 4, - value_size: 4, - max_entries: 1024, - ..Default::default() - }, - section_index: 0, - section_kind: BpfSectionKind::Maps, - symbol_index: None, - data: Vec::new(), - }), - fd: None, - pinned: false, - btf_fd: None, - }; - - let map = Map::PerfEventArray(map_data); + let map = new_map(obj::Map::Legacy(LegacyMap { + def: bpf_map_def { + map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32, + key_size: 4, + value_size: 4, + max_entries: 1024, + ..Default::default() + }, + section_index: 0, + section_kind: BpfSectionKind::Maps, + symbol_index: None, + data: Vec::new(), + })); + + let map = Map::PerfEventArray(map); assert_matches!( BloomFilter::<_, u32>::try_from(&map), @@ -156,57 +160,27 @@ mod tests { ); } - #[test] - fn test_new_not_created() { - let mut map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - btf_fd: None, - }; - - assert_matches!( - BloomFilter::<_, u32>::new(&mut map), - Err(MapError::NotCreated { .. }) - ); - } - #[test] fn test_new_ok() { - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - - assert!(BloomFilter::<_, u32>::new(&mut map).is_ok()); + let map = new_map(new_obj_map()); + + assert!(BloomFilter::<_, u32>::new(&map).is_ok()); } #[test] fn test_try_from_ok() { - let map_data = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - - let map = Map::BloomFilter(map_data); + let map = new_map(new_obj_map()); + + let map = Map::BloomFilter(map); assert!(BloomFilter::<_, u32>::try_from(&map).is_ok()) } #[test] fn test_insert_syscall_error() { - override_syscall(|_| sys_error(EFAULT)); + let mut map = new_map(new_obj_map()); + let mut bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap(); - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - let bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap(); + override_syscall(|_| sys_error(EFAULT)); assert_matches!( bloom_filter.insert(1, 0), @@ -216,6 +190,9 @@ mod tests { #[test] fn test_insert_ok() { + let mut map = new_map(new_obj_map()); + let mut bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap(); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_UPDATE_ELEM, @@ -224,28 +201,16 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - - let bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap(); assert!(bloom_filter.insert(0, 42).is_ok()); } #[test] fn test_contains_syscall_error() { - override_syscall(|_| sys_error(EFAULT)); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; + let map = new_map(new_obj_map()); let bloom_filter = BloomFilter::<_, u32>::new(&map).unwrap(); + override_syscall(|_| sys_error(EFAULT)); + assert_matches!( bloom_filter.contains(&1, 0), Err(MapError::SyscallError(SyscallError { call: "bpf_map_lookup_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) @@ -254,6 +219,9 @@ mod tests { #[test] fn test_contains_not_found() { + let map = new_map(new_obj_map()); + let bloom_filter = BloomFilter::<_, u32>::new(&map).unwrap(); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_LOOKUP_ELEM, @@ -261,13 +229,6 @@ mod tests { } => sys_error(ENOENT), _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - let bloom_filter = BloomFilter::<_, u32>::new(&map).unwrap(); assert_matches!(bloom_filter.contains(&1, 0), Err(MapError::ElementNotFound)); } diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs index 0cb8e408..b2f9e547 100644 --- a/aya/src/maps/hash_map/hash_map.rs +++ b/aya/src/maps/hash_map/hash_map.rs @@ -42,7 +42,6 @@ impl, K: Pod, V: Pod> HashMap { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.borrow(); check_kv_size::(data)?; - let _ = data.fd_or_err()?; Ok(HashMap { inner: map, @@ -53,7 +52,7 @@ impl, K: Pod, V: Pod> HashMap { /// Returns a copy of the value associated with the key. pub fn get(&self, key: &K, flags: u64) -> Result { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", io_error, @@ -137,18 +136,24 @@ mod tests { }) } + fn new_map(obj: obj::Map) -> MapData { + override_syscall(|call| match call { + Syscall::Bpf { + cmd: bpf_cmd::BPF_MAP_CREATE, + .. + } => Ok(1337), + call => panic!("unexpected syscall {:?}", call), + }); + MapData::create(obj, "foo", None).unwrap() + } + fn sys_error(value: i32) -> SysResult { Err((-1, io::Error::from_raw_os_error(value))) } #[test] fn test_wrong_key_size() { - let map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - btf_fd: None, - }; + let map = new_map(new_obj_map()); assert_matches!( HashMap::<_, u8, u32>::new(&map), Err(MapError::InvalidKeySize { @@ -160,12 +165,7 @@ mod tests { #[test] fn test_wrong_value_size() { - let map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - btf_fd: None, - }; + let map = new_map(new_obj_map()); assert_matches!( HashMap::<_, u32, u16>::new(&map), Err(MapError::InvalidValueSize { @@ -177,14 +177,8 @@ mod tests { #[test] fn test_try_from_wrong_map() { - let map_data = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - btf_fd: None, - }; - - let map = Map::Array(map_data); + let map = new_map(new_obj_map()); + let map = Map::Array(map); assert_matches!( HashMap::<_, u8, u32>::try_from(&map), Err(MapError::InvalidMapType { .. }) @@ -193,14 +187,8 @@ mod tests { #[test] fn test_try_from_wrong_map_values() { - let map_data = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - btf_fd: None, - }; - - let map = Map::HashMap(map_data); + let map = new_map(new_obj_map()); + let map = Map::HashMap(map); assert_matches!( HashMap::<_, u32, u16>::try_from(&map), Err(MapError::InvalidValueSize { @@ -210,84 +198,46 @@ mod tests { ); } - #[test] - fn test_new_not_created() { - let mut map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - btf_fd: None, - }; - - assert_matches!( - HashMap::<_, u32, u32>::new(&mut map), - Err(MapError::NotCreated { .. }) - ); - } - #[test] fn test_new_ok() { - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - - assert!(HashMap::<_, u32, u32>::new(&mut map).is_ok()); + let map = new_map(new_obj_map()); + assert!(HashMap::<_, u32, u32>::new(&map).is_ok()); } #[test] fn test_try_from_ok() { - let map_data = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - - let map = Map::HashMap(map_data); + let map = new_map(new_obj_map()); + let map = Map::HashMap(map); assert!(HashMap::<_, u32, u32>::try_from(&map).is_ok()) } #[test] fn test_try_from_ok_lru() { - let map_data = MapData { - obj: obj::Map::Legacy(LegacyMap { - def: bpf_map_def { - map_type: BPF_MAP_TYPE_LRU_HASH as u32, - key_size: 4, - value_size: 4, - max_entries: 1024, - ..Default::default() - }, - section_index: 0, - section_kind: BpfSectionKind::Maps, - symbol_index: None, - data: Vec::new(), - }), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - - let map = Map::HashMap(map_data); + let map = new_map(obj::Map::Legacy(LegacyMap { + def: bpf_map_def { + map_type: BPF_MAP_TYPE_LRU_HASH as u32, + key_size: 4, + value_size: 4, + max_entries: 1024, + ..Default::default() + }, + section_index: 0, + section_kind: BpfSectionKind::Maps, + symbol_index: None, + data: Vec::new(), + })); + let map = Map::HashMap(map); assert!(HashMap::<_, u32, u32>::try_from(&map).is_ok()) } #[test] fn test_insert_syscall_error() { - override_syscall(|_| sys_error(EFAULT)); - - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; + let mut map = new_map(new_obj_map()); let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); + override_syscall(|_| sys_error(EFAULT)); + assert_matches!( hm.insert(1, 42, 0), Err(MapError::SyscallError(SyscallError { call: "bpf_map_update_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) @@ -296,6 +246,9 @@ mod tests { #[test] fn test_insert_ok() { + let mut map = new_map(new_obj_map()); + let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_UPDATE_ELEM, @@ -304,19 +257,14 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); - assert!(hm.insert(1, 42, 0).is_ok()); } #[test] fn test_insert_boxed_ok() { + let mut map = new_map(new_obj_map()); + let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_UPDATE_ELEM, @@ -325,29 +273,16 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); - assert!(hm.insert(Box::new(1), Box::new(42), 0).is_ok()); } #[test] fn test_remove_syscall_error() { - override_syscall(|_| sys_error(EFAULT)); - - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; + let mut map = new_map(new_obj_map()); let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); + override_syscall(|_| sys_error(EFAULT)); + assert_matches!( hm.remove(&1), Err(MapError::SyscallError(SyscallError { call: "bpf_map_delete_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) @@ -356,6 +291,9 @@ mod tests { #[test] fn test_remove_ok() { + let mut map = new_map(new_obj_map()); + let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_DELETE_ELEM, @@ -364,26 +302,13 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); - assert!(hm.remove(&1).is_ok()); } #[test] fn test_get_syscall_error() { + let map = new_map(new_obj_map()); override_syscall(|_| sys_error(EFAULT)); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); assert_matches!( @@ -394,6 +319,7 @@ mod tests { #[test] fn test_get_not_found() { + let map = new_map(new_obj_map()); override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_LOOKUP_ELEM, @@ -401,12 +327,6 @@ mod tests { } => sys_error(ENOENT), _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); assert_matches!(hm.get(&1, 0), Err(MapError::KeyNotFound)); @@ -431,6 +351,7 @@ mod tests { #[test] fn test_keys_empty() { + let map = new_map(new_obj_map()); override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_GET_NEXT_KEY, @@ -438,12 +359,6 @@ mod tests { } => sys_error(ENOENT), _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let keys = hm.keys().collect::, _>>(); assert_matches!(keys, Ok(ks) if ks.is_empty()) @@ -479,6 +394,8 @@ mod tests { // to support stable as well. #[cfg_attr(miri, ignore)] fn test_keys() { + let map = new_map(new_obj_map()); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_GET_NEXT_KEY, @@ -487,12 +404,6 @@ mod tests { _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let keys = hm.keys().collect::, _>>().unwrap(); @@ -505,6 +416,7 @@ mod tests { // to support stable as well. #[cfg_attr(miri, ignore)] fn test_keys_error() { + let map = new_map(new_obj_map()); override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_GET_NEXT_KEY, @@ -520,12 +432,6 @@ mod tests { } _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let mut keys = hm.keys(); @@ -547,6 +453,7 @@ mod tests { // to support stable as well. #[cfg_attr(miri, ignore)] fn test_iter() { + let map = new_map(new_obj_map()); override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_GET_NEXT_KEY, @@ -558,12 +465,6 @@ mod tests { } => lookup_elem(attr), _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let items = hm.iter().collect::, _>>().unwrap(); assert_eq!(&items, &[(10, 100), (20, 200), (30, 300)]) @@ -575,6 +476,7 @@ mod tests { // to support stable as well. #[cfg_attr(miri, ignore)] fn test_iter_key_deleted() { + let map = new_map(new_obj_map()); override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_GET_NEXT_KEY, @@ -596,12 +498,6 @@ mod tests { } _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let items = hm.iter().collect::, _>>().unwrap(); @@ -614,6 +510,7 @@ mod tests { // to support stable as well. #[cfg_attr(miri, ignore)] fn test_iter_key_error() { + let map = new_map(new_obj_map()); override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_GET_NEXT_KEY, @@ -635,12 +532,6 @@ mod tests { } => lookup_elem(attr), _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let mut iter = hm.iter(); @@ -662,6 +553,7 @@ mod tests { // to support stable as well. #[cfg_attr(miri, ignore)] fn test_iter_value_error() { + let map = new_map(new_obj_map()); override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_GET_NEXT_KEY, @@ -683,12 +575,6 @@ mod tests { } _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let mut iter = hm.iter(); diff --git a/aya/src/maps/hash_map/mod.rs b/aya/src/maps/hash_map/mod.rs index 62d3fc55..87fc0d70 100644 --- a/aya/src/maps/hash_map/mod.rs +++ b/aya/src/maps/hash_map/mod.rs @@ -20,7 +20,7 @@ pub(crate) fn insert( value: &V, flags: u64, ) -> Result<(), MapError> { - let fd = map.fd_or_err()?; + let fd = map.fd; bpf_map_update_elem(fd, Some(key), value, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_update_elem", io_error, @@ -30,7 +30,7 @@ pub(crate) fn insert( } pub(crate) fn remove(map: &MapData, key: &K) -> Result<(), MapError> { - let fd = map.fd_or_err()?; + let fd = map.fd; bpf_map_delete_elem(fd, key) .map(|_| ()) .map_err(|(_, io_error)| { diff --git a/aya/src/maps/hash_map/per_cpu_hash_map.rs b/aya/src/maps/hash_map/per_cpu_hash_map.rs index 979970cc..7fd90ec0 100644 --- a/aya/src/maps/hash_map/per_cpu_hash_map.rs +++ b/aya/src/maps/hash_map/per_cpu_hash_map.rs @@ -52,8 +52,6 @@ impl, K: Pod, V: Pod> PerCpuHashMap { let data = map.borrow(); check_kv_size::(data)?; - let _ = data.fd_or_err()?; - Ok(PerCpuHashMap { inner: map, _k: PhantomData, @@ -63,7 +61,7 @@ impl, K: Pod, V: Pod> PerCpuHashMap { /// Returns a slice of values - one for each CPU - associated with the key. pub fn get(&self, key: &K, flags: u64) -> Result, MapError> { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; let values = bpf_map_lookup_elem_per_cpu(fd, key, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", @@ -120,7 +118,7 @@ impl, K: Pod, V: Pod> PerCpuHashMap { values: PerCpuValues, flags: u64, ) -> Result<(), MapError> { - let fd = self.inner.borrow_mut().fd_or_err()?; + let fd = self.inner.borrow_mut().fd; bpf_map_update_elem_per_cpu(fd, key.borrow(), &values, flags).map_err( |(_, io_error)| SyscallError { call: "bpf_map_update_elem", diff --git a/aya/src/maps/lpm_trie.rs b/aya/src/maps/lpm_trie.rs index 075aa558..d05ec2cf 100644 --- a/aya/src/maps/lpm_trie.rs +++ b/aya/src/maps/lpm_trie.rs @@ -117,8 +117,6 @@ impl, K: Pod, V: Pod> LpmTrie { let data = map.borrow(); check_kv_size::, V>(data)?; - let _ = data.fd_or_err()?; - Ok(LpmTrie { inner: map, _k: PhantomData, @@ -128,7 +126,7 @@ impl, K: Pod, V: Pod> LpmTrie { /// Returns a copy of the value associated with the longest prefix matching key in the LpmTrie. pub fn get(&self, key: &Key, flags: u64) -> Result { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", io_error, @@ -157,7 +155,7 @@ impl, K: Pod, V: Pod> LpmTrie { value: impl Borrow, flags: u64, ) -> Result<(), MapError> { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; bpf_map_update_elem(fd, Some(key), value.borrow(), flags).map_err(|(_, io_error)| { SyscallError { call: "bpf_map_update_elem", @@ -172,7 +170,7 @@ impl, K: Pod, V: Pod> LpmTrie { /// /// Both the prefix and data must match exactly - this method does not do a longest prefix match. pub fn remove(&mut self, key: &Key) -> Result<(), MapError> { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; bpf_map_delete_elem(fd, key) .map(|_| ()) .map_err(|(_, io_error)| { @@ -228,18 +226,24 @@ mod tests { }) } + fn new_map(obj: obj::Map) -> MapData { + override_syscall(|call| match call { + Syscall::Bpf { + cmd: bpf_cmd::BPF_MAP_CREATE, + .. + } => Ok(1337), + call => panic!("unexpected syscall {:?}", call), + }); + MapData::create(obj, "foo", None).unwrap() + } + fn sys_error(value: i32) -> SysResult { Err((-1, io::Error::from_raw_os_error(value))) } #[test] fn test_wrong_key_size() { - let map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - btf_fd: None, - }; + let map = new_map(new_obj_map()); assert_matches!( LpmTrie::<_, u16, u32>::new(&map), Err(MapError::InvalidKeySize { @@ -251,12 +255,7 @@ mod tests { #[test] fn test_wrong_value_size() { - let map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - btf_fd: None, - }; + let map = new_map(new_obj_map()); assert_matches!( LpmTrie::<_, u32, u16>::new(&map), Err(MapError::InvalidValueSize { @@ -268,26 +267,21 @@ mod tests { #[test] fn test_try_from_wrong_map() { - let map_data = MapData { - obj: obj::Map::Legacy(LegacyMap { - def: bpf_map_def { - map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32, - key_size: 4, - value_size: 4, - max_entries: 1024, - ..Default::default() - }, - section_index: 0, - section_kind: BpfSectionKind::Maps, - symbol_index: None, - data: Vec::new(), - }), - fd: None, - btf_fd: None, - pinned: false, - }; - - let map = Map::PerfEventArray(map_data); + let map = new_map(obj::Map::Legacy(LegacyMap { + def: bpf_map_def { + map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32, + key_size: 4, + value_size: 4, + max_entries: 1024, + ..Default::default() + }, + section_index: 0, + section_kind: BpfSectionKind::Maps, + symbol_index: None, + data: Vec::new(), + })); + + let map = Map::PerfEventArray(map); assert_matches!( LpmTrie::<_, u32, u32>::try_from(&map), @@ -295,59 +289,30 @@ mod tests { ); } - #[test] - fn test_new_not_created() { - let mut map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - btf_fd: None, - }; - - assert_matches!( - LpmTrie::<_, u32, u32>::new(&mut map), - Err(MapError::NotCreated { .. }) - ); - } - #[test] fn test_new_ok() { - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - - assert!(LpmTrie::<_, u32, u32>::new(&mut map).is_ok()); + let map = new_map(new_obj_map()); + + assert!(LpmTrie::<_, u32, u32>::new(&map).is_ok()); } #[test] fn test_try_from_ok() { - let map_data = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - - let map = Map::LpmTrie(map_data); + let map = new_map(new_obj_map()); + + let map = Map::LpmTrie(map); assert!(LpmTrie::<_, u32, u32>::try_from(&map).is_ok()) } #[test] fn test_insert_syscall_error() { - override_syscall(|_| sys_error(EFAULT)); - - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; + let mut map = new_map(new_obj_map()); let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); let ipaddr = Ipv4Addr::new(8, 8, 8, 8); let key = Key::new(16, u32::from(ipaddr).to_be()); + + override_syscall(|_| sys_error(EFAULT)); + assert_matches!( trie.insert(&key, 1, 0), Err(MapError::SyscallError(SyscallError { call: "bpf_map_update_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) @@ -356,6 +321,11 @@ mod tests { #[test] fn test_insert_ok() { + let mut map = new_map(new_obj_map()); + let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); + let ipaddr = Ipv4Addr::new(8, 8, 8, 8); + let key = Key::new(16, u32::from(ipaddr).to_be()); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_UPDATE_ELEM, @@ -364,32 +334,18 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - - let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); - let ipaddr = Ipv4Addr::new(8, 8, 8, 8); - let key = Key::new(16, u32::from(ipaddr).to_be()); assert!(trie.insert(&key, 1, 0).is_ok()); } #[test] fn test_remove_syscall_error() { - override_syscall(|_| sys_error(EFAULT)); - - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; + let mut map = new_map(new_obj_map()); let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); let ipaddr = Ipv4Addr::new(8, 8, 8, 8); let key = Key::new(16, u32::from(ipaddr).to_be()); + + override_syscall(|_| sys_error(EFAULT)); + assert_matches!( trie.remove(&key), Err(MapError::SyscallError(SyscallError { call: "bpf_map_delete_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) @@ -398,6 +354,11 @@ mod tests { #[test] fn test_remove_ok() { + let mut map = new_map(new_obj_map()); + let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); + let ipaddr = Ipv4Addr::new(8, 8, 8, 8); + let key = Key::new(16, u32::from(ipaddr).to_be()); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_DELETE_ELEM, @@ -406,31 +367,18 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); - let ipaddr = Ipv4Addr::new(8, 8, 8, 8); - let key = Key::new(16, u32::from(ipaddr).to_be()); assert!(trie.remove(&key).is_ok()); } #[test] fn test_get_syscall_error() { - override_syscall(|_| sys_error(EFAULT)); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; + let map = new_map(new_obj_map()); let trie = LpmTrie::<_, u32, u32>::new(&map).unwrap(); let ipaddr = Ipv4Addr::new(8, 8, 8, 8); let key = Key::new(16, u32::from(ipaddr).to_be()); + override_syscall(|_| sys_error(EFAULT)); + assert_matches!( trie.get(&key, 0), Err(MapError::SyscallError(SyscallError { call: "bpf_map_lookup_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) @@ -439,6 +387,11 @@ mod tests { #[test] fn test_get_not_found() { + let map = new_map(new_obj_map()); + let trie = LpmTrie::<_, u32, u32>::new(&map).unwrap(); + let ipaddr = Ipv4Addr::new(8, 8, 8, 8); + let key = Key::new(16, u32::from(ipaddr).to_be()); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_LOOKUP_ELEM, @@ -446,15 +399,6 @@ mod tests { } => sys_error(ENOENT), _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - btf_fd: None, - }; - let trie = LpmTrie::<_, u32, u32>::new(&map).unwrap(); - let ipaddr = Ipv4Addr::new(8, 8, 8, 8); - let key = Key::new(16, u32::from(ipaddr).to_be()); assert_matches!(trie.get(&key, 0), Err(MapError::KeyNotFound)); } diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 25ca21be..8458989c 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -42,10 +42,9 @@ use std::{ marker::PhantomData, mem, ops::Deref, - os::fd::{AsFd as _, AsRawFd, IntoRawFd as _, OwnedFd, RawFd}, + os::fd::{AsFd as _, AsRawFd, BorrowedFd, IntoRawFd as _, OwnedFd, RawFd}, path::Path, ptr, - sync::Arc, }; use crate::util::KernelVersion; @@ -104,17 +103,6 @@ pub enum MapError { name: String, }, - /// The map has not been created - #[error("the map has not been created")] - NotCreated, - - /// The map has already been created - #[error("the map `{name}` has already been created")] - AlreadyCreated { - /// Map name - name: String, - }, - /// Failed to create map #[error("failed to create map `{name}` with code {code}")] CreateError { @@ -481,62 +469,71 @@ pub(crate) fn check_v_size(map: &MapData) -> Result<(), MapError> { #[derive(Debug)] pub struct MapData { pub(crate) obj: obj::Map, - pub(crate) fd: Option, - pub(crate) btf_fd: Option>, + pub(crate) fd: RawFd, /// Indicates if this map has been pinned to bpffs pub pinned: bool, } impl MapData { /// Creates a new map with the provided `name` - pub fn create(&mut self, name: &str) -> Result { - if self.fd.is_some() { - return Err(MapError::AlreadyCreated { name: name.into() }); - } - + pub fn create( + obj: obj::Map, + name: &str, + btf_fd: Option>, + ) -> Result { let c_name = CString::new(name).map_err(|_| MapError::InvalidName { name: name.into() })?; #[cfg(not(test))] let kernel_version = KernelVersion::current().unwrap(); #[cfg(test)] let kernel_version = KernelVersion::new(0xff, 0xff, 0xff); - let fd = bpf_create_map( - &c_name, - &self.obj, - self.btf_fd.as_ref().map(|f| f.as_fd()), - kernel_version, - ) - .map_err(|(code, io_error)| { - if kernel_version < KernelVersion::new(5, 11, 0) { - maybe_warn_rlimit(); - } + let fd = + bpf_create_map(&c_name, &obj, btf_fd, kernel_version).map_err(|(code, io_error)| { + if kernel_version < KernelVersion::new(5, 11, 0) { + maybe_warn_rlimit(); + } - MapError::CreateError { - name: name.into(), - code, - io_error, - } - })?; + MapError::CreateError { + name: name.into(), + code, + io_error, + } + })?; - Ok(*self.fd.insert(fd as RawFd)) + Ok(Self { + obj, + fd: fd as RawFd, + pinned: false, + }) } - pub(crate) fn open_pinned>( - &mut self, - name: &str, + pub(crate) fn create_pinned>( path: P, - ) -> Result { - if self.fd.is_some() { - return Err(MapError::AlreadyCreated { name: name.into() }); - } + obj: obj::Map, + name: &str, + btf_fd: Option>, + ) -> Result { + // try to open map in case it's already pinned let map_path = path.as_ref().join(name); let path_string = CString::new(map_path.to_str().unwrap()).unwrap(); - let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError { + match bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError { call: "BPF_OBJ_GET", io_error, - })?; - - Ok(*self.fd.insert(fd.into_raw_fd())) + }) { + Ok(fd) => Ok(Self { + obj, + fd: fd.into_raw_fd(), + pinned: false, + }), + Err(_) => { + let mut map = Self::create(obj, name, btf_fd)?; + map.pin(name, path).map_err(|error| MapError::PinError { + name: Some(name.into()), + error, + })?; + Ok(map) + } + } } /// Loads a map from a pinned path in bpffs. @@ -560,8 +557,7 @@ impl MapData { Ok(MapData { obj: parse_map_info(info, PinningType::ByName), - fd: Some(fd.into_raw_fd()), - btf_fd: None, + fd: fd.into_raw_fd(), pinned: true, }) } @@ -576,61 +572,54 @@ impl MapData { Ok(MapData { obj: parse_map_info(info, PinningType::None), - fd: Some(fd.into_raw_fd()), - btf_fd: None, + fd: fd.into_raw_fd(), pinned: false, }) } - pub(crate) fn fd_or_err(&self) -> Result { - self.fd.ok_or(MapError::NotCreated) - } - pub(crate) fn pin>(&mut self, name: &str, path: P) -> Result<(), PinError> { - if self.pinned { + let Self { fd, pinned, obj: _ } = self; + if *pinned { return Err(PinError::AlreadyPinned { name: name.into() }); } let map_path = path.as_ref().join(name); - let fd = self.fd.ok_or(PinError::NoFd { - name: name.to_string(), - })?; let path_string = CString::new(map_path.to_string_lossy().into_owned()).map_err(|e| { PinError::InvalidPinPath { error: e.to_string(), } })?; - bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| SyscallError { + bpf_pin_object(*fd, &path_string).map_err(|(_, io_error)| SyscallError { call: "BPF_OBJ_PIN", io_error, })?; - self.pinned = true; + *pinned = true; Ok(()) } /// Returns the file descriptor of the map. /// /// Can be converted to [`RawFd`] using [`AsRawFd`]. - pub fn fd(&self) -> Option { - self.fd.map(MapFd) + pub fn fd(&self) -> MapFd { + MapFd(self.fd) } } impl Drop for MapData { fn drop(&mut self) { // TODO: Replace this with an OwnedFd once that is stabilized. - if let Some(fd) = self.fd.take() { - unsafe { libc::close(fd) }; - } + // + // SAFETY: `drop` is only called once. + unsafe { libc::close(self.fd) }; } } impl Clone for MapData { - fn clone(&self) -> MapData { - MapData { - obj: self.obj.clone(), - fd: self.fd.map(|fd| unsafe { libc::dup(fd) }), - btf_fd: self.btf_fd.as_ref().map(Arc::clone), - pinned: self.pinned, + fn clone(&self) -> Self { + let Self { obj, fd, pinned } = self; + Self { + obj: obj.clone(), + fd: unsafe { libc::dup(*fd) }, + pinned: *pinned, } } } @@ -669,14 +658,7 @@ impl Iterator for MapKeys<'_, K> { return None; } - let fd = match self.map.fd_or_err() { - Ok(fd) => fd, - Err(e) => { - self.err = true; - return Some(Err(e)); - } - }; - + let fd = self.map.fd; let key = bpf_map_get_next_key(fd, self.key.as_ref()).map_err(|(_, io_error)| SyscallError { call: "bpf_map_get_next_key", @@ -859,15 +841,6 @@ mod tests { }) } - fn new_map() -> MapData { - MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - btf_fd: None, - } - } - #[test] fn test_create() { override_syscall(|call| match call { @@ -878,29 +851,27 @@ mod tests { _ => Err((-1, io::Error::from_raw_os_error(EFAULT))), }); - let mut map = new_map(); - assert_matches!(map.create("foo"), Ok(42)); - assert_eq!(map.fd, Some(42)); - assert_matches!(map.create("foo"), Err(MapError::AlreadyCreated { .. })); + assert_matches!( + MapData::create(new_obj_map(), "foo", None), + Ok(MapData { + obj: _, + fd: 42, + pinned: false + }) + ); } #[test] fn test_create_failed() { override_syscall(|_| Err((-42, io::Error::from_raw_os_error(EFAULT)))); - let mut map = new_map(); - let ret = map.create("foo"); - assert_matches!(ret, Err(MapError::CreateError { .. })); - if let Err(MapError::CreateError { - name, - code, - io_error, - }) = ret - { - assert_eq!(name, "foo"); - assert_eq!(code, -42); - assert_eq!(io_error.raw_os_error(), Some(EFAULT)); - } - assert_eq!(map.fd, None); + assert_matches!( + MapData::create(new_obj_map(), "foo", None), + Err(MapError::CreateError { name, code, io_error }) => { + assert_eq!(name, "foo"); + assert_eq!(code, -42); + assert_eq!(io_error.raw_os_error(), Some(EFAULT)); + } + ); } } diff --git a/aya/src/maps/perf/async_perf_event_array.rs b/aya/src/maps/perf/async_perf_event_array.rs index 4de4dd86..447df95d 100644 --- a/aya/src/maps/perf/async_perf_event_array.rs +++ b/aya/src/maps/perf/async_perf_event_array.rs @@ -1,7 +1,7 @@ use bytes::BytesMut; use std::{ borrow::{Borrow, BorrowMut}, - os::fd::{AsRawFd, RawFd}, + os::fd::{AsRawFd as _, RawFd}, }; // See https://doc.rust-lang.org/cargo/reference/features.html#mutually-exclusive-features. diff --git a/aya/src/maps/perf/perf_event_array.rs b/aya/src/maps/perf/perf_event_array.rs index 3d6a8103..7d647164 100644 --- a/aya/src/maps/perf/perf_event_array.rs +++ b/aya/src/maps/perf/perf_event_array.rs @@ -162,8 +162,6 @@ pub struct PerfEventArray { impl> PerfEventArray { pub(crate) fn new(map: T) -> Result, MapError> { - let _fd = map.borrow().fd_or_err()?; - Ok(PerfEventArray { map: Arc::new(map), page_size: page_size(), @@ -184,7 +182,7 @@ impl + Borrow> PerfEventArray { // this cannot fail as new() checks that the fd is open let map_data: &MapData = self.map.deref().borrow(); - let map_fd = map_data.fd_or_err().unwrap(); + let map_fd = map_data.fd; let buf = PerfBuffer::open(index, self.page_size, page_count.unwrap_or(2))?; bpf_map_update_elem(map_fd, Some(&index), &buf.as_raw_fd(), 0) .map_err(|(_, io_error)| io_error)?; diff --git a/aya/src/maps/queue.rs b/aya/src/maps/queue.rs index 6b635dcb..78b81ec2 100644 --- a/aya/src/maps/queue.rs +++ b/aya/src/maps/queue.rs @@ -38,8 +38,6 @@ impl, V: Pod> Queue { let data = map.borrow(); check_kv_size::<(), V>(data)?; - let _fd = data.fd_or_err()?; - Ok(Queue { inner: map, _v: PhantomData, @@ -62,7 +60,7 @@ impl, V: Pod> Queue { /// Returns [`MapError::ElementNotFound`] if the queue is empty, [`MapError::SyscallError`] /// if `bpf_map_lookup_and_delete_elem` fails. pub fn pop(&mut self, flags: u64) -> Result { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; let value = bpf_map_lookup_and_delete_elem::(fd, None, flags).map_err( |(_, io_error)| SyscallError { @@ -79,7 +77,7 @@ impl, V: Pod> Queue { /// /// [`MapError::SyscallError`] if `bpf_map_update_elem` fails. pub fn push(&mut self, value: impl Borrow, flags: u64) -> Result<(), MapError> { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; bpf_map_push_elem(fd, value.borrow(), flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_push_elem", io_error, diff --git a/aya/src/maps/sock/sock_hash.rs b/aya/src/maps/sock/sock_hash.rs index 0e87aa98..1904ec1e 100644 --- a/aya/src/maps/sock/sock_hash.rs +++ b/aya/src/maps/sock/sock_hash.rs @@ -72,7 +72,6 @@ impl, K: Pod> SockHash { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.borrow(); check_kv_size::(data)?; - let _ = data.fd_or_err()?; Ok(SockHash { inner: map, @@ -82,7 +81,7 @@ impl, K: Pod> SockHash { /// Returns the fd of the socket stored at the given key. pub fn get(&self, key: &K, flags: u64) -> Result { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", io_error, @@ -107,7 +106,7 @@ impl, K: Pod> SockHash { /// The returned file descriptor can be used to attach programs that work with /// socket maps, like [`SkMsg`](crate::programs::SkMsg) and [`SkSkb`](crate::programs::SkSkb). pub fn fd(&self) -> Result { - Ok(SockMapFd(self.inner.borrow().fd_or_err()?)) + Ok(SockMapFd(self.inner.borrow().fd)) } } diff --git a/aya/src/maps/sock/sock_map.rs b/aya/src/maps/sock/sock_map.rs index b6877827..52574f23 100644 --- a/aya/src/maps/sock/sock_map.rs +++ b/aya/src/maps/sock/sock_map.rs @@ -49,8 +49,6 @@ impl> SockMap { let data = map.borrow(); check_kv_size::(data)?; - let _fd = data.fd_or_err()?; - Ok(SockMap { inner: map }) } @@ -65,7 +63,7 @@ impl> SockMap { /// The returned file descriptor can be used to attach programs that work with /// socket maps, like [`SkMsg`](crate::programs::SkMsg) and [`SkSkb`](crate::programs::SkSkb). pub fn fd(&self) -> Result { - Ok(SockMapFd(self.inner.borrow().fd_or_err()?)) + Ok(SockMapFd(self.inner.borrow().fd)) } } @@ -73,7 +71,7 @@ impl> SockMap { /// Stores a socket into the map. pub fn set(&mut self, index: u32, socket: &I, flags: u64) -> Result<(), MapError> { let data = self.inner.borrow_mut(); - let fd = data.fd_or_err()?; + let fd = data.fd; check_bounds(data, index)?; bpf_map_update_elem(fd, Some(&index), &socket.as_raw_fd(), flags).map_err( |(_, io_error)| SyscallError { @@ -87,7 +85,7 @@ impl> SockMap { /// Removes the socket stored at `index` from the map. pub fn clear_index(&mut self, index: &u32) -> Result<(), MapError> { let data = self.inner.borrow_mut(); - let fd = data.fd_or_err()?; + let fd = data.fd; check_bounds(data, *index)?; bpf_map_delete_elem(fd, index) .map(|_| ()) diff --git a/aya/src/maps/stack.rs b/aya/src/maps/stack.rs index 8004e486..0cc9b1d8 100644 --- a/aya/src/maps/stack.rs +++ b/aya/src/maps/stack.rs @@ -38,8 +38,6 @@ impl, V: Pod> Stack { let data = map.borrow(); check_kv_size::<(), V>(data)?; - let _fd = data.fd_or_err()?; - Ok(Stack { inner: map, _v: PhantomData, @@ -62,7 +60,7 @@ impl, V: Pod> Stack { /// Returns [`MapError::ElementNotFound`] if the stack is empty, [`MapError::SyscallError`] /// if `bpf_map_lookup_and_delete_elem` fails. pub fn pop(&mut self, flags: u64) -> Result { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; let value = bpf_map_lookup_and_delete_elem::(fd, None, flags).map_err( |(_, io_error)| SyscallError { @@ -79,7 +77,7 @@ impl, V: Pod> Stack { /// /// [`MapError::SyscallError`] if `bpf_map_update_elem` fails. pub fn push(&mut self, value: impl Borrow, flags: u64) -> Result<(), MapError> { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; bpf_map_update_elem(fd, None::<&u32>, value.borrow(), flags).map_err(|(_, io_error)| { SyscallError { call: "bpf_map_update_elem", diff --git a/aya/src/maps/stack_trace.rs b/aya/src/maps/stack_trace.rs index 63a92fe9..8f84a09e 100644 --- a/aya/src/maps/stack_trace.rs +++ b/aya/src/maps/stack_trace.rs @@ -1,12 +1,7 @@ //! A hash map of kernel or user space stack traces. //! //! See [`StackTraceMap`] for documentation and examples. -use std::{ - borrow::{Borrow, Cow}, - fs, io, mem, - path::Path, - str::FromStr, -}; +use std::{borrow::Borrow, fs, io, mem, path::Path, str::FromStr}; use crate::{ maps::{IterableMap, MapData, MapError, MapIter, MapKeys}, @@ -51,15 +46,19 @@ use crate::{ /// // here we resolve symbol names using kernel symbols. If this was a user space stack (for /// // example captured from a uprobe), you'd have to load the symbols using some other mechanism /// // (eg loading the target binary debuginfo) -/// for frame in stack_trace.resolve(&ksyms).frames() { -/// println!( -/// "{:#x} {}", -/// frame.ip, -/// frame -/// .symbol_name -/// .as_deref() -/// .unwrap_or("[unknown symbol name]") -/// ); +/// for frame in stack_trace.frames() { +/// if let Some(sym) = ksyms.range(..=frame.ip).next_back().map(|(_, s)| s) { +/// println!( +/// "{:#x} {}", +/// frame.ip, +/// sym +/// ); +/// } else { +/// println!( +/// "{:#x}", +/// frame.ip +/// ); +/// } /// } /// /// # Ok::<(), Error>(()) @@ -90,7 +89,6 @@ impl> StackTraceMap { if size > max_stack_depth * mem::size_of::() { return Err(MapError::InvalidValueSize { size, expected }); } - let _fd = data.fd_or_err()?; Ok(StackTraceMap { inner: map, @@ -105,7 +103,7 @@ impl> StackTraceMap { /// Returns [`MapError::KeyNotFound`] if there is no stack trace with the /// given `stack_id`, or [`MapError::SyscallError`] if `bpf_map_lookup_elem` fails. pub fn get(&self, stack_id: &u32, flags: u64) -> Result { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; let mut frames = vec![0; self.max_stack_depth]; bpf_map_lookup_elem_ptr(fd, Some(stack_id), frames.as_mut_ptr(), flags) @@ -118,10 +116,7 @@ impl> StackTraceMap { let frames = frames .into_iter() .take_while(|ip| *ip != 0) - .map(|ip| StackFrame { - ip, - symbol_name: None, - }) + .map(|ip| StackFrame { ip }) .collect::>(); Ok(StackTrace { @@ -162,12 +157,6 @@ impl<'a, T: Borrow> IntoIterator for &'a StackTraceMap { } } -/// A resolver for symbols based on an address obtained from a stack trace. -pub trait SymbolResolver { - /// Resolve a symbol for a given address, if possible. - fn resolve_symbol(&self, addr: u64) -> Option>; -} - /// A kernel or user space stack trace. /// /// See the [`StackTraceMap`] documentation for examples. @@ -178,19 +167,6 @@ pub struct StackTrace { } impl StackTrace { - /// Resolves symbol names using the given symbol map. - /// - /// You can use [`util::kernel_symbols()`](crate::util::kernel_symbols) to load kernel symbols. For - /// user-space traces you need to provide the symbols, for example loading - /// them from debug info. - pub fn resolve(&mut self, symbols: &R) -> &StackTrace { - for frame in self.frames.iter_mut() { - frame.symbol_name = symbols.resolve_symbol(frame.ip).map(|s| s.into_owned()) - } - - self - } - /// Returns the frames in this stack trace. pub fn frames(&self) -> &[StackFrame] { &self.frames @@ -201,11 +177,6 @@ impl StackTrace { pub struct StackFrame { /// The instruction pointer of this frame. pub ip: u64, - /// The symbol name corresponding to the start of this frame. - /// - /// Set to `Some()` if the frame address can be found in the symbols passed - /// to [`StackTrace::resolve`]. - pub symbol_name: Option, } fn sysctl(key: &str) -> Result { diff --git a/aya/src/programs/cgroup_device.rs b/aya/src/programs/cgroup_device.rs index dc318086..1244d27c 100644 --- a/aya/src/programs/cgroup_device.rs +++ b/aya/src/programs/cgroup_device.rs @@ -1,7 +1,7 @@ //! Cgroup device programs. use crate::util::KernelVersion; -use std::os::fd::AsRawFd; +use std::os::fd::{AsFd as _, AsRawFd}; use crate::{ generated::{bpf_attach_type::BPF_CGROUP_DEVICE, bpf_prog_type::BPF_PROG_TYPE_CGROUP_DEVICE}, @@ -61,7 +61,9 @@ impl CgroupDevice { /// /// The returned value can be used to detach, see [CgroupDevice::detach] pub fn attach(&mut self, cgroup: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/cgroup_skb.rs b/aya/src/programs/cgroup_skb.rs index d0cda14a..684fd18e 100644 --- a/aya/src/programs/cgroup_skb.rs +++ b/aya/src/programs/cgroup_skb.rs @@ -1,7 +1,11 @@ //! Cgroup skb programs. use crate::util::KernelVersion; -use std::{hash::Hash, os::fd::AsRawFd, path::Path}; +use std::{ + hash::Hash, + os::fd::{AsFd as _, AsRawFd}, + path::Path, +}; use crate::{ generated::{ @@ -88,7 +92,9 @@ impl CgroupSkb { cgroup: T, attach_type: CgroupSkbAttachType, ) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); let attach_type = match attach_type { diff --git a/aya/src/programs/cgroup_sock.rs b/aya/src/programs/cgroup_sock.rs index a7a70e13..c906ee6c 100644 --- a/aya/src/programs/cgroup_sock.rs +++ b/aya/src/programs/cgroup_sock.rs @@ -3,7 +3,11 @@ pub use aya_obj::programs::CgroupSockAttachType; use crate::util::KernelVersion; -use std::{hash::Hash, os::fd::AsRawFd, path::Path}; +use std::{ + hash::Hash, + os::fd::{AsFd as _, AsRawFd}, + path::Path, +}; use crate::{ generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK, @@ -67,7 +71,9 @@ impl CgroupSock { /// /// The returned value can be used to detach, see [CgroupSock::detach]. pub fn attach(&mut self, cgroup: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); let attach_type = self.data.expected_attach_type.unwrap(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/cgroup_sock_addr.rs b/aya/src/programs/cgroup_sock_addr.rs index 827cbe57..98d60eb1 100644 --- a/aya/src/programs/cgroup_sock_addr.rs +++ b/aya/src/programs/cgroup_sock_addr.rs @@ -3,7 +3,11 @@ pub use aya_obj::programs::CgroupSockAddrAttachType; use crate::util::KernelVersion; -use std::{hash::Hash, os::fd::AsRawFd, path::Path}; +use std::{ + hash::Hash, + os::fd::{AsFd as _, AsRawFd}, + path::Path, +}; use crate::{ generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK_ADDR, @@ -68,7 +72,9 @@ impl CgroupSockAddr { /// /// The returned value can be used to detach, see [CgroupSockAddr::detach]. pub fn attach(&mut self, cgroup: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); let attach_type = self.data.expected_attach_type.unwrap(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/cgroup_sockopt.rs b/aya/src/programs/cgroup_sockopt.rs index e2ae3b64..c137d769 100644 --- a/aya/src/programs/cgroup_sockopt.rs +++ b/aya/src/programs/cgroup_sockopt.rs @@ -3,7 +3,11 @@ pub use aya_obj::programs::CgroupSockoptAttachType; use crate::util::KernelVersion; -use std::{hash::Hash, os::fd::AsRawFd, path::Path}; +use std::{ + hash::Hash, + os::fd::{AsFd as _, AsRawFd}, + path::Path, +}; use crate::{ generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCKOPT, @@ -65,7 +69,9 @@ impl CgroupSockopt { /// /// The returned value can be used to detach, see [CgroupSockopt::detach]. pub fn attach(&mut self, cgroup: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); let attach_type = self.data.expected_attach_type.unwrap(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/cgroup_sysctl.rs b/aya/src/programs/cgroup_sysctl.rs index 8e887657..d5325089 100644 --- a/aya/src/programs/cgroup_sysctl.rs +++ b/aya/src/programs/cgroup_sysctl.rs @@ -1,7 +1,10 @@ //! Cgroup sysctl programs. use crate::util::KernelVersion; -use std::{hash::Hash, os::fd::AsRawFd}; +use std::{ + hash::Hash, + os::fd::{AsFd as _, AsRawFd}, +}; use crate::{ generated::{bpf_attach_type::BPF_CGROUP_SYSCTL, bpf_prog_type::BPF_PROG_TYPE_CGROUP_SYSCTL}, @@ -60,7 +63,9 @@ impl CgroupSysctl { /// /// The returned value can be used to detach, see [CgroupSysctl::detach]. pub fn attach(&mut self, cgroup: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs index 143c909f..e1aab2c2 100644 --- a/aya/src/programs/extension.rs +++ b/aya/src/programs/extension.rs @@ -1,5 +1,5 @@ //! Extension programs. -use std::os::fd::{AsRawFd, RawFd}; +use std::os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, OwnedFd}; use thiserror::Error; use object::Endianness; @@ -42,6 +42,7 @@ pub enum ExtensionError { /// prog.attach("eth0", XdpFlags::default())?; /// /// let prog_fd = prog.fd().unwrap(); +/// let prog_fd = prog_fd.try_clone().unwrap(); /// let ext: &mut Extension = bpf.program_mut("extension").unwrap().try_into()?; /// ext.load(prog_fd, "function_to_replace")?; /// ext.attach()?; @@ -69,11 +70,10 @@ impl Extension { /// There are no restrictions on what functions may be replaced, so you could replace /// the main entry point of your program with an extension. pub fn load(&mut self, program: ProgramFd, func_name: &str) -> Result<(), ProgramError> { - let target_prog_fd = program.as_raw_fd(); - let (btf_fd, btf_id) = get_btf_info(target_prog_fd, func_name)?; + let (btf_fd, btf_id) = get_btf_info(program.as_fd(), func_name)?; - self.data.attach_btf_obj_fd = Some(btf_fd as u32); - self.data.attach_prog_fd = Some(target_prog_fd); + self.data.attach_btf_obj_fd = Some(btf_fd); + self.data.attach_prog_fd = Some(program); self.data.attach_btf_id = Some(btf_id); load_program(BPF_PROG_TYPE_EXT, &mut self.data) } @@ -86,8 +86,16 @@ impl Extension { /// The returned value can be used to detach the extension and restore the /// original function, see [Extension::detach]. pub fn attach(&mut self) -> Result { - let prog_fd = self.data.fd_or_err()?; - let target_fd = self.data.attach_prog_fd.ok_or(ProgramError::NotLoaded)?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); + let target_fd = self + .data + .attach_prog_fd + .as_ref() + .ok_or(ProgramError::NotLoaded)?; + let target_fd = target_fd.as_fd(); + let target_fd = target_fd.as_raw_fd(); let btf_id = self.data.attach_btf_id.ok_or(ProgramError::NotLoaded)?; // the attach type must be set as 0, which is bpf_attach_type::BPF_CGROUP_INET_INGRESS let link_fd = bpf_link_create(prog_fd, target_fd, BPF_CGROUP_INET_INGRESS, Some(btf_id), 0) @@ -113,18 +121,26 @@ impl Extension { /// original function, see [Extension::detach]. pub fn attach_to_program( &mut self, - program: ProgramFd, + program: &ProgramFd, func_name: &str, ) -> Result { - let target_fd = program.as_raw_fd(); + let target_fd = program.as_fd(); let (_, btf_id) = get_btf_info(target_fd, func_name)?; - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); // the attach type must be set as 0, which is bpf_attach_type::BPF_CGROUP_INET_INGRESS - let link_fd = bpf_link_create(prog_fd, target_fd, BPF_CGROUP_INET_INGRESS, Some(btf_id), 0) - .map_err(|(_, io_error)| SyscallError { - call: "bpf_link_create", - io_error, - })?; + let link_fd = bpf_link_create( + prog_fd, + target_fd.as_raw_fd(), + BPF_CGROUP_INET_INGRESS, + Some(btf_id), + 0, + ) + .map_err(|(_, io_error)| SyscallError { + call: "bpf_link_create", + io_error, + })?; self.data .links .insert(ExtensionLink::new(FdLink::new(link_fd))) @@ -149,9 +165,9 @@ impl Extension { /// Retrieves the FD of the BTF object for the provided `prog_fd` and the BTF ID of the function /// with the name `func_name` within that BTF object. -fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramError> { +fn get_btf_info(prog_fd: BorrowedFd<'_>, func_name: &str) -> Result<(OwnedFd, u32), ProgramError> { // retrieve program information - let info = sys::bpf_prog_get_info_by_fd(prog_fd)?; + let info = sys::bpf_prog_get_info_by_fd(prog_fd, &mut [])?; // btf_id refers to the ID of the program btf that was loaded with bpf(BPF_BTF_LOAD) if info.btf_id == 0 { @@ -159,36 +175,23 @@ fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramEr } // the bpf fd of the BTF object - let btf_fd = sys::bpf_btf_get_fd_by_id(info.btf_id).map_err(|io_error| SyscallError { - call: "bpf_btf_get_fd_by_id", - io_error, - })?; + let btf_fd = sys::bpf_btf_get_fd_by_id(info.btf_id)?; // we need to read the btf bytes into a buffer but we don't know the size ahead of time. // assume 4kb. if this is too small we can resize based on the size obtained in the response. let mut buf = vec![0u8; 4096]; - let btf_info = match sys::btf_obj_get_info_by_fd(btf_fd, &buf) { - Ok(info) => { - if info.btf_size > buf.len() as u32 { - buf.resize(info.btf_size as usize, 0u8); - let btf_info = - sys::btf_obj_get_info_by_fd(btf_fd, &buf).map_err(|io_error| SyscallError { - call: "bpf_prog_get_info_by_fd", - io_error, - })?; - Ok(btf_info) - } else { - Ok(info) - } + loop { + let info = sys::btf_obj_get_info_by_fd(btf_fd.as_fd(), &mut buf)?; + let btf_size = info.btf_size as usize; + if btf_size > buf.len() { + buf.resize(btf_size, 0u8); + continue; } - Err(io_error) => Err(SyscallError { - call: "bpf_prog_get_info_by_fd", - io_error, - }), - }?; + buf.truncate(btf_size); + break; + } - let btf = Btf::parse(&buf[0..btf_info.btf_size as usize], Endianness::default()) - .map_err(ProgramError::Btf)?; + let btf = Btf::parse(&buf, Endianness::default()).map_err(ProgramError::Btf)?; let btf_id = btf .id_by_type_name_kind(func_name, BtfKind::Func) diff --git a/aya/src/programs/lirc_mode2.rs b/aya/src/programs/lirc_mode2.rs index e39bbf1a..906eec96 100644 --- a/aya/src/programs/lirc_mode2.rs +++ b/aya/src/programs/lirc_mode2.rs @@ -1,13 +1,10 @@ //! Lirc programs. -use std::os::fd::{AsRawFd, IntoRawFd as _, RawFd}; +use std::os::fd::{AsFd as _, AsRawFd, BorrowedFd, IntoRawFd as _, RawFd}; use crate::{ generated::{bpf_attach_type::BPF_LIRC_MODE2, bpf_prog_type::BPF_PROG_TYPE_LIRC_MODE2}, programs::{load_program, query, Link, ProgramData, ProgramError, ProgramInfo}, - sys::{ - bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, - SyscallError, - }, + sys::{bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id, SyscallError}, }; use libc::{close, dup}; @@ -64,7 +61,9 @@ impl LircMode2 { /// /// The returned value can be used to detach, see [LircMode2::detach]. pub fn attach(&mut self, lircdev: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let lircdev_fd = lircdev.as_raw_fd(); bpf_prog_attach(prog_fd, lircdev_fd, BPF_LIRC_MODE2).map_err(|(_, io_error)| { @@ -131,9 +130,9 @@ impl LircLink { /// Get ProgramInfo from this link pub fn info(&self) -> Result { - bpf_prog_get_info_by_fd(self.prog_fd) - .map(ProgramInfo) - .map_err(Into::into) + // SAFETY: TODO(https://github.com/aya-rs/aya/issues/612): make this safe by not holding `RawFd`s. + let prog_fd = unsafe { BorrowedFd::borrow_raw(self.prog_fd) }; + ProgramInfo::new_from_fd(prog_fd) } } diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index eab30abe..b79627a8 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -68,9 +68,11 @@ use libc::ENOSPC; use std::{ ffi::CString, io, - os::fd::{AsFd, AsRawFd, IntoRawFd as _, OwnedFd, RawFd}, + num::NonZeroU32, + os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd}, path::{Path, PathBuf}, sync::Arc, + time::{Duration, SystemTime}, }; use thiserror::Error; @@ -108,6 +110,7 @@ use crate::{ maps::MapError, obj::{self, btf::BtfError, Function, VerifierLog}, pin::PinError, + programs::utils::{boot_time, get_fdinfo}, sys::{ bpf_btf_get_fd_by_id, bpf_get_object, bpf_link_get_fd_by_id, bpf_link_get_info_by_fd, bpf_load_program, bpf_pin_object, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, @@ -211,12 +214,23 @@ pub enum ProgramError { } /// A [`Program`] file descriptor. -#[derive(Copy, Clone)] -pub struct ProgramFd(RawFd); +#[derive(Debug)] +pub struct ProgramFd(OwnedFd); + +impl ProgramFd { + /// Creates a new `ProgramFd` instance that shares the same underlying file + /// description as the existing `ProgramFd` instance. + pub fn try_clone(&self) -> Result { + let Self(inner) = self; + let inner = inner.try_clone()?; + Ok(Self(inner)) + } +} -impl AsRawFd for ProgramFd { - fn as_raw_fd(&self) -> RawFd { - self.0 +impl AsFd for ProgramFd { + fn as_fd(&self) -> BorrowedFd<'_> { + let Self(fd) = self; + fd.as_fd() } } @@ -368,8 +382,7 @@ impl Program { /// Returns the file descriptor of a program. /// /// Can be used to add a program to a [`crate::maps::ProgramArray`] or attach an [`Extension`] program. - /// Can be converted to [`RawFd`] using [`AsRawFd`]. - pub fn fd(&self) -> Option { + pub fn fd(&self) -> Result<&ProgramFd, ProgramError> { match self { Program::KProbe(p) => p.fd(), Program::UProbe(p) => p.fd(), @@ -403,12 +416,12 @@ impl Program { pub(crate) struct ProgramData { pub(crate) name: Option, pub(crate) obj: Option<(obj::Program, obj::Function)>, - pub(crate) fd: Option, + pub(crate) fd: Option, pub(crate) links: LinkMap, pub(crate) expected_attach_type: Option, - pub(crate) attach_btf_obj_fd: Option, + pub(crate) attach_btf_obj_fd: Option, pub(crate) attach_btf_id: Option, - pub(crate) attach_prog_fd: Option, + pub(crate) attach_prog_fd: Option, pub(crate) btf_fd: Option>, pub(crate) verifier_log_level: VerifierLogLevel, pub(crate) path: Option, @@ -450,21 +463,14 @@ impl ProgramData { } else { None }; - let attach_btf_obj_fd = if info.attach_btf_obj_id > 0 { - let fd = - bpf_btf_get_fd_by_id(info.attach_btf_obj_id).map_err(|io_error| SyscallError { - call: "bpf_btf_get_fd_by_id", - io_error, - })?; - Some(fd as u32) - } else { - None - }; + let attach_btf_obj_fd = (info.attach_btf_obj_id != 0) + .then(|| bpf_btf_get_fd_by_id(info.attach_btf_obj_id)) + .transpose()?; Ok(ProgramData { name, obj: None, - fd: Some(fd.into_raw_fd()), + fd: Some(ProgramFd(fd)), links: LinkMap::new(), expected_attach_type: None, attach_btf_obj_fd, @@ -483,20 +489,21 @@ impl ProgramData { ) -> Result, ProgramError> { let path_string = CString::new(path.as_ref().as_os_str().to_string_lossy().as_bytes()).unwrap(); + let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError { call: "bpf_obj_get", io_error, })?; - let info = bpf_prog_get_info_by_fd(fd.as_raw_fd())?; - let name = ProgramInfo(info).name_as_str().map(|s| s.to_string()); - ProgramData::from_bpf_prog_info(name, fd, path.as_ref(), info, verifier_log_level) + let info = ProgramInfo::new_from_fd(fd.as_fd())?; + let name = info.name_as_str().map(|s| s.to_string()); + ProgramData::from_bpf_prog_info(name, fd, path.as_ref(), info.0, verifier_log_level) } } impl ProgramData { - fn fd_or_err(&self) -> Result { - self.fd.ok_or(ProgramError::NotLoaded) + fn fd(&self) -> Result<&ProgramFd, ProgramError> { + self.fd.as_ref().ok_or(ProgramError::NotLoaded) } pub(crate) fn take_link(&mut self, link_id: T::Id) -> Result { @@ -506,15 +513,14 @@ impl ProgramData { fn unload_program(data: &mut ProgramData) -> Result<(), ProgramError> { data.links.remove_all()?; - let fd = data.fd.take().ok_or(ProgramError::NotLoaded)?; - unsafe { - libc::close(fd); - } - Ok(()) + data.fd + .take() + .ok_or(ProgramError::NotLoaded) + .map(|ProgramFd { .. }| ()) } fn pin_program>(data: &ProgramData, path: P) -> Result<(), PinError> { - let fd = data.fd.ok_or(PinError::NoFd { + let fd = data.fd.as_ref().ok_or(PinError::NoFd { name: data .name .as_deref() @@ -526,7 +532,7 @@ fn pin_program>(data: &ProgramData, path: P) -> Resul error: e.to_string(), } })?; - bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| SyscallError { + bpf_pin_object(fd.as_fd().as_raw_fd(), &path_string).map_err(|(_, io_error)| SyscallError { call: "BPF_OBJ_PIN", io_error, })?; @@ -604,9 +610,9 @@ fn load_program( kernel_version: target_kernel_version, expected_attach_type: *expected_attach_type, prog_btf_fd: btf_fd.as_ref().map(|f| f.as_fd()), - attach_btf_obj_fd: *attach_btf_obj_fd, + attach_btf_obj_fd: attach_btf_obj_fd.as_ref().map(|fd| fd.as_fd()), attach_btf_id: *attach_btf_id, - attach_prog_fd: *attach_prog_fd, + attach_prog_fd: attach_prog_fd.as_ref().map(|fd| fd.as_fd()), func_info_rec_size: *func_info_rec_size, func_info: func_info.clone(), line_info_rec_size: *line_info_rec_size, @@ -620,7 +626,7 @@ fn load_program( match ret { Ok(prog_fd) => { - *fd = Some(prog_fd as RawFd); + *fd = Some(ProgramFd(prog_fd)); Ok(()) } Err((_, io_error)) => Err(ProgramError::LoadError { @@ -725,8 +731,8 @@ macro_rules! impl_fd { $( impl $struct_name { /// Returns the file descriptor of this Program. - pub fn fd(&self) -> Option { - self.data.fd.map(|fd| ProgramFd(fd)) + pub fn fd(&self) -> Result<&ProgramFd, ProgramError> { + self.data.fd() } } )+ @@ -908,11 +914,63 @@ impl_try_from_program!( CgroupDevice, ); +/// Returns information about a loaded program with the [`ProgramInfo`] structure. +/// +/// This information is populated at load time by the kernel and can be used +/// to correlate a given [`Program`] to it's corresponding [`ProgramInfo`] +/// metadata. +macro_rules! impl_program_info { + ($($struct_name:ident),+ $(,)?) => { + $( + impl $struct_name { + /// Returns the file descriptor of this Program. + pub fn program_info(&self) -> Result { + let ProgramFd(fd) = self.fd()?; + + ProgramInfo::new_from_fd(fd.as_fd()) + } + } + )+ + } +} + +impl_program_info!( + KProbe, + UProbe, + TracePoint, + SocketFilter, + Xdp, + SkMsg, + SkSkb, + SchedClassifier, + CgroupSkb, + CgroupSysctl, + CgroupSockopt, + LircMode2, + PerfEvent, + Lsm, + RawTracePoint, + BtfTracePoint, + FEntry, + FExit, + Extension, + CgroupSockAddr, + SkLookup, + SockOps, + CgroupSock, + CgroupDevice, +); + /// Provides information about a loaded program, like name, id and statistics #[derive(Debug)] pub struct ProgramInfo(bpf_prog_info); impl ProgramInfo { + fn new_from_fd(fd: BorrowedFd<'_>) -> Result { + let info = bpf_prog_get_info_by_fd(fd, &mut [])?; + Ok(Self(info)) + } + /// The name of the program as was provided when it was load. This is limited to 16 bytes pub fn name(&self) -> &[u8] { let length = self @@ -928,23 +986,89 @@ impl ProgramInfo { unsafe { std::slice::from_raw_parts(self.0.name.as_ptr() as *const _, length) } } - /// The name of the program as a &str. If the name was not valid unicode, None is returned + /// The name of the program as a &str. If the name was not valid unicode, None is returned. pub fn name_as_str(&self) -> Option<&str> { std::str::from_utf8(self.name()).ok() } - /// The program id for this program. Each program has a unique id. + /// The id for this program. Each program has a unique id. pub fn id(&self) -> u32 { self.0.id } - /// Returns the fd associated with the program. + /// The program tag. + /// + /// The program tag is a SHA sum of the program's instructions which be used as an alternative to + /// [`Self::id()`]". A program's id can vary every time it's loaded or unloaded, but the tag + /// will remain the same. + pub fn tag(&self) -> u64 { + u64::from_be_bytes(self.0.tag) + } + + /// The program type as defined by the linux kernel enum + /// [`bpf_prog_type`](https://elixir.bootlin.com/linux/v6.4.4/source/include/uapi/linux/bpf.h#L948). + pub fn program_type(&self) -> u32 { + self.0.type_ + } + + /// Returns true if the program is defined with a GPL-compatible license. + pub fn gpl_compatible(&self) -> bool { + self.0.gpl_compatible() != 0 + } + + /// The ids of the maps used by the program. + pub fn map_ids(&self) -> Result, ProgramError> { + let ProgramFd(fd) = self.fd()?; + let mut map_ids = vec![0u32; self.0.nr_map_ids as usize]; + + bpf_prog_get_info_by_fd(fd.as_fd(), &mut map_ids)?; + + Ok(map_ids) + } + + /// The btf id for the program. + pub fn btf_id(&self) -> Option { + NonZeroU32::new(self.0.btf_id) + } + + /// The size in bytes of the program's translated eBPF bytecode, which is + /// the bytecode after it has been passed though the verifier where it was + /// possibly modified by the kernel. + pub fn size_translated(&self) -> u32 { + self.0.xlated_prog_len + } + + /// The size in bytes of the program's JIT-compiled machine code. + pub fn size_jitted(&self) -> u32 { + self.0.jited_prog_len + } + + /// How much memory in bytes has been allocated and locked for the program. + pub fn memory_locked(&self) -> Result { + get_fdinfo(self.fd()?.as_fd(), "memlock") + } + + /// The number of verified instructions in the program. + /// + /// This may be less than the total number of instructions in the compiled + /// program due to dead code elimination in the verifier. + pub fn verified_instruction_count(&self) -> u32 { + self.0.verified_insns + } + + /// The time the program was loaded. + pub fn loaded_at(&self) -> SystemTime { + boot_time() + Duration::from_nanos(self.0.load_time) + } + + /// Returns a file descriptor referencing the program. /// - /// The returned fd must be closed when no longer needed. - pub fn fd(&self) -> Result { + /// The returned file descriptor can be closed at any time and doing so does + /// not influence the life cycle of the program. + pub fn fd(&self) -> Result { let Self(info) = self; let fd = bpf_prog_get_fd_by_id(info.id)?; - Ok(fd.into_raw_fd()) + Ok(ProgramFd(fd)) } /// Loads a program from a pinned path in bpffs. @@ -955,7 +1079,7 @@ impl ProgramInfo { io_error, })?; - let info = bpf_prog_get_info_by_fd(fd.as_raw_fd())?; + let info = bpf_prog_get_info_by_fd(fd.as_fd(), &mut [])?; Ok(ProgramInfo(info)) } } @@ -991,7 +1115,7 @@ pub fn loaded_programs() -> impl Iterator Result { + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let (sample_period, sample_frequency) = match sample_policy { SamplePolicy::Period(period) => (period, None), SamplePolicy::Frequency(frequency) => (0, Some(frequency)), @@ -172,7 +175,7 @@ impl PerfEvent { io_error, })?; - let link = perf_attach(self.data.fd_or_err()?, fd)?; + let link = perf_attach(prog_fd, fd)?; self.data.links.insert(PerfEventLink::new(link)) } diff --git a/aya/src/programs/probe.rs b/aya/src/programs/probe.rs index fa04d31d..151c87ef 100644 --- a/aya/src/programs/probe.rs +++ b/aya/src/programs/probe.rs @@ -3,7 +3,7 @@ use libc::pid_t; use std::{ fs::{self, OpenOptions}, io::{self, Write}, - os::fd::OwnedFd, + os::fd::{AsFd as _, AsRawFd as _, OwnedFd}, path::Path, process, sync::atomic::{AtomicUsize, Ordering}, @@ -57,19 +57,17 @@ pub(crate) fn attach>( ) -> Result { // https://github.com/torvalds/linux/commit/e12f03d7031a977356e3d7b75a68c2185ff8d155 // Use debugfs to create probe - if KernelVersion::current().unwrap() < KernelVersion::new(4, 17, 0) { + let prog_fd = program_data.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); + let link = if KernelVersion::current().unwrap() < KernelVersion::new(4, 17, 0) { let (fd, event_alias) = create_as_trace_point(kind, fn_name, offset, pid)?; - let link = T::from(perf_attach_debugfs( - program_data.fd_or_err()?, - fd, - ProbeEvent { kind, event_alias }, - )?); - return program_data.links.insert(link); - }; - - let fd = create_as_probe(kind, fn_name, offset, pid)?; - let link = T::from(perf_attach(program_data.fd_or_err()?, fd)?); - program_data.links.insert(link) + perf_attach_debugfs(prog_fd, fd, ProbeEvent { kind, event_alias }) + } else { + let fd = create_as_probe(kind, fn_name, offset, pid)?; + perf_attach(prog_fd, fd) + }?; + program_data.links.insert(T::from(link)) } pub(crate) fn detach_debug_fs(event: ProbeEvent) -> Result<(), ProgramError> { diff --git a/aya/src/programs/sk_lookup.rs b/aya/src/programs/sk_lookup.rs index 15687e43..bbcdc3a3 100644 --- a/aya/src/programs/sk_lookup.rs +++ b/aya/src/programs/sk_lookup.rs @@ -1,4 +1,4 @@ -use std::os::fd::AsRawFd; +use std::os::fd::{AsFd as _, AsRawFd}; use crate::{ generated::{bpf_attach_type::BPF_SK_LOOKUP, bpf_prog_type::BPF_PROG_TYPE_SK_LOOKUP}, @@ -61,7 +61,9 @@ impl SkLookup { /// /// The returned value can be used to detach, see [SkLookup::detach]. pub fn attach(&mut self, netns: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let netns_fd = netns.as_raw_fd(); let link_fd = bpf_link_create(prog_fd, netns_fd, BPF_SK_LOOKUP, None, 0).map_err( diff --git a/aya/src/programs/sk_msg.rs b/aya/src/programs/sk_msg.rs index 93819fbe..7a03b8e3 100644 --- a/aya/src/programs/sk_msg.rs +++ b/aya/src/programs/sk_msg.rs @@ -1,6 +1,6 @@ //! Skmsg programs. -use std::os::fd::AsRawFd; +use std::os::fd::{AsFd as _, AsRawFd as _}; use crate::{ generated::{bpf_attach_type::BPF_SK_MSG_VERDICT, bpf_prog_type::BPF_PROG_TYPE_SK_MSG}, @@ -79,7 +79,9 @@ impl SkMsg { /// /// The returned value can be used to detach, see [SkMsg::detach]. pub fn attach(&mut self, map: SockMapFd) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let map_fd = map.as_raw_fd(); bpf_prog_attach(prog_fd, map_fd, BPF_SK_MSG_VERDICT).map_err(|(_, io_error)| { diff --git a/aya/src/programs/sk_skb.rs b/aya/src/programs/sk_skb.rs index 70960265..a4c5de63 100644 --- a/aya/src/programs/sk_skb.rs +++ b/aya/src/programs/sk_skb.rs @@ -1,6 +1,9 @@ //! Skskb programs. -use std::{os::fd::AsRawFd, path::Path}; +use std::{ + os::fd::{AsFd as _, AsRawFd as _}, + path::Path, +}; use crate::{ generated::{ @@ -72,7 +75,9 @@ impl SkSkb { /// /// The returned value can be used to detach, see [SkSkb::detach]. pub fn attach(&mut self, map: SockMapFd) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let map_fd = map.as_raw_fd(); let attach_type = match self.kind { diff --git a/aya/src/programs/sock_ops.rs b/aya/src/programs/sock_ops.rs index 16e71677..2a469048 100644 --- a/aya/src/programs/sock_ops.rs +++ b/aya/src/programs/sock_ops.rs @@ -1,5 +1,5 @@ //! Socket option programs. -use std::os::fd::AsRawFd; +use std::os::fd::{AsFd as _, AsRawFd}; use crate::{ generated::{bpf_attach_type::BPF_CGROUP_SOCK_OPS, bpf_prog_type::BPF_PROG_TYPE_SOCK_OPS}, @@ -59,7 +59,9 @@ impl SockOps { /// /// The returned value can be used to detach, see [SockOps::detach]. pub fn attach(&mut self, cgroup: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS).map_err(|(_, io_error)| { diff --git a/aya/src/programs/socket_filter.rs b/aya/src/programs/socket_filter.rs index 5ff9a301..e737d8ae 100644 --- a/aya/src/programs/socket_filter.rs +++ b/aya/src/programs/socket_filter.rs @@ -2,7 +2,7 @@ use libc::{setsockopt, SOL_SOCKET}; use std::{ io, mem, - os::fd::{AsRawFd, RawFd}, + os::fd::{AsFd as _, AsRawFd, RawFd}, }; use thiserror::Error; @@ -73,7 +73,9 @@ impl SocketFilter { /// /// The returned value can be used to detach from the socket, see [SocketFilter::detach]. pub fn attach(&mut self, socket: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let socket = socket.as_raw_fd(); let ret = unsafe { diff --git a/aya/src/programs/tc.rs b/aya/src/programs/tc.rs index fad633a3..e289e7d0 100644 --- a/aya/src/programs/tc.rs +++ b/aya/src/programs/tc.rs @@ -4,6 +4,7 @@ use thiserror::Error; use std::{ ffi::{CStr, CString}, io, + os::fd::{AsFd as _, AsRawFd as _}, path::Path, }; @@ -152,7 +153,9 @@ impl SchedClassifier { attach_type: TcAttachType, options: TcOptions, ) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let if_index = ifindex_from_ifname(interface) .map_err(|io_error| TcError::NetlinkError { io_error })?; let (priority, handle) = unsafe { diff --git a/aya/src/programs/trace_point.rs b/aya/src/programs/trace_point.rs index 4e7b75b3..4c5d38db 100644 --- a/aya/src/programs/trace_point.rs +++ b/aya/src/programs/trace_point.rs @@ -1,5 +1,9 @@ //! Tracepoint programs. -use std::{fs, io, os::fd::AsFd as _, path::Path}; +use std::{ + fs, io, + os::fd::{AsFd as _, AsRawFd as _}, + path::Path, +}; use thiserror::Error; use crate::{ @@ -78,6 +82,9 @@ impl TracePoint { /// /// The returned value can be used to detach, see [TracePoint::detach]. pub fn attach(&mut self, category: &str, name: &str) -> Result { + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let tracefs = find_tracefs_path()?; let id = read_sys_fs_trace_point_id(tracefs, category, name)?; let fd = @@ -86,7 +93,7 @@ impl TracePoint { io_error, })?; - let link = perf_attach(self.data.fd_or_err()?, fd)?; + let link = perf_attach(prog_fd, fd)?; self.data.links.insert(TracePointLink::new(link)) } diff --git a/aya/src/programs/utils.rs b/aya/src/programs/utils.rs index 66f62142..beb9b5f5 100644 --- a/aya/src/programs/utils.rs +++ b/aya/src/programs/utils.rs @@ -1,5 +1,12 @@ //! Common functions shared between multiple eBPF program types. -use std::{ffi::CStr, io, path::Path}; +use std::{ + ffi::CStr, + fs::File, + io::{self, BufRead, BufReader}, + os::fd::{AsFd as _, AsRawFd as _, BorrowedFd}, + path::Path, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; use crate::{ programs::{FdLink, Link, ProgramData, ProgramError}, @@ -11,8 +18,9 @@ pub(crate) fn attach_raw_tracepoint>( program_data: &mut ProgramData, tp_name: Option<&CStr>, ) -> Result { - let prog_fd = program_data.fd_or_err()?; - + let prog_fd = program_data.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let pfd = bpf_raw_tracepoint_open(tp_name, prog_fd).map_err(|(_code, io_error)| SyscallError { call: "bpf_raw_tracepoint_open", @@ -22,7 +30,7 @@ pub(crate) fn attach_raw_tracepoint>( program_data.links.insert(FdLink::new(pfd).into()) } -/// Find tracefs filesystem path +/// Find tracefs filesystem path. pub(crate) fn find_tracefs_path() -> Result<&'static Path, ProgramError> { lazy_static::lazy_static! { static ref TRACE_FS: Option<&'static Path> = { @@ -50,3 +58,40 @@ pub(crate) fn find_tracefs_path() -> Result<&'static Path, ProgramError> { .as_deref() .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "tracefs not found").into()) } + +/// The time at which the system is booted. +pub(crate) fn boot_time() -> SystemTime { + let get_time = |clock_id| { + let mut time = unsafe { std::mem::zeroed::() }; + assert_eq!( + unsafe { libc::clock_gettime(clock_id, &mut time) }, + 0, + "clock_gettime({}, _)", + clock_id + ); + let libc::timespec { tv_sec, tv_nsec } = time; + + Duration::new(tv_sec as u64, tv_nsec as u32) + }; + let since_boot = get_time(libc::CLOCK_BOOTTIME); + let since_epoch = get_time(libc::CLOCK_REALTIME); + UNIX_EPOCH + since_boot - since_epoch +} + +/// Get the specified information from a file descriptor's fdinfo. +pub(crate) fn get_fdinfo(fd: BorrowedFd, key: &str) -> Result { + let info = File::open(format!("/proc/self/fdinfo/{}", fd.as_raw_fd()))?; + let reader = BufReader::new(info); + for line in reader.lines() { + let line = line.map_err(ProgramError::IOError)?; + if !line.contains(key) { + continue; + } + + let (_key, val) = line.rsplit_once('\t').unwrap(); + + return Ok(val.parse().unwrap()); + } + + Ok(0) +} diff --git a/aya/src/programs/xdp.rs b/aya/src/programs/xdp.rs index 35164e72..36eec7d6 100644 --- a/aya/src/programs/xdp.rs +++ b/aya/src/programs/xdp.rs @@ -8,7 +8,7 @@ use std::{ ffi::CString, hash::Hash, io, - os::fd::{AsFd as _, RawFd}, + os::fd::{AsFd as _, AsRawFd as _, RawFd}, }; use thiserror::Error; @@ -128,7 +128,9 @@ impl Xdp { if_index: u32, flags: XdpFlags, ) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let if_index = if_index as RawFd; if KernelVersion::current().unwrap() >= KernelVersion::new(5, 9, 0) { @@ -174,7 +176,9 @@ impl Xdp { /// /// Ownership of the link will transfer to this program. pub fn attach_to_link(&mut self, link: XdpLink) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); match link.into_inner() { XdpLinkInner::FdLink(fd_link) => { let link_fd = fd_link.fd; diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index d3446cc8..23fcf8e3 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -3,13 +3,14 @@ use std::{ ffi::{CStr, CString}, io, iter, mem::{self, MaybeUninit}, - os::fd::{AsRawFd, BorrowedFd, FromRawFd as _, OwnedFd, RawFd}, + os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, FromRawFd as _, OwnedFd, RawFd}, slice, }; use crate::util::KernelVersion; -use libc::{c_char, c_long, close, ENOENT, ENOSPC}; +use libc::{c_char, c_long, ENOENT, ENOSPC}; use obj::{ + btf::{BtfEnum64, Enum64}, maps::{bpf_map_def, LegacyMap}, BpfSectionKind, VerifierLog, }; @@ -117,9 +118,9 @@ pub(crate) struct BpfLoadProgramAttrs<'a> { pub(crate) kernel_version: u32, pub(crate) expected_attach_type: Option, pub(crate) prog_btf_fd: Option>, - pub(crate) attach_btf_obj_fd: Option, + pub(crate) attach_btf_obj_fd: Option>, pub(crate) attach_btf_id: Option, - pub(crate) attach_prog_fd: Option, + pub(crate) attach_prog_fd: Option>, pub(crate) func_info_rec_size: usize, pub(crate) func_info: FuncSecInfo, pub(crate) line_info_rec_size: usize, @@ -131,7 +132,7 @@ pub(crate) fn bpf_load_program( aya_attr: &BpfLoadProgramAttrs, log_buf: &mut [u8], verifier_log_level: VerifierLogLevel, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_3 }; @@ -180,16 +181,16 @@ pub(crate) fn bpf_load_program( u.log_size = log_buf.len() as u32; } if let Some(v) = aya_attr.attach_btf_obj_fd { - u.__bindgen_anon_1.attach_btf_obj_fd = v; + u.__bindgen_anon_1.attach_btf_obj_fd = v.as_raw_fd() as _; } if let Some(v) = aya_attr.attach_prog_fd { - u.__bindgen_anon_1.attach_prog_fd = v as u32; + u.__bindgen_anon_1.attach_prog_fd = v.as_raw_fd() as u32; } if let Some(v) = aya_attr.attach_btf_id { u.attach_btf_id = v; } - sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) + bpf_prog_load(&mut attr) } fn lookup( @@ -476,10 +477,14 @@ pub(crate) fn bpf_prog_get_fd_by_id(prog_id: u32) -> Result(fd: BorrowedFd<'_>) -> Result { +fn bpf_obj_get_info_by_fd( + fd: BorrowedFd<'_>, + init: F, +) -> Result { let mut attr = unsafe { mem::zeroed::() }; - // info gets entirely populated by the kernel - let info = MaybeUninit::zeroed(); + let mut info = unsafe { mem::zeroed() }; + + init(&mut info); attr.info.bpf_fd = fd.as_raw_fd() as u32; attr.info.info = &info as *const _ as u64; @@ -488,7 +493,7 @@ fn bpf_obj_get_info_by_fd(fd: BorrowedFd<'_>) -> Result { match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) { Ok(code) => { assert_eq!(code, 0); - Ok(unsafe { info.assume_init() }) + Ok(info) } Err((code, io_error)) => { assert_eq!(code, -1); @@ -500,13 +505,18 @@ fn bpf_obj_get_info_by_fd(fd: BorrowedFd<'_>) -> Result { } } -pub(crate) fn bpf_prog_get_info_by_fd(fd: RawFd) -> Result { - let fd = unsafe { BorrowedFd::borrow_raw(fd) }; - bpf_obj_get_info_by_fd::(fd) +pub(crate) fn bpf_prog_get_info_by_fd( + fd: BorrowedFd<'_>, + map_ids: &mut [u32], +) -> Result { + bpf_obj_get_info_by_fd(fd, |info: &mut bpf_prog_info| { + info.nr_map_ids = map_ids.len() as _; + info.map_ids = map_ids.as_mut_ptr() as _; + }) } pub(crate) fn bpf_map_get_info_by_fd(fd: BorrowedFd<'_>) -> Result { - bpf_obj_get_info_by_fd::(fd) + bpf_obj_get_info_by_fd(fd, |_| {}) } pub(crate) fn bpf_link_get_fd_by_id(link_id: u32) -> Result { @@ -524,26 +534,17 @@ pub(crate) fn bpf_link_get_fd_by_id(link_id: u32) -> Result) -> Result { - bpf_obj_get_info_by_fd::(fd) + bpf_obj_get_info_by_fd(fd, |_| {}) } pub(crate) fn btf_obj_get_info_by_fd( - prog_fd: RawFd, - buf: &[u8], -) -> Result { - let mut attr = unsafe { mem::zeroed::() }; - let mut info = unsafe { mem::zeroed::() }; - let buf_size = buf.len() as u32; - info.btf = buf.as_ptr() as u64; - info.btf_size = buf_size; - attr.info.bpf_fd = prog_fd as u32; - attr.info.info = &info as *const bpf_btf_info as u64; - attr.info.info_len = mem::size_of::() as u32; - - match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) { - Ok(_) => Ok(info), - Err((_, err)) => Err(err), - } + fd: BorrowedFd<'_>, + buf: &mut [u8], +) -> Result { + bpf_obj_get_info_by_fd(fd, |info: &mut bpf_btf_info| { + info.btf = buf.as_mut_ptr() as _; + info.btf_size = buf.len() as _; + }) } pub(crate) fn bpf_raw_tracepoint_open(name: Option<&CStr>, prog_fd: RawFd) -> SysResult { @@ -592,14 +593,18 @@ unsafe fn fd_sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult { Ok(OwnedFd::from_raw_fd(fd)) } -pub(crate) fn bpf_btf_get_fd_by_id(id: u32) -> Result { +pub(crate) fn bpf_btf_get_fd_by_id(id: u32) -> Result { let mut attr = unsafe { mem::zeroed::() }; attr.__bindgen_anon_6.__bindgen_anon_1.btf_id = id; - match sys_bpf(bpf_cmd::BPF_BTF_GET_FD_BY_ID, &mut attr) { - Ok(v) => Ok(v as RawFd), - Err((_, err)) => Err(err), - } + // SAFETY: BPF_BTF_GET_FD_BY_ID returns a new file descriptor. + unsafe { fd_sys_bpf(bpf_cmd::BPF_BTF_GET_FD_BY_ID, &mut attr) }.map_err(|(code, io_error)| { + assert_eq!(code, -1); + SyscallError { + call: "bpf_btf_get_fd_by_id", + io_error, + } + }) } pub(crate) fn is_prog_name_supported() -> bool { @@ -627,14 +632,7 @@ pub(crate) fn is_prog_name_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32; - match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - Ok(v) => { - let fd = v as RawFd; - unsafe { close(fd) }; - true - } - Err(_) => false, - } + bpf_prog_load(&mut attr).is_ok() } pub(crate) fn is_probe_read_kernel_supported() -> bool { @@ -658,14 +656,7 @@ pub(crate) fn is_probe_read_kernel_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32; - match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - Ok(v) => { - let fd = v as RawFd; - unsafe { close(fd) }; - true - } - Err(_) => false, - } + bpf_prog_load(&mut attr).is_ok() } pub(crate) fn is_perf_link_supported() -> bool { @@ -685,18 +676,18 @@ pub(crate) fn is_perf_link_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32; - if let Ok(fd) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - if let Err((_, e)) = + if let Ok(fd) = bpf_prog_load(&mut attr) { + let fd = fd.as_fd(); + let fd = fd.as_raw_fd(); + matches!( // Uses an invalid target FD so we get EBADF if supported. - bpf_link_create(fd as i32, -1, bpf_attach_type::BPF_PERF_EVENT, None, 0) - { + bpf_link_create(fd, -1, bpf_attach_type::BPF_PERF_EVENT, None, 0), // Returns EINVAL if unsupported. EBADF if supported. - let res = e.raw_os_error() == Some(libc::EBADF); - unsafe { libc::close(fd as i32) }; - return res; - } + Err((_, e)) if e.raw_os_error() == Some(libc::EBADF), + ) + } else { + false } - false } pub(crate) fn is_bpf_global_data_supported() -> bool { @@ -713,8 +704,8 @@ pub(crate) fn is_bpf_global_data_supported() -> bool { let mut insns = copy_instructions(prog).unwrap(); - let mut map_data = MapData { - obj: obj::Map::Legacy(LegacyMap { + let map = MapData::create( + obj::Map::Legacy(LegacyMap { def: bpf_map_def { map_type: bpf_map_type::BPF_MAP_TYPE_ARRAY as u32, key_size: 4, @@ -727,13 +718,12 @@ pub(crate) fn is_bpf_global_data_supported() -> bool { symbol_index: None, data: Vec::new(), }), - fd: None, - pinned: false, - btf_fd: None, - }; + "aya_global", + None, + ); - if let Ok(map_fd) = map_data.create("aya_global") { - insns[0].imm = map_fd; + if let Ok(map) = map { + insns[0].imm = map.fd; let gpl = b"GPL\0"; u.license = gpl.as_ptr() as u64; @@ -741,16 +731,10 @@ pub(crate) fn is_bpf_global_data_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32; - if let Ok(v) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - let fd = v as RawFd; - - unsafe { close(fd) }; - - return true; - } + bpf_prog_load(&mut attr).is_ok() + } else { + false } - - false } pub(crate) fn is_bpf_cookie_supported() -> bool { @@ -770,14 +754,7 @@ pub(crate) fn is_bpf_cookie_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_KPROBE as u32; - match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - Ok(v) => { - let fd = v as RawFd; - unsafe { close(fd) }; - true - } - Err(_) => false, - } + bpf_prog_load(&mut attr).is_ok() } pub(crate) fn is_btf_supported() -> bool { @@ -873,6 +850,22 @@ pub(crate) fn is_btf_datasec_supported() -> bool { bpf_load_btf(btf_bytes.as_slice(), &mut [], Default::default()).is_ok() } +pub(crate) fn is_btf_enum64_supported() -> bool { + let mut btf = Btf::new(); + let name_offset = btf.add_string("enum64"); + + let enum_64_type = BtfType::Enum64(Enum64::new( + name_offset, + true, + vec![BtfEnum64::new(btf.add_string("a"), 1)], + )); + btf.add_type(enum_64_type); + + let btf_bytes = btf.to_bytes(); + + bpf_load_btf(btf_bytes.as_slice(), &mut [], Default::default()).is_ok() +} + pub(crate) fn is_btf_float_supported() -> bool { let mut btf = Btf::new(); let name_offset = btf.add_string("float"); @@ -920,6 +913,11 @@ pub(crate) fn is_btf_type_tag_supported() -> bool { bpf_load_btf(btf_bytes.as_slice(), &mut [], Default::default()).is_ok() } +fn bpf_prog_load(attr: &mut bpf_attr) -> SysResult { + // SAFETY: BPF_PROG_LOAD returns a new file descriptor. + unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_LOAD, attr) } +} + fn sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult { syscall(Syscall::Bpf { cmd, attr }) } diff --git a/aya/src/util.rs b/aya/src/util.rs index 1161885e..65bcb415 100644 --- a/aya/src/util.rs +++ b/aya/src/util.rs @@ -1,18 +1,18 @@ //! Utility functions. use std::{ - borrow::Cow, collections::BTreeMap, error::Error, ffi::{CStr, CString}, fs::{self, File}, io::{self, BufRead, BufReader}, - mem, slice, + mem, + num::ParseIntError, + slice, str::{FromStr, Utf8Error}, }; use crate::{ generated::{TC_H_MAJ_MASK, TC_H_MIN_MASK}, - maps::stack_trace::SymbolResolver, Pod, }; @@ -203,36 +203,33 @@ fn parse_cpu_ranges(data: &str) -> Result, ()> { Ok(cpus) } -/// The simplest resolver: a direct map from addresses to strings. -pub type SimpleSymbolResolver = BTreeMap; - -impl SymbolResolver for SimpleSymbolResolver { - fn resolve_symbol(&self, addr: u64) -> Option> { - self.range(..=addr).next_back().map(|(_, s)| s.into()) - } -} - /// Loads kernel symbols from `/proc/kallsyms`. /// -/// The symbols can be passed to [`StackTrace::resolve`](crate::maps::stack_trace::StackTrace::resolve). -pub fn kernel_symbols() -> Result { +/// See [`crate::maps::StackTraceMap`] for an example on how to use this to resolve kernel addresses to symbols. +pub fn kernel_symbols() -> Result, io::Error> { let mut reader = BufReader::new(File::open("/proc/kallsyms")?); parse_kernel_symbols(&mut reader) } -fn parse_kernel_symbols(reader: impl BufRead) -> Result { - let mut syms = SimpleSymbolResolver::new(); - - for line in reader.lines() { - let line = line?; - let parts = line.splitn(4, ' ').collect::>(); - let addr = u64::from_str_radix(parts[0], 16) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, line.clone()))?; - let name = parts[2].to_owned(); - syms.insert(addr, name); - } - - Ok(syms) +fn parse_kernel_symbols(reader: impl BufRead) -> Result, io::Error> { + reader + .lines() + .map(|line| { + let line = line?; + (|| { + let mut parts = line.splitn(4, ' '); + let addr = parts.next()?; + let _kind = parts.next()?; + let name = parts.next()?; + let addr = match u64::from_str_radix(addr, 16) { + Ok(addr) => Some(addr), + Err(ParseIntError { .. }) => None, + }?; + Some((addr, name.to_owned())) + })() + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, line.clone())) + }) + .collect() } /// Returns the prefix used by syscalls. diff --git a/bpf/aya-bpf-bindings/include/bindings.h b/bpf/aya-bpf-bindings/include/bindings.h index b2f3b072..05344214 100644 --- a/bpf/aya-bpf-bindings/include/bindings.h +++ b/bpf/aya-bpf-bindings/include/bindings.h @@ -3,9 +3,9 @@ // https://elixir.bootlin.com/linux/v5.13/source/include/uapi/linux/types.h typedef __u32 __bitwise __wsum; +#include "bpf_helpers.h" #include -#include -#include // needed for TC_ACT_* #include -#include "bpf_helpers.h" \ No newline at end of file +#include +#include diff --git a/bpf/aya-log-ebpf/src/lib.rs b/bpf/aya-log-ebpf/src/lib.rs index 2933509c..5962c239 100644 --- a/bpf/aya-log-ebpf/src/lib.rs +++ b/bpf/aya-log-ebpf/src/lib.rs @@ -1,10 +1,9 @@ #![no_std] #![warn(clippy::cast_lossless, clippy::cast_sign_loss)] -use aya_bpf::{ - macros::map, - maps::{PerCpuArray, PerfEventByteArray}, -}; +#[cfg(target_arch = "bpf")] +use aya_bpf::macros::map; +use aya_bpf::maps::{PerCpuArray, PerfEventByteArray}; pub use aya_log_common::{write_record_header, Level, WriteToBuf, LOG_BUF_CAPACITY}; pub use aya_log_ebpf_macros::{debug, error, info, log, trace, warn}; @@ -15,11 +14,19 @@ pub struct LogBuf { } #[doc(hidden)] -#[map] +// This cfg_attr prevents compilation failures on macOS where the generated section name doesn't +// meet mach-o's requirements. We wouldn't ordinarily build this crate for macOS, but we do so +// because the integration-test crate depends on this crate transitively. See comment in +// test/integration-test/Cargo.toml. +#[cfg_attr(target_arch = "bpf", map)] pub static mut AYA_LOG_BUF: PerCpuArray = PerCpuArray::with_max_entries(1, 0); #[doc(hidden)] -#[map] +// This cfg_attr prevents compilation failures on macOS where the generated section name doesn't +// meet mach-o's requirements. We wouldn't ordinarily build this crate for macOS, but we do so +// because the integration-test crate depends on this crate transitively. See comment in +// test/integration-test/Cargo.toml. +#[cfg_attr(target_arch = "bpf", map)] pub static mut AYA_LOGS: PerfEventByteArray = PerfEventByteArray::new(0); #[doc(hidden)] diff --git a/init/Cargo.toml b/init/Cargo.toml new file mode 100644 index 00000000..6adf153e --- /dev/null +++ b/init/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "init" +version = "0.1.0" +authors = ["Tamir Duberstein "] +edition = "2021" +publish = false + +[dependencies] +anyhow = { workspace = true, features = ["std"] } +nix = { workspace = true, features = ["fs", "mount", "reboot"] } diff --git a/init/src/main.rs b/init/src/main.rs new file mode 100644 index 00000000..89253de7 --- /dev/null +++ b/init/src/main.rs @@ -0,0 +1,166 @@ +//! init is the first process started by the kernel. +//! +//! This implementation creates the minimal mounts required to run BPF programs, runs all binaries +//! in /bin, prints a final message ("init: success|failure"), and powers off the machine. + +use anyhow::Context as _; + +#[derive(Debug)] +struct Errors(Vec); + +impl std::fmt::Display for Errors { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self(errors) = self; + for (i, error) in errors.iter().enumerate() { + if i != 0 { + writeln!(f)?; + } + write!(f, "{:?}", error)?; + } + Ok(()) + } +} + +impl std::error::Error for Errors {} + +fn run() -> anyhow::Result<()> { + const RXRXRX: nix::sys::stat::Mode = nix::sys::stat::Mode::empty() + .union(nix::sys::stat::Mode::S_IRUSR) + .union(nix::sys::stat::Mode::S_IXUSR) + .union(nix::sys::stat::Mode::S_IRGRP) + .union(nix::sys::stat::Mode::S_IXGRP) + .union(nix::sys::stat::Mode::S_IROTH) + .union(nix::sys::stat::Mode::S_IXOTH); + + struct Mount { + source: &'static str, + target: &'static str, + fstype: &'static str, + flags: nix::mount::MsFlags, + data: Option<&'static str>, + target_mode: Option, + } + + for Mount { + source, + target, + fstype, + flags, + data, + target_mode, + } in [ + Mount { + source: "proc", + target: "/proc", + fstype: "proc", + flags: nix::mount::MsFlags::empty(), + data: None, + target_mode: Some(RXRXRX), + }, + Mount { + source: "sysfs", + target: "/sys", + fstype: "sysfs", + flags: nix::mount::MsFlags::empty(), + data: None, + target_mode: Some(RXRXRX), + }, + Mount { + source: "debugfs", + target: "/sys/kernel/debug", + fstype: "debugfs", + flags: nix::mount::MsFlags::empty(), + data: None, + target_mode: None, + }, + Mount { + source: "bpffs", + target: "/sys/fs/bpf", + fstype: "bpf", + flags: nix::mount::MsFlags::empty(), + data: None, + target_mode: None, + }, + ] { + match target_mode { + None => { + // Must exist. + let nix::sys::stat::FileStat { st_mode, .. } = nix::sys::stat::stat(target) + .with_context(|| format!("stat({target}) failed"))?; + let s_flag = nix::sys::stat::SFlag::from_bits_truncate(st_mode); + + if !s_flag.contains(nix::sys::stat::SFlag::S_IFDIR) { + anyhow::bail!("{target} is not a directory"); + } + } + Some(target_mode) => { + // Must not exist. + nix::unistd::mkdir(target, target_mode) + .with_context(|| format!("mkdir({target}) failed"))?; + } + } + nix::mount::mount(Some(source), target, Some(fstype), flags, data).with_context(|| { + format!("mount({source}, {target}, {fstype}, {flags:?}, {data:?}) failed") + })?; + } + + // By contract we run everything in /bin and assume they're rust test binaries. + // + // If the user requested command line arguments, they're named init.arg={}. + + // Read kernel parameters from /proc/cmdline. They're space separated on a single line. + let cmdline = std::fs::read_to_string("/proc/cmdline") + .with_context(|| "read_to_string(/proc/cmdline) failed")?; + let args = cmdline + .split_whitespace() + .filter_map(|parameter| { + parameter + .strip_prefix("init.arg=") + .map(std::ffi::OsString::from) + }) + .collect::>(); + + // Iterate files in /bin. + let read_dir = std::fs::read_dir("/bin").context("read_dir(/bin) failed")?; + let errors = read_dir + .filter_map(|entry| { + match (|| { + let entry = entry.context("read_dir(/bin) failed")?; + let path = entry.path(); + let status = std::process::Command::new(&path) + .args(&args) + .status() + .with_context(|| format!("failed to execute {}", path.display()))?; + + if status.code() == Some(0) { + Ok(()) + } else { + Err(anyhow::anyhow!("{} failed: {status:?}", path.display())) + } + })() { + Ok(()) => None, + Err(err) => Some(err), + } + }) + .collect::>(); + if errors.is_empty() { + Ok(()) + } else { + Err(Errors(errors).into()) + } +} + +fn main() { + match run() { + Ok(()) => { + println!("init: success"); + } + Err(err) => { + println!("{err:?}"); + println!("init: failure"); + } + } + let how = nix::sys::reboot::RebootMode::RB_POWER_OFF; + let _: std::convert::Infallible = nix::sys::reboot::reboot(how) + .unwrap_or_else(|err| panic!("reboot({how:?}) failed: {err:?}")); +} diff --git a/test/README.md b/test/README.md index a9521c0b..82e41da0 100644 --- a/test/README.md +++ b/test/README.md @@ -3,21 +3,15 @@ Aya Integration Tests The aya integration test suite is a set of tests to ensure that common usage behaviours work on real Linux distros -## Prerequisites - -### Linux - -To run locally all you need is: -1. Rust nightly -1. `cargo install bpf-linker` +## Prerequisites -### Other OSs +You'll need: -1. A POSIX shell -1. `rustup target add x86_64-unknown-linux-musl` +1. `rustup toolchain install nightly` +1. `rustup target add {aarch64,x86_64}-unknown-linux-musl` 1. `cargo install bpf-linker` -1. Install `qemu` and `cloud-init-utils` package - or any package that provides `cloud-localds` +1. (virtualized only) `qemu` ## Usage @@ -26,15 +20,13 @@ From the root of this repository: ### Native ``` -cargo xtask integration-test +cargo xtask integration-test local ``` ### Virtualized ``` -mkdir -p integration-test-binaries -cargo xtask build-integration-test | xargs -I % cp % integration-test-binaries -./test/run.sh integration-test-binaries +cargo xtask integration-test vm ``` ### Writing an integration test diff --git a/test/cloud-localds b/test/cloud-localds deleted file mode 100755 index 3a28129f..00000000 --- a/test/cloud-localds +++ /dev/null @@ -1,264 +0,0 @@ -#!/bin/bash - -VERBOSITY=0 -TEMP_D="" -DEF_DISK_FORMAT="raw" -DEF_FILESYSTEM="iso9660" -CR=" -" - -error() { echo "$@" 1>&2; } -fail() { [ $# -eq 0 ] || error "$@"; exit 1; } - -Usage() { - cat < my-meta-data - * ${0##*/} my-seed.img my-user-data my-meta-data - * kvm -net nic -net user,hostfwd=tcp::2222-:22 \\ - -drive file=disk1.img,if=virtio -drive file=my-seed.img,if=virtio - * ssh -p 2222 ubuntu@localhost -EOF -} - -bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; exit 1; } -cleanup() { - [ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}" -} - -debug() { - local level=${1}; shift; - [ "${level}" -gt "${VERBOSITY}" ] && return - error "${@}" -} - -has_cmd() { - command -v "$1" >/dev/null 2>&1 -} - -short_opts="hH:i:d:f:m:N:o:V:v" -long_opts="disk-format:,dsmode:,filesystem:,help,hostname:,interfaces:," -long_opts="${long_opts}network-config:,output:,vendor-data:,verbose" -getopt_out=$(getopt -n "${0##*/}" \ - -o "${short_opts}" -l "${long_opts}" -- "$@") && - eval set -- "${getopt_out}" || - bad_Usage - -## <> -output="" -userdata="" -metadata="" -vendordata="" -filesystem="" -diskformat=$DEF_DISK_FORMAT -interfaces=_unset -dsmode="" -hostname="" -ncname="network-config" - - -while [ $# -ne 0 ]; do - cur=${1}; next=${2}; - case "$cur" in - -h|--help) Usage ; exit 0;; - -d|--disk-format) diskformat=$next; shift;; - -f|--filesystem) filesystem=$next; shift;; - -H|--hostname) hostname=$next; shift;; - -i|--interfaces) interfaces=$next; shift;; - -N|--network-config) netcfg=$next; shift;; - -m|--dsmode) dsmode=$next; shift;; - -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));; - -V|--vendor-data) vendordata="$next";; - --) shift; break;; - esac - shift; -done - -## check arguments here -## how many args do you expect? -echo $1 -echo $2 -echo $3 -[ $# -ge 2 ] || bad_Usage "must provide output, userdata" -[ $# -le 3 ] || bad_Usage "confused by additional args" - -output=$1 -userdata=$2 -metadata=$3 - -if [ -n "$metadata" ]; then - [ "$interfaces" = "_unset" -a -z "$dsmode" -a -z "$hostname" ] || - fail "metadata is incompatible with:" \ - "--interfaces, --hostname, --dsmode" -fi - -case "$diskformat" in - tar|tar-seed-local|tar-seed-net) - if [ "${filesystem:-tar}" != "tar" ]; then - fail "diskformat=tar is incompatible with filesystem" - fi - filesystem="$diskformat" - ;; - tar*) - fail "supported 'tar' formats are tar, tar-seed-local, tar-seed-net" -esac - -if [ -z "$filesystem" ]; then - filesystem="$DEF_FILESYSTEM" -fi -if [ "$filesystem" = "iso" ]; then - filesystem="iso9660" -fi - -case "$filesystem" in - tar*) - has_cmd tar || - fail "missing 'tar'. Required for --filesystem=$filesystem";; - vfat) - has_cmd mkfs.vfat || - fail "missing 'mkfs.vfat'. Required for --filesystem=vfat." - has_cmd mcopy || - fail "missing 'mcopy'. Required for --filesystem=vfat." - ;; - iso9660) - has_cmd mkisofs || - fail "missing 'mkisofs'. Required for --filesystem=iso9660." - ;; - *) fail "unknown filesystem $filesystem";; -esac - -case "$diskformat" in - tar*|raw) :;; - *) has_cmd "qemu-img" || - fail "missing 'qemu-img'. Required for --disk-format=$diskformat." -esac - -[ "$interfaces" = "_unset" -o -r "$interfaces" ] || - fail "$interfaces: not a readable file" - -TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") || - fail "failed to make tempdir" -trap cleanup EXIT - -files=( "${TEMP_D}/user-data" "${TEMP_D}/meta-data" ) -if [ -n "$metadata" ]; then - cp "$metadata" "$TEMP_D/meta-data" || fail "$metadata: failed to copy" -else - instance_id="iid-local01" - iface_data="" - [ "$interfaces" != "_unset" ] && - iface_data=$(sed ':a;N;$!ba;s/\n/\\n/g' "$interfaces") - - # write json formatted user-data (json is a subset of yaml) - mdata="" - for kv in "instance-id:$instance_id" "local-hostname:$hostname" \ - "interfaces:${iface_data}" "dsmode:$dsmode"; do - key=${kv%%:*} - val=${kv#*:} - [ -n "$val" ] || continue - mdata="${mdata:+${mdata},${CR}}\"$key\": \"$val\"" - done - printf "{\n%s\n}\n" "$mdata" > "${TEMP_D}/meta-data" -fi - -if [ -n "$netcfg" ]; then - cp "$netcfg" "${TEMP_D}/$ncname" || - fail "failed to copy network config" - files[${#files[@]}]="$TEMP_D/$ncname" -fi - -if [ -n "$vendordata" ]; then - cp "$vendordata" "${TEMP_D}/vendor-data" || - fail "failed to copy vendor data" - files[${#files[@]}]="$TEMP_D/vendor-data" -fi - -files_rel=( ) -for f in "${files[@]}"; do - files_rel[${#files_rel[@]}]="${f#${TEMP_D}/}" -done - -if [ "$userdata" = "-" ]; then - cat > "$TEMP_D/user-data" || fail "failed to read from stdin" -else - cp "$userdata" "$TEMP_D/user-data" || fail "$userdata: failed to copy" -fi - -## alternatively, create a vfat filesystem with same files -img="$TEMP_D/seed-data" -tar_opts=( --owner=root --group=root ) - -case "$filesystem" in - tar) - tar "${tar_opts[@]}" -C "${TEMP_D}" -cf "$img" "${files_rel[@]}" || - fail "failed to create tarball of ${files_rel[*]}" - ;; - tar-seed-local|tar-seed-net) - if [ "$filesystem" = "tar-seed-local" ]; then - path="var/lib/cloud/seed/nocloud" - else - path="var/lib/cloud/seed/nocloud-net" - fi - mkdir -p "${TEMP_D}/${path}" || - fail "failed making path for seed files" - mv "${files[@]}" "${TEMP_D}/$path" || - fail "failed moving files" - tar "${tar_opts[@]}" -C "${TEMP_D}" -cf "$img" "${path}" || - fail "failed to create tarball with $path" - ;; - iso9660) - mkisofs -output "$img" -volid cidata \ - -joliet -rock "${files[@]}" > "$TEMP_D/err" 2>&1 || - { cat "$TEMP_D/err" 1>&2; fail "failed to mkisofs"; } - ;; - vfat) - truncate -s 128K "$img" || fail "failed truncate image" - out=$(mkfs.vfat -n cidata "$img" 2>&1) || - { error "failed: mkfs.vfat -n cidata $img"; error "$out"; } - mcopy -oi "$img" "${files[@]}" :: || - fail "failed to copy user-data, meta-data to img" - ;; -esac - -[ "$output" = "-" ] && output="$TEMP_D/final" -if [ "${diskformat#tar}" != "$diskformat" -o "$diskformat" = "raw" ]; then - cp "$img" "$output" || - fail "failed to copy image to $output" -else - qemu-img convert -f raw -O "$diskformat" "$img" "$output" || - fail "failed to convert to disk format $diskformat" -fi - -[ "$output" != "$TEMP_D/final" ] || { cat "$output" && output="-"; } || - fail "failed to write to -" - -debug 1 "wrote ${output} with filesystem=$filesystem and diskformat=$diskformat" -# vi: ts=4 noexpandtab diff --git a/test/integration-ebpf/src/log.rs b/test/integration-ebpf/src/log.rs index 03cdde76..51c1a46d 100644 --- a/test/integration-ebpf/src/log.rs +++ b/test/integration-ebpf/src/log.rs @@ -7,7 +7,14 @@ use aya_log_ebpf::{debug, error, info, trace, warn}; #[uprobe] pub fn test_log(ctx: ProbeContext) { debug!(&ctx, "Hello from eBPF!"); - error!(&ctx, "{}, {}, {}", 69, 420i32, "wao"); + error!( + &ctx, + "{}, {}, {}, {:x}", + 69, + 420i32, + "wao", + "wao".as_bytes() + ); let ipv4 = 167772161u32; // 10.0.0.1 let ipv6 = [ 32u8, 1u8, 13u8, 184u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, diff --git a/test/integration-test/Cargo.toml b/test/integration-test/Cargo.toml index 876a9a86..4d1a466b 100644 --- a/test/integration-test/Cargo.toml +++ b/test/integration-test/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -anyhow = { workspace = true, default-features = true } +anyhow = { workspace = true, features = ["std"] } assert_matches = { workspace = true } aya = { workspace = true } aya-log = { workspace = true } @@ -16,10 +16,7 @@ netns-rs = { workspace = true } object = { workspace = true } rbpf = { workspace = true } test-case = { workspace = true } -tokio = { workspace = true, default-features = false, features = [ - "macros", - "time", -] } +tokio = { workspace = true, features = ["macros", "time"] } [build-dependencies] cargo_metadata = { workspace = true } diff --git a/test/integration-test/bpf/ext.bpf.c b/test/integration-test/bpf/ext.bpf.c index dc82f5cf..2996fcf7 100644 --- a/test/integration-test/bpf/ext.bpf.c +++ b/test/integration-test/bpf/ext.bpf.c @@ -1,10 +1,9 @@ -#include +// clang-format off +#include #include +// clang-format on SEC("xdp") -int xdp_drop(struct xdp_md *ctx) -{ - return XDP_DROP; -} +int xdp_drop(struct xdp_md *ctx) { return XDP_DROP; } char _license[] SEC("license") = "GPL"; diff --git a/test/integration-test/bpf/main.bpf.c b/test/integration-test/bpf/main.bpf.c index 2a30577f..b9365622 100644 --- a/test/integration-test/bpf/main.bpf.c +++ b/test/integration-test/bpf/main.bpf.c @@ -1,10 +1,9 @@ -#include +// clang-format off +#include #include +// clang-format on SEC("xdp") -int xdp_pass(struct xdp_md *ctx) -{ - return XDP_PASS; -} +int xdp_pass(struct xdp_md *ctx) { return XDP_PASS; } char _license[] SEC("license") = "GPL"; diff --git a/test/integration-test/bpf/multimap-btf.bpf.c b/test/integration-test/bpf/multimap-btf.bpf.c index 955a91d3..2bd7978b 100644 --- a/test/integration-test/bpf/multimap-btf.bpf.c +++ b/test/integration-test/bpf/multimap-btf.bpf.c @@ -1,30 +1,30 @@ -#include +// clang-format off +#include #include +// clang-format on struct { - __uint(type, BPF_MAP_TYPE_ARRAY); - __type(key, __u32); - __type(value, __u64); - __uint(max_entries, 1); + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, __u64); + __uint(max_entries, 1); } map_1 SEC(".maps"); struct { - __uint(type, BPF_MAP_TYPE_ARRAY); - __type(key, __u32); - __type(value, __u64); - __uint(max_entries, 1); + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, __u64); + __uint(max_entries, 1); } map_2 SEC(".maps"); - SEC("tracepoint") -int bpf_prog(void *ctx) -{ - __u32 key = 0; - __u64 twenty_four = 24; - __u64 forty_two = 42; - bpf_map_update_elem(&map_1, &key, &twenty_four, BPF_ANY); - bpf_map_update_elem(&map_2, &key, &forty_two, BPF_ANY); - return 0; +int bpf_prog(void *ctx) { + __u32 key = 0; + __u64 twenty_four = 24; + __u64 forty_two = 42; + bpf_map_update_elem(&map_1, &key, &twenty_four, BPF_ANY); + bpf_map_update_elem(&map_2, &key, &forty_two, BPF_ANY); + return 0; } char _license[] SEC("license") = "GPL"; diff --git a/test/integration-test/bpf/reloc.bpf.c b/test/integration-test/bpf/reloc.bpf.c index dbc464a4..609e504b 100644 --- a/test/integration-test/bpf/reloc.bpf.c +++ b/test/integration-test/bpf/reloc.bpf.c @@ -1,10 +1,10 @@ // clang-format off -#include +#include #include #include // clang-format on -char _license[] __attribute__((section("license"), used)) = "GPL"; +char _license[] SEC("license") = "GPL"; struct { __uint(type, BPF_MAP_TYPE_ARRAY); @@ -19,12 +19,17 @@ long set_output(__u64 value) { } struct relocated_struct_with_scalars { +#ifndef TARGET __u8 a; +#endif __u8 b; __u8 c; +#ifdef TARGET + __u8 d; +#endif }; -__attribute__((noinline)) int field_global() { +__noinline int field_global() { struct relocated_struct_with_scalars s = {1, 2, 3}; return set_output(__builtin_preserve_access_index(s.b)); } @@ -32,11 +37,16 @@ __attribute__((noinline)) int field_global() { SEC("uprobe") int field(void *ctx) { return field_global(); } struct relocated_struct_with_pointer { +#ifndef TARGET struct relocated_struct_with_pointer *first; +#endif struct relocated_struct_with_pointer *second; +#ifdef TARGET + struct relocated_struct_with_pointer *first; +#endif }; -__attribute__((noinline)) int pointer_global() { +__noinline int pointer_global() { struct relocated_struct_with_pointer s = { (struct relocated_struct_with_pointer *)42, (struct relocated_struct_with_pointer *)21, @@ -46,49 +56,86 @@ __attribute__((noinline)) int pointer_global() { SEC("uprobe") int pointer(void *ctx) { return pointer_global(); } -__attribute__((noinline)) int struct_flavors_global() { +__noinline int struct_flavors_global() { struct relocated_struct_with_scalars s = {1, 2, 3}; +#ifndef TARGET if (bpf_core_field_exists(s.a)) { return set_output(__builtin_preserve_access_index(s.a)); +#else + if (bpf_core_field_exists(s.d)) { + return set_output(__builtin_preserve_access_index(s.d)); +#endif } else { - return set_output(__builtin_preserve_access_index(s.b)); + return set_output(__builtin_preserve_access_index(s.c)); } } SEC("uprobe") int struct_flavors(void *ctx) { return struct_flavors_global(); } -enum relocated_enum_unsigned_32 { U32 = 0xAAAAAAAA }; +enum relocated_enum_unsigned_32 { + U32_VAL = +#ifndef TARGET + 0xAAAAAAAA +#else + 0xBBBBBBBB +#endif +}; -__attribute__((noinline)) int enum_unsigned_32_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_unsigned_32, U32)); +__noinline int enum_unsigned_32_global() { + return set_output( + bpf_core_enum_value(enum relocated_enum_unsigned_32, U32_VAL)); } SEC("uprobe") int enum_unsigned_32(void *ctx) { return enum_unsigned_32_global(); } -enum relocated_enum_signed_32 { S32 = -0x7AAAAAAA }; +enum relocated_enum_signed_32 { + S32_VAL = +#ifndef TARGET + -0x7AAAAAAA +#else + -0x7BBBBBBB +#endif +}; -__attribute__((noinline)) int enum_signed_32_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_signed_32, S32)); +__noinline int enum_signed_32_global() { + return set_output( + bpf_core_enum_value(enum relocated_enum_signed_32, S32_VAL)); } SEC("uprobe") int enum_signed_32(void *ctx) { return enum_signed_32_global(); } -enum relocated_enum_unsigned_64 { U64 = 0xAAAAAAAABBBBBBBB }; +enum relocated_enum_unsigned_64 { + U64_VAL = +#ifndef TARGET + 0xAAAAAAAABBBBBBBB +#else + 0xCCCCCCCCDDDDDDDD +#endif +}; -__attribute__((noinline)) int enum_unsigned_64_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_unsigned_64, U64)); +__noinline int enum_unsigned_64_global() { + return set_output( + bpf_core_enum_value(enum relocated_enum_unsigned_64, U64_VAL)); } SEC("uprobe") int enum_unsigned_64(void *ctx) { return enum_unsigned_64_global(); } -enum relocated_enum_signed_64 { u64 = -0xAAAAAAABBBBBBBB }; +enum relocated_enum_signed_64 { + S64_VAL = +#ifndef TARGET + -0xAAAAAAABBBBBBBB +#else + -0xCCCCCCCDDDDDDDD +#endif +}; -__attribute__((noinline)) int enum_signed_64_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_signed_64, u64)); +__noinline int enum_signed_64_global() { + return set_output( + bpf_core_enum_value(enum relocated_enum_signed_64, S64_VAL)); } SEC("uprobe") int enum_signed_64(void *ctx) { return enum_signed_64_global(); } diff --git a/test/integration-test/bpf/reloc.btf.c b/test/integration-test/bpf/reloc.btf.c deleted file mode 100644 index 86801061..00000000 --- a/test/integration-test/bpf/reloc.btf.c +++ /dev/null @@ -1,77 +0,0 @@ -// clang-format off -#include -#include -#include -// clang-format on - -#include - -long set_output(__u64 value) { exit((int)value); } - -struct relocated_struct_with_scalars { - __u8 b; - __u8 c; - __u8 d; -}; - -__attribute__((noinline)) int field_global() { - struct relocated_struct_with_scalars s = {1, 2, 3}; - return set_output(__builtin_preserve_access_index(s.b)); -} - -struct relocated_struct_with_pointer { - struct relocated_struct_with_pointer *second; - struct relocated_struct_with_pointer *first; -}; - -__attribute__((noinline)) int pointer_global() { - struct relocated_struct_with_pointer s = { - (struct relocated_struct_with_pointer *)42, - (struct relocated_struct_with_pointer *)21, - }; - return set_output((__u64)__builtin_preserve_access_index(s.first)); -} - -__attribute__((noinline)) int struct_flavors_global() { - struct relocated_struct_with_scalars s = {1, 2, 3}; - if (bpf_core_field_exists(s.b)) { - return set_output(__builtin_preserve_access_index(s.b)); - } else { - return set_output(__builtin_preserve_access_index(s.c)); - } -} - -enum relocated_enum_unsigned_32 { U32 = 0xBBBBBBBB }; - -__attribute__((noinline)) int enum_unsigned_32_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_unsigned_32, U32)); -} - -enum relocated_enum_signed_32 { S32 = -0x7BBBBBBB }; - -__attribute__((noinline)) int enum_signed_32_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_signed_32, S32)); -} - -enum relocated_enum_unsigned_64 { U64 = 0xCCCCCCCCDDDDDDDD }; - -__attribute__((noinline)) int enum_unsigned_64_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_unsigned_64, U64)); -} - -enum relocated_enum_signed_64 { u64 = -0xCCCCCCCDDDDDDDD }; - -__attribute__((noinline)) int enum_signed_64_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_signed_64, u64)); -} - -// Avoids dead code elimination by the compiler. -int main() { - field_global(); - pointer_global(); - struct_flavors_global(); - enum_unsigned_32_global(); - enum_signed_32_global(); - enum_unsigned_64_global(); - enum_signed_64_global(); -} diff --git a/test/integration-test/bpf/text_64_64_reloc.c b/test/integration-test/bpf/text_64_64_reloc.c index 877c7628..067350cc 100644 --- a/test/integration-test/bpf/text_64_64_reloc.c +++ b/test/integration-test/bpf/text_64_64_reloc.c @@ -1,28 +1,25 @@ -#include +// clang-format off +#include #include +// clang-format on char _license[] SEC("license") = "GPL"; struct { - __uint(type, BPF_MAP_TYPE_ARRAY); - __type(key, __u32); - __type(value, __u64); - __uint(max_entries, 2); + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, __u64); + __uint(max_entries, 2); } RESULTS SEC(".maps"); -static __u64 -inc_cb(void *map, __u32 *key, void *val, - void *data) -{ - __u64 *value = val; - *value += 1; - return 0; +static __u64 inc_cb(void *map, __u32 *key, void *val, void *data) { + __u64 *value = val; + *value += 1; + return 0; } SEC("uprobe/test_text_64_64_reloc") -int test_text_64_64_reloc(struct pt_regs *ctx) -{ - bpf_for_each_map_elem(&RESULTS, inc_cb, NULL, 0); - return 0; +int test_text_64_64_reloc(struct pt_regs *ctx) { + bpf_for_each_map_elem(&RESULTS, inc_cb, NULL, 0); + return 0; } - diff --git a/test/integration-test/build.rs b/test/integration-test/build.rs index cd816164..fec40483 100644 --- a/test/integration-test/build.rs +++ b/test/integration-test/build.rs @@ -4,7 +4,7 @@ use std::{ fs, io::{BufRead as _, BufReader}, path::PathBuf, - process::{Child, Command, Stdio}, + process::{Child, Command, Output, Stdio}, }; use cargo_metadata::{ @@ -64,20 +64,14 @@ fn main() { panic!("unsupported endian={:?}", endian) }; - const C_BPF: &[(&str, &str)] = &[ - ("ext.bpf.c", "ext.bpf.o"), - ("main.bpf.c", "main.bpf.o"), - ("multimap-btf.bpf.c", "multimap-btf.bpf.o"), - ("reloc.bpf.c", "reloc.bpf.o"), - ("text_64_64_reloc.c", "text_64_64_reloc.o"), + const C_BPF: &[(&str, bool)] = &[ + ("ext.bpf.c", false), + ("main.bpf.c", false), + ("multimap-btf.bpf.c", false), + ("reloc.bpf.c", true), + ("text_64_64_reloc.c", false), ]; - let c_bpf = C_BPF.iter().map(|(src, dst)| (src, out_dir.join(dst))); - - const C_BTF: &[(&str, &str)] = &[("reloc.btf.c", "reloc.btf.o")]; - - let c_btf = C_BTF.iter().map(|(src, dst)| (src, out_dir.join(dst))); - if build_integration_bpf { let libbpf_dir = manifest_dir .parent() @@ -116,65 +110,67 @@ fn main() { target_arch.push(arch); }; - for (src, dst) in c_bpf { - let src = bpf_dir.join(src); - println!("cargo:rerun-if-changed={}", src.to_str().unwrap()); + // NB: libbpf's documentation suggests that vmlinux.h be generated by running `bpftool btf + // dump file /sys/kernel/btf/vmlinux format c`; this allows CO-RE to work. + // + // However in our tests we do not make use of kernel data structures, and so any vmlinux.h + // which defines the constants we need (e.g. `__u8`, `__u64`, `BPF_MAP_TYPE_ARRAY`, + // `BPF_ANY`, `XDP_PASS`, `XDP_DROP`, etc.) will suffice. Since we already have a libbpf + // submodule which happens to include such a file, we use it. + let libbpf_vmlinux_dir = libbpf_dir.join(".github/actions/build-selftests"); - exec( - Command::new("clang") - .arg("-I") - .arg(&libbpf_headers_dir) - .args(["-g", "-O2", "-target", target, "-c"]) - .arg(&target_arch) - .arg(src) - .arg("-o") - .arg(dst), - ) - .unwrap(); - } + let clang = || { + let mut cmd = Command::new("clang"); + cmd.arg("-nostdlibinc") + .arg("-I") + .arg(&libbpf_headers_dir) + .arg("-I") + .arg(&libbpf_vmlinux_dir) + .args(["-g", "-O2", "-target", target, "-c"]) + .arg(&target_arch); + cmd + }; - for (src, dst) in c_btf { + for (src, build_btf) in C_BPF { + let dst = out_dir.join(src).with_extension("o"); let src = bpf_dir.join(src); println!("cargo:rerun-if-changed={}", src.to_str().unwrap()); - let mut cmd = Command::new("clang"); - cmd.arg("-I") - .arg(&libbpf_headers_dir) - .args(["-g", "-target", target, "-c"]) - .arg(&target_arch) - .arg(src) - .args(["-o", "-"]); - - let mut child = cmd - .stdout(Stdio::piped()) - .spawn() - .unwrap_or_else(|err| panic!("failed to spawn {cmd:?}: {err}")); - - let Child { stdout, .. } = &mut child; - let stdout = stdout.take().unwrap(); - - let mut output = OsString::new(); - output.push(".BTF="); - output.push(dst); - exec( - // NB: objcopy doesn't support reading from stdin, so we have to use llvm-objcopy. - Command::new("llvm-objcopy") - .arg("--dump-section") - .arg(output) - .arg("-") - .stdin(stdout), - ) - .unwrap(); - - let status = child - .wait() - .unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}")); - match status.code() { - Some(code) => match code { - 0 => {} - code => panic!("{cmd:?} exited with status code {code}"), - }, - None => panic!("{cmd:?} terminated by signal"), + exec(clang().arg(&src).arg("-o").arg(&dst)).unwrap(); + + if *build_btf { + let mut cmd = clang(); + let mut child = cmd + .arg("-DTARGET") + .arg(&src) + .args(["-o", "-"]) + .stdout(Stdio::piped()) + .spawn() + .unwrap_or_else(|err| panic!("failed to spawn {cmd:?}: {err}")); + + let Child { stdout, .. } = &mut child; + let stdout = stdout.take().unwrap(); + + let dst = dst.with_extension("target.o"); + + let mut output = OsString::new(); + output.push(".BTF="); + output.push(dst); + exec( + // NB: objcopy doesn't support reading from stdin, so we have to use llvm-objcopy. + Command::new("llvm-objcopy") + .arg("--dump-section") + .arg(output) + .arg("-") + .stdin(stdout), + ) + .unwrap(); + + let output = child + .wait_with_output() + .unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}")); + let Output { status, .. } = &output; + assert_eq!(status.code(), Some(0), "{cmd:?} failed: {output:?}"); } } @@ -257,13 +253,7 @@ fn main() { let status = child .wait() .unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}")); - match status.code() { - Some(code) => match code { - 0 => {} - code => panic!("{cmd:?} exited with status code {code}"), - }, - None => panic!("{cmd:?} terminated by signal"), - } + assert_eq!(status.code(), Some(0), "{cmd:?} failed: {status:?}"); stderr.join().map_err(std::panic::resume_unwind).unwrap(); @@ -273,8 +263,13 @@ fn main() { .unwrap_or_else(|err| panic!("failed to copy {binary:?} to {dst:?}: {err}")); } } else { - for (_src, dst) in c_bpf.chain(c_btf) { + for (src, build_btf) in C_BPF { + let dst = out_dir.join(src).with_extension("o"); fs::write(&dst, []).unwrap_or_else(|err| panic!("failed to create {dst:?}: {err}")); + if *build_btf { + let dst = dst.with_extension("target.o"); + fs::write(&dst, []).unwrap_or_else(|err| panic!("failed to create {dst:?}: {err}")); + } } let Package { targets, .. } = integration_ebpf_package; diff --git a/test/integration-test/src/lib.rs b/test/integration-test/src/lib.rs index 42d7c394..4ef2b712 100644 --- a/test/integration-test/src/lib.rs +++ b/test/integration-test/src/lib.rs @@ -5,7 +5,8 @@ pub const MAIN: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/main.b pub const MULTIMAP_BTF: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/multimap-btf.bpf.o")); pub const RELOC_BPF: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/reloc.bpf.o")); -pub const RELOC_BTF: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/reloc.btf.o")); +pub const RELOC_BTF: &[u8] = + include_bytes_aligned!(concat!(env!("OUT_DIR"), "/reloc.bpf.target.o")); pub const TEXT_64_64_RELOC: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/text_64_64_reloc.o")); diff --git a/test/integration-test/src/tests/btf_relocations.rs b/test/integration-test/src/tests/btf_relocations.rs index 7e1020ba..79eb3e52 100644 --- a/test/integration-test/src/tests/btf_relocations.rs +++ b/test/integration-test/src/tests/btf_relocations.rs @@ -2,20 +2,20 @@ use test_case::test_case; use aya::{maps::Array, programs::UProbe, util::KernelVersion, BpfLoader, Btf, Endianness}; -#[test_case("field", false, None, 2)] -#[test_case("field", true, None, 1)] +#[test_case("enum_signed_32", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7AAAAAAAi32 as u64)] +#[test_case("enum_signed_32", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7BBBBBBBi32 as u64)] +#[test_case("enum_signed_64", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xAAAAAAABBBBBBBBi64 as u64)] +#[test_case("enum_signed_64", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xCCCCCCCDDDDDDDDi64 as u64)] #[test_case("enum_unsigned_32", false, None, 0xAAAAAAAA)] #[test_case("enum_unsigned_32", true, None, 0xBBBBBBBB)] +#[test_case("enum_unsigned_64", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xAAAAAAAABBBBBBBB)] +#[test_case("enum_unsigned_64", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xCCCCCCCCDDDDDDDD)] +#[test_case("field", false, None, 2)] +#[test_case("field", true, None, 1)] #[test_case("pointer", false, None, 42)] #[test_case("pointer", true, None, 21)] #[test_case("struct_flavors", false, None, 1)] -#[test_case("struct_flavors", true, None, 1)] -#[test_case("enum_signed_32", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7AAAAAAAi32 as u64)] -#[test_case("enum_signed_32", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7BBBBBBBi32 as u64)] -#[test_case("enum_unsigned_64", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xAAAAAAAABBBBBBBB)] -#[test_case("enum_unsigned_64", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xCCCCCCCCDDDDDDDD)] -#[test_case("enum_signed_64", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xAAAAAAABBBBBBBBi64 as u64)] -#[test_case("enum_signed_64", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xCCCCCCCDDDDDDDDi64 as u64)] +#[test_case("struct_flavors", true, None, 2)] fn relocation_tests( program: &str, with_relocations: bool, diff --git a/test/integration-test/src/tests/log.rs b/test/integration-test/src/tests/log.rs index 8645762b..c51f7e96 100644 --- a/test/integration-test/src/tests/log.rs +++ b/test/integration-test/src/tests/log.rs @@ -70,12 +70,16 @@ async fn log() { let mut logs = 0; let records = loop { - tokio::time::sleep(std::time::Duration::from_millis(10)).await; + tokio::time::sleep(std::time::Duration::from_millis(100)).await; let records = captured_logs.lock().unwrap(); - if records.len() == logs { + let len = records.len(); + if len == 0 { + continue; + } + if len == logs { break records; } - logs = records.len(); + logs = len; }; let mut records = records.iter(); @@ -92,7 +96,7 @@ async fn log() { assert_eq!( records.next(), Some(&CapturedLog { - body: "69, 420, wao".into(), + body: "69, 420, wao, 77616f".into(), level: Level::Error, target: "log".into(), }) diff --git a/test/integration-test/src/tests/rbpf.rs b/test/integration-test/src/tests/rbpf.rs index 44e648d1..0a85adbf 100644 --- a/test/integration-test/src/tests/rbpf.rs +++ b/test/integration-test/src/tests/rbpf.rs @@ -74,7 +74,7 @@ fn use_map_with_rbpf() { object .relocate_maps( maps.iter() - .map(|(s, (fd, map))| (s.as_ref() as &str, Some(*fd), map)), + .map(|(s, (fd, map))| (s.as_ref() as &str, *fd, map)), &text_sections, ) .expect("Relocation failed"); diff --git a/test/integration-test/src/tests/smoke.rs b/test/integration-test/src/tests/smoke.rs index 78614bd9..48c1600b 100644 --- a/test/integration-test/src/tests/smoke.rs +++ b/test/integration-test/src/tests/smoke.rs @@ -1,5 +1,5 @@ use aya::{ - programs::{Extension, TracePoint, Xdp, XdpFlags}, + programs::{loaded_programs, Extension, TracePoint, Xdp, XdpFlags}, util::KernelVersion, Bpf, BpfLoader, }; @@ -63,5 +63,36 @@ fn extension() { .load(crate::EXT) .unwrap(); let drop_: &mut Extension = bpf.program_mut("xdp_drop").unwrap().try_into().unwrap(); - drop_.load(pass.fd().unwrap(), "xdp_pass").unwrap(); + drop_ + .load(pass.fd().unwrap().try_clone().unwrap(), "xdp_pass") + .unwrap(); +} + +#[test] +fn list_loaded_programs() { + // Load a program. + let mut bpf = Bpf::load(crate::PASS).unwrap(); + let dispatcher: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap(); + dispatcher.load().unwrap(); + dispatcher.attach("lo", XdpFlags::default()).unwrap(); + + // Ensure the loaded_programs() api doesn't panic. + let prog = loaded_programs() + .map(|p| p.unwrap()) + .find(|p| p.name_as_str().unwrap() == "pass") + .unwrap(); + + // Ensure all relevant helper functions don't panic. + prog.name(); + prog.id(); + prog.tag(); + prog.program_type(); + prog.gpl_compatible(); + prog.map_ids().unwrap(); + prog.btf_id(); + prog.size_translated(); + prog.memory_locked().unwrap(); + prog.verified_instruction_count(); + prog.loaded_at(); + prog.fd().unwrap(); } diff --git a/test/run.sh b/test/run.sh deleted file mode 100755 index 26c98918..00000000 --- a/test/run.sh +++ /dev/null @@ -1,241 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -if [ "$(uname -s)" = "Darwin" ]; then - PATH="$(dirname "$(brew list gnu-getopt | grep "bin/getopt$")"):$PATH" - export PATH -fi - -AYA_SOURCE_DIR="$(realpath "$(dirname "$0")"/..)" - -# Temporary directory for tests to use. -AYA_TMPDIR="${AYA_SOURCE_DIR}/.tmp" - -# Directory for VM images -AYA_IMGDIR=${AYA_TMPDIR} - -if [ -z "${AYA_BUILD_TARGET}" ]; then - AYA_BUILD_TARGET=$(rustc -vV | sed -n 's|host: ||p') -fi - -AYA_HOST_ARCH=$(uname -m) -if [ "${AYA_HOST_ARCH}" = "arm64" ]; then - AYA_HOST_ARCH="aarch64" -fi - -if [ -z "${AYA_GUEST_ARCH}" ]; then - AYA_GUEST_ARCH="${AYA_HOST_ARCH}" -fi - -if [ "${AYA_GUEST_ARCH}" = "aarch64" ]; then - if [ -z "${AARCH64_UEFI}" ]; then - AARCH64_UEFI="$(brew list qemu -1 -v | grep edk2-aarch64-code.fd)" - fi -fi - -if [ -z "$AYA_MUSL_TARGET" ]; then - AYA_MUSL_TARGET=${AYA_GUEST_ARCH}-unknown-linux-musl -fi - -# Test Image -if [ -z "${AYA_TEST_IMAGE}" ]; then - AYA_TEST_IMAGE="fedora38" -fi - -case "${AYA_TEST_IMAGE}" in - fedora*) AYA_SSH_USER="fedora";; - centos*) AYA_SSH_USER="centos";; -esac - -download_images() { - mkdir -p "${AYA_IMGDIR}" - case $1 in - fedora37) - if [ ! -f "${AYA_IMGDIR}/fedora37.${AYA_GUEST_ARCH}.qcow2" ]; then - IMAGE="Fedora-Cloud-Base-37-1.7.${AYA_GUEST_ARCH}.qcow2" - IMAGE_URL="https://download.fedoraproject.org/pub/fedora/linux/releases/37/Cloud/${AYA_GUEST_ARCH}/images" - echo "Downloading: ${IMAGE}, this may take a while..." - curl -o "${AYA_IMGDIR}/fedora37.${AYA_GUEST_ARCH}.qcow2" -sSL "${IMAGE_URL}/${IMAGE}" - fi - ;; - fedora38) - if [ ! -f "${AYA_IMGDIR}/fedora38.${AYA_GUEST_ARCH}.qcow2" ]; then - IMAGE="Fedora-Cloud-Base-38_Beta-1.3.${AYA_GUEST_ARCH}.qcow2" - IMAGE_URL="https://fr2.rpmfind.net/linux/fedora/linux/releases/test/38_Beta/Cloud/${AYA_GUEST_ARCH}/images" - echo "Downloading: ${IMAGE}, this may take a while..." - curl -o "${AYA_IMGDIR}/fedora38.${AYA_GUEST_ARCH}.qcow2" -sSL "${IMAGE_URL}/${IMAGE}" - fi - ;; - centos8) - if [ ! -f "${AYA_IMGDIR}/centos8.${AYA_GUEST_ARCH}.qcow2" ]; then - IMAGE="CentOS-8-GenericCloud-8.4.2105-20210603.0.${AYA_GUEST_ARCH}.qcow2" - IMAGE_URL="https://cloud.centos.org/centos/8/${AYA_GUEST_ARCH}/images" - echo "Downloading: ${IMAGE}, this may take a while..." - curl -o "${AYA_IMGDIR}/centos8.${AYA_GUEST_ARCH}.qcow2" -sSL "${IMAGE_URL}/${IMAGE}" - fi - ;; - *) - echo "$1 is not a recognized image name" - return 1 - ;; - esac -} - -start_vm() { - download_images "${AYA_TEST_IMAGE}" - # prepare config - cat > "${AYA_TMPDIR}/metadata.yaml" < "${AYA_TMPDIR}/ssh_config" < "${AYA_TMPDIR}/user-data.yaml" < actual_cores - nr_cpus=8 - fi - fi - ;; - *) - echo "${AYA_GUEST_ARCH} is not supported" - return 1 - ;; - esac - - if [ ! -f "${AYA_IMGDIR}/vm.qcow2" ]; then - echo "Creating VM image" - qemu-img create -F qcow2 -f qcow2 -o backing_file="${AYA_IMGDIR}/${AYA_TEST_IMAGE}.${AYA_GUEST_ARCH}.qcow2" "${AYA_IMGDIR}/vm.qcow2" || return 1 - else - echo "Reusing existing VM image" - fi - $QEMU \ - -machine "${machine}" \ - -cpu "${cpu}" \ - -m 3G \ - -smp "${nr_cpus}" \ - -display none \ - -monitor none \ - -daemonize \ - -pidfile "${AYA_TMPDIR}/vm.pid" \ - -device virtio-net-pci,netdev=net0 \ - -netdev user,id=net0,hostfwd=tcp::2222-:22 \ - "${uefi[@]}" \ - -drive if=virtio,format=qcow2,file="${AYA_IMGDIR}/vm.qcow2" \ - -drive if=virtio,format=raw,file="${AYA_TMPDIR}/seed.img" || return 1 - - trap cleanup_vm EXIT - echo "Waiting for SSH on port 2222..." - retry=0 - max_retries=300 - while ! ssh -q -F "${AYA_TMPDIR}/ssh_config" -o ConnectTimeout=1 -i "${AYA_TMPDIR}/test_rsa" "${AYA_SSH_USER}"@localhost -p 2222 echo "Hello VM"; do - retry=$((retry+1)) - if [ ${retry} -gt ${max_retries} ]; then - echo "Unable to connect to VM" - return 1 - fi - sleep 1 - done - - echo "VM launched" - exec_vm uname -a - echo "Enabling testing repositories" - exec_vm sudo dnf config-manager --set-enabled updates-testing - exec_vm sudo dnf config-manager --set-enabled updates-testing-modular -} - -scp_vm() { - local=$1 - remote=$(basename "$1") - scp -q -F "${AYA_TMPDIR}/ssh_config" \ - -i "${AYA_TMPDIR}/test_rsa" \ - -P 2222 "${local}" \ - "${AYA_SSH_USER}@localhost:${remote}" -} - -rsync_vm() { - rsync -a -e "ssh -p 2222 -F ${AYA_TMPDIR}/ssh_config -i ${AYA_TMPDIR}/test_rsa" "$1" "$AYA_SSH_USER"@localhost: -} - -exec_vm() { - ssh -q -F "${AYA_TMPDIR}/ssh_config" \ - -i "${AYA_TMPDIR}/test_rsa" \ - -p 2222 \ - "${AYA_SSH_USER}"@localhost \ - "$@" -} - -stop_vm() { - if [ -f "${AYA_TMPDIR}/vm.pid" ]; then - echo "Stopping VM forcefully" - kill -9 "$(cat "${AYA_TMPDIR}/vm.pid")" - rm "${AYA_TMPDIR}/vm.pid" - fi -} - -cleanup_vm() { - if ! stop_vm; then - rm -f "${AYA_IMGDIR}/vm.qcow2" - fi -} - -start_vm -trap cleanup_vm EXIT - -# make sure we always use fresh sources (also see comment at the end) -rsync_vm "$*" - -exec_vm "find $* -type f -executable -print0 | xargs -0 -I {} sudo {} --test-threads=1" - -# 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 -# before rsyncing. -exec_vm "rm -rf $*; sync" diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 0349e022..1a2ae931 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -6,10 +6,10 @@ edition = "2021" publish = false [dependencies] -anyhow = { workspace = true, default-features = true } +anyhow = { workspace = true, features = ["std"] } aya-tool = { workspace = true } cargo_metadata = { workspace = true } -clap = { workspace = true, default-features = true, features = ["derive"] } +clap = { workspace = true, features = ["derive"] } dialoguer = { workspace = true } diff = { workspace = true } indoc = { workspace = true } diff --git a/xtask/public-api/aya-log-common.txt b/xtask/public-api/aya-log-common.txt index 7e28268a..fd921d9b 100644 --- a/xtask/public-api/aya-log-common.txt +++ b/xtask/public-api/aya-log-common.txt @@ -18,6 +18,8 @@ pub aya_log_common::Argument::U32 pub aya_log_common::Argument::U64 pub aya_log_common::Argument::U8 pub aya_log_common::Argument::Usize +impl core::convert::From for u8 +pub fn u8::from(enum_value: aya_log_common::Argument) -> Self impl core::clone::Clone for aya_log_common::Argument pub fn aya_log_common::Argument::clone(&self) -> aya_log_common::Argument impl core::fmt::Debug for aya_log_common::Argument @@ -52,7 +54,7 @@ pub aya_log_common::DisplayHint::LowerMac pub aya_log_common::DisplayHint::UpperHex pub aya_log_common::DisplayHint::UpperMac impl aya_log_common::WriteToBuf for aya_log_common::DisplayHint -pub fn aya_log_common::DisplayHint::write(self, buf: &mut [u8]) -> core::result::Result +pub fn aya_log_common::DisplayHint::write(self, buf: &mut [u8]) -> core::option::Option impl core::convert::From for u8 pub fn u8::from(enum_value: aya_log_common::DisplayHint) -> Self impl core::clone::Clone for aya_log_common::DisplayHint @@ -134,6 +136,8 @@ pub aya_log_common::RecordField::Line pub aya_log_common::RecordField::Module pub aya_log_common::RecordField::NumArgs pub aya_log_common::RecordField::Target = 1 +impl core::convert::From for u8 +pub fn u8::from(enum_value: aya_log_common::RecordField) -> Self impl core::clone::Clone for aya_log_common::RecordField pub fn aya_log_common::RecordField::clone(&self) -> aya_log_common::RecordField impl core::fmt::Debug for aya_log_common::RecordField @@ -212,41 +216,41 @@ impl aya_log_common::UpperHexFormatter for usize pub trait aya_log_common::UpperMacFormatter impl aya_log_common::UpperMacFormatter for [u8; 6] pub trait aya_log_common::WriteToBuf -pub fn aya_log_common::WriteToBuf::write(self, buf: &mut [u8]) -> core::result::Result +pub fn aya_log_common::WriteToBuf::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for &[u8] -pub fn &[u8]::write(self, buf: &mut [u8]) -> core::result::Result +pub fn &[u8]::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for &str -pub fn &str::write(self, buf: &mut [u8]) -> core::result::Result +pub fn &str::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for [u16; 8] -pub fn [u16; 8]::write(self, buf: &mut [u8]) -> core::result::Result +pub fn [u16; 8]::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for [u8; 16] -pub fn [u8; 16]::write(self, buf: &mut [u8]) -> core::result::Result +pub fn [u8; 16]::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for [u8; 6] -pub fn [u8; 6]::write(self, buf: &mut [u8]) -> core::result::Result +pub fn [u8; 6]::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for aya_log_common::DisplayHint -pub fn aya_log_common::DisplayHint::write(self, buf: &mut [u8]) -> core::result::Result +pub fn aya_log_common::DisplayHint::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for f32 -pub fn f32::write(self, buf: &mut [u8]) -> core::result::Result +pub fn f32::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for f64 -pub fn f64::write(self, buf: &mut [u8]) -> core::result::Result +pub fn f64::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for i16 -pub fn i16::write(self, buf: &mut [u8]) -> core::result::Result +pub fn i16::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for i32 -pub fn i32::write(self, buf: &mut [u8]) -> core::result::Result +pub fn i32::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for i64 -pub fn i64::write(self, buf: &mut [u8]) -> core::result::Result +pub fn i64::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for i8 -pub fn i8::write(self, buf: &mut [u8]) -> core::result::Result +pub fn i8::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for isize -pub fn isize::write(self, buf: &mut [u8]) -> core::result::Result +pub fn isize::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for u16 -pub fn u16::write(self, buf: &mut [u8]) -> core::result::Result +pub fn u16::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for u32 -pub fn u32::write(self, buf: &mut [u8]) -> core::result::Result +pub fn u32::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for u64 -pub fn u64::write(self, buf: &mut [u8]) -> core::result::Result +pub fn u64::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for u8 -pub fn u8::write(self, buf: &mut [u8]) -> core::result::Result +pub fn u8::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for usize -pub fn usize::write(self, buf: &mut [u8]) -> core::result::Result +pub fn usize::write(self, buf: &mut [u8]) -> core::option::Option pub type aya_log_common::LogValueLength = u16 diff --git a/xtask/public-api/aya-log.txt b/xtask/public-api/aya-log.txt index 61bd2867..55276bc9 100644 --- a/xtask/public-api/aya-log.txt +++ b/xtask/public-api/aya-log.txt @@ -19,8 +19,6 @@ impl core::marker::Sync for aya_log::Error impl core::marker::Unpin for aya_log::Error impl !core::panic::unwind_safe::RefUnwindSafe for aya_log::Error impl !core::panic::unwind_safe::UnwindSafe for aya_log::Error -impl core::any::Provider for aya_log::Error where E: core::error::Error + core::marker::Sized -pub fn aya_log::Error::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_log::Error where U: core::convert::From pub fn aya_log::Error::into(self) -> U impl core::convert::TryFrom for aya_log::Error where U: core::convert::Into diff --git a/xtask/public-api/aya-obj.txt b/xtask/public-api/aya-obj.txt index 398df4d8..574862f4 100644 --- a/xtask/public-api/aya-obj.txt +++ b/xtask/public-api/aya-obj.txt @@ -51,8 +51,6 @@ impl core::marker::Sync for aya_obj::btf::BtfError impl core::marker::Unpin for aya_obj::btf::BtfError impl !core::panic::unwind_safe::RefUnwindSafe for aya_obj::btf::BtfError impl !core::panic::unwind_safe::UnwindSafe for aya_obj::btf::BtfError -impl core::any::Provider for aya_obj::btf::BtfError where E: core::error::Error + core::marker::Sized -pub fn aya_obj::btf::BtfError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_obj::btf::BtfError where U: core::convert::From pub fn aya_obj::btf::BtfError::into(self) -> U impl core::convert::TryFrom for aya_obj::btf::BtfError where U: core::convert::Into @@ -384,6 +382,8 @@ pub fn aya_obj::btf::Btf::from(t: T) -> T #[repr(C)] pub struct aya_obj::btf::BtfEnum pub aya_obj::btf::BtfEnum::name_offset: u32 pub aya_obj::btf::BtfEnum::value: u32 +impl aya_obj::btf::BtfEnum +pub fn aya_obj::btf::BtfEnum::new(name_offset: u32, value: u32) -> Self impl core::clone::Clone for aya_obj::btf::BtfEnum pub fn aya_obj::btf::BtfEnum::clone(&self) -> aya_obj::btf::BtfEnum impl core::fmt::Debug for aya_obj::btf::BtfEnum @@ -414,6 +414,8 @@ pub fn aya_obj::btf::BtfEnum::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_obj::btf::BtfEnum pub fn aya_obj::btf::BtfEnum::from(t: T) -> T #[repr(C)] pub struct aya_obj::btf::BtfEnum64 +impl aya_obj::btf::BtfEnum64 +pub fn aya_obj::btf::BtfEnum64::new(name_offset: u32, value: u64) -> Self impl core::clone::Clone for aya_obj::btf::BtfEnum64 pub fn aya_obj::btf::BtfEnum64::clone(&self) -> aya_obj::btf::BtfEnum64 impl core::fmt::Debug for aya_obj::btf::BtfEnum64 @@ -477,6 +479,7 @@ pub struct aya_obj::btf::BtfFeatures impl aya_obj::btf::BtfFeatures pub fn aya_obj::btf::BtfFeatures::btf_datasec(&self) -> bool pub fn aya_obj::btf::BtfFeatures::btf_decl_tag(&self) -> bool +pub fn aya_obj::btf::BtfFeatures::btf_enum64(&self) -> bool pub fn aya_obj::btf::BtfFeatures::btf_float(&self) -> bool pub fn aya_obj::btf::BtfFeatures::btf_func(&self) -> bool pub fn aya_obj::btf::BtfFeatures::btf_func_global(&self) -> bool @@ -552,8 +555,6 @@ impl core::marker::Sync for aya_obj::btf::BtfRelocationError impl core::marker::Unpin for aya_obj::btf::BtfRelocationError impl !core::panic::unwind_safe::RefUnwindSafe for aya_obj::btf::BtfRelocationError impl !core::panic::unwind_safe::UnwindSafe for aya_obj::btf::BtfRelocationError -impl core::any::Provider for aya_obj::btf::BtfRelocationError where E: core::error::Error + core::marker::Sized -pub fn aya_obj::btf::BtfRelocationError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_obj::btf::BtfRelocationError where U: core::convert::From pub fn aya_obj::btf::BtfRelocationError::into(self) -> U impl core::convert::TryFrom for aya_obj::btf::BtfRelocationError where U: core::convert::Into @@ -701,7 +702,7 @@ impl core::convert::From for aya_obj::btf::DeclTag pub fn aya_obj::btf::DeclTag::from(t: T) -> T #[repr(C)] pub struct aya_obj::btf::Enum impl aya_obj::btf::Enum -pub fn aya_obj::btf::Enum::new(name_offset: u32, variants: alloc::vec::Vec) -> Self +pub fn aya_obj::btf::Enum::new(name_offset: u32, signed: bool, variants: alloc::vec::Vec) -> Self impl core::clone::Clone for aya_obj::btf::Enum pub fn aya_obj::btf::Enum::clone(&self) -> aya_obj::btf::Enum impl core::fmt::Debug for aya_obj::btf::Enum @@ -732,6 +733,8 @@ pub fn aya_obj::btf::Enum::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_obj::btf::Enum pub fn aya_obj::btf::Enum::from(t: T) -> T #[repr(C)] pub struct aya_obj::btf::Enum64 +impl aya_obj::btf::Enum64 +pub fn aya_obj::btf::Enum64::new(name_offset: u32, signed: bool, variants: alloc::vec::Vec) -> Self impl core::clone::Clone for aya_obj::btf::Enum64 pub fn aya_obj::btf::Enum64::clone(&self) -> aya_obj::btf::Enum64 impl core::fmt::Debug for aya_obj::btf::Enum64 @@ -5452,8 +5455,6 @@ impl core::marker::Sync for aya_obj::maps::PinningError impl core::marker::Unpin for aya_obj::maps::PinningError impl core::panic::unwind_safe::RefUnwindSafe for aya_obj::maps::PinningError impl core::panic::unwind_safe::UnwindSafe for aya_obj::maps::PinningError -impl core::any::Provider for aya_obj::maps::PinningError where E: core::error::Error + core::marker::Sized -pub fn aya_obj::maps::PinningError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_obj::maps::PinningError where U: core::convert::From pub fn aya_obj::maps::PinningError::into(self) -> U impl core::convert::TryFrom for aya_obj::maps::PinningError where U: core::convert::Into @@ -5791,8 +5792,6 @@ impl core::marker::Sync for aya_obj::ParseError impl core::marker::Unpin for aya_obj::ParseError impl !core::panic::unwind_safe::RefUnwindSafe for aya_obj::ParseError impl !core::panic::unwind_safe::UnwindSafe for aya_obj::ParseError -impl core::any::Provider for aya_obj::ParseError where E: core::error::Error + core::marker::Sized -pub fn aya_obj::ParseError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_obj::ParseError where U: core::convert::From pub fn aya_obj::ParseError::into(self) -> U impl core::convert::TryFrom for aya_obj::ParseError where U: core::convert::Into @@ -5973,7 +5972,7 @@ impl aya_obj::Object pub fn aya_obj::Object::relocate_btf(&mut self, target_btf: &aya_obj::btf::Btf) -> core::result::Result<(), aya_obj::btf::BtfRelocationError> impl aya_obj::Object pub fn aya_obj::Object::relocate_calls(&mut self, text_sections: &std::collections::hash::set::HashSet) -> core::result::Result<(), aya_obj::relocation::BpfRelocationError> -pub fn aya_obj::Object::relocate_maps<'a, I: core::iter::traits::iterator::Iterator, &'a aya_obj::maps::Map)>>(&mut self, maps: I, text_sections: &std::collections::hash::set::HashSet) -> core::result::Result<(), aya_obj::relocation::BpfRelocationError> +pub fn aya_obj::Object::relocate_maps<'a, I: core::iter::traits::iterator::Iterator>(&mut self, maps: I, text_sections: &std::collections::hash::set::HashSet) -> core::result::Result<(), aya_obj::relocation::BpfRelocationError> impl core::clone::Clone for aya_obj::Object pub fn aya_obj::Object::clone(&self) -> aya_obj::Object impl core::fmt::Debug for aya_obj::Object @@ -6289,9 +6288,6 @@ pub enum aya_obj::relocation::RelocationError pub aya_obj::relocation::RelocationError::InvalidRelocationOffset pub aya_obj::relocation::RelocationError::InvalidRelocationOffset::offset: u64 pub aya_obj::relocation::RelocationError::InvalidRelocationOffset::relocation_number: usize -pub aya_obj::relocation::RelocationError::MapNotCreated -pub aya_obj::relocation::RelocationError::MapNotCreated::name: alloc::string::String -pub aya_obj::relocation::RelocationError::MapNotCreated::section_index: usize pub aya_obj::relocation::RelocationError::SectionNotFound pub aya_obj::relocation::RelocationError::SectionNotFound::section_index: usize pub aya_obj::relocation::RelocationError::SectionNotFound::symbol_index: usize @@ -6314,8 +6310,6 @@ impl core::marker::Sync for aya_obj::relocation::RelocationError impl core::marker::Unpin for aya_obj::relocation::RelocationError impl core::panic::unwind_safe::RefUnwindSafe for aya_obj::relocation::RelocationError impl core::panic::unwind_safe::UnwindSafe for aya_obj::relocation::RelocationError -impl core::any::Provider for aya_obj::relocation::RelocationError where E: core::error::Error + core::marker::Sized -pub fn aya_obj::relocation::RelocationError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_obj::relocation::RelocationError where U: core::convert::From pub fn aya_obj::relocation::RelocationError::into(self) -> U impl core::convert::TryFrom for aya_obj::relocation::RelocationError where U: core::convert::Into @@ -6346,8 +6340,6 @@ impl core::marker::Sync for aya_obj::relocation::BpfRelocationError impl core::marker::Unpin for aya_obj::relocation::BpfRelocationError impl core::panic::unwind_safe::RefUnwindSafe for aya_obj::relocation::BpfRelocationError impl core::panic::unwind_safe::UnwindSafe for aya_obj::relocation::BpfRelocationError -impl core::any::Provider for aya_obj::relocation::BpfRelocationError where E: core::error::Error + core::marker::Sized -pub fn aya_obj::relocation::BpfRelocationError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_obj::relocation::BpfRelocationError where U: core::convert::From pub fn aya_obj::relocation::BpfRelocationError::into(self) -> U impl core::convert::TryFrom for aya_obj::relocation::BpfRelocationError where U: core::convert::Into @@ -6512,8 +6504,6 @@ impl core::marker::Sync for aya_obj::ParseError impl core::marker::Unpin for aya_obj::ParseError impl !core::panic::unwind_safe::RefUnwindSafe for aya_obj::ParseError impl !core::panic::unwind_safe::UnwindSafe for aya_obj::ParseError -impl core::any::Provider for aya_obj::ParseError where E: core::error::Error + core::marker::Sized -pub fn aya_obj::ParseError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_obj::ParseError where U: core::convert::From pub fn aya_obj::ParseError::into(self) -> U impl core::convert::TryFrom for aya_obj::ParseError where U: core::convert::Into @@ -6694,7 +6684,7 @@ impl aya_obj::Object pub fn aya_obj::Object::relocate_btf(&mut self, target_btf: &aya_obj::btf::Btf) -> core::result::Result<(), aya_obj::btf::BtfRelocationError> impl aya_obj::Object pub fn aya_obj::Object::relocate_calls(&mut self, text_sections: &std::collections::hash::set::HashSet) -> core::result::Result<(), aya_obj::relocation::BpfRelocationError> -pub fn aya_obj::Object::relocate_maps<'a, I: core::iter::traits::iterator::Iterator, &'a aya_obj::maps::Map)>>(&mut self, maps: I, text_sections: &std::collections::hash::set::HashSet) -> core::result::Result<(), aya_obj::relocation::BpfRelocationError> +pub fn aya_obj::Object::relocate_maps<'a, I: core::iter::traits::iterator::Iterator>(&mut self, maps: I, text_sections: &std::collections::hash::set::HashSet) -> core::result::Result<(), aya_obj::relocation::BpfRelocationError> impl core::clone::Clone for aya_obj::Object pub fn aya_obj::Object::clone(&self) -> aya_obj::Object impl core::fmt::Debug for aya_obj::Object diff --git a/xtask/public-api/aya-tool.txt b/xtask/public-api/aya-tool.txt index 59e6dc4d..5d857bd1 100644 --- a/xtask/public-api/aya-tool.txt +++ b/xtask/public-api/aya-tool.txt @@ -25,8 +25,6 @@ impl core::marker::Sync for aya_tool::generate::Error impl core::marker::Unpin for aya_tool::generate::Error impl !core::panic::unwind_safe::RefUnwindSafe for aya_tool::generate::Error impl !core::panic::unwind_safe::UnwindSafe for aya_tool::generate::Error -impl core::any::Provider for aya_tool::generate::Error where E: core::error::Error + core::marker::Sized -pub fn aya_tool::generate::Error::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_tool::generate::Error where U: core::convert::From pub fn aya_tool::generate::Error::into(self) -> U impl core::convert::TryFrom for aya_tool::generate::Error where U: core::convert::Into diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index 7adc9b63..ebf7699f 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -91,7 +91,7 @@ impl> aya::maps::ProgramArray pub fn aya::maps::ProgramArray::indices(&self) -> aya::maps::MapKeys<'_, u32> impl> aya::maps::ProgramArray pub fn aya::maps::ProgramArray::clear_index(&mut self, index: &u32) -> core::result::Result<(), aya::maps::MapError> -pub fn aya::maps::ProgramArray::set(&mut self, index: u32, program: aya::programs::ProgramFd, flags: u64) -> core::result::Result<(), aya::maps::MapError> +pub fn aya::maps::ProgramArray::set(&mut self, index: u32, program: &aya::programs::ProgramFd, flags: u64) -> core::result::Result<(), aya::maps::MapError> impl core::convert::TryFrom for aya::maps::ProgramArray pub type aya::maps::ProgramArray::Error = aya::maps::MapError pub fn aya::maps::ProgramArray::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> @@ -126,7 +126,8 @@ pub mod aya::maps::bloom_filter pub struct aya::maps::bloom_filter::BloomFilter impl, V: aya::Pod> aya::maps::bloom_filter::BloomFilter pub fn aya::maps::bloom_filter::BloomFilter::contains(&self, value: &V, flags: u64) -> core::result::Result<(), aya::maps::MapError> -pub fn aya::maps::bloom_filter::BloomFilter::insert(&self, value: impl core::borrow::Borrow, flags: u64) -> core::result::Result<(), aya::maps::MapError> +impl, V: aya::Pod> aya::maps::bloom_filter::BloomFilter +pub fn aya::maps::bloom_filter::BloomFilter::insert(&mut self, value: impl core::borrow::Borrow, flags: u64) -> core::result::Result<(), aya::maps::MapError> impl<'a, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V> pub type aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V>::Error = aya::maps::MapError pub fn aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> @@ -352,8 +353,6 @@ impl core::marker::Sync for aya::maps::perf::PerfBufferError impl core::marker::Unpin for aya::maps::perf::PerfBufferError impl !core::panic::unwind_safe::RefUnwindSafe for aya::maps::perf::PerfBufferError impl !core::panic::unwind_safe::UnwindSafe for aya::maps::perf::PerfBufferError -impl core::any::Provider for aya::maps::perf::PerfBufferError where E: core::error::Error + core::marker::Sized -pub fn aya::maps::perf::PerfBufferError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::maps::perf::PerfBufferError where U: core::convert::From pub fn aya::maps::perf::PerfBufferError::into(self) -> U impl core::convert::TryFrom for aya::maps::perf::PerfBufferError where U: core::convert::Into @@ -708,7 +707,6 @@ pub fn aya::maps::stack::Stack::from(t: T) -> T pub mod aya::maps::stack_trace pub struct aya::maps::stack_trace::StackFrame pub aya::maps::stack_trace::StackFrame::ip: u64 -pub aya::maps::stack_trace::StackFrame::symbol_name: core::option::Option impl core::marker::Send for aya::maps::stack_trace::StackFrame impl core::marker::Sync for aya::maps::stack_trace::StackFrame impl core::marker::Unpin for aya::maps::stack_trace::StackFrame @@ -734,7 +732,6 @@ pub struct aya::maps::stack_trace::StackTrace pub aya::maps::stack_trace::StackTrace::id: u32 impl aya::maps::stack_trace::StackTrace pub fn aya::maps::stack_trace::StackTrace::frames(&self) -> &[aya::maps::stack_trace::StackFrame] -pub fn aya::maps::stack_trace::StackTrace::resolve(&mut self, symbols: &R) -> &aya::maps::stack_trace::StackTrace impl> aya::maps::IterableMap for aya::maps::stack_trace::StackTraceMap pub fn aya::maps::stack_trace::StackTraceMap::get(&self, index: &u32) -> core::result::Result pub fn aya::maps::stack_trace::StackTraceMap::map(&self) -> &aya::maps::MapData @@ -803,10 +800,6 @@ impl core::borrow::BorrowMut for aya::maps::stack_trace::StackTraceMap pub fn aya::maps::stack_trace::StackTraceMap::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::stack_trace::StackTraceMap pub fn aya::maps::stack_trace::StackTraceMap::from(t: T) -> T -pub trait aya::maps::stack_trace::SymbolResolver -pub fn aya::maps::stack_trace::SymbolResolver::resolve_symbol(&self, addr: u64) -> core::option::Option> -impl aya::maps::stack_trace::SymbolResolver for aya::util::SimpleSymbolResolver -pub fn aya::util::SimpleSymbolResolver::resolve_symbol(&self, addr: u64) -> core::option::Option> pub enum aya::maps::Map pub aya::maps::Map::Array(aya::maps::MapData) pub aya::maps::Map::BloomFilter(aya::maps::MapData) @@ -974,8 +967,6 @@ pub fn aya::maps::Map::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::Map pub fn aya::maps::Map::from(t: T) -> T pub enum aya::maps::MapError -pub aya::maps::MapError::AlreadyCreated -pub aya::maps::MapError::AlreadyCreated::name: alloc::string::String pub aya::maps::MapError::CreateError pub aya::maps::MapError::CreateError::code: libc::unix::linux_like::linux::gnu::b64::x86_64::not_x32::c_long pub aya::maps::MapError::CreateError::io_error: std::io::error::Error @@ -992,7 +983,6 @@ pub aya::maps::MapError::InvalidValueSize pub aya::maps::MapError::InvalidValueSize::expected: usize pub aya::maps::MapError::InvalidValueSize::size: usize pub aya::maps::MapError::KeyNotFound -pub aya::maps::MapError::NotCreated pub aya::maps::MapError::OutOfBounds pub aya::maps::MapError::OutOfBounds::index: u32 pub aya::maps::MapError::OutOfBounds::max_entries: u32 @@ -1018,8 +1008,6 @@ impl core::marker::Sync for aya::maps::MapError impl core::marker::Unpin for aya::maps::MapError impl !core::panic::unwind_safe::RefUnwindSafe for aya::maps::MapError impl !core::panic::unwind_safe::UnwindSafe for aya::maps::MapError -impl core::any::Provider for aya::maps::MapError where E: core::error::Error + core::marker::Sized -pub fn aya::maps::MapError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::maps::MapError where U: core::convert::From pub fn aya::maps::MapError::into(self) -> U impl core::convert::TryFrom for aya::maps::MapError where U: core::convert::Into @@ -1114,7 +1102,8 @@ pub fn aya::maps::perf::AsyncPerfEventArray::from(t: T) -> T pub struct aya::maps::BloomFilter impl, V: aya::Pod> aya::maps::bloom_filter::BloomFilter pub fn aya::maps::bloom_filter::BloomFilter::contains(&self, value: &V, flags: u64) -> core::result::Result<(), aya::maps::MapError> -pub fn aya::maps::bloom_filter::BloomFilter::insert(&self, value: impl core::borrow::Borrow, flags: u64) -> core::result::Result<(), aya::maps::MapError> +impl, V: aya::Pod> aya::maps::bloom_filter::BloomFilter +pub fn aya::maps::bloom_filter::BloomFilter::insert(&mut self, value: impl core::borrow::Borrow, flags: u64) -> core::result::Result<(), aya::maps::MapError> impl<'a, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V> pub type aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V>::Error = aya::maps::MapError pub fn aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> @@ -1236,12 +1225,12 @@ pub fn aya::maps::lpm_trie::LpmTrie::from(t: T) -> T pub struct aya::maps::MapData pub aya::maps::MapData::pinned: bool impl aya::maps::MapData -pub fn aya::maps::MapData::create(&mut self, name: &str) -> core::result::Result -pub fn aya::maps::MapData::fd(&self) -> core::option::Option +pub fn aya::maps::MapData::create(obj: aya_obj::maps::Map, name: &str, btf_fd: core::option::Option>) -> core::result::Result +pub fn aya::maps::MapData::fd(&self) -> aya::maps::MapFd pub fn aya::maps::MapData::from_fd(fd: std::os::fd::owned::OwnedFd) -> core::result::Result pub fn aya::maps::MapData::from_pin>(path: P) -> core::result::Result impl core::clone::Clone for aya::maps::MapData -pub fn aya::maps::MapData::clone(&self) -> aya::maps::MapData +pub fn aya::maps::MapData::clone(&self) -> Self impl core::ops::drop::Drop for aya::maps::MapData pub fn aya::maps::MapData::drop(&mut self) impl core::fmt::Debug for aya::maps::MapData @@ -1508,7 +1497,7 @@ impl> aya::maps::ProgramArray pub fn aya::maps::ProgramArray::indices(&self) -> aya::maps::MapKeys<'_, u32> impl> aya::maps::ProgramArray pub fn aya::maps::ProgramArray::clear_index(&mut self, index: &u32) -> core::result::Result<(), aya::maps::MapError> -pub fn aya::maps::ProgramArray::set(&mut self, index: u32, program: aya::programs::ProgramFd, flags: u64) -> core::result::Result<(), aya::maps::MapError> +pub fn aya::maps::ProgramArray::set(&mut self, index: u32, program: &aya::programs::ProgramFd, flags: u64) -> core::result::Result<(), aya::maps::MapError> impl core::convert::TryFrom for aya::maps::ProgramArray pub type aya::maps::ProgramArray::Error = aya::maps::MapError pub fn aya::maps::ProgramArray::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> @@ -1778,8 +1767,6 @@ impl core::marker::Sync for aya::pin::PinError impl core::marker::Unpin for aya::pin::PinError impl !core::panic::unwind_safe::RefUnwindSafe for aya::pin::PinError impl !core::panic::unwind_safe::UnwindSafe for aya::pin::PinError -impl core::any::Provider for aya::pin::PinError where E: core::error::Error + core::marker::Sized -pub fn aya::pin::PinError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::pin::PinError where U: core::convert::From pub fn aya::pin::PinError::into(self) -> U impl core::convert::TryFrom for aya::pin::PinError where U: core::convert::Into @@ -1810,13 +1797,15 @@ pub fn aya::programs::cgroup_device::CgroupDevice::detach(&mut self, link_id: ay pub fn aya::programs::cgroup_device::CgroupDevice::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_device::CgroupDevice::take_link(&mut self, link_id: aya::programs::cgroup_device::CgroupDeviceLinkId) -> core::result::Result impl aya::programs::cgroup_device::CgroupDevice -pub fn aya::programs::cgroup_device::CgroupDevice::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_device::CgroupDevice::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::from_pin>(path: P) -> core::result::Result impl aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_device::CgroupDevice::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_device::CgroupDevice +pub fn aya::programs::cgroup_device::CgroupDevice::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::drop(&mut self) @@ -1953,11 +1942,13 @@ pub fn aya::programs::cgroup_skb::CgroupSkb::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_skb::CgroupSkb::take_link(&mut self, link_id: aya::programs::cgroup_skb::CgroupSkbLinkId) -> core::result::Result impl aya::programs::cgroup_skb::CgroupSkb -pub fn aya::programs::cgroup_skb::CgroupSkb::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_skb::CgroupSkb::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_skb::CgroupSkb::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_skb::CgroupSkb +pub fn aya::programs::cgroup_skb::CgroupSkb::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::drop(&mut self) @@ -2061,11 +2052,13 @@ pub fn aya::programs::cgroup_sock::CgroupSock::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sock::CgroupSock::take_link(&mut self, link_id: aya::programs::cgroup_sock::CgroupSockLinkId) -> core::result::Result impl aya::programs::cgroup_sock::CgroupSock -pub fn aya::programs::cgroup_sock::CgroupSock::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sock::CgroupSock::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sock::CgroupSock::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sock::CgroupSock +pub fn aya::programs::cgroup_sock::CgroupSock::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::drop(&mut self) @@ -2169,11 +2162,13 @@ pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::take_link(&mut self, link_id: aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId) -> core::result::Result impl aya::programs::cgroup_sock_addr::CgroupSockAddr -pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sock_addr::CgroupSockAddr pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sock_addr::CgroupSockAddr +pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sock_addr::CgroupSockAddr pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sock_addr::CgroupSockAddr pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::drop(&mut self) @@ -2277,11 +2272,13 @@ pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sockopt::CgroupSockopt::take_link(&mut self, link_id: aya::programs::cgroup_sockopt::CgroupSockoptLinkId) -> core::result::Result impl aya::programs::cgroup_sockopt::CgroupSockopt -pub fn aya::programs::cgroup_sockopt::CgroupSockopt::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sockopt::CgroupSockopt::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sockopt::CgroupSockopt::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sockopt::CgroupSockopt +pub fn aya::programs::cgroup_sockopt::CgroupSockopt::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::drop(&mut self) @@ -2383,13 +2380,15 @@ pub fn aya::programs::cgroup_sysctl::CgroupSysctl::detach(&mut self, link_id: ay pub fn aya::programs::cgroup_sysctl::CgroupSysctl::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sysctl::CgroupSysctl::take_link(&mut self, link_id: aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> core::result::Result impl aya::programs::cgroup_sysctl::CgroupSysctl -pub fn aya::programs::cgroup_sysctl::CgroupSysctl::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sysctl::CgroupSysctl::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::from_pin>(path: P) -> core::result::Result impl aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sysctl::CgroupSysctl::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sysctl::CgroupSysctl +pub fn aya::programs::cgroup_sysctl::CgroupSysctl::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::drop(&mut self) @@ -2498,8 +2497,6 @@ impl core::marker::Sync for aya::programs::extension::ExtensionError impl core::marker::Unpin for aya::programs::extension::ExtensionError impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::extension::ExtensionError impl core::panic::unwind_safe::UnwindSafe for aya::programs::extension::ExtensionError -impl core::any::Provider for aya::programs::extension::ExtensionError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::extension::ExtensionError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::extension::ExtensionError where U: core::convert::From pub fn aya::programs::extension::ExtensionError::into(self) -> U impl core::convert::TryFrom for aya::programs::extension::ExtensionError where U: core::convert::Into @@ -2521,18 +2518,20 @@ pub fn aya::programs::extension::ExtensionError::from(t: T) -> T pub struct aya::programs::extension::Extension impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::attach(&mut self) -> core::result::Result -pub fn aya::programs::extension::Extension::attach_to_program(&mut self, program: aya::programs::ProgramFd, func_name: &str) -> core::result::Result +pub fn aya::programs::extension::Extension::attach_to_program(&mut self, program: &aya::programs::ProgramFd, func_name: &str) -> core::result::Result pub fn aya::programs::extension::Extension::detach(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::extension::Extension::load(&mut self, program: aya::programs::ProgramFd, func_name: &str) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::extension::Extension::take_link(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result impl aya::programs::extension::Extension -pub fn aya::programs::extension::Extension::fd(&self) -> core::option::Option +pub fn aya::programs::extension::Extension::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::from_pin>(path: P) -> core::result::Result impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::extension::Extension::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::extension::Extension +pub fn aya::programs::extension::Extension::program_info(&self) -> core::result::Result +impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::extension::Extension pub fn aya::programs::extension::Extension::drop(&mut self) @@ -2638,13 +2637,15 @@ pub fn aya::programs::fentry::FEntry::detach(&mut self, link_id: aya::programs:: pub fn aya::programs::fentry::FEntry::load(&mut self, fn_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::fentry::FEntry::take_link(&mut self, link_id: aya::programs::fentry::FEntryLinkId) -> core::result::Result impl aya::programs::fentry::FEntry -pub fn aya::programs::fentry::FEntry::fd(&self) -> core::option::Option +pub fn aya::programs::fentry::FEntry::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::from_pin>(path: P) -> core::result::Result impl aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::fentry::FEntry::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::fentry::FEntry +pub fn aya::programs::fentry::FEntry::program_info(&self) -> core::result::Result +impl aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::drop(&mut self) @@ -2750,13 +2751,15 @@ pub fn aya::programs::fexit::FExit::detach(&mut self, link_id: aya::programs::fe pub fn aya::programs::fexit::FExit::load(&mut self, fn_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::fexit::FExit::take_link(&mut self, link_id: aya::programs::fexit::FExitLinkId) -> core::result::Result impl aya::programs::fexit::FExit -pub fn aya::programs::fexit::FExit::fd(&self) -> core::option::Option +pub fn aya::programs::fexit::FExit::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::from_pin>(path: P) -> core::result::Result impl aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::fexit::FExit::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::fexit::FExit +pub fn aya::programs::fexit::FExit::program_info(&self) -> core::result::Result +impl aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::drop(&mut self) @@ -2872,8 +2875,6 @@ impl core::marker::Sync for aya::programs::kprobe::KProbeError impl core::marker::Unpin for aya::programs::kprobe::KProbeError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::kprobe::KProbeError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::kprobe::KProbeError -impl core::any::Provider for aya::programs::kprobe::KProbeError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::kprobe::KProbeError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::kprobe::KProbeError where U: core::convert::From pub fn aya::programs::kprobe::KProbeError::into(self) -> U impl core::convert::TryFrom for aya::programs::kprobe::KProbeError where U: core::convert::Into @@ -2901,11 +2902,13 @@ pub fn aya::programs::kprobe::KProbe::kind(&self) -> aya::programs::ProbeKind pub fn aya::programs::kprobe::KProbe::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::kprobe::KProbe::take_link(&mut self, link_id: aya::programs::kprobe::KProbeLinkId) -> core::result::Result impl aya::programs::kprobe::KProbe -pub fn aya::programs::kprobe::KProbe::fd(&self) -> core::option::Option +pub fn aya::programs::kprobe::KProbe::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::kprobe::KProbe::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::kprobe::KProbe +pub fn aya::programs::kprobe::KProbe::program_info(&self) -> core::result::Result +impl aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::drop(&mut self) @@ -3020,8 +3023,6 @@ impl core::marker::Sync for aya::programs::links::LinkError impl core::marker::Unpin for aya::programs::links::LinkError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::links::LinkError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::links::LinkError -impl core::any::Provider for aya::programs::links::LinkError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::links::LinkError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::links::LinkError where U: core::convert::From pub fn aya::programs::links::LinkError::into(self) -> U impl core::convert::TryFrom for aya::programs::links::LinkError where U: core::convert::Into @@ -3399,13 +3400,15 @@ pub fn aya::programs::lirc_mode2::LircMode2::load(&mut self) -> core::result::Re pub fn aya::programs::lirc_mode2::LircMode2::query(target_fd: T) -> core::result::Result, aya::programs::ProgramError> pub fn aya::programs::lirc_mode2::LircMode2::take_link(&mut self, link_id: aya::programs::lirc_mode2::LircLinkId) -> core::result::Result impl aya::programs::lirc_mode2::LircMode2 -pub fn aya::programs::lirc_mode2::LircMode2::fd(&self) -> core::option::Option +pub fn aya::programs::lirc_mode2::LircMode2::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::from_pin>(path: P) -> core::result::Result impl aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::lirc_mode2::LircMode2::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::lirc_mode2::LircMode2 +pub fn aya::programs::lirc_mode2::LircMode2::program_info(&self) -> core::result::Result +impl aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::drop(&mut self) @@ -3446,13 +3449,15 @@ pub fn aya::programs::lsm::Lsm::detach(&mut self, link_id: aya::programs::lsm::L pub fn aya::programs::lsm::Lsm::load(&mut self, lsm_hook_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::lsm::Lsm::take_link(&mut self, link_id: aya::programs::lsm::LsmLinkId) -> core::result::Result impl aya::programs::lsm::Lsm -pub fn aya::programs::lsm::Lsm::fd(&self) -> core::option::Option +pub fn aya::programs::lsm::Lsm::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::from_pin>(path: P) -> core::result::Result impl aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::lsm::Lsm::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::lsm::Lsm +pub fn aya::programs::lsm::Lsm::program_info(&self) -> core::result::Result +impl aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::drop(&mut self) @@ -3731,13 +3736,15 @@ pub fn aya::programs::perf_event::PerfEvent::detach(&mut self, link_id: aya::pro pub fn aya::programs::perf_event::PerfEvent::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::perf_event::PerfEvent::take_link(&mut self, link_id: aya::programs::perf_event::PerfEventLinkId) -> core::result::Result impl aya::programs::perf_event::PerfEvent -pub fn aya::programs::perf_event::PerfEvent::fd(&self) -> core::option::Option +pub fn aya::programs::perf_event::PerfEvent::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::from_pin>(path: P) -> core::result::Result impl aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::perf_event::PerfEvent::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::perf_event::PerfEvent +pub fn aya::programs::perf_event::PerfEvent::program_info(&self) -> core::result::Result +impl aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::drop(&mut self) @@ -3896,8 +3903,6 @@ impl core::marker::Sync for aya::programs::tc::TcError impl core::marker::Unpin for aya::programs::tc::TcError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::TcError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::tc::TcError -impl core::any::Provider for aya::programs::tc::TcError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::tc::TcError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::tc::TcError where U: core::convert::From pub fn aya::programs::tc::TcError::into(self) -> U impl core::convert::TryFrom for aya::programs::tc::TcError where U: core::convert::Into @@ -3925,11 +3930,13 @@ pub fn aya::programs::tc::SchedClassifier::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::tc::SchedClassifier::take_link(&mut self, link_id: aya::programs::tc::SchedClassifierLinkId) -> core::result::Result impl aya::programs::tc::SchedClassifier -pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::option::Option +pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::tc::SchedClassifier::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::tc::SchedClassifier +pub fn aya::programs::tc::SchedClassifier::program_info(&self) -> core::result::Result +impl aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::drop(&mut self) @@ -4063,13 +4070,15 @@ pub fn aya::programs::tp_btf::BtfTracePoint::detach(&mut self, link_id: aya::pro pub fn aya::programs::tp_btf::BtfTracePoint::load(&mut self, tracepoint: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::tp_btf::BtfTracePoint::take_link(&mut self, link_id: aya::programs::tp_btf::BtfTracePointLinkId) -> core::result::Result impl aya::programs::tp_btf::BtfTracePoint -pub fn aya::programs::tp_btf::BtfTracePoint::fd(&self) -> core::option::Option +pub fn aya::programs::tp_btf::BtfTracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::from_pin>(path: P) -> core::result::Result impl aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::tp_btf::BtfTracePoint::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::tp_btf::BtfTracePoint +pub fn aya::programs::tp_btf::BtfTracePoint::program_info(&self) -> core::result::Result +impl aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::drop(&mut self) @@ -4185,8 +4194,6 @@ impl core::marker::Sync for aya::programs::trace_point::TracePointError impl core::marker::Unpin for aya::programs::trace_point::TracePointError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::trace_point::TracePointError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::trace_point::TracePointError -impl core::any::Provider for aya::programs::trace_point::TracePointError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::trace_point::TracePointError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::trace_point::TracePointError where U: core::convert::From pub fn aya::programs::trace_point::TracePointError::into(self) -> U impl core::convert::TryFrom for aya::programs::trace_point::TracePointError where U: core::convert::Into @@ -4212,13 +4219,15 @@ pub fn aya::programs::trace_point::TracePoint::detach(&mut self, link_id: aya::p pub fn aya::programs::trace_point::TracePoint::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::trace_point::TracePoint::take_link(&mut self, link_id: aya::programs::trace_point::TracePointLinkId) -> core::result::Result impl aya::programs::trace_point::TracePoint -pub fn aya::programs::trace_point::TracePoint::fd(&self) -> core::option::Option +pub fn aya::programs::trace_point::TracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::from_pin>(path: P) -> core::result::Result impl aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::trace_point::TracePoint::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::trace_point::TracePoint +pub fn aya::programs::trace_point::TracePoint::program_info(&self) -> core::result::Result +impl aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::drop(&mut self) @@ -4343,8 +4352,6 @@ impl core::marker::Sync for aya::programs::uprobe::UProbeError impl core::marker::Unpin for aya::programs::uprobe::UProbeError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::uprobe::UProbeError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::uprobe::UProbeError -impl core::any::Provider for aya::programs::uprobe::UProbeError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::uprobe::UProbeError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::uprobe::UProbeError where U: core::convert::From pub fn aya::programs::uprobe::UProbeError::into(self) -> U impl core::convert::TryFrom for aya::programs::uprobe::UProbeError where U: core::convert::Into @@ -4372,11 +4379,13 @@ pub fn aya::programs::uprobe::UProbe::kind(&self) -> aya::programs::ProbeKind pub fn aya::programs::uprobe::UProbe::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::uprobe::UProbe::take_link(&mut self, link_id: aya::programs::uprobe::UProbeLinkId) -> core::result::Result impl aya::programs::uprobe::UProbe -pub fn aya::programs::uprobe::UProbe::fd(&self) -> core::option::Option +pub fn aya::programs::uprobe::UProbe::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::uprobe::UProbe pub fn aya::programs::uprobe::UProbe::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::uprobe::UProbe::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::uprobe::UProbe +pub fn aya::programs::uprobe::UProbe::program_info(&self) -> core::result::Result +impl aya::programs::uprobe::UProbe pub fn aya::programs::uprobe::UProbe::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::uprobe::UProbe pub fn aya::programs::uprobe::UProbe::drop(&mut self) @@ -4493,8 +4502,6 @@ impl core::marker::Sync for aya::programs::xdp::XdpError impl core::marker::Unpin for aya::programs::xdp::XdpError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::xdp::XdpError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::xdp::XdpError -impl core::any::Provider for aya::programs::xdp::XdpError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::xdp::XdpError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::xdp::XdpError where U: core::convert::From pub fn aya::programs::xdp::XdpError::into(self) -> U impl core::convert::TryFrom for aya::programs::xdp::XdpError where U: core::convert::Into @@ -4522,13 +4529,15 @@ pub fn aya::programs::xdp::Xdp::detach(&mut self, link_id: aya::programs::xdp::X pub fn aya::programs::xdp::Xdp::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::xdp::Xdp::take_link(&mut self, link_id: aya::programs::xdp::XdpLinkId) -> core::result::Result impl aya::programs::xdp::Xdp -pub fn aya::programs::xdp::Xdp::fd(&self) -> core::option::Option +pub fn aya::programs::xdp::Xdp::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::from_pin>(path: P) -> core::result::Result impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::xdp::Xdp::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::xdp::Xdp +pub fn aya::programs::xdp::Xdp::program_info(&self) -> core::result::Result +impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::drop(&mut self) @@ -4651,9 +4660,6 @@ impl core::marker::Sync for aya::programs::xdp::XdpFlags impl core::marker::Unpin for aya::programs::xdp::XdpFlags impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::xdp::XdpFlags impl core::panic::unwind_safe::UnwindSafe for aya::programs::xdp::XdpFlags -impl bitflags::traits::BitFlags for aya::programs::xdp::XdpFlags where B: bitflags::traits::Flags -pub type aya::programs::xdp::XdpFlags::Iter = bitflags::iter::Iter -pub type aya::programs::xdp::XdpFlags::IterNames = bitflags::iter::IterNames impl core::convert::Into for aya::programs::xdp::XdpFlags where U: core::convert::From pub fn aya::programs::xdp::XdpFlags::into(self) -> U impl core::convert::TryFrom for aya::programs::xdp::XdpFlags where U: core::convert::Into @@ -4788,8 +4794,6 @@ impl core::marker::Sync for aya::programs::extension::ExtensionError impl core::marker::Unpin for aya::programs::extension::ExtensionError impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::extension::ExtensionError impl core::panic::unwind_safe::UnwindSafe for aya::programs::extension::ExtensionError -impl core::any::Provider for aya::programs::extension::ExtensionError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::extension::ExtensionError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::extension::ExtensionError where U: core::convert::From pub fn aya::programs::extension::ExtensionError::into(self) -> U impl core::convert::TryFrom for aya::programs::extension::ExtensionError where U: core::convert::Into @@ -4825,8 +4829,6 @@ impl core::marker::Sync for aya::programs::kprobe::KProbeError impl core::marker::Unpin for aya::programs::kprobe::KProbeError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::kprobe::KProbeError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::kprobe::KProbeError -impl core::any::Provider for aya::programs::kprobe::KProbeError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::kprobe::KProbeError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::kprobe::KProbeError where U: core::convert::From pub fn aya::programs::kprobe::KProbeError::into(self) -> U impl core::convert::TryFrom for aya::programs::kprobe::KProbeError where U: core::convert::Into @@ -4982,7 +4984,7 @@ pub aya::programs::Program::TracePoint(aya::programs::trace_point::TracePoint) pub aya::programs::Program::UProbe(aya::programs::uprobe::UProbe) pub aya::programs::Program::Xdp(aya::programs::xdp::Xdp) impl aya::programs::Program -pub fn aya::programs::Program::fd(&self) -> core::option::Option +pub fn aya::programs::Program::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> pub fn aya::programs::Program::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::Program::prog_type(&self) -> aya_obj::generated::linux_bindings_x86_64::bpf_prog_type pub fn aya::programs::Program::unload(self) -> core::result::Result<(), aya::programs::ProgramError> @@ -5210,8 +5212,6 @@ impl core::marker::Sync for aya::programs::ProgramError impl core::marker::Unpin for aya::programs::ProgramError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::ProgramError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::ProgramError -impl core::any::Provider for aya::programs::ProgramError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::ProgramError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::ProgramError where U: core::convert::From pub fn aya::programs::ProgramError::into(self) -> U impl core::convert::TryFrom for aya::programs::ProgramError where U: core::convert::Into @@ -5311,8 +5311,6 @@ impl core::marker::Sync for aya::programs::SocketFilterError impl core::marker::Unpin for aya::programs::SocketFilterError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::SocketFilterError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::SocketFilterError -impl core::any::Provider for aya::programs::SocketFilterError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::SocketFilterError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::SocketFilterError where U: core::convert::From pub fn aya::programs::SocketFilterError::into(self) -> U impl core::convert::TryFrom for aya::programs::SocketFilterError where U: core::convert::Into @@ -5389,8 +5387,6 @@ impl core::marker::Sync for aya::programs::tc::TcError impl core::marker::Unpin for aya::programs::tc::TcError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::TcError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::tc::TcError -impl core::any::Provider for aya::programs::tc::TcError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::tc::TcError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::tc::TcError where U: core::convert::From pub fn aya::programs::tc::TcError::into(self) -> U impl core::convert::TryFrom for aya::programs::tc::TcError where U: core::convert::Into @@ -5426,8 +5422,6 @@ impl core::marker::Sync for aya::programs::trace_point::TracePointError impl core::marker::Unpin for aya::programs::trace_point::TracePointError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::trace_point::TracePointError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::trace_point::TracePointError -impl core::any::Provider for aya::programs::trace_point::TracePointError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::trace_point::TracePointError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::trace_point::TracePointError where U: core::convert::From pub fn aya::programs::trace_point::TracePointError::into(self) -> U impl core::convert::TryFrom for aya::programs::trace_point::TracePointError where U: core::convert::Into @@ -5470,8 +5464,6 @@ impl core::marker::Sync for aya::programs::uprobe::UProbeError impl core::marker::Unpin for aya::programs::uprobe::UProbeError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::uprobe::UProbeError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::uprobe::UProbeError -impl core::any::Provider for aya::programs::uprobe::UProbeError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::uprobe::UProbeError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::uprobe::UProbeError where U: core::convert::From pub fn aya::programs::uprobe::UProbeError::into(self) -> U impl core::convert::TryFrom for aya::programs::uprobe::UProbeError where U: core::convert::Into @@ -5506,8 +5498,6 @@ impl core::marker::Sync for aya::programs::xdp::XdpError impl core::marker::Unpin for aya::programs::xdp::XdpError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::xdp::XdpError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::xdp::XdpError -impl core::any::Provider for aya::programs::xdp::XdpError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::xdp::XdpError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::xdp::XdpError where U: core::convert::From pub fn aya::programs::xdp::XdpError::into(self) -> U impl core::convert::TryFrom for aya::programs::xdp::XdpError where U: core::convert::Into @@ -5533,13 +5523,15 @@ pub fn aya::programs::tp_btf::BtfTracePoint::detach(&mut self, link_id: aya::pro pub fn aya::programs::tp_btf::BtfTracePoint::load(&mut self, tracepoint: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::tp_btf::BtfTracePoint::take_link(&mut self, link_id: aya::programs::tp_btf::BtfTracePointLinkId) -> core::result::Result impl aya::programs::tp_btf::BtfTracePoint -pub fn aya::programs::tp_btf::BtfTracePoint::fd(&self) -> core::option::Option +pub fn aya::programs::tp_btf::BtfTracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::from_pin>(path: P) -> core::result::Result impl aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::tp_btf::BtfTracePoint::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::tp_btf::BtfTracePoint +pub fn aya::programs::tp_btf::BtfTracePoint::program_info(&self) -> core::result::Result +impl aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::drop(&mut self) @@ -5579,13 +5571,15 @@ pub fn aya::programs::cgroup_device::CgroupDevice::detach(&mut self, link_id: ay pub fn aya::programs::cgroup_device::CgroupDevice::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_device::CgroupDevice::take_link(&mut self, link_id: aya::programs::cgroup_device::CgroupDeviceLinkId) -> core::result::Result impl aya::programs::cgroup_device::CgroupDevice -pub fn aya::programs::cgroup_device::CgroupDevice::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_device::CgroupDevice::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::from_pin>(path: P) -> core::result::Result impl aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_device::CgroupDevice::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_device::CgroupDevice +pub fn aya::programs::cgroup_device::CgroupDevice::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::drop(&mut self) @@ -5627,11 +5621,13 @@ pub fn aya::programs::cgroup_skb::CgroupSkb::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_skb::CgroupSkb::take_link(&mut self, link_id: aya::programs::cgroup_skb::CgroupSkbLinkId) -> core::result::Result impl aya::programs::cgroup_skb::CgroupSkb -pub fn aya::programs::cgroup_skb::CgroupSkb::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_skb::CgroupSkb::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_skb::CgroupSkb::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_skb::CgroupSkb +pub fn aya::programs::cgroup_skb::CgroupSkb::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::drop(&mut self) @@ -5672,11 +5668,13 @@ pub fn aya::programs::cgroup_sock::CgroupSock::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sock::CgroupSock::take_link(&mut self, link_id: aya::programs::cgroup_sock::CgroupSockLinkId) -> core::result::Result impl aya::programs::cgroup_sock::CgroupSock -pub fn aya::programs::cgroup_sock::CgroupSock::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sock::CgroupSock::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sock::CgroupSock::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sock::CgroupSock +pub fn aya::programs::cgroup_sock::CgroupSock::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::drop(&mut self) @@ -5717,11 +5715,13 @@ pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::take_link(&mut self, link_id: aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId) -> core::result::Result impl aya::programs::cgroup_sock_addr::CgroupSockAddr -pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sock_addr::CgroupSockAddr pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sock_addr::CgroupSockAddr +pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sock_addr::CgroupSockAddr pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sock_addr::CgroupSockAddr pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::drop(&mut self) @@ -5762,11 +5762,13 @@ pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sockopt::CgroupSockopt::take_link(&mut self, link_id: aya::programs::cgroup_sockopt::CgroupSockoptLinkId) -> core::result::Result impl aya::programs::cgroup_sockopt::CgroupSockopt -pub fn aya::programs::cgroup_sockopt::CgroupSockopt::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sockopt::CgroupSockopt::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sockopt::CgroupSockopt::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sockopt::CgroupSockopt +pub fn aya::programs::cgroup_sockopt::CgroupSockopt::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::drop(&mut self) @@ -5806,13 +5808,15 @@ pub fn aya::programs::cgroup_sysctl::CgroupSysctl::detach(&mut self, link_id: ay pub fn aya::programs::cgroup_sysctl::CgroupSysctl::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sysctl::CgroupSysctl::take_link(&mut self, link_id: aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> core::result::Result impl aya::programs::cgroup_sysctl::CgroupSysctl -pub fn aya::programs::cgroup_sysctl::CgroupSysctl::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sysctl::CgroupSysctl::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::from_pin>(path: P) -> core::result::Result impl aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sysctl::CgroupSysctl::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sysctl::CgroupSysctl +pub fn aya::programs::cgroup_sysctl::CgroupSysctl::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::drop(&mut self) @@ -5848,18 +5852,20 @@ pub fn aya::programs::cgroup_sysctl::CgroupSysctl::from(t: T) -> T pub struct aya::programs::Extension impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::attach(&mut self) -> core::result::Result -pub fn aya::programs::extension::Extension::attach_to_program(&mut self, program: aya::programs::ProgramFd, func_name: &str) -> core::result::Result +pub fn aya::programs::extension::Extension::attach_to_program(&mut self, program: &aya::programs::ProgramFd, func_name: &str) -> core::result::Result pub fn aya::programs::extension::Extension::detach(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::extension::Extension::load(&mut self, program: aya::programs::ProgramFd, func_name: &str) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::extension::Extension::take_link(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result impl aya::programs::extension::Extension -pub fn aya::programs::extension::Extension::fd(&self) -> core::option::Option +pub fn aya::programs::extension::Extension::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::from_pin>(path: P) -> core::result::Result impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::extension::Extension::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::extension::Extension +pub fn aya::programs::extension::Extension::program_info(&self) -> core::result::Result +impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::extension::Extension pub fn aya::programs::extension::Extension::drop(&mut self) @@ -5899,13 +5905,15 @@ pub fn aya::programs::fentry::FEntry::detach(&mut self, link_id: aya::programs:: pub fn aya::programs::fentry::FEntry::load(&mut self, fn_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::fentry::FEntry::take_link(&mut self, link_id: aya::programs::fentry::FEntryLinkId) -> core::result::Result impl aya::programs::fentry::FEntry -pub fn aya::programs::fentry::FEntry::fd(&self) -> core::option::Option +pub fn aya::programs::fentry::FEntry::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::from_pin>(path: P) -> core::result::Result impl aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::fentry::FEntry::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::fentry::FEntry +pub fn aya::programs::fentry::FEntry::program_info(&self) -> core::result::Result +impl aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::drop(&mut self) @@ -5945,13 +5953,15 @@ pub fn aya::programs::fexit::FExit::detach(&mut self, link_id: aya::programs::fe pub fn aya::programs::fexit::FExit::load(&mut self, fn_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::fexit::FExit::take_link(&mut self, link_id: aya::programs::fexit::FExitLinkId) -> core::result::Result impl aya::programs::fexit::FExit -pub fn aya::programs::fexit::FExit::fd(&self) -> core::option::Option +pub fn aya::programs::fexit::FExit::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::from_pin>(path: P) -> core::result::Result impl aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::fexit::FExit::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::fexit::FExit +pub fn aya::programs::fexit::FExit::program_info(&self) -> core::result::Result +impl aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::drop(&mut self) @@ -5993,11 +6003,13 @@ pub fn aya::programs::kprobe::KProbe::kind(&self) -> aya::programs::ProbeKind pub fn aya::programs::kprobe::KProbe::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::kprobe::KProbe::take_link(&mut self, link_id: aya::programs::kprobe::KProbeLinkId) -> core::result::Result impl aya::programs::kprobe::KProbe -pub fn aya::programs::kprobe::KProbe::fd(&self) -> core::option::Option +pub fn aya::programs::kprobe::KProbe::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::kprobe::KProbe::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::kprobe::KProbe +pub fn aya::programs::kprobe::KProbe::program_info(&self) -> core::result::Result +impl aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::drop(&mut self) @@ -6038,13 +6050,15 @@ pub fn aya::programs::lirc_mode2::LircMode2::load(&mut self) -> core::result::Re pub fn aya::programs::lirc_mode2::LircMode2::query(target_fd: T) -> core::result::Result, aya::programs::ProgramError> pub fn aya::programs::lirc_mode2::LircMode2::take_link(&mut self, link_id: aya::programs::lirc_mode2::LircLinkId) -> core::result::Result impl aya::programs::lirc_mode2::LircMode2 -pub fn aya::programs::lirc_mode2::LircMode2::fd(&self) -> core::option::Option +pub fn aya::programs::lirc_mode2::LircMode2::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::from_pin>(path: P) -> core::result::Result impl aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::lirc_mode2::LircMode2::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::lirc_mode2::LircMode2 +pub fn aya::programs::lirc_mode2::LircMode2::program_info(&self) -> core::result::Result +impl aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::drop(&mut self) @@ -6084,13 +6098,15 @@ pub fn aya::programs::lsm::Lsm::detach(&mut self, link_id: aya::programs::lsm::L pub fn aya::programs::lsm::Lsm::load(&mut self, lsm_hook_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::lsm::Lsm::take_link(&mut self, link_id: aya::programs::lsm::LsmLinkId) -> core::result::Result impl aya::programs::lsm::Lsm -pub fn aya::programs::lsm::Lsm::fd(&self) -> core::option::Option +pub fn aya::programs::lsm::Lsm::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::from_pin>(path: P) -> core::result::Result impl aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::lsm::Lsm::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::lsm::Lsm +pub fn aya::programs::lsm::Lsm::program_info(&self) -> core::result::Result +impl aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::drop(&mut self) @@ -6130,13 +6146,15 @@ pub fn aya::programs::perf_event::PerfEvent::detach(&mut self, link_id: aya::pro pub fn aya::programs::perf_event::PerfEvent::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::perf_event::PerfEvent::take_link(&mut self, link_id: aya::programs::perf_event::PerfEventLinkId) -> core::result::Result impl aya::programs::perf_event::PerfEvent -pub fn aya::programs::perf_event::PerfEvent::fd(&self) -> core::option::Option +pub fn aya::programs::perf_event::PerfEvent::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::from_pin>(path: P) -> core::result::Result impl aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::perf_event::PerfEvent::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::perf_event::PerfEvent +pub fn aya::programs::perf_event::PerfEvent::program_info(&self) -> core::result::Result +impl aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::drop(&mut self) @@ -6170,11 +6188,12 @@ pub fn aya::programs::perf_event::PerfEvent::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::from(t: T) -> T pub struct aya::programs::ProgramFd(_) -impl std::os::fd::raw::AsRawFd for aya::programs::ProgramFd -pub fn aya::programs::ProgramFd::as_raw_fd(&self) -> std::os::fd::raw::RawFd -impl core::clone::Clone for aya::programs::ProgramFd -pub fn aya::programs::ProgramFd::clone(&self) -> aya::programs::ProgramFd -impl core::marker::Copy for aya::programs::ProgramFd +impl aya::programs::ProgramFd +pub fn aya::programs::ProgramFd::try_clone(&self) -> core::result::Result +impl std::os::fd::owned::AsFd for aya::programs::ProgramFd +pub fn aya::programs::ProgramFd::as_fd(&self) -> std::os::fd::owned::BorrowedFd<'_> +impl core::fmt::Debug for aya::programs::ProgramFd +pub fn aya::programs::ProgramFd::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Send for aya::programs::ProgramFd impl core::marker::Sync for aya::programs::ProgramFd impl core::marker::Unpin for aya::programs::ProgramFd @@ -6188,10 +6207,6 @@ pub fn aya::programs::ProgramFd::try_from(value: U) -> core::result::Result core::convert::TryInto for aya::programs::ProgramFd where U: core::convert::TryFrom pub type aya::programs::ProgramFd::Error = >::Error pub fn aya::programs::ProgramFd::try_into(self) -> core::result::Result>::Error> -impl alloc::borrow::ToOwned for aya::programs::ProgramFd where T: core::clone::Clone -pub type aya::programs::ProgramFd::Owned = T -pub fn aya::programs::ProgramFd::clone_into(&self, target: &mut T) -pub fn aya::programs::ProgramFd::to_owned(&self) -> T impl core::any::Any for aya::programs::ProgramFd where T: 'static + core::marker::Sized pub fn aya::programs::ProgramFd::type_id(&self) -> core::any::TypeId impl core::borrow::Borrow for aya::programs::ProgramFd where T: core::marker::Sized @@ -6202,11 +6217,21 @@ impl core::convert::From for aya::programs::ProgramFd pub fn aya::programs::ProgramFd::from(t: T) -> T pub struct aya::programs::ProgramInfo(_) impl aya::programs::ProgramInfo -pub fn aya::programs::ProgramInfo::fd(&self) -> core::result::Result +pub fn aya::programs::ProgramInfo::btf_id(&self) -> core::option::Option +pub fn aya::programs::ProgramInfo::fd(&self) -> core::result::Result pub fn aya::programs::ProgramInfo::from_pin>(path: P) -> core::result::Result +pub fn aya::programs::ProgramInfo::gpl_compatible(&self) -> bool pub fn aya::programs::ProgramInfo::id(&self) -> u32 +pub fn aya::programs::ProgramInfo::loaded_at(&self) -> std::time::SystemTime +pub fn aya::programs::ProgramInfo::map_ids(&self) -> core::result::Result, aya::programs::ProgramError> +pub fn aya::programs::ProgramInfo::memory_locked(&self) -> core::result::Result pub fn aya::programs::ProgramInfo::name(&self) -> &[u8] pub fn aya::programs::ProgramInfo::name_as_str(&self) -> core::option::Option<&str> +pub fn aya::programs::ProgramInfo::program_type(&self) -> u32 +pub fn aya::programs::ProgramInfo::size_jitted(&self) -> u32 +pub fn aya::programs::ProgramInfo::size_translated(&self) -> u32 +pub fn aya::programs::ProgramInfo::tag(&self) -> u64 +pub fn aya::programs::ProgramInfo::verified_instruction_count(&self) -> u32 impl core::fmt::Debug for aya::programs::ProgramInfo pub fn aya::programs::ProgramInfo::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Send for aya::programs::ProgramInfo @@ -6237,13 +6262,15 @@ pub fn aya::programs::RawTracePoint::detach(&mut self, link_id: RawTracePointLin pub fn aya::programs::RawTracePoint::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::RawTracePoint::take_link(&mut self, link_id: RawTracePointLinkId) -> core::result::Result impl aya::programs::RawTracePoint -pub fn aya::programs::RawTracePoint::fd(&self) -> core::option::Option +pub fn aya::programs::RawTracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::RawTracePoint pub fn aya::programs::RawTracePoint::from_pin>(path: P) -> core::result::Result impl aya::programs::RawTracePoint pub fn aya::programs::RawTracePoint::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::RawTracePoint::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::RawTracePoint +pub fn aya::programs::RawTracePoint::program_info(&self) -> core::result::Result +impl aya::programs::RawTracePoint pub fn aya::programs::RawTracePoint::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::RawTracePoint pub fn aya::programs::RawTracePoint::drop(&mut self) @@ -6285,11 +6312,13 @@ pub fn aya::programs::tc::SchedClassifier::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::tc::SchedClassifier::take_link(&mut self, link_id: aya::programs::tc::SchedClassifierLinkId) -> core::result::Result impl aya::programs::tc::SchedClassifier -pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::option::Option +pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::tc::SchedClassifier::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::tc::SchedClassifier +pub fn aya::programs::tc::SchedClassifier::program_info(&self) -> core::result::Result +impl aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::drop(&mut self) @@ -6329,13 +6358,15 @@ pub fn aya::programs::SkLookup::detach(&mut self, link_id: SkLookupLinkId) -> co pub fn aya::programs::SkLookup::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::SkLookup::take_link(&mut self, link_id: SkLookupLinkId) -> core::result::Result impl aya::programs::SkLookup -pub fn aya::programs::SkLookup::fd(&self) -> core::option::Option +pub fn aya::programs::SkLookup::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::SkLookup pub fn aya::programs::SkLookup::from_pin>(path: P) -> core::result::Result impl aya::programs::SkLookup pub fn aya::programs::SkLookup::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::SkLookup::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::SkLookup +pub fn aya::programs::SkLookup::program_info(&self) -> core::result::Result +impl aya::programs::SkLookup pub fn aya::programs::SkLookup::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::SkLookup pub fn aya::programs::SkLookup::drop(&mut self) @@ -6375,13 +6406,15 @@ pub fn aya::programs::SkMsg::detach(&mut self, link_id: SkMsgLinkId) -> core::re pub fn aya::programs::SkMsg::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::SkMsg::take_link(&mut self, link_id: SkMsgLinkId) -> core::result::Result impl aya::programs::SkMsg -pub fn aya::programs::SkMsg::fd(&self) -> core::option::Option +pub fn aya::programs::SkMsg::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::SkMsg pub fn aya::programs::SkMsg::from_pin>(path: P) -> core::result::Result impl aya::programs::SkMsg pub fn aya::programs::SkMsg::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::SkMsg::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::SkMsg +pub fn aya::programs::SkMsg::program_info(&self) -> core::result::Result +impl aya::programs::SkMsg pub fn aya::programs::SkMsg::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::SkMsg pub fn aya::programs::SkMsg::drop(&mut self) @@ -6422,11 +6455,13 @@ pub fn aya::programs::SkSkb::from_pin>( pub fn aya::programs::SkSkb::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::SkSkb::take_link(&mut self, link_id: SkSkbLinkId) -> core::result::Result impl aya::programs::SkSkb -pub fn aya::programs::SkSkb::fd(&self) -> core::option::Option +pub fn aya::programs::SkSkb::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::SkSkb pub fn aya::programs::SkSkb::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::SkSkb::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::SkSkb +pub fn aya::programs::SkSkb::program_info(&self) -> core::result::Result +impl aya::programs::SkSkb pub fn aya::programs::SkSkb::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::SkSkb pub fn aya::programs::SkSkb::drop(&mut self) @@ -6466,13 +6501,15 @@ pub fn aya::programs::SockOps::detach(&mut self, link_id: SockOpsLinkId) -> core pub fn aya::programs::SockOps::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::SockOps::take_link(&mut self, link_id: SockOpsLinkId) -> core::result::Result impl aya::programs::SockOps -pub fn aya::programs::SockOps::fd(&self) -> core::option::Option +pub fn aya::programs::SockOps::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::SockOps pub fn aya::programs::SockOps::from_pin>(path: P) -> core::result::Result impl aya::programs::SockOps pub fn aya::programs::SockOps::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::SockOps::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::SockOps +pub fn aya::programs::SockOps::program_info(&self) -> core::result::Result +impl aya::programs::SockOps pub fn aya::programs::SockOps::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::SockOps pub fn aya::programs::SockOps::drop(&mut self) @@ -6512,13 +6549,15 @@ pub fn aya::programs::SocketFilter::detach(&mut self, link_id: SocketFilterLinkI pub fn aya::programs::SocketFilter::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::SocketFilter::take_link(&mut self, link_id: SocketFilterLinkId) -> core::result::Result impl aya::programs::SocketFilter -pub fn aya::programs::SocketFilter::fd(&self) -> core::option::Option +pub fn aya::programs::SocketFilter::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::SocketFilter pub fn aya::programs::SocketFilter::from_pin>(path: P) -> core::result::Result impl aya::programs::SocketFilter pub fn aya::programs::SocketFilter::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::SocketFilter::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::SocketFilter +pub fn aya::programs::SocketFilter::program_info(&self) -> core::result::Result +impl aya::programs::SocketFilter pub fn aya::programs::SocketFilter::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::SocketFilter pub fn aya::programs::SocketFilter::drop(&mut self) @@ -6558,13 +6597,15 @@ pub fn aya::programs::trace_point::TracePoint::detach(&mut self, link_id: aya::p pub fn aya::programs::trace_point::TracePoint::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::trace_point::TracePoint::take_link(&mut self, link_id: aya::programs::trace_point::TracePointLinkId) -> core::result::Result impl aya::programs::trace_point::TracePoint -pub fn aya::programs::trace_point::TracePoint::fd(&self) -> core::option::Option +pub fn aya::programs::trace_point::TracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::from_pin>(path: P) -> core::result::Result impl aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::trace_point::TracePoint::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::trace_point::TracePoint +pub fn aya::programs::trace_point::TracePoint::program_info(&self) -> core::result::Result +impl aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::drop(&mut self) @@ -6606,11 +6647,13 @@ pub fn aya::programs::uprobe::UProbe::kind(&self) -> aya::programs::ProbeKind pub fn aya::programs::uprobe::UProbe::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::uprobe::UProbe::take_link(&mut self, link_id: aya::programs::uprobe::UProbeLinkId) -> core::result::Result impl aya::programs::uprobe::UProbe -pub fn aya::programs::uprobe::UProbe::fd(&self) -> core::option::Option +pub fn aya::programs::uprobe::UProbe::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::uprobe::UProbe pub fn aya::programs::uprobe::UProbe::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::uprobe::UProbe::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::uprobe::UProbe +pub fn aya::programs::uprobe::UProbe::program_info(&self) -> core::result::Result +impl aya::programs::uprobe::UProbe pub fn aya::programs::uprobe::UProbe::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::uprobe::UProbe pub fn aya::programs::uprobe::UProbe::drop(&mut self) @@ -6652,13 +6695,15 @@ pub fn aya::programs::xdp::Xdp::detach(&mut self, link_id: aya::programs::xdp::X pub fn aya::programs::xdp::Xdp::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::xdp::Xdp::take_link(&mut self, link_id: aya::programs::xdp::XdpLinkId) -> core::result::Result impl aya::programs::xdp::Xdp -pub fn aya::programs::xdp::Xdp::fd(&self) -> core::option::Option +pub fn aya::programs::xdp::Xdp::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::from_pin>(path: P) -> core::result::Result impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::xdp::Xdp::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::xdp::Xdp +pub fn aya::programs::xdp::Xdp::program_info(&self) -> core::result::Result +impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::drop(&mut self) @@ -6781,9 +6826,6 @@ impl core::marker::Sync for aya::programs::xdp::XdpFlags impl core::marker::Unpin for aya::programs::xdp::XdpFlags impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::xdp::XdpFlags impl core::panic::unwind_safe::UnwindSafe for aya::programs::xdp::XdpFlags -impl bitflags::traits::BitFlags for aya::programs::xdp::XdpFlags where B: bitflags::traits::Flags -pub type aya::programs::xdp::XdpFlags::Iter = bitflags::iter::Iter -pub type aya::programs::xdp::XdpFlags::IterNames = bitflags::iter::IterNames impl core::convert::Into for aya::programs::xdp::XdpFlags where U: core::convert::From pub fn aya::programs::xdp::XdpFlags::into(self) -> U impl core::convert::TryFrom for aya::programs::xdp::XdpFlags where U: core::convert::Into @@ -6935,11 +6977,10 @@ impl core::borrow::BorrowMut for aya::util::KernelVersion where T: core::m pub fn aya::util::KernelVersion::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::util::KernelVersion pub fn aya::util::KernelVersion::from(t: T) -> T -pub fn aya::util::kernel_symbols() -> core::result::Result +pub fn aya::util::kernel_symbols() -> core::result::Result, std::io::error::Error> pub fn aya::util::nr_cpus() -> core::result::Result pub fn aya::util::online_cpus() -> core::result::Result, std::io::error::Error> pub fn aya::util::syscall_prefix() -> core::result::Result<&'static str, std::io::error::Error> -pub type aya::util::SimpleSymbolResolver = alloc::collections::btree::map::BTreeMap pub macro aya::include_bytes_aligned! pub enum aya::BpfError pub aya::BpfError::BtfError(aya_obj::btf::btf::BtfError) @@ -6980,8 +7021,6 @@ impl core::marker::Sync for aya::BpfError impl core::marker::Unpin for aya::BpfError impl !core::panic::unwind_safe::RefUnwindSafe for aya::BpfError impl !core::panic::unwind_safe::UnwindSafe for aya::BpfError -impl core::any::Provider for aya::BpfError where E: core::error::Error + core::marker::Sized -pub fn aya::BpfError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::BpfError where U: core::convert::From pub fn aya::BpfError::into(self) -> U impl core::convert::TryFrom for aya::BpfError where U: core::convert::Into @@ -7187,9 +7226,6 @@ impl core::marker::Sync for aya::VerifierLogLevel impl core::marker::Unpin for aya::VerifierLogLevel impl core::panic::unwind_safe::RefUnwindSafe for aya::VerifierLogLevel impl core::panic::unwind_safe::UnwindSafe for aya::VerifierLogLevel -impl bitflags::traits::BitFlags for aya::VerifierLogLevel where B: bitflags::traits::Flags -pub type aya::VerifierLogLevel::Iter = bitflags::iter::Iter -pub type aya::VerifierLogLevel::IterNames = bitflags::iter::IterNames impl core::convert::Into for aya::VerifierLogLevel where U: core::convert::From pub fn aya::VerifierLogLevel::into(self) -> U impl core::convert::TryFrom for aya::VerifierLogLevel where U: core::convert::Into diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 09db4cbc..9e5c8737 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Context as _, Result}; +use anyhow::{bail, Context as _, Result}; use std::{ fs, path::{Path, PathBuf}, @@ -13,13 +13,10 @@ pub fn exec(cmd: &mut Command) -> Result<()> { let status = cmd .status() .with_context(|| format!("failed to run {cmd:?}"))?; - match status.code() { - Some(code) => match code { - 0 => Ok(()), - code => Err(anyhow!("{cmd:?} exited with code {code}")), - }, - None => Err(anyhow!("{cmd:?} terminated by signal")), + if status.code() != Some(0) { + bail!("{cmd:?} failed: {status:?}") } + Ok(()) } // Create a symlink in the out directory to work around the fact that cargo ignores anything diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 3f93d692..01105c00 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -19,7 +19,6 @@ pub struct XtaskOptions { enum Subcommand { Codegen(codegen::Options), Docs, - BuildIntegrationTest(run::BuildOptions), IntegrationTest(run::Options), PublicApi(public_api::Options), } @@ -45,17 +44,6 @@ fn main() -> Result<()> { match command { Subcommand::Codegen(opts) => codegen::codegen(opts, libbpf_dir), Subcommand::Docs => docs::docs(metadata), - Subcommand::BuildIntegrationTest(opts) => { - let binaries = run::build(opts)?; - let mut stdout = std::io::stdout(); - for (_name, binary) in binaries { - use std::{io::Write as _, os::unix::ffi::OsStrExt as _}; - - stdout.write_all(binary.as_os_str().as_bytes())?; - stdout.write_all("\n".as_bytes())?; - } - Ok(()) - } Subcommand::IntegrationTest(opts) => run::run(opts), Subcommand::PublicApi(opts) => public_api::public_api(opts, metadata), } diff --git a/xtask/src/public_api.rs b/xtask/src/public_api.rs index 56db350b..b5b58f07 100644 --- a/xtask/src/public_api.rs +++ b/xtask/src/public_api.rs @@ -62,7 +62,7 @@ pub fn public_api(options: Options, metadata: Metadata) -> Result<()> { }); if !errors.is_empty() { - bail!("public API errors:\n{errors}"); + bail!("public API errors:\n{errors}") } Ok(()) } diff --git a/xtask/src/run.rs b/xtask/src/run.rs index 7a29ad5f..15ee7035 100644 --- a/xtask/src/run.rs +++ b/xtask/src/run.rs @@ -1,47 +1,68 @@ use std::{ + env::consts::{ARCH, OS}, ffi::OsString, fmt::Write as _, - io::BufReader, - path::PathBuf, - process::{Child, Command, Stdio}, + fs::{copy, create_dir_all, metadata, File}, + io::{BufRead as _, BufReader, ErrorKind, Write as _}, + path::{Path, PathBuf}, + process::{Child, ChildStdin, Command, Output, Stdio}, + sync::{Arc, Mutex}, + thread, }; -use anyhow::{bail, Context as _, Result}; +use anyhow::{anyhow, bail, Context as _, Result}; use cargo_metadata::{Artifact, CompilerMessage, Message, Target}; use clap::Parser; -use xtask::AYA_BUILD_INTEGRATION_BPF; +use xtask::{exec, AYA_BUILD_INTEGRATION_BPF}; -#[derive(Debug, Parser)] -pub struct BuildOptions { - /// Arguments to pass to `cargo build`. - #[clap(long)] - pub cargo_arg: Vec, +#[derive(Parser)] +enum Environment { + /// Runs the integration tests locally. + Local { + /// The command used to wrap your application. + #[clap(short, long, default_value = "sudo -E")] + runner: String, + }, + /// Runs the integration tests in a VM. + VM { + /// The kernel images to use. + /// + /// You can download some images with: + /// + /// wget --accept-regex '.*/linux-image-[0-9\.-]+-cloud-.*-unsigned*' \ + /// --recursive ftp://ftp.us.debian.org/debian/pool/main/l/linux/ + /// + /// You can then extract them with: + /// + /// find . -name '*.deb' -print0 \ + /// | xargs -0 -I {} sh -c "dpkg --fsys-tarfile {} \ + /// | tar --wildcards --extract '*vmlinuz*' --file -" + #[clap(required = true)] + kernel_image: Vec, + }, } -#[derive(Debug, Parser)] +#[derive(Parser)] pub struct Options { - #[command(flatten)] - pub build_options: BuildOptions, - /// The command used to wrap your application. - #[clap(short, long, default_value = "sudo -E")] - pub runner: String, + #[clap(subcommand)] + environment: Environment, /// Arguments to pass to your application. - #[clap(last = true)] - pub run_args: Vec, + #[clap(global = true, last = true)] + run_args: Vec, } -/// Build the project -pub fn build(opts: BuildOptions) -> Result> { - let BuildOptions { cargo_arg } = opts; +pub fn build(target: Option<&str>, f: F) -> Result> +where + F: FnOnce(&mut Command) -> &mut Command, +{ + // Always use rust-lld and -Zbuild-std in case we're cross-compiling. let mut cmd = Command::new("cargo"); - cmd.env(AYA_BUILD_INTEGRATION_BPF, "true") - .args([ - "build", - "--tests", - "--message-format=json", - "--package=integration-test", - ]) - .args(cargo_arg); + cmd.args(["build", "--message-format=json"]); + if let Some(target) = target { + let config = format!("target.{target}.linker = \"rust-lld\""); + cmd.args(["--target", target, "--config", &config]); + } + f(&mut cmd); let mut child = cmd .stdout(Stdio::piped()) @@ -77,57 +98,457 @@ pub fn build(opts: BuildOptions) -> Result> { let status = child .wait() .with_context(|| format!("failed to wait for {cmd:?}"))?; - match status.code() { - Some(code) => match code { - 0 => {} - code => bail!("{cmd:?} exited with status code {code}"), - }, - None => bail!("{cmd:?} terminated by signal"), + if status.code() != Some(0) { + bail!("{cmd:?} failed: {status:?}") } - Ok(executables) } -/// Build and run the project +#[derive(Debug)] +struct Errors(Vec); + +impl std::fmt::Display for Errors { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self(errors) = self; + for (i, error) in errors.iter().enumerate() { + if i != 0 { + writeln!(f)?; + } + write!(f, "{:?}", error)?; + } + Ok(()) + } +} + +impl std::error::Error for Errors {} + +/// Build and run the project. pub fn run(opts: Options) -> Result<()> { let Options { - build_options, - runner, + environment, run_args, } = opts; - let binaries = build(build_options).context("error while building userspace application")?; - let mut args = runner.trim().split_terminator(' '); - let runner = args.next().ok_or(anyhow::anyhow!("no first argument"))?; - let args = args.collect::>(); - - let mut failures = String::new(); - for (name, binary) in binaries { - let mut cmd = Command::new(runner); - let cmd = cmd - .args(args.iter()) - .arg(binary) - .args(run_args.iter()) - .arg("--test-threads=1"); - - println!("{} running {cmd:?}", name); - - let status = cmd - .status() - .with_context(|| format!("failed to run {cmd:?}"))?; - match status.code() { - Some(code) => match code { - 0 => {} - code => writeln!(&mut failures, "{} exited with status code {code}", name) - .context("String write failed")?, - }, - None => writeln!(&mut failures, "{} terminated by signal", name) - .context("String write failed")?, - } + type Binary = (String, PathBuf); + fn binaries(target: Option<&str>) -> Result)>> { + ["dev", "release"] + .into_iter() + .map(|profile| { + let binaries = build(target, |cmd| { + cmd.env(AYA_BUILD_INTEGRATION_BPF, "true").args([ + "--package", + "integration-test", + "--tests", + "--profile", + profile, + ]) + })?; + anyhow::Ok((profile, binaries)) + }) + .collect() } - if failures.is_empty() { - Ok(()) - } else { - Err(anyhow::anyhow!("failures:\n{}", failures)) + + // Use --test-threads=1 to prevent tests from interacting with shared + // kernel state due to the lack of inter-test isolation. + let default_args = [OsString::from("--test-threads=1")]; + let run_args = default_args.iter().chain(run_args.iter()); + + match environment { + Environment::Local { runner } => { + let mut args = runner.trim().split_terminator(' '); + let runner = args.next().ok_or(anyhow!("no first argument"))?; + let args = args.collect::>(); + + let binaries = binaries(None)?; + + let mut failures = String::new(); + for (profile, binaries) in binaries { + for (name, binary) in binaries { + let mut cmd = Command::new(runner); + let cmd = cmd.args(args.iter()).arg(binary).args(run_args.clone()); + + println!("{profile}:{name} running {cmd:?}"); + + let status = cmd + .status() + .with_context(|| format!("failed to run {cmd:?}"))?; + if status.code() != Some(0) { + writeln!(&mut failures, "{profile}:{name} failed: {status:?}") + .context("String write failed")? + } + } + } + if failures.is_empty() { + Ok(()) + } else { + Err(anyhow!("failures:\n{}", failures)) + } + } + Environment::VM { kernel_image } => { + // The user has asked us to run the tests on a VM. This is involved; strap in. + // + // We need tools to build the initramfs; we use gen_init_cpio from the Linux repository, + // taking care to cache it. + // + // Then we iterate the kernel images, using the `file` program to guess the target + // architecture. We then build the init program and our test binaries for that + // architecture, and use gen_init_cpio to build an initramfs containing the test + // binaries. We're almost ready to run the VM. + // + // We consult our OS, our architecture, and the target architecture to determine if + // hardware acceleration is available, and then start QEMU with the provided kernel + // image and the initramfs we built. + // + // We consume the output of QEMU, looking for the output of our init program. This is + // the only way to distinguish success from failure. We batch up the errors across all + // VM images and report to the user. The end. + let cache_dir = Path::new("test/.tmp"); + create_dir_all(cache_dir).context("failed to create cache dir")?; + let gen_init_cpio = cache_dir.join("gen_init_cpio"); + if !gen_init_cpio + .try_exists() + .context("failed to check existence of gen_init_cpio")? + { + let mut curl = Command::new("curl"); + curl.args([ + "-sfSL", + "https://raw.githubusercontent.com/torvalds/linux/master/usr/gen_init_cpio.c", + ]); + let mut curl_child = curl + .stdout(Stdio::piped()) + .spawn() + .with_context(|| format!("failed to spawn {curl:?}"))?; + let Child { stdout, .. } = &mut curl_child; + let curl_stdout = stdout.take().unwrap(); + + let mut clang = Command::new("clang"); + let clang = exec( + clang + .args(["-g", "-O2", "-x", "c", "-", "-o"]) + .arg(&gen_init_cpio) + .stdin(curl_stdout), + ); + + let output = curl_child + .wait_with_output() + .with_context(|| format!("failed to wait for {curl:?}"))?; + let Output { status, .. } = &output; + if status.code() != Some(0) { + bail!("{curl:?} failed: {output:?}") + } + + // Check the result of clang *after* checking curl; in case the download failed, + // only curl's output will be useful. + clang?; + } + + let mut errors = Vec::new(); + for kernel_image in kernel_image { + // Guess the guest architecture. + let mut cmd = Command::new("file"); + let output = cmd + .arg("--brief") + .arg(&kernel_image) + .output() + .with_context(|| format!("failed to run {cmd:?}"))?; + let Output { status, .. } = &output; + if status.code() != Some(0) { + bail!("{cmd:?} failed: {output:?}") + } + let Output { stdout, .. } = output; + + // Now parse the output of the file command, which looks something like + // + // - Linux kernel ARM64 boot executable Image, little-endian, 4K pages + // + // - Linux kernel x86 boot executable bzImage, version 6.1.0-10-cloud-amd64 [..] + + let stdout = String::from_utf8(stdout) + .with_context(|| format!("invalid UTF-8 in {cmd:?} stdout"))?; + let (_, stdout) = stdout + .split_once("Linux kernel") + .ok_or_else(|| anyhow!("failed to parse {cmd:?} stdout: {stdout}"))?; + let (guest_arch, _) = stdout + .split_once("boot executable") + .ok_or_else(|| anyhow!("failed to parse {cmd:?} stdout: {stdout}"))?; + let guest_arch = guest_arch.trim(); + + let (guest_arch, machine, cpu) = match guest_arch { + "ARM64" => ("aarch64", Some("virt"), Some("cortex-a57")), + "x86" => ("x86_64", Some("q35"), Some("qemu64")), + guest_arch => (guest_arch, None, None), + }; + + let target = format!("{guest_arch}-unknown-linux-musl"); + + // Build our init program. The contract is that it will run anything it finds in /bin. + let init = build(Some(&target), |cmd| { + cmd.args(["--package", "init", "--profile", "release"]) + }) + .context("building init program failed")?; + + let init = match &*init { + [(name, init)] => { + if name != "init" { + bail!("expected init program to be named init, found {name}") + } + init + } + init => bail!("expected exactly one init program, found {init:?}"), + }; + + let binaries = binaries(Some(&target))?; + + let tmp_dir = tempfile::tempdir().context("tempdir failed")?; + + let initrd_image = tmp_dir.path().join("qemu-initramfs.img"); + let initrd_image_file = File::create(&initrd_image).with_context(|| { + format!("failed to create {} for writing", initrd_image.display()) + })?; + + let mut gen_init_cpio = Command::new(&gen_init_cpio); + let mut gen_init_cpio_child = gen_init_cpio + .arg("-") + .stdin(Stdio::piped()) + .stdout(initrd_image_file) + .spawn() + .with_context(|| format!("failed to spawn {gen_init_cpio:?}"))?; + let Child { stdin, .. } = &mut gen_init_cpio_child; + let mut stdin = stdin.take().unwrap(); + + use std::os::unix::ffi::OsStrExt as _; + + // Send input into gen_init_cpio which looks something like + // + // file /init path-to-init 0755 0 0 + // dir /bin 0755 0 0 + // file /bin/foo path-to-foo 0755 0 0 + // file /bin/bar path-to-bar 0755 0 0 + + for bytes in [ + "file /init ".as_bytes(), + init.as_os_str().as_bytes(), + " 0755 0 0\n".as_bytes(), + "dir /bin 0755 0 0\n".as_bytes(), + ] { + stdin.write_all(bytes).expect("write"); + } + + for (profile, binaries) in binaries { + for (name, binary) in binaries { + let name = format!("{}-{}", profile, name); + let path = tmp_dir.path().join(&name); + copy(&binary, &path).with_context(|| { + format!("copy({}, {}) failed", binary.display(), path.display()) + })?; + for bytes in [ + "file /bin/".as_bytes(), + name.as_bytes(), + " ".as_bytes(), + path.as_os_str().as_bytes(), + " 0755 0 0\n".as_bytes(), + ] { + stdin.write_all(bytes).expect("write"); + } + } + } + // Must explicitly close to signal EOF. + drop(stdin); + + let output = gen_init_cpio_child + .wait_with_output() + .with_context(|| format!("failed to wait for {gen_init_cpio:?}"))?; + let Output { status, .. } = &output; + if status.code() != Some(0) { + bail!("{gen_init_cpio:?} failed: {output:?}") + } + + copy(&initrd_image, "/tmp/initrd.img").context("copy failed")?; + + let mut qemu = Command::new(format!("qemu-system-{guest_arch}")); + if let Some(machine) = machine { + qemu.args(["-machine", machine]); + } + if guest_arch == ARCH { + match OS { + "linux" => match metadata("/dev/kvm") { + Ok(metadata) => { + use std::os::unix::fs::FileTypeExt as _; + if metadata.file_type().is_char_device() { + qemu.args(["-accel", "kvm"]); + } + } + Err(error) => { + if error.kind() != ErrorKind::NotFound { + Err(error).context("failed to check existence of /dev/kvm")?; + } + } + }, + "macos" => { + qemu.args(["-accel", "hvf"]); + } + os => bail!("unsupported OS: {os}"), + } + } else if let Some(cpu) = cpu { + qemu.args(["-cpu", cpu]); + } + let console = OsString::from("ttyS0"); + let mut kernel_args = std::iter::once(("console", &console)) + .chain(run_args.clone().map(|run_arg| ("init.arg", run_arg))) + .enumerate() + .fold(OsString::new(), |mut acc, (i, (k, v))| { + if i != 0 { + acc.push(" "); + } + acc.push(k); + acc.push("="); + acc.push(v); + acc + }); + // We sometimes see kernel panics containing: + // + // [ 0.064000] Kernel panic - not syncing: IO-APIC + timer doesn't work! Boot with apic=debug and send a report. Then try booting with the 'noapic' option. + // + // Heed the advice and boot with noapic. We don't know why this happens. + kernel_args.push(" noapic"); + qemu.args(["-no-reboot", "-nographic", "-m", "512M", "-smp", "2"]) + .arg("-append") + .arg(kernel_args) + .arg("-kernel") + .arg(&kernel_image) + .arg("-initrd") + .arg(&initrd_image); + if guest_arch == "aarch64" { + match OS { + "linux" => { + let mut cmd = Command::new("locate"); + let output = cmd + .arg("QEMU_EFI.fd") + .output() + .with_context(|| format!("failed to run {cmd:?}"))?; + let Output { status, .. } = &output; + if status.code() != Some(0) { + bail!("{qemu:?} failed: {output:?}") + } + let Output { stdout, .. } = output; + let bios = String::from_utf8(stdout) + .with_context(|| format!("failed to parse output of {cmd:?}"))?; + qemu.args(["-bios", bios.trim()]); + } + "macos" => { + let mut cmd = Command::new("brew"); + let output = cmd + .args(["list", "qemu", "-1", "-v"]) + .output() + .with_context(|| format!("failed to run {cmd:?}"))?; + let Output { status, .. } = &output; + if status.code() != Some(0) { + bail!("{qemu:?} failed: {output:?}") + } + let Output { stdout, .. } = output; + let output = String::from_utf8(stdout) + .with_context(|| format!("failed to parse output of {cmd:?}"))?; + const NAME: &str = "edk2-aarch64-code.fd"; + let bios = output.lines().find(|line| line.contains(NAME)).ok_or_else( + || anyhow!("failed to find {NAME} in output of {cmd:?}: {output}"), + )?; + qemu.args(["-bios", bios.trim()]); + } + os => bail!("unsupported OS: {os}"), + }; + } + let mut qemu_child = qemu + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .with_context(|| format!("failed to spawn {qemu:?}"))?; + let Child { + stdin, + stdout, + stderr, + .. + } = &mut qemu_child; + let stdin = stdin.take().unwrap(); + let stdin = Arc::new(Mutex::new(stdin)); + let stdout = stdout.take().unwrap(); + let stdout = BufReader::new(stdout); + let stderr = stderr.take().unwrap(); + let stderr = BufReader::new(stderr); + + fn terminate_if_contains_kernel_panic( + line: &str, + stdin: &Arc>, + ) -> anyhow::Result<()> { + if line.contains("end Kernel panic") { + println!("kernel panic detected; terminating QEMU"); + let mut stdin = stdin.lock().unwrap(); + stdin + .write_all(&[0x01, b'x']) + .context("failed to write to stdin")?; + println!("waiting for QEMU to terminate"); + } + Ok(()) + } + + let stderr = { + let stdin = stdin.clone(); + thread::Builder::new() + .spawn(move || { + for line in stderr.lines() { + let line = line.context("failed to read line from stderr")?; + eprintln!("{}", line); + // Try to get QEMU to exit on kernel panic; otherwise it might hang indefinitely. + terminate_if_contains_kernel_panic(&line, &stdin)?; + } + anyhow::Ok(()) + }) + .unwrap() + }; + + let mut outcome = None; + for line in stdout.lines() { + let line = line.context("failed to read line from stdout")?; + println!("{}", line); + // Try to get QEMU to exit on kernel panic; otherwise it might hang indefinitely. + terminate_if_contains_kernel_panic(&line, &stdin)?; + // The init program will print "init: success" or "init: failure" to indicate + // the outcome of running the binaries it found in /bin. + if let Some(line) = line.strip_prefix("init: ") { + let previous = match line { + "success" => outcome.replace(Ok(())), + "failure" => outcome.replace(Err(())), + line => bail!("unexpected init output: {}", line), + }; + if let Some(previous) = previous { + bail!("multiple exit status: previous={previous:?}, current={line}"); + } + } + } + + let output = qemu_child + .wait_with_output() + .with_context(|| format!("failed to wait for {qemu:?}"))?; + let Output { status, .. } = &output; + if status.code() != Some(0) { + bail!("{qemu:?} failed: {output:?}") + } + + stderr.join().unwrap()?; + + let outcome = outcome.ok_or(anyhow!("init did not exit"))?; + match outcome { + Ok(()) => {} + Err(()) => { + errors.push(anyhow!("VM binaries failed on {}", kernel_image.display())) + } + } + } + if errors.is_empty() { + Ok(()) + } else { + Err(Errors(errors).into()) + } + } } }